From cafa284b70e2f681d1e77d1c0f03e50ce9cf2b59 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 10 Nov 2025 13:51:41 +0100 Subject: [PATCH 001/234] [v8] Register %GetHoleNaN() and %GetUndefinedNaN() V8 side change: https://crrev.com/c/7137442 Bug: 457866804 Change-Id: Id01597d3194e4c88d38623f646c1671330e63b43 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8753396 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 8 ++++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 2 ++ Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift | 2 ++ 3 files changed, 12 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 4c83c2b31..ff5eb1df6 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -143,6 +143,14 @@ public let PretenureAllocationSiteGenerator = CodeGenerator("PretenureAllocation b.eval("%PretenureAllocationSite(%@)", with: [obj]); } +public let HoleNanGenerator = CodeGenerator("HoleNanGenerator") { b in + b.eval("%GetHoleNaN()", hasOutput: true); +} + +public let UndefinedNanGenerator = CodeGenerator("UndefinedNanGenerator") { b in + b.eval("%GetUndefinedNaN()", hasOutput: true); +} + public let MapTransitionFuzzer = ProgramTemplate("MapTransitionFuzzer") { b in // This template is meant to stress the v8 Map transition mechanisms. // Basically, it generates a bunch of CreateObject, GetProperty, SetProperty, FunctionDefinition, diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index b239caf55..abc30bdcf 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -66,6 +66,8 @@ let v8Profile = Profile( (WasmArrayGenerator, 15), (SharedObjectGenerator, 5), (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), ], additionalProgramTemplates: WeightedList([ diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 91ff6d8ea..daeb71525 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -476,6 +476,8 @@ let v8SandboxProfile = Profile( (WasmArrayGenerator, 5), (SharedObjectGenerator, 5), (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), ], additionalProgramTemplates: WeightedList([ From 6218da5b87677d333beb66abcd93e7cc7b0f4d91 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Wed, 12 Nov 2025 15:39:46 +0100 Subject: [PATCH 002/234] Refactoring: Use stub-state storage also for functions This replaces the separate logic for lastFunctionVariable with the generic runtimeData approach. This doesn't change behavior. Change-Id: I9cc988879638b423dabc99d4598028caacb6a3de Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8714836 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 28 ---------- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 55 +++++++++++-------- 2 files changed, 31 insertions(+), 52 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 940b8d4af..7d5e3ed08 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -134,17 +134,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 { @@ -4883,23 +4872,6 @@ public class ProgramBuilder { .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() default: assert(!instr.op.requiredContext.contains(.objectLiteral)) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index c31dfab81..ea2ff12cb 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -462,15 +462,16 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = probability(0.5) ? .parameters(n: 0) : b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + let f = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("functionArgsAccess", f) b.loadArguments() }, GeneratorStub("FunctionWithArgumentsAccessEndGenerator", inContext: .single([.javascript, .subroutine])) { b in // Ideally we would like to return the arguments Variable from above here. b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable b.emit(EndPlainFunction()) + let f = b.runtimeData.pop("functionArgsAccess") let args = b.randomJsVariables(n: Int.random(in: 0...5)) b.callFunction(f, withArgs: args) }, @@ -1200,13 +1201,14 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + let f = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("plainFunction", f) }, GeneratorStub("PlainFunctionEndGenerator", inContext: .single([.javascript, .subroutine])) { b in b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable b.emit(EndPlainFunction()) + let f = b.runtimeData.pop("plainFunction") let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) b.callFunction(f, withArgs: arguments, guard: !matches) }, @@ -1219,14 +1221,15 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + let f = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("strictFunction", f) b.directive("use strict") }, GeneratorStub("StrictModeFunctionEndGenerator", inContext: .single([.javascript, .subroutine])) { b in b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable b.emit(EndPlainFunction()) + let f = b.runtimeData.pop("strictFunction") let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) b.callFunction(f, withArgs: arguments, guard: !matches) }, @@ -1259,8 +1262,9 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginGeneratorFunction(parameters: randomParameters.parameters, functionName: nil)) + let f = b.emit( + BeginGeneratorFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("generatorFunction", f) }, GeneratorStub("GeneratorFunctionEndGenerator", inContext: .single([.generatorFunction, .subroutine, .javascript])) { b in if probability(0.5) { @@ -1272,8 +1276,8 @@ public let CodeGenerators: [CodeGenerator] = [ b.yieldEach(array) } b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable b.emit(EndGeneratorFunction()) + let f = b.runtimeData.pop("generatorFunction") let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) b.callFunction(f, withArgs: arguments, guard: !matches) }, @@ -1284,14 +1288,15 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)) + let f = b.emit( + BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("asyncFunction", f) }, 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 f = b.runtimeData.pop("asyncFunction") let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) b.callFunction(f, withArgs: arguments, guard: !matches) }, @@ -1335,9 +1340,10 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( + let f = b.emit( BeginAsyncGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) + parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("asyncGeneratorFunction", f) }, GeneratorStub("AsyncGeneratorFunctionEndGenerator", inContext: .single([.javascript, .subroutine, .generatorFunction, .asyncFunction])) { b in b.await(b.randomJsVariable()) @@ -1350,8 +1356,8 @@ public let CodeGenerators: [CodeGenerator] = [ b.yieldEach(array) } b.doReturn(b.randomJsVariable()) - let f = b.lastFunctionVariable b.emit(EndAsyncGeneratorFunction()) + let f = b.runtimeData.pop("asyncGeneratorFunction") let (arguments, matches) = b.randomArguments(forCallingGuardableFunction: f) b.callFunction(f, withArgs: arguments, guard: !matches) }, @@ -2519,13 +2525,13 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) - + let handler = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output + b.runtimeData.push("promiseHandler", handler) }, GeneratorStub("PromiseEndGenerator", inContext: .single([.subroutine, .javascript])) { b in - let handler = b.lastFunctionVariable b.emit(EndPlainFunction()) + let handler = b.runtimeData.pop("promiseHandler") let Promise = b.createNamedVariable(forBuiltin: "Promise") b.hide(Promise) // We want the promise to be used by following code generators, not the Promise constructor b.construct(Promise, withArgs: [handler]) @@ -2579,11 +2585,12 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("EvalGenerator", [ GeneratorStub("EvalBeginGenerator", provides: [.javascript]) { b in - b.emit(BeginCodeString()) + let code = b.emit(BeginCodeString()).output + b.runtimeData.push("codeToEval", code) }, GeneratorStub("EvalEndGenerator") { b in - let code = b.lastFunctionVariable b.emit(EndCodeString()) + let code = b.runtimeData.pop("codeToEval") let eval = b.createNamedVariable(forBuiltin: "eval") b.callFunction(eval, withArgs: [code]) }, From 0f911af266d45ce1c76d035a708fab272a1178c0 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 28 Oct 2025 15:59:12 +0100 Subject: [PATCH 003/234] Enable generating disposable class variables Similarly to objects as disposable variables, this enables generating instances of classes as disposable variables, used with both: `using` and `await using`. The generators have the new style and provide a class with a computed method with Symbol.dispose or Symbol.asyncDispose. As a fly-by, this also makes use of `b.runtimeData` to store the symbol of the existing generator for disposable objects. Bug: 446632644 Change-Id: I433ce357e4649230b803361e6fba15ca2cb954e2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8715016 Reviewed-by: Danylo Mocherniuk Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 6 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 99 +++++++++++++++++-- 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index c5e030303..a387c7097 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -47,8 +47,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, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index ea2ff12cb..dfb78c433 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Generator stubs for disposable and async-disposable variables. -func disposableVariableGeneratorStubs( +// Generator stubs for disposable and async-disposable object variables. +func disposableObjVariableGeneratorStubs( inContext contextRequirement : Context, withSymbol symbolProperty : String, genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { @@ -24,7 +24,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 +34,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 +60,69 @@ 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( + BeginClassInstanceComputedMethod( + parameters: parameters.parameters), + withInputs: [symbol]) + }, + GeneratorStub( + "DisposableClassInstanceComputedMethodEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]), + provides: [.classDefinition] + ) { b in + b.maybeReturnRandomJsVariable(0.9) + b.emit(EndClassInstanceComputedMethod()) + }, + 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. // @@ -478,16 +541,32 @@ public let CodeGenerators: [CodeGenerator] = [ ]), CodeGenerator( - "DisposableVariableGenerator", - disposableVariableGeneratorStubs( + "DisposableObjVariableGenerator", + disposableObjVariableGeneratorStubs( + inContext: .subroutine, + withSymbol: "dispose") { b, variable in + b.loadDisposableVariable(variable) + }), + + CodeGenerator( + "AsyncDisposableObjVariableGenerator", + disposableObjVariableGeneratorStubs( + inContext: .asyncFunction, + withSymbol: "asyncDispose") { b, variable in + b.loadAsyncDisposableVariable(variable) + }), + + CodeGenerator( + "DisposableClassVariableGenerator", + disposableClassVariableGeneratorStubs( inContext: .subroutine, withSymbol: "dispose") { b, variable in b.loadDisposableVariable(variable) }), CodeGenerator( - "AsyncDisposableVariableGenerator", - disposableVariableGeneratorStubs( + "AsyncDisposableClassVariableGenerator", + disposableClassVariableGeneratorStubs( inContext: .asyncFunction, withSymbol: "asyncDispose") { b, variable in b.loadAsyncDisposableVariable(variable) From 07403150c305ea014adbc8865cf6792ba4dd3a5a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 11 Nov 2025 12:44:01 +0100 Subject: [PATCH 004/234] [v8] Add code generator for various string shapes V8-side change: https://crrev.com/c/7137292 Bug: 455552707 Change-Id: Ifd5f44b69ef62f18ecfa03525e988bd2f43253cc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8756377 Commit-Queue: Matthias Liedtke Reviewed-by: Victor Gomes --- .../Profiles/V8CommonProfile.swift | 27 +++++++++++++++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 1 + .../Profiles/V8SandboxProfile.swift | 1 + 3 files changed, 29 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index ff5eb1df6..3018dd6ba 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -151,6 +151,33 @@ public let UndefinedNanGenerator = CodeGenerator("UndefinedNanGenerator") { b in b.eval("%GetUndefinedNaN()", hasOutput: true); } +public let StringShapeGenerator = CodeGenerator("StringShapeGenerator") { b in + withEqualProbability( + { + // Use one random input string (can be 1-byte or 2-byte etc.) and a predefined second + // string so that the string is guaranteed to be long enough for emitting a cons string. + let lhs = b.randomVariable(forUseAs: .jsString) + let rhs = b.loadString("ConsStringConcatenation") + b.hide(rhs) + b.eval("%ConstructConsString(%@, %@)", with: [lhs, rhs], hasOutput: true) + }, { + let str = b.loadString( + Bool.random() ? "Long enough 1-byte string" : "Long enoµgh 2-byte string") + b.hide(str) + let offset = b.loadInt(Int64.random(in: 1...5)) + b.eval("%ConstructSlicedString(%@, %@)", with: [str, offset], hasOutput: true) + }, { + let str = b.randomVariable(forUseAs: .jsString) + b.eval("%ConstructInternalizedString(%@)", with: [str], hasOutput: true) + }, { + let str = b.loadString( + Bool.random() ? "Long enough 1-byte string" : "Long enoµgh 2-byte string") + b.hide(str) + b.eval("%ConstructThinString(%@)", with: [str], hasOutput: true) + } + ) +} + public let MapTransitionFuzzer = ProgramTemplate("MapTransitionFuzzer") { b in // This template is meant to stress the v8 Map transition mechanisms. // Basically, it generates a bunch of CreateObject, GetProperty, SetProperty, FunctionDefinition, diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index abc30bdcf..98344b37a 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -68,6 +68,7 @@ let v8Profile = Profile( (PretenureAllocationSiteGenerator, 5), (HoleNanGenerator, 5), (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), ], additionalProgramTemplates: WeightedList([ diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index daeb71525..1e96c7762 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -478,6 +478,7 @@ let v8SandboxProfile = Profile( (PretenureAllocationSiteGenerator, 5), (HoleNanGenerator, 5), (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), ], additionalProgramTemplates: WeightedList([ From 87123d56c4309c851b485977fe28b41e40158094 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 11 Nov 2025 13:54:49 +0100 Subject: [PATCH 005/234] [js] Add code generator for concatenated strings Many (all?) JS engines have optimizations for string concatenations. To make it more likely having such concatenated strings (ConsString in V8), add a code generator for string concatenation. Fixed: 455552707 Change-Id: I0a9bf66a5f721d38f34327f7acd8c5344086cf10 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8756756 Commit-Queue: Matthias Liedtke Reviewed-by: Dominik Klemba Reviewed-by: Victor Gomes --- .../Fuzzilli/CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index a387c7097..c6889a0e8 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -94,6 +94,7 @@ public let codeGeneratorWeights = [ "ObjectWithSpreadGenerator": 2, "ArrayWithSpreadGenerator": 2, "TemplateStringGenerator": 1, + "ConcatenatedStringGenerator": 2, "StringNormalizeGenerator": 1, "PlainFunctionGenerator": 15, "StrictModeFunctionGenerator": 3, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index dfb78c433..13a20b613 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -161,6 +161,22 @@ 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()) From fbfe35c47281bafbd8c1ec2a9bfd35f3d6140b65 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 10 Nov 2025 14:35:57 +0100 Subject: [PATCH 006/234] [wasm] Add code generators for wasm-gc signatures So far this will only fuzz the definition of these signatures as there aren't any operations registered which would make use of these definitions, yet. Bug: 445356784 Change-Id: I1c6b99e863bf359e4c505605d2d7f64533553f19 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8753596 Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 1 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 32 +++++++++++++++++++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 3 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index c6889a0e8..280a13780 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -347,6 +347,7 @@ public let codeGeneratorWeights = [ "WasmTypeGroupGenerator": 5, "WasmArrayTypeGenerator": 5, "WasmStructTypeGenerator": 5, + "WasmSignatureTypeGenerator": 5, "WasmSelfReferenceGenerator": 5, "WasmForwardReferenceGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index f63a168e5..7ea893b47 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -118,6 +118,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ elementType: .wasmRef(.Index(), nullability: nullability), mutability: mutability, indexType: elementType) } else { + // TODO(mliedtke): Extend list with abstract heap types. b.wasmDefineArrayType( elementType: chooseUniform(from: [ .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, @@ -138,6 +139,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ indexTypes.append(elementType) type = .wasmRef(.Index(), nullability: nullability) } else { + // TODO(mliedtke): Extend list with abstract heap types. type = chooseUniform(from: [ .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, ]) @@ -149,6 +151,36 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.wasmDefineStructType(fields: fields, indexTypes: indexTypes) }, + CodeGenerator( + "WasmSignatureTypeGenerator", + inContext: .single(.wasmTypeGroup), + produces: [.wasmTypeDef()] + ) { 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.. desc.signature.outputTypes }) } else { From 363ed2b23a59e695e34a860d8277d0776f182f9f Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Tue, 18 Nov 2025 10:31:47 +0000 Subject: [PATCH 007/234] Remove unused ValueGeneratorFunc Change-Id: Ib70851f9cd9d11f39501815280d6ea641c6df40e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8764020 Reviewed-by: Carl Smith Commit-Queue: Carl Smith Auto-Submit: Pawel Krawczyk --- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 07be36f35..a3409b41b 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -17,16 +17,6 @@ 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 { let expectedNumberOfInputs = 0 From 2e3e639b1db60851ad678d6f7361e3fe33386899 Mon Sep 17 00:00:00 2001 From: Darius Mercadier Date: Thu, 20 Nov 2025 12:33:39 +0100 Subject: [PATCH 008/234] [turboshaft] Fuzz --turboshaft-verify-load-store-taggedness Bug: 458429784 Change-Id: If21b4e7bd0670939f0413c11e8d6c8ef1b5e5823 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8783156 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Darius Mercadier --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 3018dd6ba..12b466c82 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -878,6 +878,9 @@ 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) { From ec80efade6fb320637d090e0150782d6010caf41 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 12 Nov 2025 14:58:53 +0100 Subject: [PATCH 009/234] Extend new code generation logic to allow specifying more than just a type for input requirements and output guarantees. Bug: 445356784 Change-Id: Ib1319c8e42e33688c7c0921b166e46e50b031748 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8760696 Commit-Queue: Matthias Liedtke Reviewed-by: Carl Smith --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 70 ++++++------ Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 106 +++++++++++++++--- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 26 +++-- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 2 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 59 +++++++++- 5 files changed, 196 insertions(+), 67 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 7d5e3ed08..17f111300 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -770,8 +770,8 @@ public class ProgramBuilder { (.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()) + gen.produces.contains { produces in + produces.type.Is(.wasmTypeDef()) } } let _ = self.complete(generator: generators.randomElement(), withBudget: 5) @@ -862,8 +862,8 @@ public class ProgramBuilder { // 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) + $0.parts.last!.produces.contains(where: { produces in + produces.type.Is(type) }) }) if generators.count > 0 { @@ -1798,14 +1798,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)) @@ -1820,16 +1820,14 @@ 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) - }) { + // 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 expected type \(t)" + fatalErrorString += "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)" fatalError(fatalErrorString) } } @@ -2113,31 +2111,29 @@ 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]}] } @@ -2151,17 +2147,17 @@ 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) } } } @@ -2169,7 +2165,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() { @@ -2191,7 +2187,7 @@ public class ProgramBuilder { 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. @@ -2215,8 +2211,9 @@ 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 { + private func createRequiredInputVariables(for requirements: Set) { + for requirement in requirements { + let type = requirement.type if type.Is(.jsAnything) && context.contains(.javascript) { let _ = findOrGenerateType(type) } else { @@ -2224,13 +2221,12 @@ public class ProgramBuilder { // Check if we can produce it with findOrGenerateWasmVar let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) } - if randomVariable(ofType: type) == nil { + if (findVariable {requirement.fulfilled(by: self.type(of: $0))} == nil) { + // Check for other CodeGenerators that can produce the given type in this context. let usableGenerators = fuzzer.codeGenerators.filter { $0.requiredContext.isSubset(of: context) && - $0.produces.contains { - $0.Is(type) - } + $0.produces.contains(where: requirement.fulfilled) } // Cannot build type here. @@ -2344,18 +2340,18 @@ 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.") } // 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) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index a3409b41b..78bef10fb 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -78,6 +78,53 @@ 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 + } + + 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 + } + } + } + + 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. @@ -92,48 +139,51 @@ 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) } @@ -142,14 +192,19 @@ public class GeneratorStub: Contributor { // 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. @@ -157,7 +212,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. @@ -225,13 +280,13 @@ 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 @@ -243,6 +298,10 @@ 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 { @@ -259,6 +318,10 @@ public class GeneratorStub: Contributor { self.init(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) } + public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), producesComplex: [Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { + self.init(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + } + public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), 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)) @@ -320,7 +383,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 } @@ -345,11 +408,20 @@ public class CodeGenerator { self.init(name, [GeneratorStub(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) } + public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { + self.init(name, [GeneratorStub(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) + } + public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { assert(inputs.count == 1) self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) } + public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + assert(inputs.count == 1) + self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) + } + public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc2Args) { assert(inputs.count == 2) self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter2Args(f: f))]) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 7ea893b47..c65d55a84 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -100,11 +100,10 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ]), - // TODO: refine this `produces` annotation? CodeGenerator( "WasmArrayTypeGenerator", inContext: .single(.wasmTypeGroup), - produces: [.wasmTypeDef()] + producesComplex: [.init(.wasmTypeDef(), .IsWasmArray)] ) { b in let mutability = probability(0.75) if let elementType = b.randomVariable(ofType: .wasmTypeDef()), @@ -126,6 +125,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ } }, + // TODO(mliedtke): Refine this `produces` annotation. CodeGenerator("WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), produces: [.wasmTypeDef()]) { b in var indexTypes: [Variable] = [] let fields = (0.. { diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 2932757cb..fc05859e3 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2982,12 +2982,18 @@ class ProgramBuilderTests: XCTestCase { // XCTAssertGreaterThan(numGeneratedInstructions, 30) } - func testWasmCallDirectGeneratorSchedulingTest() { + func testWasmStructNewDefaultGeneratorSchedulingTest() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() b.buildPrefix() - // Pick the Branch Generator. + // TODO(mliedtke): The mechanism needs to learn how to resolve nested input dependencies. + b.wasmDefineTypeGroup {[ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), + ]} + + // Pick the generator. let generator = fuzzer.codeGenerators.filter { $0.name == "WasmStructNewDefaultGenerator" }[0] @@ -2998,11 +3004,18 @@ class ProgramBuilderTests: XCTestCase { let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) XCTAssertGreaterThan(numGeneratedInstructions, 0) + XCTAssertTrue(b.finalize().code.contains(where: { instr in + if case .wasmStructNewDefault(_) = instr.op.opcode { + return true + } else { + return false + } + })) } func testWasmMemorySizeSchedulingTest() { let fuzzer = makeMockFuzzer() - let numPrograms = 100 + let numPrograms = 30 for _ in 0...numPrograms { let b = fuzzer.makeBuilder() @@ -3033,6 +3046,46 @@ class ProgramBuilderTests: XCTestCase { } } + func testArrayGetSchedulingTest() { + let fuzzer = makeMockFuzzer() + let numPrograms = 30 + + for _ in 0.. Date: Thu, 20 Nov 2025 15:48:14 +0100 Subject: [PATCH 010/234] [v8] Add ProgramTemplate for --proto-assign-seq-opt pattern Bug: 429332174 Change-Id: Ic644ce211f96e1bd2c3044bc14fa12ee4410fa24 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8783696 Commit-Queue: Matthias Liedtke Reviewed-by: Dominik Klemba --- .../Profiles/V8CommonProfile.swift | 46 +++++++++++++++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 23 +++++----- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 12b466c82..6a6ca3916 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -686,6 +686,52 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in b.build(n: 10) } +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..([ - (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), ]), disabledCodeGenerators: [], @@ -87,9 +88,9 @@ 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": .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], From 9ccd9ea0757c3d61e23318a9bb65cbc059351e4b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 24 Nov 2025 11:00:42 +0100 Subject: [PATCH 011/234] [v8] Add flag for stress-testing prototype assignment optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V8-side-change: https://crrev.com/c/7178541 Right now this probably doesn't change much as the ProgramTemplate from commit 9e2e2a359467d59790a194a34b821da05b684c2d uses multiple assignments and other instructions will never emit the correct bytecode due to how expression inlining is implemented for assignments right now. Still, it doesn't hurt to add this flag to Fuzzilli as well. Bug: 429332174 Change-Id: I7a4318ba434d701c530fef72a31bce1497f51529 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8792496 Auto-Submit: Matthias Liedtke Commit-Queue: Raphaël Hérouart Reviewed-by: Raphaël Hérouart --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 6a6ca3916..5a7c329bf 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -897,6 +897,9 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { if probability(0.5) { args.append("--proto-assign-seq-opt") + if probability(0.5) { + args.append("--proto-assign-seq-opt-count=1") + } } // From 9b7e15395193f9d0e97663b46cd9319739e69be8 Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Mon, 24 Nov 2025 13:43:11 +0000 Subject: [PATCH 012/234] [cleanup] Improve readability, remove dead code, fix comments. Change-Id: Ib196ad69f5a3a09620b82da5e60694777a024aef Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8783856 Reviewed-by: Dominik Klemba Commit-Queue: Pawel Krawczyk Reviewed-by: Matthias Liedtke Auto-Submit: Pawel Krawczyk --- Sources/Fuzzilli/Base/ContextGraph.swift | 50 +++++----- Sources/Fuzzilli/Base/ProgramBuilder.swift | 95 ++++++++----------- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 21 +--- .../Environment/JavaScriptEnvironment.swift | 1 + Tests/FuzzilliTests/ProgramBuilderTest.swift | 2 - 5 files changed, 76 insertions(+), 93 deletions(-) diff --git a/Sources/Fuzzilli/Base/ContextGraph.swift b/Sources/Fuzzilli/Base/ContextGraph.swift index 38d6992dd..153f76541 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 @@ -55,19 +55,24 @@ public class ContextGraph { 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() + assertBasicConsistency(in: generators) + warnOfSuspiciousContexts(in: generators, 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) @@ -82,8 +87,21 @@ public class ContextGraph { fatalError("Inconsistent requires/provides Contexts for \(generator.name)") } - currentContext = Context(stub.providedContext) + currentContext = stub.providedContext.isEmpty ? currentContext : Context(stub.providedContext) + } + } + } + + private func warnOfSuspiciousContexts(in generators: WeightedList, withLogger logger: Logger) { + // Technically we don't need any generator to emit the .javascript context, as this is provided by the toplevel. + var providedContexts = Set([.javascript]) + var requiredContexts = Set() + + for generator in generators { + generator.providedContexts.forEach { ctx in + providedContexts.insert(ctx) } + requiredContexts.insert(generator.requiredContext) } for generator in generators { @@ -100,18 +118,6 @@ public class ContextGraph { 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) - } - } } /// Gets all possible paths from the `from` Context to the `to` Context. diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 17f111300..bbef5a758 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -72,34 +72,6 @@ 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 @@ -166,7 +138,7 @@ 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() @@ -1245,6 +1217,39 @@ 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: () -> ()) { + hide(variableToHide) + body() + unhide(variableToHide) + } + private static func matchingWasmTypes(jsType: ILType) -> [ILType] { if jsType.Is(.integer) { return [.wasmi32, .wasmf64, .wasmf32] @@ -2746,9 +2751,7 @@ public class ProgramBuilder { public func buildClassDefinition(withSuperclass superclass: Variable? = nil, isExpression: Bool = false, _ body: (ClassDefinition) -> ()) -> 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) } + bodyWithRecursionGuard(output) { body(currentClassDefinition) } emit(EndClassDefinition()) return output } @@ -2963,9 +2966,7 @@ public class ProgramBuilder { public func buildPlainFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil,_ body: ([Variable]) -> ()) -> Variable { 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) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndPlainFunction()) return instr.output } @@ -2974,9 +2975,7 @@ public class ProgramBuilder { public func buildArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndArrowFunction()) return instr.output } @@ -2985,9 +2984,7 @@ public class ProgramBuilder { public func buildGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { 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) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndGeneratorFunction()) return instr.output } @@ -2996,9 +2993,7 @@ public class ProgramBuilder { public func buildAsyncFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { 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) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncFunction()) return instr.output } @@ -3007,9 +3002,7 @@ public class ProgramBuilder { public func buildAsyncArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncArrowFunction()) return instr.output } @@ -3018,9 +3011,7 @@ public class ProgramBuilder { public func buildAsyncGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { 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) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncGeneratorFunction()) return instr.output } @@ -3029,9 +3020,7 @@ public class ProgramBuilder { public func buildConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginConstructor(parameters: descriptor.parameters)) - if enableRecursionGuard { hide(instr.output) } - body(Array(instr.innerOutputs)) - if enableRecursionGuard { unhide(instr.output) } + bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndConstructor()) return instr.output } diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 13a20b613..3b64d0903 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1936,7 +1936,7 @@ public let CodeGenerators: [CodeGenerator] = [ b, arr in // Fuzzilli generated arrays can have a length ranging from 0 to 10 elements, // We want to ensure that 1) when destructing arrays we are usually within this length range - // and 2) The probability with which we select indices allows defining atleast 2-3 variables. + // and 2) the probability with which we select indices allows defining at least 2-3 variables. var indices: [Int64] = [] for idx in 0.. GeneratorStub { - for generator in self { - if generator.name == name { - return generator - } - } - fatalError("Unknown code generator \(name)") - } -} diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 17888b9f1..9ef54f216 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -912,6 +912,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]? diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index fc05859e3..c5c071536 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -431,8 +431,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 From 47630fad4fa6f9cb233cdfa58833562987319ff2 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 13 Nov 2025 14:16:06 +0100 Subject: [PATCH 013/234] [wasm] Register code generator that produces all wasm-gc type kinds This way the new code generation logic can resolve dependencies when it requires a Wasm struct, array, or signature type. In theory, these could all be registered as separate code generators, however it seems simpler having one that just generates all 3 types. We need the separate generator and can't rely on the "inner" generators like the "ArrayTypeGenerator" as these can only run inside the `.wasmTypeGroup` context. Bug: 445356784 Change-Id: I5c2b9e37aeb9b3ab50f05a37e49147efff4acaa7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8767377 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 + Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 9 + .../CodeGen/CodeGeneratorWeights.swift | 1 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 229 ++++++++++-------- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 4 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 79 +++--- 6 files changed, 186 insertions(+), 141 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index bbef5a758..4249fabfc 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4617,6 +4617,11 @@ public class ProgramBuilder { public func wasmDefineTypeGroup(recursiveGenerator: () -> ()) -> [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) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 78bef10fb..174e72924 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -82,6 +82,7 @@ public class GeneratorStub: Contributor { case None case IsWasmArray case IsWasmStruct + case IsWasmFunction // On a type definition this means "signature". } public struct Constraint : Hashable { @@ -116,6 +117,14 @@ public class GeneratorStub: Contributor { } else { false } + case .IsWasmFunction: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmSignatureTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmFuncRef) + } else { + false + } } } diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 280a13780..1dff70aed 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -345,6 +345,7 @@ 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, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index c65d55a84..3878e4d4e 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -88,99 +88,36 @@ public let WasmCodeGenerators: [CodeGenerator] = [ "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 - ) + b.wasmEndTypeGroup() }, ]), - CodeGenerator( - "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 { - // TODO(mliedtke): Extend list with abstract heap types. - b.wasmDefineArrayType( - elementType: chooseUniform(from: [ - .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, - ]), mutability: mutability) - } - }, - - // TODO(mliedtke): Refine this `produces` annotation. - CodeGenerator("WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), produces: [.wasmTypeDef()]) { b in - var indexTypes: [Variable] = [] - let fields = (0.. (0.. (0.. { diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index c5c071536..5a9c53b63 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2980,37 +2980,6 @@ class ProgramBuilderTests: XCTestCase { // XCTAssertGreaterThan(numGeneratedInstructions, 30) } - func testWasmStructNewDefaultGeneratorSchedulingTest() { - let fuzzer = makeMockFuzzer() - let b = fuzzer.makeBuilder() - b.buildPrefix() - - // TODO(mliedtke): The mechanism needs to learn how to resolve nested input dependencies. - b.wasmDefineTypeGroup {[ - b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), - ]} - - // Pick the generator. - let generator = fuzzer.codeGenerators.filter { - $0.name == "WasmStructNewDefaultGenerator" - }[0] - - // Now build this. - let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) - XCTAssertNotNil(syntheticGenerator) - - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) - XCTAssertGreaterThan(numGeneratedInstructions, 0) - XCTAssertTrue(b.finalize().code.contains(where: { instr in - if case .wasmStructNewDefault(_) = instr.op.opcode { - return true - } else { - return false - } - })) - } - func testWasmMemorySizeSchedulingTest() { let fuzzer = makeMockFuzzer() let numPrograms = 30 @@ -3066,9 +3035,7 @@ class ProgramBuilderTests: XCTestCase { 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) let program = b.finalize() @@ -3084,6 +3051,50 @@ class ProgramBuilderTests: XCTestCase { } } + func testWasmGCScheduling() { + func test( + _ generatorName: String, + expectAny: repeat (each ExpectedOp).Type, + requiresTypes: Bool = false) { + let fuzzer = makeMockFuzzer() + let numPrograms = 30 + + for _ in 0.. Date: Fri, 14 Nov 2025 16:52:04 +0100 Subject: [PATCH 014/234] [wasm] Slightly increase chance of successful wasm-gc operations Change-Id: I9f502e7d70fcccbb335f424391bebfdb6561f3e0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8764022 Commit-Queue: Matthias Liedtke Reviewed-by: Pawel Krawczyk --- Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 3878e4d4e..697f84d4a 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -201,8 +201,10 @@ public let WasmCodeGenerators: [CodeGenerator] = [ fatalError("unreachable: array.set input not an array") } guard arrayType.mutability else { return } - guard let element = b.randomVariable(ofType: arrayType.elementType.unpacked()) else { return } + let inputType = arrayType.elementType.unpacked() let function = b.currentWasmModule.currentWasmFunction + guard let element = b.randomVariable(ofType: inputType) ?? function.generateRandomWasmVar(ofType: inputType) + else { return } // TODO(mliedtke): Track array length and use other indices as well. let index = function.consti32(0) function.wasmArraySet(array: array, index: index, element: element) @@ -255,17 +257,14 @@ public let WasmCodeGenerators: [CodeGenerator] = [ guard let structType = desc.get()! as? WasmStructTypeDescription else { fatalError("Invalid type description for \(b.type(of: theStruct))") } - guard - let fieldWithIndex = structType.fields.enumerated().filter({ - (offset, field) in + guard let fieldWithIndex = structType.fields.enumerated().filter({(offset, field) in field.mutability }).randomElement() else { return } - // TODO(mliedtke): Create the input when not available! - guard - let newValue = b.randomVariable(ofType: fieldWithIndex.element.type) - else { return } let function = b.currentWasmModule.currentWasmFunction + let inputType = fieldWithIndex.element.type.unpacked() + guard let newValue = b.randomVariable(ofType: inputType) ?? function.generateRandomWasmVar(ofType: inputType) + else { return } function.wasmStructSet( theStruct: theStruct, fieldIndex: fieldWithIndex.offset, value: newValue) From 633c823b41e285cec7590148297b69c4d7362d03 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 24 Nov 2025 17:43:50 +0100 Subject: [PATCH 015/234] [v8] Add code generator for %MajorGCForCompilerTesting() V8-side-change: https://crrev.com/c/7198340 Change-Id: I423361da98643dcde469b8a13c6b7df44114d8c6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8793536 Reviewed-by: Dominik Klemba Auto-Submit: Matthias Liedtke Commit-Queue: Dominik Klemba --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 6 ++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 5a7c329bf..967210b97 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -51,6 +51,12 @@ public let V8GcGenerator = CodeGenerator("GcGenerator") { b in b.callFunction(gc, withArgs: b.findOrGenerateArguments(forSignature: b.fuzzer.environment.type(ofBuiltin: "gc").signature!)) } +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 assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index b1eb26365..0a858aee8 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -60,7 +60,8 @@ let v8Profile = Profile( (TurbofanVerifyTypeGenerator, 10), (WorkerGenerator, 10), - (V8GcGenerator, 10), + (V8GcGenerator, 5), + (V8MajorGcGenerator, 5), (WasmStructGenerator, 15), (WasmArrayGenerator, 15), From 72dd5d7d9fcb648881543cd31bbac0d1baaa106f Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 21 Nov 2025 12:03:00 +0100 Subject: [PATCH 016/234] [wasm] Add a new operation for defining signatures directly inside a function To allow defining a block with a wasm-gc signature while already being in the .wasmFunction context, this change adds a new operation WasmDefineAdHocSignature. This way statements requiring a signature type input can directly embed this signature definition inside the function. Bug: 445356784 Change-Id: I56754224551ea82883c71410f4aca957b7bf24d4 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8787096 Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 7 +++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 7 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 25 +++++----- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 12 +++++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 1 + Sources/Fuzzilli/Lifting/WasmLifter.swift | 33 +++++++------ .../Fuzzilli/Mutators/OperationMutator.swift | 1 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 49 +++++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 5 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 28 ++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 1 + Tests/FuzzilliTests/WasmTests.swift | 27 +++++++++- 14 files changed, 171 insertions(+), 30 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 4249fabfc..6bc1dbd6b 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4635,6 +4635,13 @@ 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. + @discardableResult + func wasmDefineAdHocSignatureType(signature: WasmSignature, indexTypes: [Variable]) -> Variable { + return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes).output + } + @discardableResult func wasmDefineArrayType(elementType: ILType, mutability: Bool, indexType: Variable? = nil) -> Variable { let inputs = indexType != nil ? [indexType!] : [] diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ee017f20a..6486e4603 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1559,6 +1559,11 @@ 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 .wasmDefineSignatureType(let op): $0.wasmDefineSignatureType = Fuzzilli_Protobuf_WasmDefineSignatureType.with { $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) @@ -2566,6 +2571,8 @@ extension Instruction: ProtobufConvertible { op = WasmDefineArrayType(elementType: WasmTypeEnumToILType(p.elementType), mutability: p.mutability) case .wasmDefineSignatureType(let p): 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 .wasmDefineStructType(let p): op = WasmDefineStructType(fields: p.fields.map { field in return WasmDefineStructType.Field(type: WasmTypeEnumToILType(field.type), mutability: field.mutability) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 0ca07622c..054f242a2 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -433,8 +433,9 @@ public struct JSTyper: Analyzer { } 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 @@ -477,13 +478,12 @@ public struct JSTyper: Analyzer { 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) - } + 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 + assert(isWithinTypeGroup) + let tgIndex = typeGroups.count - 1 let resolvedElementType: ILType if let elementRef = elementRef { let elementNullability = elementType.wasmReferenceType!.nullability @@ -519,13 +519,11 @@ public struct JSTyper: Analyzer { elementType: resolvedElementType, mutability: mutability, typeGroupIndex: tgIndex))) - if isWithinTypeGroup { - typeGroups[typeGroups.count - 1].append(def) - } + typeGroups[typeGroups.count - 1].append(def) } mutating func addStructType(def: Variable, fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)]) { - let tgIndex = isWithinTypeGroup ? typeGroups.count - 1 : -1 + let tgIndex = typeGroups.count - 1 let resolvedFields = fieldsWithRefs.enumerated().map { (fieldIndex, fieldWithInput) in let (field, fieldTypeRef) = fieldWithInput if let fieldTypeRef { @@ -556,9 +554,7 @@ public struct JSTyper: Analyzer { set(def, .wasmTypeDef(description: WasmStructTypeDescription( fields: resolvedFields, typeGroupIndex: tgIndex))) - if (isWithinTypeGroup) { - typeGroups[typeGroups.count - 1].append(def) - } + typeGroups[typeGroups.count - 1].append(def) } func getTypeGroup(_ index: Int) -> [Variable] { @@ -588,7 +584,6 @@ public struct JSTyper: Analyzer { } } selfReferences.removeAll() - isWithinTypeGroup = false } @@ -904,6 +899,10 @@ public struct JSTyper: Analyzer { // extern.convert_any forwards the nullability bit from the input. let null = type(of: instr.input(0)).wasmReferenceType!.nullability setType(of: instr.output, to: .wasmRef(.Abstract(.WasmExtern), nullability: null)) + case .wasmDefineAdHocSignatureType(let op): + startTypeGroup() + addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) + finishTypeGroup() default: if instr.numInnerOutputs + instr.numOutputs != 0 { fatalError("Missing typing of outputs for \(instr.op.opcode)") diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index f9fda2f00..d28dd189f 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -363,4 +363,5 @@ enum Opcode { case wasmDefineSignatureType(WasmDefineSignatureType) case createNamedDisposableVariable(CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(CreateNamedAsyncDisposableVariable) + case wasmDefineAdHocSignatureType(WasmDefineAdHocSignatureType) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index bed8bd6ae..452dd9cc5 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2391,3 +2391,15 @@ final class WasmAtomicCmpxchg: WasmOperation { 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]) + } +} diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 9a4e77785..33d47fa16 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1354,6 +1354,10 @@ 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 .wasmDefineArrayType(let op): let typeInput = op.elementType.requiredInputCount() == 1 ? " \(input(0))" : "" w.emit("\(output()) <- WasmDefineArrayType \(op.elementType) mutability=\(op.mutability)\(typeInput)") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 1cf8b75b9..49cfb5a04 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1722,6 +1722,7 @@ public class JavaScriptLifter: Lifter { .wasmBeginTypeGroup(_), .wasmEndTypeGroup(_), .wasmDefineSignatureType(_), + .wasmDefineAdHocSignatureType(_), .wasmDefineArrayType(_), .wasmDefineStructType(_), .wasmDefineForwardOrSelfReference(_), diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 287d1cc5e..4944ac161 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -294,7 +294,6 @@ public class WasmLifter { // private var tags: VariableMap<[ILType]> = VariableMap() private var typeGroups: Set = [] - private var freeTypes: Set = [] private var typeDescToIndex : [WasmTypeDescription:Int] = [:] private var userDefinedTypesCount = 0 @@ -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] @@ -1343,8 +1341,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 } @@ -1376,9 +1376,11 @@ 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 } @@ -1455,13 +1457,12 @@ public class WasmLifter { if inputType.Is(.wasmTypeDef()) || inputType.Is(.wasmRef(.Index(), nullability: true)) { 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)) } } @@ -2196,6 +2197,10 @@ public class WasmLifter { return Data([Prefix.GC.rawValue, 0x1A]) case .wasmExternConvertAny(_): return Data([Prefix.GC.rawValue, 0x1B]) + case .wasmDefineAdHocSignatureType(_): + // Nothing to do here, types are defined inside the typegroups, not inside a wasm + // function. + return Data() default: fatalError("unreachable") diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index dfe3438df..94e7e297c 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -712,6 +712,7 @@ public class OperationMutator: BaseInstructionMutator { .wasmDefineArrayType(_), .wasmDefineStructType(_), .wasmDefineSignatureType(_), + .wasmDefineAdHocSignatureType(_), .wasmDefineForwardOrSelfReference(_), .wasmResolveForwardReference(_), .wasmArrayNewFixed(_), diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 7a1549674..2b2248232 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5709,6 +5709,20 @@ 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_WasmDefineArrayType: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -14994,6 +15008,41 @@ 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_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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 72266a1fb..8ed578def 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1503,6 +1503,11 @@ message WasmDefineSignatureType { repeated WasmILType outputTypes = 2; } +message WasmDefineAdHocSignatureType { + repeated WasmILType parameterTypes = 1; + repeated WasmILType outputTypes = 2; +} + message WasmDefineArrayType { WasmILType elementType = 1; bool mutability = 2; diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index bf4e21f82..293a03607 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2721,6 +2721,14 @@ 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3058,6 +3066,7 @@ 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) } @@ -3106,7 +3115,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}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7452,6 +7461,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedAsyncDisposableVariable(v) } }() + case 336: 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) + } + }() default: break } } @@ -8802,6 +8824,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .createNamedAsyncDisposableVariable(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 335) }() + case .wasmDefineAdHocSignatureType?: try { + guard case .wasmDefineAdHocSignatureType(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 336) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 0582386bf..db2587934 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -359,6 +359,7 @@ message Instruction { WasmDefineSignatureType wasmDefineSignatureType = 333; CreateNamedDisposableVariable createNamedDisposableVariable = 334; CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 335; + WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 05a3c6b61..f7955e212 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4165,7 +4165,7 @@ class WasmFoundationTests: XCTestCase { 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 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) } @@ -4210,7 +4210,7 @@ class WasmFoundationTests: XCTestCase { 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 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) } @@ -4489,6 +4489,29 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\n") } + func testAdHocSignature() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + let jsProg = buildAndLiftProgram { b in + + let module = b.buildWasmModule { wasmModule 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. + let signatureType = b.wasmDefineAdHocSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) + return [function.wasmRefNull(typeDef: signatureType)] + } + } + + 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: "null\n") + } + func testSelfReferenceType() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) From 9ddaf186a6584967ef156c15707769c069692e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Gro=C3=9F?= Date: Tue, 25 Nov 2025 10:55:40 +0100 Subject: [PATCH 017/234] [v8] Add startup test for new abort_with_sandbox_violation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ensure that this function is correctly detected as a crash in both regular fuzzing and sandbox fuzzing configurations Change-Id: I22eae385d08d343926624d5e6f33b7e6dbf72993 Bug: 461681036 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8796176 Commit-Queue: Samuel Groß Reviewed-by: Matthias Liedtke --- Sources/FuzzilliCli/Profiles/V8Profile.swift | 2 ++ Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 0a858aee8..ade2d87ac 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -49,6 +49,8 @@ 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). ], diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 1e96c7762..3177c273e 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -457,6 +457,8 @@ let v8SandboxProfile = Profile( ("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), // Crashes that are not sandbox violations and so should be filtered out by the crash filter. // This triggers an IMMEDIATE_CRASH. From 33ed3cf706ff07cd8692e4fd9ae43ac9760b0956 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Wed, 26 Nov 2025 08:40:13 +0000 Subject: [PATCH 018/234] Improve RestLength parameter fuzzing This change increases the probability of accessing the length of rest parameters and rest elements to improve fuzzing coverage of V8's optimizations for RestLength (rest.length). With a 20% probability, FuzzIL variable is created for the "length" property of a newly created rest parameter or element. This affects all function types and array destructuring generators. For function generators and 'ForOfWithDestructLoopGenerator', we do not need to check if outputs are empty: 'hasRestParameter' implies the existence of parameters, and loop generation logic guarantees non-empty indices. For 'DestructArrayGenerator' and 'DestructArrayAndReassignGenerator', we now ensure that 'lastIsRest' is only true when the variable list is non-empty. Assertions were also added to the DestructArray instructions to enforce this invariant. Bug: 456162872 Change-Id: I37b78cc892aac5bb5e5164864863dc51dba40f51 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8741996 Reviewed-by: Matthias Liedtke Commit-Queue: Dominik Klemba --- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 83 ++++++++++++++----- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 2 + 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 3b64d0903..0c5442f4a 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -795,6 +795,10 @@ public let CodeGenerators: [CodeGenerator] = [ parameters: randomParameters.parameters) ).innerOutputs + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: args.last!) + } + let this = args[0] // Derived classes must call `super()` before accessing this, but non-derived classes must not call `super()`. if b.currentClassDefinition.isDerivedClass { @@ -1296,9 +1300,12 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - let f = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output - b.runtimeData.push("plainFunction", f) + let instr = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + 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()) @@ -1316,9 +1323,12 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - let f = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)).output - b.runtimeData.push("strictFunction", f) + let instr = b.emit( + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + 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 @@ -1340,8 +1350,11 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( + let instr = b.emit( BeginArrowFunction(parameters: randomParameters.parameters)) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } }, GeneratorStub( "ArrowFunctionEndGenerator", @@ -1357,9 +1370,12 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - let f = b.emit( - BeginGeneratorFunction(parameters: randomParameters.parameters, functionName: nil)).output - b.runtimeData.push("generatorFunction", f) + let instr = b.emit( + BeginGeneratorFunction(parameters: randomParameters.parameters, functionName: nil)) + 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) { @@ -1383,9 +1399,12 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - let f = b.emit( - BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)).output - b.runtimeData.push("asyncFunction", f) + let instr = b.emit( + BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)) + 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()) @@ -1407,9 +1426,12 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - b.emit( + let instr = b.emit( BeginAsyncArrowFunction( parameters: randomParameters.parameters)) + if randomParameters.parameters.hasRestParameter && probability(0.2) { + b.getProperty("length", of: instr.innerOutputs.last!) + } }, GeneratorStub( "AsyncArrowFunctionAwaitGenerator", @@ -1435,10 +1457,13 @@ public let CodeGenerators: [CodeGenerator] = [ let randomParameters = b.randomParameters() b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) - let f = b.emit( + let instr = b.emit( BeginAsyncGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)).output - b.runtimeData.push("asyncGeneratorFunction", f) + parameters: randomParameters.parameters, functionName: nil)) + 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()) @@ -1944,7 +1969,12 @@ public let CodeGenerators: [CodeGenerator] = [ } } - b.destruct(arr, selecting: indices, lastIsRest: probability(0.33)) + let lastIsRest = !indices.isEmpty && probability(0.33) + let vars = b.destruct(arr, selecting: indices, lastIsRest: lastIsRest) + + if lastIsRest && probability(0.2) { + b.getProperty("length", of: vars.last!) + } }, CodeGenerator( @@ -1958,9 +1988,14 @@ public let CodeGenerators: [CodeGenerator] = [ candidates.append(b.randomJsVariable()) } } + let lastIsRest = !candidates.isEmpty && probability(0.33) b.destruct( arr, selecting: indices, into: candidates, - lastIsRest: probability(0.33)) + lastIsRest: lastIsRest) + + if lastIsRest && probability(0.2) { + b.getProperty("length", of: candidates.last!) + } }, CodeGenerator("DestructObjectGenerator", inputs: .preferred(.object())) { @@ -2398,10 +2433,14 @@ public let CodeGenerators: [CodeGenerator] = [ indices = [0] } - b.emit( + let hasRestElement = probability(0.2) + let vars = b.emit( BeginForOfLoopWithDestruct( - indices: indices, hasRestElement: probability(0.2)), - withInputs: [obj]) + indices: indices, hasRestElement: hasRestElement), + withInputs: [obj]).innerOutputs + if hasRestElement && probability(0.2) { + b.getProperty("length", of: vars.last!) + } }, GeneratorStub( "ForOfWithDestructLoopEndGenerator", diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index d8dcbe154..bc87ecb2a 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1748,6 +1748,7 @@ 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) @@ -1764,6 +1765,7 @@ final class DestructArrayAndReassign: 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 // The first input is the array being destructed From 15f47d074dd4e9044e390ba2d91b0c69f27dc09c Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Thu, 27 Nov 2025 16:55:33 +0000 Subject: [PATCH 019/234] Small readability improvement. Change-Id: I02ac85b1f90e3a21a6310157457d2e0c0ec364d3 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8796658 Auto-Submit: Pawel Krawczyk Commit-Queue: Dominik Klemba Reviewed-by: Dominik Klemba --- Tests/FuzzilliTests/ContextGraphTest.swift | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index 1ffdbc914..fb068f34f 100644 --- a/Tests/FuzzilliTests/ContextGraphTest.swift +++ b/Tests/FuzzilliTests/ContextGraphTest.swift @@ -26,21 +26,9 @@ 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) + XCTAssertEqual(reachableContexts, expectedReachedContexts) } func testSubsetReachabilityCalculation() { From 8a542afbbf2c6b6dd5f62fdcf8361ec7f6979110 Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Fri, 28 Nov 2025 09:45:09 +0000 Subject: [PATCH 020/234] Throw exception in TryCatchFinally blocks (with certain probability). Bug: 455512155,455513417 Change-Id: I52dc1b9d27d02ee1e5d905eca3705d9a9c4a6661 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8796096 Commit-Queue: Pawel Krawczyk Reviewed-by: Dominik Klemba --- .../CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 1dff70aed..c60c853ce 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -186,6 +186,7 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "TryFinallyGenerator": 5, "ThrowGenerator": 1, + "NondeterministiclyThrowGenerator": 1, "BlockStatementGenerator": 1, // Special generators diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 0c5442f4a..002b46b01 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2492,6 +2492,8 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), provides: [.javascript] ) { b in + if (probability(0.1)) { throwRandomJSVariable(b) } + else if (probability(0.3)) { nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.5)} b.emit(BeginCatch()) }, GeneratorStub( @@ -2524,6 +2526,8 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), provides: [.javascript] ) { b in + if (probability(0.1)) { throwRandomJSVariable(b) } + else if (probability(0.3)) { nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.5)} b.emit(BeginCatch()) }, GeneratorStub( @@ -2560,8 +2564,11 @@ public let CodeGenerators: [CodeGenerator] = [ ]), CodeGenerator("ThrowGenerator") { b in - let v = b.randomJsVariable() - b.throwException(v) + throwRandomJSVariable(b) + }, + + CodeGenerator("NondeterministiclyThrowGenerator") { b in + nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.3) }, // @@ -3018,3 +3025,24 @@ public let CodeGenerators: [CodeGenerator] = [ }, catchBody: { _ in }) }, ] + +private func nondeterministiclyThrowRandomJSVariable(_ b: ProgramBuilder, withProbability probability: Double) { + assert(probability >= 0 && probability <= 1) + + let threshold = b.loadFloat(probability) + let Math = b.createNamedVariable(forBuiltin: "Math") + let randomNumber = b.callMethod("random", on: Math, withArgs: []) + // Let's not influence other generators with Math & randomly generated number. + b.hide(Math) + b.hide(randomNumber) + + let condition = b.compare(threshold, with: randomNumber, using: Comparator.greaterThan) + b.buildIf(condition) { + throwRandomJSVariable(b) + } +} + +private func throwRandomJSVariable(_ b: ProgramBuilder) { + let v = b.randomJsVariable() + b.throwException(v) +} From 8adcc7639ffea09e3aa96bd5cdd77f0650a91a88 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 1 Dec 2025 11:26:51 +0100 Subject: [PATCH 021/234] Add script to transpile existing test cases This adds a stand-alone python script that with the following properties: * Mimic various test configs from V8 (for now test262 without staging) * List all supported tests from a config * Transpile all tests in parallel (i.e. compile to FuzzIL and lift back to JS) * Print statistics and return relevant results as a json file * The results contain stats that we can track as a metric, e.g. the percentage of properly transpiled tests. The script is tested with a Python unit tests that runs the script E2E, also hooked up through a presubmit script so that it's tested on updates. Bug: 442444727 Change-Id: I29c89cede59aef885e45a0ae0821d3388bc51e8f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8787097 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Tools/transpile_tests/.gitignore | 1 + Tools/transpile_tests/.vpython3 | 21 ++ Tools/transpile_tests/PRESUBMIT.py | 34 +++ Tools/transpile_tests/test_transpile_tests.py | 111 ++++++++++ .../data/test/folder1/subfolder1/Test1.js | 15 ++ .../data/test/folder1/subfolder1/Test2.js | 15 ++ .../test/test262/data/test/folder2/Test3.js | 15 ++ .../data/test/folder2/Test3_FIXTURE.js | 15 ++ .../test262/data/test/folder2/Test4_fail.js | 15 ++ .../data/test/folder2/Test4_negative.js | 15 ++ .../data/tools/packaging/parseTestRecord.py | 19 ++ Tools/transpile_tests/transpile_tests.py | 204 ++++++++++++++++++ 12 files changed, 480 insertions(+) create mode 100644 Tools/transpile_tests/.gitignore create mode 100644 Tools/transpile_tests/.vpython3 create mode 100644 Tools/transpile_tests/PRESUBMIT.py create mode 100644 Tools/transpile_tests/test_transpile_tests.py create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test1.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder1/subfolder1/Test2.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test3_FIXTURE.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_fail.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/test/folder2/Test4_negative.js create mode 100644 Tools/transpile_tests/testdata/transpile_full_run/v8/test/test262/data/tools/packaging/parseTestRecord.py create mode 100644 Tools/transpile_tests/transpile_tests.py 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/test_transpile_tests.py b/Tools/transpile_tests/test_transpile_tests.py new file mode 100644 index 000000000..cc776ce27 --- /dev/null +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -0,0 +1,111 @@ +# 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' + +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) + + Process = namedtuple('Process', 'returncode stdout') + + # Mock out the FuzzIL tool, but mimick writing the desired output file. + # Simulate one compilation failure for the test with "fail" in its name. + 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) + + 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 = { + 'num_tests': 4, + 'num_successes': 3, + 'percent_successes': 75.0, + 'failures': [ + { + 'output': 'Failed!', + 'path': 'test/test262/data/test/folder2/Test4_fail.js', + }, + ], + } + self.assertEqual(expected_results, actual_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..8deccb1a9 --- /dev/null +++ b/Tools/transpile_tests/transpile_tests.py @@ -0,0 +1,204 @@ +# 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 pathlib import Path + + +class DefaultMetaDataParser: + """Class instantiated once per test configuration/suite, providing a + method to check for supported tests based on their metadata. + """ + 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'] + self.excluded_dirs = ['staging'] + + 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 + + if any(str(relpath).startswith(directory) + for directory in self.excluded_dirs): + 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 = { + 'test262': { + 'path': 'test/test262/data/test', + 'excluded_suffixes': ['_FIXTURE.js'], + # TODO(https://crbug.com/442444727): We might want to track the staging + # tests separately. Those typically address in-progress JS features with + # a high import-failure rate. + 'excluded_dirs': ['staging'], + 'metadata_parser': Test262MetaDataParser, + } +} + + +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 = [ + '.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 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 abspath in list_test_filenames( + test_input_dir, metadata_parser.is_supported): + yield (abspath, output_dir / abspath.relative_to(base_dir)) + + # Iterate over all tests in parallel and collect stats. + num_tests = 0 + failures = [] + with multiprocessing.Pool(multiprocessing.cpu_count()) as pool: + for exit_code, abspath, stdout in pool.imap_unordered( + transpile_test, test_input_gen()): + num_tests += 1 + if exit_code != 0: + relpath = abspath.relative_to(base_dir) + failures.append({'path': str(relpath), 'output': stdout}) + verbose_print(options, f'Failed to compile {relpath}') + if (num_tests + 1) % 500 == 0: + print(f'Processed {num_tests + 1} test cases.') + + # Render and return results. + assert num_tests, 'Failed to find any tests.' + num_successes = num_tests - len(failures) + ratio = float(num_successes) / num_tests * 100 + print(f'Successfully compiled {ratio:.2f}% ' + f'({num_successes} of {num_tests}) test cases.') + return { + 'num_tests': num_tests, + 'num_successes': num_successes, + 'percent_successes': ratio, + 'failures': failures, + } + + +def write_json_output(path, results): + with open(path, 'w') as f: + json.dump(results, f) + + +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( + '-v', '--verbose', default=False, action='store_true', + help='Print more verbose output.') + return parser.parse_args(args) + + +def main(args): + options = parse_args(args) + 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:]) From 7f59fbf78353079f0bb873c0249dd3824fc4ab01 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 27 Nov 2025 19:14:31 +0100 Subject: [PATCH 022/234] Enable bundling Node.js in the CWD This makes the executor look for Node.js in the CWD, which makes it easy to bundle both together when porting the FuzzILTool to another machine. Bug: 442444727 Change-Id: I80adcde79fb6d773f3f47817da24188bbbe5431e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8796659 Reviewed-by: Pawel Krawczyk Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Util/JavaScriptExecutor.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift index 4340c67ef..c67e411ea 100644 --- a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift +++ b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift @@ -166,6 +166,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) { From e35cbb5b7b784cae910776e4edeefc8553316d56 Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Tue, 2 Dec 2025 11:39:11 +0000 Subject: [PATCH 023/234] Add support for shared references. Generating shared ref variables to be done in following CLs. See https://github.com/WebAssembly/shared-everything-threads/blob/main/proposals/shared-everything-threads/Overview.md. Bug: 448349112 Change-Id: I3358ce9cdd528147b66f1954ef1a008b048e06df Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8734256 Commit-Queue: Matthias Liedtke Reviewed-by: Dominik Klemba Commit-Queue: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 99 +++--- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 6 +- .../Fuzzilli/CodeGen/ProgramTemplates.swift | 11 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 39 ++- Sources/Fuzzilli/Configuration.swift | 1 + .../Environment/JavaScriptEnvironment.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 69 +++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 11 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 127 ++++++-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 45 +-- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 23 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 81 +++-- .../Fuzzilli/Mutators/OperationMutator.swift | 32 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 28 +- Sources/Fuzzilli/Protobuf/operations.proto | 3 +- .../Profiles/V8CommonProfile.swift | 5 +- Tests/FuzzilliTests/JSTyperTests.swift | 8 +- Tests/FuzzilliTests/LifterTest.swift | 2 +- Tests/FuzzilliTests/LiveTests.swift | 7 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 52 ++-- Tests/FuzzilliTests/TypeSystemTest.swift | 108 ++++--- Tests/FuzzilliTests/WasmTableTests.swift | 4 +- Tests/FuzzilliTests/WasmTests.swift | 283 ++++++++++++------ 23 files changed, 643 insertions(+), 403 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 6bc1dbd6b..63ef596ed 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1217,7 +1217,6 @@ public class ProgramBuilder { numberOfHiddenVariables -= 1 } - /// Hides a variable containing a function from the function's body. /// /// For example, in @@ -1250,19 +1249,20 @@ public class ProgramBuilder { 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()] } } @@ -1272,6 +1272,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 @@ -1288,12 +1289,12 @@ 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 @@ -3881,8 +3882,9 @@ public class ProgramBuilder { b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) } + // TODO(pawkra): support shared tables and element segments. public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { - let elementSegmentType = ILType.wasmFuncRef + let elementSegmentType = ILType.wasmFuncRef() let tableElemType = b.type(of: table).wasmTableType!.elementType assert(elementSegmentType.Is(tableElemType)) @@ -4012,18 +4014,22 @@ public class ProgramBuilder { return Array(b.emit(WasmEndLoop(outputTypes: signature.outputTypes), withInputs: fallthroughResults, types: 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)}) #if DEBUG var argIndex = signature.parameterTypes.count + let assertLabelTypeData: (ILType) -> () = { labelType in + assert(labelType.Is(.anyLabel)) + 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"))) @@ -4031,8 +4037,7 @@ public class ProgramBuilder { 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)) @@ -4095,8 +4100,8 @@ public class ProgramBuilder { b.emit(WasmThrow(parameterTypes: tagType.parameters), withInputs: [tag] + inputs, types: [.object(ofGroup: "WasmTag")] + tagType.parameters) } - public func wasmBuildThrowRef(exception: Variable) { - b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef]) + public func wasmBuildThrowRef(exception: Variable, sharedRef: Bool) { + b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef(shared: sharedRef)]) } public func wasmBuildLegacyRethrow(_ exceptionLabel: Variable) { @@ -4137,15 +4142,23 @@ public class ProgramBuilder { // 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 different types. For now + // fallback to refNull if possible. + if (type.wasmReferenceType!.nullability) { + return self.wasmRefNull(type: type) + } else { + return nil } - assert(type.wasmReferenceType!.nullability) - return self.wasmRefNull(type: type) case .Index(_), .none: break // Unimplemented @@ -4343,18 +4356,18 @@ public class ProgramBuilder { } @discardableResult - public func wasmI31Get(_ refI31: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31], types: [.wasmI31Ref]).output + public func wasmI31Get(_ refI31: Variable, isSigned: Bool, shared: Bool) -> Variable { + return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31], types: [.wasmI31Ref(shared: shared)]).output } @discardableResult - public func wasmAnyConvertExtern(_ ref: Variable) -> Variable { - b.emit(WasmAnyConvertExtern(), withInputs: [ref], types: [.wasmExternRef]).output + public func wasmAnyConvertExtern(_ ref: Variable, shared: Bool) -> Variable { + b.emit(WasmAnyConvertExtern(), withInputs: [ref], types: [.wasmExternRef(shared: shared)]).output } @discardableResult - public func wasmExternConvertAny(_ ref: Variable) -> Variable { - b.emit(WasmExternConvertAny(), withInputs: [ref], types: [.wasmAnyRef]).output + public func wasmExternConvertAny(_ ref: Variable, shared: Bool) -> Variable { + b.emit(WasmExternConvertAny(), withInputs: [ref], types: [.wasmAnyRef(shared: shared)]).output } } @@ -4423,13 +4436,14 @@ public class ProgramBuilder { @discardableResult public func addElementSegment(elements: [Variable]) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef), count: elements.count) + 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): enable shared tables and element segments (and functions?). public func getEntryTypeForTable(elementType: ILType) -> ILType { switch elementType { - case .wasmFuncRef: + case .wasmFuncRef(): return .wasmFunctionDef() | .function() default: return .object() @@ -4505,6 +4519,7 @@ public class ProgramBuilder { /// Produces a WasmGlobal that is valid to create in the given Context. public func randomWasmGlobal(forContext context: Context) -> WasmGlobal { + // TODO(pawkra): enable shared types. switch context { case .javascript: // These are valid in JS according to: https://webassembly.github.io/spec/js-api/#globals. @@ -4514,7 +4529,7 @@ public class ProgramBuilder { {.wasmf64(self.randomFloat())}, {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, {.wasmi64(self.randomInt())}, - {.externref}) + {.externref(shared: false)}) case .wasm: // TODO: Add simd128 and nullrefs. return withEqualProbability( @@ -4522,9 +4537,9 @@ public class ProgramBuilder { {.wasmf64(self.randomFloat())}, {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, {.wasmi64(self.randomInt())}, - {.externref}, - {.exnref}, - {.i31ref}) + {.externref(shared: false)}, + {.exnref(shared: false)}, + {.i31ref(shared: false)}) default: fatalError("Unsupported context \(context) for a WasmGlobal.") } @@ -4534,21 +4549,23 @@ public class ProgramBuilder { // 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. + // TODO(pawkra): enable shared types. 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)) @@ -4563,9 +4580,10 @@ public class ProgramBuilder { // 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. + // TODO(pawkra): enable shared types. (0.. [Variable] { @@ -5319,3 +5337,4 @@ public class ProgramBuilder { } } + diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 174e72924..61d9e181e 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -105,7 +105,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmArrayTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmArrayRef) + type.Is(.wasmArrayRef()) } else { false } @@ -113,7 +113,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmStructTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmStructRef) + type.Is(.wasmStructRef()) } else { false } @@ -121,7 +121,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmSignatureTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmFuncRef) + type.Is(.wasmFuncRef()) } else { false } diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 126519941..f356a4cc5 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -99,7 +99,7 @@ public let ProgramTemplates = [ 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) let wrapped = b.wrapSuspending(function: f!) @@ -152,7 +152,10 @@ public let ProgramTemplates = [ let tagToThrow = chooseUniform(from: wasmTags) let throwParamTypes = b.type(of: tagToThrow).wasmTagType!.parameters let tagToCatchForRethrow = chooseUniform(from: tags) - let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef] + // TODO(pawkra): support shared variant + let sharedRef = false + let wasmExnRefType = ILType.wasmExnRef(shared: sharedRef) + let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [wasmExnRefType] let module = b.buildWasmModule { wasmModule in // Wasm function that throws a tag, catches a tag (the same or a different one) to @@ -173,7 +176,7 @@ public let ProgramTemplates = [ return catchBlockOutputTypes.map(function.findOrGenerateWasmVar) } b.build(n: 10) - function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef)!) + function.wasmBuildThrowRef(exception: b.randomVariable(ofType: wasmExnRefType)!, sharedRef: sharedRef) return [] } } @@ -206,7 +209,7 @@ public let ProgramTemplates = [ return calleeSig.outputTypes.map(function.findOrGenerateWasmVar) }} - let table = wasmModule.addTable(elementType: .wasmFuncRef, + let table = wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, definedEntries: callees.enumerated().map { (index, callee) in .init(indexInTable: index, signature: calleeSig) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 697f84d4a..855bd34c9 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -270,6 +270,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ value: newValue) }, + // TODO(pawkra): add shared variant. CodeGenerator("WasmRefNullGenerator", inContext: .single(.wasmFunction)) { b in let function = b.currentWasmModule.currentWasmFunction if let typeDef = (b.findVariable { b.type(of: $0).Is(.wasmTypeDef()) }), @@ -280,7 +281,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmRefNull( type: .wasmRef( .Abstract( - chooseUniform(from: WasmAbstractHeapType.allCases)), + HeapTypeInfo(chooseUniform(from: WasmAbstractHeapType.allCases), shared: false)), nullability: true)) } }, @@ -296,16 +297,19 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmRefI31(value) }, - CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref)) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmI31Get(ref, isSigned: Bool.random()) + // TODO(pawkra): add shared variant. What about non-null case? + CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref())) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmI31Get(ref, isSigned: Bool.random(), shared: false) }, - CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef)) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmAnyConvertExtern(ref) + // TODO(pawkra): add shared variant. What about non-null case? + CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef())) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmAnyConvertExtern(ref, shared: false) }, - CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef)) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) + // TODO(pawkra): add shared variant. What about non-null case? + CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef())) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref, shared: false) }, // Primitive Value Generators @@ -596,7 +600,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(manoskouk): Generalize these. let minSize = 10 let maxSize: Int? = nil - let elementType = ILType.wasmFuncRef + // TODO(pawkra): support shared variant. + let elementType = ILType.wasmFuncRef() let definedEntryIndices: [Int] var definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [] @@ -609,7 +614,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. @@ -638,7 +643,7 @@ 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 } @@ -669,7 +674,8 @@ 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 } + // TODO(pawkra): support shared variant. + if !tableType.elementType.Is(.wasmFuncRef()) { return } guard let indexedSignature = tableType.knownEntries.randomElement() else { return } @@ -729,7 +735,8 @@ 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 } + // TODO(pawkra): support shared variant. + if !tableType.elementType.Is(.wasmFuncRef()) { return } guard let indexedSignature = (tableType.knownEntries.filter { @@ -1528,10 +1535,11 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmThrowRefGenerator", inContext: .single(.wasmFunction), - inputs: .required(.wasmExnRef) + // TODO(pawkra): support shared variant. + inputs: .required(.wasmExnRef()) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction - function.wasmBuildThrowRef(exception: exception) + function.wasmBuildThrowRef(exception: exception, sharedRef: false) }, CodeGenerator( @@ -1624,7 +1632,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ [] } if withExnRef { - outputTypes.append(.wasmExnRef) + // TODO(pawkra): support shared variant. + outputTypes.append(.wasmExnRef()) } function.wasmBeginBlock(with: [] => outputTypes, args: []) return outputTypes diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 121e9cbb8..9179ae663 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -14,6 +14,7 @@ public struct Configuration { /// The commandline arguments used by this instance. + /// TODO(pawkra): use these args or remove them (for now the only usage is printing them). public let arguments: [String] /// Timeout in milliseconds after which child processes will be killed. diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9ef54f216..6e8e212f8 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -2215,7 +2215,7 @@ public extension 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, diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 6486e4603..6bf1de3e7 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -388,8 +388,8 @@ extension Instruction: ProtobufConvertible { $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } } - case .Abstract(let heapType): - let kind = switch heapType { + case .Abstract(let heapTypeInfo): + let kind = switch heapTypeInfo.heapType { case .WasmExn: Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref case .WasmI31: @@ -420,6 +420,7 @@ extension Instruction: ProtobufConvertible { $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { $0.kind = kind $0.nullability = underlyingWasmType.wasmReferenceType!.nullability + $0.isShared = heapTypeInfo.shared } } } @@ -498,17 +499,26 @@ extension Instruction: ProtobufConvertible { return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.valuef64(val) 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) - case .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) + case .externref(let shared): + return nullrefGlobal(.externref, shared: shared) + case .exnref(let shared): + return nullrefGlobal(.exnref, shared: shared) + case .i31ref(let shared): + return nullrefGlobal(.i31Ref, shared: shared) case .imported(let ilType): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.imported(ILTypeToWasmTypeEnum(ilType)) } } + func nullrefGlobal(_ kind: Fuzzilli_Protobuf_WasmReferenceTypeKind, shared: Bool) -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal { + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceType.with { + $0.kind = kind + // TODO(gc): set nullability + $0.nullability = false + $0.isShared = shared + }) + } + func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) -> Fuzzilli_Protobuf_WasmCatchKind { switch catchKind { case .NoRef: @@ -1684,37 +1694,40 @@ extension Instruction: ProtobufConvertible { fatalError("Unrecognized wasm value type \(value)") } case .refType(_): - let refKind: WasmReferenceType.Kind = switch wasmType.refType.kind { - case .index: - .Index() + if wasmType.refType.kind == .index { + return .wasmRef(.Index(), nullability: wasmType.refType.nullability) + } + let heapType: WasmAbstractHeapType = switch wasmType.refType.kind { case .externref: - .Abstract(.WasmExtern) + .WasmExtern case .funcref: - .Abstract(.WasmFunc) + .WasmFunc case .exnref: - .Abstract(.WasmExn) + .WasmExn case .i31Ref: - .Abstract(.WasmI31) + .WasmI31 case .anyref: - .Abstract(.WasmAny) + .WasmAny case .eqref: - .Abstract(.WasmEq) + .WasmEq case .structref: - .Abstract(.WasmStruct) + .WasmStruct case .arrayref: - .Abstract(.WasmArray) + .WasmArray case .noneref: - .Abstract(.WasmNone) + .WasmNone case .noexternref: - .Abstract(.WasmNoExtern) + .WasmNoExtern case .nofuncref: - .Abstract(.WasmNoFunc) + .WasmNoFunc case .noexnref: - .Abstract(.WasmNoExn) + .WasmNoExn + case .index: + fatalError("Unexpected index type.") case .UNRECOGNIZED(let value): fatalError("Unrecognized wasm reference type \(value)") } - return .wasmRef(refKind, nullability: wasmType.refType.nullability) + return .wasmRef(heapType, shared: wasmType.refType.isShared, nullability: wasmType.refType.nullability) case .none: fatalError("Absent wasm type") } @@ -1785,13 +1798,13 @@ extension Instruction: ProtobufConvertible { func convertWasmGlobal(_ proto: Fuzzilli_Protobuf_WasmGlobal) -> WasmGlobal { switch proto.wasmGlobal { case .nullref(let val): - switch val { + switch val.kind { case .externref: - return .externref + return .externref(shared: val.isShared) case .exnref: - return .exnref + return .exnref(shared: val.isShared) case .i31Ref: - return .i31ref + return .i31ref(shared: val.isShared) default: fatalError("Unrecognized global wasm reference type \(val)") } diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 054f242a2..65f9689ac 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -888,17 +888,18 @@ public struct JSTyper: Analyzer { case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) case .wasmRefI31(_): - setType(of: instr.output, to: .wasmRefI31) + // TODO(pawkra): support shared variant. + setType(of: instr.output, to: .wasmRefI31()) case .wasmI31Get(_): setType(of: instr.output, to: .wasmi32) case .wasmAnyConvertExtern(_): // 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. + // 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) @@ -1834,7 +1835,7 @@ public struct JSTyper: Analyzer { 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))) diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index 729550e9c..5fe3d7269 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -247,23 +247,33 @@ 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 allWasmRefTypes() -> [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 @@ -275,6 +285,10 @@ public struct ILType: Hashable { wasmTypeDef(description: .selfReference) } + static func wasmRef(_ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true) -> ILType { + 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, @@ -286,7 +300,7 @@ 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 @@ -1089,11 +1103,13 @@ extension ILType: CustomStringConvertible { } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapType): - return ".wasmRef(.Abstract(\(nullPrefix)\(heapType)))" + 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)))" + let sharedPrefix = if desc.abstractHeapSupertype?.shared ?? false { "shared " } else { "" } + return ".wasmRef(\(nullPrefix)Index \(sharedPrefix)\(desc.format(abbreviate: abbreviate)))" } return ".wasmRef(\(nullPrefix)Index)" } @@ -1391,9 +1407,9 @@ 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 { +// TODO(pawkra): rename to HeapType +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 @@ -1475,8 +1491,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 @@ -1490,6 +1506,57 @@ 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. @@ -1514,7 +1581,7 @@ 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 { @@ -2068,10 +2135,11 @@ 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? + // TODO(pawkra): rename to heapSupertype + 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 } @@ -2101,7 +2169,8 @@ 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 { @@ -2122,7 +2191,8 @@ 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 { @@ -2153,7 +2223,8 @@ 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/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 452dd9cc5..8a441966f 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -695,9 +695,9 @@ public enum WasmGlobal { case wasmf64(Float64) // Empty reference // TODO(gc): Add support for globals with non-nullable references. - case externref - case exnref - case i31ref + case externref(shared: Bool) + case exnref(shared: Bool) + case i31ref(shared: Bool) // function reference case refFunc(Int) @@ -715,12 +715,12 @@ public enum WasmGlobal { return .wasmf32 case .wasmf64: return .wasmf64 - case .externref: - return .wasmExternRef - case .exnref: - return .wasmExnRef - case .i31ref: - return .wasmI31Ref + case let .externref(shared): + return ILType.wasmExternRef(shared: shared) + case let .exnref(shared): + return ILType.wasmExnRef(shared: shared) + case let .i31ref(shared): + return ILType.wasmI31Ref(shared: shared) case .imported(let type): assert(type.wasmGlobalType != nil) return type.wasmGlobalType!.valueType @@ -729,6 +729,7 @@ public enum WasmGlobal { } } + //TODO(pawkra): rename to jsTypeName func typeString() -> String { switch self { case .wasmi64(_): @@ -739,18 +740,26 @@ public enum WasmGlobal { return "f32" case .wasmf64(_): return "f64" - case .externref: + case let .externref(shared): + assertNotShared(shared) return "externref" - case .exnref: + case let .exnref(shared): + assertNotShared(shared) return "exnref" - case .i31ref: + case let .i31ref(shared): + assertNotShared(shared) return "i31ref" default: fatalError("Unimplemented / unhandled") } } + private func assertNotShared(_ shared: Bool) { + assert(!shared, "Shared references not supported in JS > WASM API") + } + // Returns a JS string representing the initial value. + // TODO(pawkra): rename to valueToJsString func valueToString() -> String { switch self { case .wasmi64(let val): @@ -761,10 +770,10 @@ public enum WasmGlobal { return "\(val)" case .wasmf64(let val): return "\(val)" - case .externref: + case .externref(_): return "" - case .exnref, - .i31ref: + case .exnref(_), + .i31ref(_): return "null" default: fatalError("Unimplemented / unhandled") @@ -801,9 +810,11 @@ final class WasmDefineTable: WasmOperation { self.definedEntries = definedEntries // TODO(manoskouk): Find a way to define non-function tables with initializers. - assert(elementType == .wasmFuncRef || definedEntries.isEmpty) + // TODO(pawkra): support shared refs. + let isWasmFuncRef = elementType == .wasmFuncRef() + assert(isWasmFuncRef || definedEntries.isEmpty) - super.init(numInputs: elementType == .wasmFuncRef ? definedEntries.count : 0, + super.init(numInputs: isWasmFuncRef ? definedEntries.count : 0, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasm]) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 49cfb5a04..bcd7057b7 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1540,11 +1540,12 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let type: String switch op.tableType.elementType { - case .wasmExternRef: + case .wasmExternRef(): type = "externref" - case .wasmFuncRef: + case .wasmFuncRef(): type = "anyfunc" // TODO(mliedtke): add tables for i31ref. + // TODO(pawkra): add shared ref variants. default: fatalError("Unknown table type") } @@ -1579,21 +1580,21 @@ public class JavaScriptLifter: Lifter { return "\"i64\"" case .wasmSimd128: return "\"v128\"" - case .wasmExternRef: - return "\"externref\"" - case .wasmFuncRef: + case ILType.wasmExternRef(): + return "\"externref\"" + case ILType.wasmFuncRef(): return "\"anyfunc\"" - case .wasmAnyRef: + case ILType.wasmAnyRef(): return "\"anyref\"" - case .wasmEqRef: + case ILType.wasmEqRef(): return "\"eqref\"" - case .wasmI31Ref: + case ILType.wasmI31Ref(): return "\"i31ref\"" - case .wasmStructRef: + case ILType.wasmStructRef(): return "\"structref\"" - case .wasmArrayRef: + case ILType.wasmArrayRef(): return "\"arrayref\"" - case .wasmExnRef: + case ILType.wasmExnRef(): return "\"exnref\"" default: diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 4944ac161..a11ed0dbd 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -527,39 +527,33 @@ 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 { guard let description else { throw WasmLifter.CompileError.missingTypeInformation } + // TODO(pawkra): encode shared bit return Leb128.unsignedEncode(typeDescToIndex[description]!) } @@ -568,28 +562,22 @@ 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(type) } // 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(_ 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) + case .Abstract(let heapTypeInfo): + return encodeAbstractHeapType(heapTypeInfo) } } - // HINT: If you crash here, you might not have specified an encoding for your new type in `ILTypeMapping`. - return ILTypeMapping[type] ?? ILTypeMapping[defaultType!]! + fatalError("This function supports only wasmReferenceType.") } private func buildTypeEntry(for desc: WasmTypeDescription, data: inout Data) throws { @@ -663,7 +651,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()) } } @@ -1076,14 +1064,14 @@ public class WasmLifter { temporaryInstruction = Instruction(Consti32(value: val), output: Variable()) case .wasmi64(let val): temporaryInstruction = Instruction(Consti64(value: val), output: Variable()) - case .externref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef) + Data([0x0B]) + case .externref(let shared): + temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef(shared: shared)) + Data([0x0B]) continue - case .exnref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef) + Data([0x0B]) + case .exnref(let shared): + temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef(shared: shared)) + Data([0x0B]) continue - case .i31ref: - temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref) + Data([0x0B]) + case .i31ref(let shared): + temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref(shared: shared)) + Data([0x0B]) continue case .refFunc(_), .imported(_): @@ -1506,7 +1494,8 @@ 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. diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 94e7e297c..4f8b7b843 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -369,23 +369,21 @@ public class OperationMutator: BaseInstructionMutator { case .wasmDefineGlobal(let op): // We never change the type of the global, only the value as changing the type will break the following code pretty much instantly. - let wasmGlobal: WasmGlobal - switch op.wasmGlobal.toType() { - case .wasmf32: - wasmGlobal = .wasmf32(Float32(b.randomFloat())) - case .wasmf64: - wasmGlobal = .wasmf64(b.randomFloat()) - case .wasmi32: - wasmGlobal = .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) - case .wasmi64: - wasmGlobal = .wasmi64(b.randomInt()) - case .wasmExternRef, - .wasmExnRef, - .wasmI31Ref: - wasmGlobal = op.wasmGlobal - default: - fatalError("unexpected/unimplemented Value Type!") - } + let wasmGlobal:WasmGlobal = + switch op.wasmGlobal.toType() { + case .wasmf32: + .wasmf32(Float32(b.randomFloat())) + case .wasmf64: + .wasmf64(b.randomFloat()) + case .wasmi32: + .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) + case .wasmi64: + .wasmi64(b.randomInt()) + case ILType.wasmExternRef(), ILType.wasmExnRef(), ILType.wasmI31Ref(): + op.wasmGlobal + default: + fatalError("unexpected/unimplemented Value Type!") + } newOp = WasmDefineGlobal(wasmGlobal: wasmGlobal, isMutable: probability(0.5)) case .wasmDefineTable(let op): // TODO: change table size? diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 2b2248232..cdca77467 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4138,6 +4138,8 @@ public struct Fuzzilli_Protobuf_WasmReferenceType: Sendable { public var nullability: Bool = false + public var isShared: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -4712,10 +4714,10 @@ public struct Fuzzilli_Protobuf_WasmGlobal: Sendable { set {wasmGlobal = .valuef64(newValue)} } - public var nullref: Fuzzilli_Protobuf_WasmReferenceTypeKind { + public var nullref: Fuzzilli_Protobuf_WasmReferenceType { get { if case .nullref(let v)? = wasmGlobal {return v} - return .index + return Fuzzilli_Protobuf_WasmReferenceType() } set {wasmGlobal = .nullref(newValue)} } @@ -4743,7 +4745,7 @@ public struct Fuzzilli_Protobuf_WasmGlobal: Sendable { case valuei64(Int64) case valuef32(Float) case valuef64(Double) - case nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind) + case nullref(Fuzzilli_Protobuf_WasmReferenceType) case funcref(Int64) case imported(Fuzzilli_Protobuf_WasmILType) @@ -11562,7 +11564,7 @@ extension Fuzzilli_Protobuf_WasmReturn: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmReferenceType" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{1}nullability\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{1}nullability\0\u{1}isShared\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11572,6 +11574,7 @@ extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProto switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.kind) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.nullability) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isShared) }() default: break } } @@ -11584,12 +11587,16 @@ extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProto if self.nullability != false { try visitor.visitSingularBoolField(value: self.nullability, fieldNumber: 2) } + if self.isShared != false { + try visitor.visitSingularBoolField(value: self.isShared, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmReferenceType, rhs: Fuzzilli_Protobuf_WasmReferenceType) -> Bool { if lhs.kind != rhs.kind {return false} if lhs.nullability != rhs.nullability {return false} + if lhs.isShared != rhs.isShared {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -12852,10 +12859,15 @@ extension Fuzzilli_Protobuf_WasmGlobal: SwiftProtobuf.Message, SwiftProtobuf._Me } }() case 6: try { - var v: Fuzzilli_Protobuf_WasmReferenceTypeKind? - try decoder.decodeSingularEnumField(value: &v) + var v: Fuzzilli_Protobuf_WasmReferenceType? + var hadOneofValue = false + if let current = self.wasmGlobal { + hadOneofValue = true + if case .nullref(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) if let v = v { - if self.wasmGlobal != nil {try decoder.handleConflictingOneOf()} + if hadOneofValue {try decoder.handleConflictingOneOf()} self.wasmGlobal = .nullref(v) } }() @@ -12912,7 +12924,7 @@ extension Fuzzilli_Protobuf_WasmGlobal: SwiftProtobuf.Message, SwiftProtobuf._Me }() case .nullref?: try { guard case .nullref(let v)? = self.wasmGlobal else { preconditionFailure() } - try visitor.visitSingularEnumField(value: v, fieldNumber: 6) + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) }() case .funcref?: try { guard case .funcref(let v)? = self.wasmGlobal else { preconditionFailure() } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 8ed578def..a4feaf8f3 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -920,6 +920,7 @@ enum WasmReferenceTypeKind { message WasmReferenceType { WasmReferenceTypeKind kind = 1; bool nullability = 2; + bool isShared = 3; } message WasmILType { @@ -1100,7 +1101,7 @@ message WasmGlobal { int64 valuei64 = 3; float valuef32 = 4; double valuef64 = 5; - WasmReferenceTypeKind nullref = 6; + WasmReferenceType nullref = 6; int64 funcref = 7; WasmILType imported = 8; } diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 967210b97..e8a5d66fa 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -554,7 +554,7 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in } let table = wasmModule.addTable( - elementType: .wasmFuncRef, + elementType: .wasmFuncRef(), minSize: numCallees, definedEntries: (0.. 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 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) @@ -745,6 +745,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { var args = [ "--expose-gc", "--expose-externalize-string", + "--experimental-wasm-shared", "--omit-quit", "--allow-natives-syntax", "--fuzzing", diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 56ab52d11..da45fc8c3 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1534,7 +1534,7 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - let wasmSignature = [] => [.wasmExternRef] + let wasmSignature = [] => [.wasmExternRef()] let typeDesc = b.type(of: typeGroup[0]).wasmTypeDefinition!.description! @@ -1574,7 +1574,7 @@ 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)] } @@ -1585,7 +1585,7 @@ class JSTyperTests: XCTestCase { // 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)!] } @@ -1795,7 +1795,7 @@ class JSTyperTests: XCTestCase { let wasmTableConstructor = b.getProperty("Table", of: wasm) 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) diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 7758461d1..39a00c095 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3274,7 +3274,7 @@ class LifterTests: XCTestCase { 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 diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 4ffb8c5d9..8a6dce290 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -133,15 +133,16 @@ 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: + case ILType.wasmFuncRef(): return jsFunction - case .wasmNullExternRef, .wasmNullFuncRef, .wasmNullRef: + case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): return b.loadNull() - case .wasmExternRef, .wasmAnyRef: + case ILType.wasmExternRef(), ILType.wasmAnyRef(): return b.createObject(with: [:]) default: return b.loadInt(321) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 5a9c53b63..4478f3225 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2863,21 +2863,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) @@ -2887,14 +2887,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) @@ -2903,25 +2903,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 [] } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 5e6f0fd77..073388a11 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -1110,11 +1110,12 @@ class TypeSystemTests: XCTestCase { 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 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))") + // 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])") @@ -1148,11 +1149,11 @@ class TypeSystemTests: XCTestCase { ".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))]])") + "[.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 +1164,7 @@ class TypeSystemTests: XCTestCase { } func testWasmSubsumptionRules() { - let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmFuncRef, .wasmExternRef, .wasmI31Ref, .wasmExnRef] + let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allWasmRefTypes() // Make sure that no Wasm type is subsumed by (JS-)anything. for t in wasmTypes { XCTAssertEqual(t <= .jsAnything, false) @@ -1209,14 +1210,16 @@ class TypeSystemTests: XCTestCase { // 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) + } } } @@ -1276,7 +1279,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 +1289,48 @@ 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() { @@ -1433,15 +1448,10 @@ class TypeSystemTests: XCTestCase { .wasmf32, .wasmi64, .wasmf64, - .wasmFuncRef, - .wasmExternRef, - .wasmExnRef, - .wasmI31Ref, - .wasmRefI31, .wasmFunctionDef([.wasmi32] => [.wasmi64]), .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef] => [.wasmExternRef]), + .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), .wasmMemory(limits: Limits(min: 10)), .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + ] + ILType.allWasmRefTypes() } diff --git a/Tests/FuzzilliTests/WasmTableTests.swift b/Tests/FuzzilliTests/WasmTableTests.swift index c3e59c9b7..2e4f9335f 100644 --- a/Tests/FuzzilliTests/WasmTableTests.swift +++ b/Tests/FuzzilliTests/WasmTableTests.swift @@ -22,7 +22,7 @@ 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 +31,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 f7955e212..8a78971bb 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -44,16 +44,16 @@ func testForErrorOutput(program: String, runner: JavaScriptExecutor, errorMessag 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, .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) } @@ -440,7 +440,7 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1338\n4242\n6.61e-321\n") } - func testGlobalExnRef() throws { + func globalExnRef(sharedRef: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -450,8 +450,8 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) 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))) + let global = wasmModule.addGlobal(wasmGlobal: .exnref(shared: sharedRef), isMutable: true) + XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExnRef(shared: sharedRef), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let value = function.wasmLoadGlobal(globalVariable: global) @@ -460,12 +460,12 @@ class WasmFoundationTests: XCTestCase { // Throw an exception, catch it and store it in the global. wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef], args: []) { catchLabel, _ in + let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef(shared: sharedRef)], 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(shared: sharedRef))] }[0] function.wasmStoreGlobal(globalVariable: global, to: exnref) return [] @@ -473,12 +473,12 @@ 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 + let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef(shared: sharedRef)], args: []) { catchLabel, _ in function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global), sharedRef: sharedRef) return [] } - return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef)] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef(shared: sharedRef))] } return [caughtValues[0]] } @@ -509,12 +509,12 @@ 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 + let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef(shared: sharedRef)], args: []) { catchLabel, _ in function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global), sharedRef: sharedRef) return [] } - return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef)] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef(shared: sharedRef))] } return [caughtValues[0]] } @@ -529,7 +529,16 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n42\nexception\n42\n") } - func testGlobalExternRef() throws { + func testGlobalExnRefShared() throws { + // TODO(pawkra) + throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") + } + + func testGlobalExnRefUnshared() throws { + try globalExnRef(sharedRef: false) + } + + func globalExternRef(sharedRef: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -537,14 +546,14 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() 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))) + let global = wasmModule.addGlobal(wasmGlobal: .externref(shared: sharedRef), isMutable: true) + XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(shared: sharedRef), isMutable: true))) - wasmModule.addWasmFunction(with: [] => [.wasmExternRef]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [.wasmExternRef(shared: sharedRef)]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmExternRef] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmExternRef(shared: sharedRef)] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -570,6 +579,15 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\nHello!\nHello!\n") } + func testglobalExternRefShared() throws { + // TODO(pawkra) + throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") + } + + func testglobalExternRefUnshared() throws { + try globalExternRef(sharedRef: false) + } + func testGlobalExternRefFromJS() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -577,8 +595,9 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - 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))) + // TODO(pawkra): add shared ref variant. + let global: Variable = b.createWasmGlobal(value: .externref(shared: false), 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). @@ -594,22 +613,22 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "undefined\nHello!\n") } - func testGlobalI31Ref() throws { - let runner = try GetJavaScriptExecutorOrSkipTest() + func globalI31Ref(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 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))) + let global = wasmModule.addGlobal(wasmGlobal: .i31ref(shared: sharedRef), isMutable: true) + XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(shared: sharedRef), isMutable: true))) - wasmModule.addWasmFunction(with: [] => [.wasmI31Ref]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [.wasmI31Ref(shared: sharedRef)]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmI31Ref] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmI31Ref(shared: sharedRef)] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -634,6 +653,14 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\n-42\n-42\n") } + func testGlobalI31RefShared() throws { + try globalI31Ref(sharedRef: true) + } + + func testGlobalI31RefUnshared() throws { + try globalI31Ref(sharedRef: false) + } + func testGlobalI31RefFromJS() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -641,8 +668,9 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - 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))) + // TODO(pawkra): add shared ref variant. + let global: Variable = b.createWasmGlobal(value: .i31ref(shared: false), 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,8 +694,8 @@ 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)]) @@ -675,9 +703,9 @@ class WasmFoundationTests: XCTestCase { 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) @@ -727,7 +755,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in [function.wasmi32BinOp(params[0], function.consti32(1), binOpKind: .Add)] } - wasmModule.addTable(elementType: .wasmFuncRef, + wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, definedEntries: [.init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), .init(indexInTable: 1, signature: [] => [.wasmi64])], definedEntryValues: [wasmFunction, jsFunction], @@ -745,7 +773,7 @@ class WasmFoundationTests: XCTestCase { 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: [ + 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]) @@ -793,7 +821,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef, + 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], @@ -843,7 +871,7 @@ class WasmFoundationTests: XCTestCase { 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])], definedEntryValues: [wasmFunction, jsFunction], @@ -851,7 +879,7 @@ class WasmFoundationTests: XCTestCase { } let table = b.getProperty("wt0", of: module.loadExports()) - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef, limits: Limits(min: 10), isTable64: false, knownEntries: [ + 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]) ])) @@ -866,7 +894,7 @@ class WasmFoundationTests: XCTestCase { 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])] } @@ -881,7 +909,7 @@ 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: [ + 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]) @@ -997,7 +1025,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef, + 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], @@ -3760,10 +3788,11 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let tagVoid = b.createWasmTag(parameterTypes: []) let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) + // TODO(pawkra): add shared ref variant. 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.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.WasmBuildThrow(tag: tagVoid, inputs: []) @@ -3772,10 +3801,10 @@ class WasmFoundationTests: XCTestCase { } 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)] } @@ -3865,10 +3894,8 @@ class WasmFoundationTests: XCTestCase { 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() let jsProg = fuzzer.lifter.lift(prog, withOptions: [.includeComments]) @@ -3879,7 +3906,7 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "") } - func testThrowRef() throws { + func throwRef(sharedRef: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) @@ -3894,17 +3921,17 @@ class WasmFoundationTests: XCTestCase { 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 + let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef(shared: sharedRef)], 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(shared: sharedRef))] } // Print the caught i32 value. 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]) + function.wasmBuildThrowRef(exception: caughtValues[1], sharedRef: sharedRef) return [] } @@ -3929,6 +3956,15 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n42\n") } + func testThrowRefShared() throws { + // TODO(pawkra) + throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") + } + + func testThrowRefUnshared() throws { + try throwRef(sharedRef: false) + } + func testUnreachable() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -3972,7 +4008,7 @@ class WasmFoundationTests: XCTestCase { 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])] } } @@ -4148,13 +4184,13 @@ class WasmFoundationTests: XCTestCase { 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, + // 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: [], @@ -4196,12 +4232,13 @@ class WasmFoundationTests: XCTestCase { 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]) }, definedEntryValues: [f3, f3, f1, f2], @@ -4468,8 +4505,9 @@ class WasmGCTests: XCTestCase { 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. @@ -4494,7 +4532,7 @@ class WasmGCTests: XCTestCase { let jsProg = buildAndLiftProgram { b in 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. @@ -4708,15 +4746,19 @@ 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-exnref", "--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() + // TODO(pawkra): simplify once V8 adds support for shared references of type: func, exn + 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 @@ -4732,8 +4774,8 @@ 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 + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmI31Ref()]) { function, label, args in [function.wasmRefI31(args[0])] } - 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: [.wasmI31Ref()] => [.wasmi32, .wasmi32]) { function, label, args in + [function.wasmI31Get(args[0], isSigned: true, shared: false), + function.wasmI31Get(args[0], isSigned: false, shared: false)] } } @@ -4780,36 +4830,75 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } - func testExternAnyConversions() throws { + func i31Ref(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 module = b.buildWasmModule { wasmModule in + let f1 = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmI31Ref(shared: sharedRef)]) { function, label, args in + [function.wasmRefI31(args[0])] + } + let f2 = wasmModule.addWasmFunction(with: [.wasmI31Ref(shared: sharedRef)] => [.wasmi32, .wasmi32]) { function, label, args in + [function.wasmI31Get(args[0], isSigned: true, shared: sharedRef), + function.wasmI31Get(args[0], isSigned: false, shared: sharedRef)] + } + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, args in + let ref = function.wasmCallDirect(signature: [.wasmi32] => [.wasmI31Ref(shared: sharedRef)], function: f1, functionArgs: [function.consti32(-42)]) + return function.wasmCallDirect(signature: [.wasmI31Ref(shared: sharedRef)] => [.wasmi32, .wasmi32], function: f2, functionArgs: ref) + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + let result = b.callMethod(module.getExportedMethod(at: 2), 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: "-42,2147483606\n") + } + + func testi31RefSharedRef() throws { + // TODO(pawkra) + throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") + } + + func testi31RefUnsharedRef() throws { + try i31Ref(sharedRef: false) + } + + func externAnyConversions(sharedRef: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern(shared: sharedRef)]) { 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) + let result = function.wasmExternConvertAny(function.wasmRefI31(args[0]), shared: sharedRef) + XCTAssertEqual(b.type(of: result), .wasmRefExtern(shared: sharedRef)) return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern] => [.wasmRefAny]) { function, label, args in - let result = function.wasmAnyConvertExtern(args[0]) - XCTAssertEqual(b.type(of: result), .wasmRefAny) + wasmModule.addWasmFunction(with: [.wasmRefExtern(shared: sharedRef)] => [.wasmRefAny(shared: sharedRef)]) { function, label, args in + let result = function.wasmAnyConvertExtern(args[0], shared: sharedRef) + XCTAssertEqual(b.type(of: result), .wasmRefAny(shared: sharedRef)) 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(shared: sharedRef)]) { function, label, args in + let result = function.wasmExternConvertAny(function.wasmRefNull(type: .wasmNullRef(shared: sharedRef)), shared: sharedRef) + XCTAssertEqual(b.type(of: result), .wasmExternRef(shared: sharedRef)) 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(shared: sharedRef)]) { function, label, args in + let result = function.wasmAnyConvertExtern(function.wasmRefNull(type: .wasmNullExternRef(shared: sharedRef)), shared: sharedRef) + XCTAssertEqual(b.type(of: result), .wasmAnyRef(shared: sharedRef)) return [result] } } @@ -4825,6 +4914,15 @@ class WasmGCTests: XCTestCase { let jsProg = fuzzer.lifter.lift(prog) testForOutput(program: jsProg, runner: runner, outputString: "42\n42\nnull\nnull\n") } + + func testExternAnyConversionsSharedRefs() throws { + // TODO(pawkra): double check that shared references can be converted to extern ref. + throw XCTSkip("Fix once we are able to emit shared i31, extern, null, and nullextern refs.") + } + + func testExternAnyConversionsUnsharedRefs() throws { + try externAnyConversions(sharedRef: false) + } } class WasmNumericalTests: XCTestCase { @@ -6359,9 +6457,10 @@ class WasmJSPITests: XCTestCase { XCTAssertEqual(b.type(of: importFunction), .object(ofGroup: "WasmSuspendingObject")) // Now lets build the module + // TODO(pawkra): add shared ref variant. 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])!] } } From 57064c378bb5e96913095f6d1f708f88e621084e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 2 Dec 2025 06:15:38 -0800 Subject: [PATCH 024/234] Revert "Add support for shared references." This reverts commit e35cbb5b7b784cae910776e4edeefc8553316d56. Reason for revert: Crashes and not reviewed yet. Original change's description: > Add support for shared references. > > Generating shared ref variables to be done in following CLs. > > See https://github.com/WebAssembly/shared-everything-threads/blob/main/proposals/shared-everything-threads/Overview.md. > > Bug: 448349112 > Change-Id: I3358ce9cdd528147b66f1954ef1a008b048e06df > Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8734256 > Commit-Queue: Matthias Liedtke > Reviewed-by: Dominik Klemba > Commit-Queue: Pawel Krawczyk Bug: 448349112 No-Presubmit: true No-Tree-Checks: true No-Try: true Change-Id: I8bc73bef53d053078db9318de6408d4dbf2f4cda Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8810396 Bot-Commit: Rubber Stamper Auto-Submit: Matthias Liedtke Commit-Queue: Rubber Stamper --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 99 +++--- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 6 +- .../Fuzzilli/CodeGen/ProgramTemplates.swift | 11 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 39 +-- Sources/Fuzzilli/Configuration.swift | 1 - .../Environment/JavaScriptEnvironment.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 69 ++--- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 11 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 127 ++------ Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 45 ++- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 23 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 81 ++--- .../Fuzzilli/Mutators/OperationMutator.swift | 32 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 28 +- Sources/Fuzzilli/Protobuf/operations.proto | 3 +- .../Profiles/V8CommonProfile.swift | 5 +- Tests/FuzzilliTests/JSTyperTests.swift | 8 +- Tests/FuzzilliTests/LifterTest.swift | 2 +- Tests/FuzzilliTests/LiveTests.swift | 7 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 52 ++-- Tests/FuzzilliTests/TypeSystemTest.swift | 108 +++---- Tests/FuzzilliTests/WasmTableTests.swift | 4 +- Tests/FuzzilliTests/WasmTests.swift | 283 ++++++------------ 23 files changed, 403 insertions(+), 643 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 63ef596ed..6bc1dbd6b 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1217,6 +1217,7 @@ public class ProgramBuilder { numberOfHiddenVariables -= 1 } + /// Hides a variable containing a function from the function's body. /// /// For example, in @@ -1249,20 +1250,19 @@ public class ProgramBuilder { 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] } } @@ -1272,7 +1272,6 @@ 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 @@ -1289,12 +1288,12 @@ 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 @@ -3882,9 +3881,8 @@ public class ProgramBuilder { b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) } - // TODO(pawkra): support shared tables and element segments. public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { - let elementSegmentType = ILType.wasmFuncRef() + let elementSegmentType = ILType.wasmFuncRef let tableElemType = b.type(of: table).wasmTableType!.elementType assert(elementSegmentType.Is(tableElemType)) @@ -4014,22 +4012,18 @@ public class ProgramBuilder { return Array(b.emit(WasmEndLoop(outputTypes: signature.outputTypes), withInputs: fallthroughResults, types: 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)}) #if DEBUG var argIndex = signature.parameterTypes.count - let assertLabelTypeData: (ILType) -> () = { labelType in - assert(labelType.Is(.anyLabel)) - 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]) - assertLabelTypeData(labelType) + assert(labelType.Is(.anyLabel)) + assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef)) argIndex += 2 case .NoRef: assert(b.type(of: args[argIndex]).Is(.object(ofGroup: "WasmTag"))) @@ -4037,7 +4031,8 @@ public class ProgramBuilder { argIndex += 2 case .AllRef: let labelType = b.type(of: args[argIndex]) - assertLabelTypeData(labelType) + assert(labelType.Is(.anyLabel)) + assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef)) argIndex += 1 case .AllNoRef: assert(b.type(of: args[argIndex]).Is(.anyLabel)) @@ -4100,8 +4095,8 @@ public class ProgramBuilder { b.emit(WasmThrow(parameterTypes: tagType.parameters), withInputs: [tag] + inputs, types: [.object(ofGroup: "WasmTag")] + tagType.parameters) } - public func wasmBuildThrowRef(exception: Variable, sharedRef: Bool) { - b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef(shared: sharedRef)]) + public func wasmBuildThrowRef(exception: Variable) { + b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef]) } public func wasmBuildLegacyRethrow(_ exceptionLabel: Variable) { @@ -4142,23 +4137,15 @@ public class ProgramBuilder { // 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 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 different types. For now - // fallback to refNull if possible. - if (type.wasmReferenceType!.nullability) { - return self.wasmRefNull(type: type) - } else { - return nil + 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()))) } + assert(type.wasmReferenceType!.nullability) + return self.wasmRefNull(type: type) case .Index(_), .none: break // Unimplemented @@ -4356,18 +4343,18 @@ public class ProgramBuilder { } @discardableResult - public func wasmI31Get(_ refI31: Variable, isSigned: Bool, shared: Bool) -> Variable { - return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31], types: [.wasmI31Ref(shared: shared)]).output + public func wasmI31Get(_ refI31: Variable, isSigned: Bool) -> Variable { + return b.emit(WasmI31Get(isSigned: isSigned), withInputs: [refI31], types: [.wasmI31Ref]).output } @discardableResult - public func wasmAnyConvertExtern(_ ref: Variable, shared: Bool) -> Variable { - b.emit(WasmAnyConvertExtern(), withInputs: [ref], types: [.wasmExternRef(shared: shared)]).output + public func wasmAnyConvertExtern(_ ref: Variable) -> Variable { + b.emit(WasmAnyConvertExtern(), withInputs: [ref], types: [.wasmExternRef]).output } @discardableResult - public func wasmExternConvertAny(_ ref: Variable, shared: Bool) -> Variable { - b.emit(WasmExternConvertAny(), withInputs: [ref], types: [.wasmAnyRef(shared: shared)]).output + public func wasmExternConvertAny(_ ref: Variable) -> Variable { + b.emit(WasmExternConvertAny(), withInputs: [ref], types: [.wasmAnyRef]).output } } @@ -4436,14 +4423,13 @@ public class ProgramBuilder { @discardableResult public func addElementSegment(elements: [Variable]) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef()), count: elements.count) + 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): enable shared tables and element segments (and functions?). public func getEntryTypeForTable(elementType: ILType) -> ILType { switch elementType { - case .wasmFuncRef(): + case .wasmFuncRef: return .wasmFunctionDef() | .function() default: return .object() @@ -4519,7 +4505,6 @@ public class ProgramBuilder { /// Produces a WasmGlobal that is valid to create in the given Context. public func randomWasmGlobal(forContext context: Context) -> WasmGlobal { - // TODO(pawkra): enable shared types. switch context { case .javascript: // These are valid in JS according to: https://webassembly.github.io/spec/js-api/#globals. @@ -4529,7 +4514,7 @@ public class ProgramBuilder { {.wasmf64(self.randomFloat())}, {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, {.wasmi64(self.randomInt())}, - {.externref(shared: false)}) + {.externref}) case .wasm: // TODO: Add simd128 and nullrefs. return withEqualProbability( @@ -4537,9 +4522,9 @@ public class ProgramBuilder { {.wasmf64(self.randomFloat())}, {.wasmi32(Int32(truncatingIfNeeded: self.randomInt()))}, {.wasmi64(self.randomInt())}, - {.externref(shared: false)}, - {.exnref(shared: false)}, - {.i31ref(shared: false)}) + {.externref}, + {.exnref}, + {.i31ref}) default: fatalError("Unsupported context \(context) for a WasmGlobal.") } @@ -4549,23 +4534,21 @@ public class ProgramBuilder { // 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. - // TODO(pawkra): enable shared types. 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)) @@ -4580,10 +4563,9 @@ public class ProgramBuilder { // 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. - // TODO(pawkra): enable shared types. (0.. [Variable] { @@ -5337,4 +5319,3 @@ public class ProgramBuilder { } } - diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 61d9e181e..174e72924 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -105,7 +105,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmArrayTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmArrayRef()) + type.Is(.wasmArrayRef) } else { false } @@ -113,7 +113,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmStructTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmStructRef()) + type.Is(.wasmStructRef) } else { false } @@ -121,7 +121,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmSignatureTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmFuncRef()) + type.Is(.wasmFuncRef) } else { false } diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index f356a4cc5..126519941 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -99,7 +99,7 @@ public let ProgramTemplates = [ 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) let wrapped = b.wrapSuspending(function: f!) @@ -152,10 +152,7 @@ public let ProgramTemplates = [ let tagToThrow = chooseUniform(from: wasmTags) let throwParamTypes = b.type(of: tagToThrow).wasmTagType!.parameters let tagToCatchForRethrow = chooseUniform(from: tags) - // TODO(pawkra): support shared variant - let sharedRef = false - let wasmExnRefType = ILType.wasmExnRef(shared: sharedRef) - let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [wasmExnRefType] + 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 @@ -176,7 +173,7 @@ public let ProgramTemplates = [ return catchBlockOutputTypes.map(function.findOrGenerateWasmVar) } b.build(n: 10) - function.wasmBuildThrowRef(exception: b.randomVariable(ofType: wasmExnRefType)!, sharedRef: sharedRef) + function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef)!) return [] } } @@ -209,7 +206,7 @@ public let ProgramTemplates = [ return calleeSig.outputTypes.map(function.findOrGenerateWasmVar) }} - let table = wasmModule.addTable(elementType: .wasmFuncRef(), + let table = wasmModule.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: callees.enumerated().map { (index, callee) in .init(indexInTable: index, signature: calleeSig) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 855bd34c9..697f84d4a 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -270,7 +270,6 @@ public let WasmCodeGenerators: [CodeGenerator] = [ value: newValue) }, - // TODO(pawkra): add shared variant. CodeGenerator("WasmRefNullGenerator", inContext: .single(.wasmFunction)) { b in let function = b.currentWasmModule.currentWasmFunction if let typeDef = (b.findVariable { b.type(of: $0).Is(.wasmTypeDef()) }), @@ -281,7 +280,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmRefNull( type: .wasmRef( .Abstract( - HeapTypeInfo(chooseUniform(from: WasmAbstractHeapType.allCases), shared: false)), + chooseUniform(from: WasmAbstractHeapType.allCases)), nullability: true)) } }, @@ -297,19 +296,16 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmRefI31(value) }, - // TODO(pawkra): add shared variant. What about non-null case? - CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref())) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmI31Get(ref, isSigned: Bool.random(), shared: false) + CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref)) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmI31Get(ref, isSigned: Bool.random()) }, - // TODO(pawkra): add shared variant. What about non-null case? - CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef())) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmAnyConvertExtern(ref, shared: false) + CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef)) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmAnyConvertExtern(ref) }, - // TODO(pawkra): add shared variant. What about non-null case? - CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef())) { b, ref in - b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref, shared: false) + CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef)) { b, ref in + b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) }, // Primitive Value Generators @@ -600,8 +596,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(manoskouk): Generalize these. let minSize = 10 let maxSize: Int? = nil - // TODO(pawkra): support shared variant. - let elementType = ILType.wasmFuncRef() + let elementType = ILType.wasmFuncRef let definedEntryIndices: [Int] var definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [] @@ -614,7 +609,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. @@ -643,7 +638,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, CodeGenerator("WasmDefineElementSegmentGenerator", inContext: .single(.wasm)) { b in - let expectedEntryType = b.currentWasmModule.getEntryTypeForTable(elementType: .wasmFuncRef()) + let expectedEntryType = b.currentWasmModule.getEntryTypeForTable(elementType: ILType.wasmFuncRef) if b.randomVariable(ofType: expectedEntryType) == nil { return } @@ -674,8 +669,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inputs: .required(.object(ofGroup: "WasmTable")) ) { b, table in let tableType = b.type(of: table).wasmTableType! - // TODO(pawkra): support shared variant. - if !tableType.elementType.Is(.wasmFuncRef()) { return } + if !tableType.elementType.Is(.wasmFuncRef) { return } guard let indexedSignature = tableType.knownEntries.randomElement() else { return } @@ -735,8 +729,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ ) { b, table in let function = b.currentWasmModule.currentWasmFunction let tableType = b.type(of: table).wasmTableType! - // TODO(pawkra): support shared variant. - if !tableType.elementType.Is(.wasmFuncRef()) { return } + if !tableType.elementType.Is(.wasmFuncRef) { return } guard let indexedSignature = (tableType.knownEntries.filter { @@ -1535,11 +1528,10 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmThrowRefGenerator", inContext: .single(.wasmFunction), - // TODO(pawkra): support shared variant. - inputs: .required(.wasmExnRef()) + inputs: .required(.wasmExnRef) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction - function.wasmBuildThrowRef(exception: exception, sharedRef: false) + function.wasmBuildThrowRef(exception: exception) }, CodeGenerator( @@ -1632,8 +1624,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ [] } if withExnRef { - // TODO(pawkra): support shared variant. - outputTypes.append(.wasmExnRef()) + outputTypes.append(.wasmExnRef) } function.wasmBeginBlock(with: [] => outputTypes, args: []) return outputTypes diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 9179ae663..121e9cbb8 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -14,7 +14,6 @@ public struct Configuration { /// The commandline arguments used by this instance. - /// TODO(pawkra): use these args or remove them (for now the only usage is printing them). public let arguments: [String] /// Timeout in milliseconds after which child processes will be killed. diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 6e8e212f8..9ef54f216 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -2215,7 +2215,7 @@ public extension 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, diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 6bf1de3e7..6486e4603 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -388,8 +388,8 @@ extension Instruction: ProtobufConvertible { $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } } - case .Abstract(let heapTypeInfo): - let kind = switch heapTypeInfo.heapType { + case .Abstract(let heapType): + let kind = switch heapType { case .WasmExn: Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref case .WasmI31: @@ -420,7 +420,6 @@ extension Instruction: ProtobufConvertible { $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { $0.kind = kind $0.nullability = underlyingWasmType.wasmReferenceType!.nullability - $0.isShared = heapTypeInfo.shared } } } @@ -499,26 +498,17 @@ extension Instruction: ProtobufConvertible { return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.valuef64(val) case .refFunc(let val): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.funcref(Int64(val)) - case .externref(let shared): - return nullrefGlobal(.externref, shared: shared) - case .exnref(let shared): - return nullrefGlobal(.exnref, shared: shared) - case .i31ref(let shared): - return nullrefGlobal(.i31Ref, shared: shared) + case .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) + case .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)) } } - func nullrefGlobal(_ kind: Fuzzilli_Protobuf_WasmReferenceTypeKind, shared: Bool) -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal { - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceType.with { - $0.kind = kind - // TODO(gc): set nullability - $0.nullability = false - $0.isShared = shared - }) - } - func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) -> Fuzzilli_Protobuf_WasmCatchKind { switch catchKind { case .NoRef: @@ -1694,40 +1684,37 @@ extension Instruction: ProtobufConvertible { fatalError("Unrecognized wasm value type \(value)") } case .refType(_): - if wasmType.refType.kind == .index { - return .wasmRef(.Index(), nullability: wasmType.refType.nullability) - } - let heapType: WasmAbstractHeapType = switch wasmType.refType.kind { + let refKind: WasmReferenceType.Kind = switch wasmType.refType.kind { + case .index: + .Index() case .externref: - .WasmExtern + .Abstract(.WasmExtern) case .funcref: - .WasmFunc + .Abstract(.WasmFunc) case .exnref: - .WasmExn + .Abstract(.WasmExn) case .i31Ref: - .WasmI31 + .Abstract(.WasmI31) case .anyref: - .WasmAny + .Abstract(.WasmAny) case .eqref: - .WasmEq + .Abstract(.WasmEq) case .structref: - .WasmStruct + .Abstract(.WasmStruct) case .arrayref: - .WasmArray + .Abstract(.WasmArray) case .noneref: - .WasmNone + .Abstract(.WasmNone) case .noexternref: - .WasmNoExtern + .Abstract(.WasmNoExtern) case .nofuncref: - .WasmNoFunc + .Abstract(.WasmNoFunc) case .noexnref: - .WasmNoExn - case .index: - fatalError("Unexpected index type.") + .Abstract(.WasmNoExn) case .UNRECOGNIZED(let value): fatalError("Unrecognized wasm reference type \(value)") } - return .wasmRef(heapType, shared: wasmType.refType.isShared, nullability: wasmType.refType.nullability) + return .wasmRef(refKind, nullability: wasmType.refType.nullability) case .none: fatalError("Absent wasm type") } @@ -1798,13 +1785,13 @@ extension Instruction: ProtobufConvertible { func convertWasmGlobal(_ proto: Fuzzilli_Protobuf_WasmGlobal) -> WasmGlobal { switch proto.wasmGlobal { case .nullref(let val): - switch val.kind { + switch val { case .externref: - return .externref(shared: val.isShared) + return .externref case .exnref: - return .exnref(shared: val.isShared) + return .exnref case .i31Ref: - return .i31ref(shared: val.isShared) + return .i31ref default: fatalError("Unrecognized global wasm reference type \(val)") } diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 65f9689ac..054f242a2 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -888,18 +888,17 @@ public struct JSTyper: Analyzer { case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) case .wasmRefI31(_): - // TODO(pawkra): support shared variant. - setType(of: instr.output, to: .wasmRefI31()) + setType(of: instr.output, to: .wasmRefI31) case .wasmI31Get(_): setType(of: instr.output, to: .wasmi32) case .wasmAnyConvertExtern(_): // 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(.WasmAny, shared: false, nullability: null)) + setType(of: instr.output, to: .wasmRef(.Abstract(.WasmAny), nullability: null)) case .wasmExternConvertAny(_): - // extern.convert_any forwards the nullability from the input. + // extern.convert_any forwards the nullability bit from the input. let null = type(of: instr.input(0)).wasmReferenceType!.nullability - setType(of: instr.output, to: .wasmRef(.WasmExtern, shared: false, nullability: null)) + setType(of: instr.output, to: .wasmRef(.Abstract(.WasmExtern), nullability: null)) case .wasmDefineAdHocSignatureType(let op): startTypeGroup() addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) @@ -1835,7 +1834,7 @@ public struct JSTyper: Analyzer { 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))) diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index 5fe3d7269..729550e9c 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -247,33 +247,23 @@ public struct ILType: Hashable { public static let wasmi64 = ILType(definiteType: .wasmi64) public static let wasmf32 = ILType(definiteType: .wasmf32) public static let wasmf64 = ILType(definiteType: .wasmf64) - public static func wasmExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: true) } - public static func wasmRefExtern(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: false) } - public static func wasmFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmFunc, shared: shared, nullability: true) } - public static func wasmExnRef(shared: Bool = false) -> ILType { wasmRef(.WasmExn, shared: shared, nullability: true) } - public static func wasmI31Ref(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: true) } - public static func wasmRefI31(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: false) } - public static func wasmAnyRef(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: true) } - public static func wasmRefAny(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: false) } - public static func wasmNullRef(shared: Bool = false) -> ILType { wasmRef(.WasmNone, shared: shared, nullability: true) } - public static func wasmNullExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoExtern, shared: shared, nullability: true) } - public static func wasmNullFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoFunc, shared: shared, nullability: true) } - public static func wasmEqRef(shared: Bool = false) -> ILType { wasmRef(.WasmEq, shared: shared, nullability: true) } - public static func wasmStructRef(shared: Bool = false) -> ILType { wasmRef(.WasmStruct, shared: shared, nullability: true) } - public static func wasmArrayRef(shared: Bool = false) -> ILType { wasmRef(.WasmArray, shared: shared, nullability: true) } + public static 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 let wasmSimd128 = ILType(definiteType: .wasmSimd128) public static let wasmGenericRef = ILType(definiteType: .wasmRef) - public static func allWasmRefTypes() -> [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 @@ -285,10 +275,6 @@ public struct ILType: Hashable { wasmTypeDef(description: .selfReference) } - static func wasmRef(_ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true) -> ILType { - 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, @@ -300,7 +286,7 @@ public struct ILType: Hashable { } // The union of all primitive wasm types - public static let wasmPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef + public static let wasmPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmExternRef | .wasmFuncRef | .wasmI31Ref | .wasmSimd128 | .wasmGenericRef public static let wasmNumericalPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 @@ -1103,13 +1089,11 @@ extension ILType: CustomStringConvertible { } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapTypeInfo): - let sharedPrefix = heapTypeInfo.shared ? "shared " : "" - return ".wasmRef(.Abstract(\(nullPrefix)\(sharedPrefix)\(heapTypeInfo.heapType)))" + case .Abstract(let heapType): + return ".wasmRef(.Abstract(\(nullPrefix)\(heapType)))" case .Index(let indexRef): if let desc = indexRef.get() { - let sharedPrefix = if desc.abstractHeapSupertype?.shared ?? false { "shared " } else { "" } - return ".wasmRef(\(nullPrefix)Index \(sharedPrefix)\(desc.format(abbreviate: abbreviate)))" + return ".wasmRef(\(nullPrefix)Index \(desc.format(abbreviate: abbreviate)))" } return ".wasmRef(\(nullPrefix)Index)" } @@ -1407,9 +1391,9 @@ 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. -// TODO(pawkra): rename to HeapType -public enum WasmAbstractHeapType: CaseIterable, Comparable { +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 @@ -1491,8 +1475,8 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { if self == other { return self } - if !self.inSameHierarchy(other) { - return nil // Incompatible heap types. + if self.getBottom() != other.getBottom() { + return nil } if self.subsumes(other) { return other @@ -1506,57 +1490,6 @@ public 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. @@ -1581,7 +1514,7 @@ 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(HeapTypeInfo) + case Abstract(WasmAbstractHeapType) func union(_ other: Self) -> Self? { switch self { @@ -2135,11 +2068,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. - // TODO(pawkra): rename to heapSupertype - public let abstractHeapSupertype: HeapTypeInfo? + public let abstractHeapSupertype: WasmAbstractHeapType? // TODO(gc): We will also need to support subtyping of struct and array types at some point. - init(typeGroupIndex: Int, superType: HeapTypeInfo? = nil) { + init(typeGroupIndex: Int, superType: WasmAbstractHeapType? = nil) { self.typeGroupIndex = typeGroupIndex self.abstractHeapSupertype = superType } @@ -2169,8 +2101,7 @@ class WasmSignatureTypeDescription: WasmTypeDescription { init(signature: WasmSignature, typeGroupIndex: Int) { self.signature = signature - // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) + super.init(typeGroupIndex: typeGroupIndex, superType: .WasmFunc) } override func format(abbreviate: Bool) -> String { @@ -2191,8 +2122,7 @@ class WasmArrayTypeDescription: WasmTypeDescription { init(elementType: ILType, mutability: Bool, typeGroupIndex: Int) { self.elementType = elementType self.mutability = mutability - // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) + super.init(typeGroupIndex: typeGroupIndex, superType: .WasmArray) } override func format(abbreviate: Bool) -> String { @@ -2223,8 +2153,7 @@ class WasmStructTypeDescription: WasmTypeDescription { init(fields: [Field], typeGroupIndex: Int) { self.fields = fields - // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmStruct, shared: false)) + super.init(typeGroupIndex: typeGroupIndex, superType: .WasmStruct) } override func format(abbreviate: Bool) -> String { diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 8a441966f..452dd9cc5 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -695,9 +695,9 @@ public enum WasmGlobal { case wasmf64(Float64) // Empty reference // TODO(gc): Add support for globals with non-nullable references. - case externref(shared: Bool) - case exnref(shared: Bool) - case i31ref(shared: Bool) + case externref + case exnref + case i31ref // function reference case refFunc(Int) @@ -715,12 +715,12 @@ public enum WasmGlobal { return .wasmf32 case .wasmf64: return .wasmf64 - case let .externref(shared): - return ILType.wasmExternRef(shared: shared) - case let .exnref(shared): - return ILType.wasmExnRef(shared: shared) - case let .i31ref(shared): - return ILType.wasmI31Ref(shared: shared) + case .externref: + return .wasmExternRef + case .exnref: + return .wasmExnRef + case .i31ref: + return .wasmI31Ref case .imported(let type): assert(type.wasmGlobalType != nil) return type.wasmGlobalType!.valueType @@ -729,7 +729,6 @@ public enum WasmGlobal { } } - //TODO(pawkra): rename to jsTypeName func typeString() -> String { switch self { case .wasmi64(_): @@ -740,26 +739,18 @@ public enum WasmGlobal { return "f32" case .wasmf64(_): return "f64" - case let .externref(shared): - assertNotShared(shared) + case .externref: return "externref" - case let .exnref(shared): - assertNotShared(shared) + case .exnref: return "exnref" - case let .i31ref(shared): - assertNotShared(shared) + case .i31ref: return "i31ref" default: fatalError("Unimplemented / unhandled") } } - private func assertNotShared(_ shared: Bool) { - assert(!shared, "Shared references not supported in JS > WASM API") - } - // Returns a JS string representing the initial value. - // TODO(pawkra): rename to valueToJsString func valueToString() -> String { switch self { case .wasmi64(let val): @@ -770,10 +761,10 @@ public enum WasmGlobal { return "\(val)" case .wasmf64(let val): return "\(val)" - case .externref(_): + case .externref: return "" - case .exnref(_), - .i31ref(_): + case .exnref, + .i31ref: return "null" default: fatalError("Unimplemented / unhandled") @@ -810,11 +801,9 @@ final class WasmDefineTable: WasmOperation { self.definedEntries = definedEntries // TODO(manoskouk): Find a way to define non-function tables with initializers. - // TODO(pawkra): support shared refs. - let isWasmFuncRef = elementType == .wasmFuncRef() - assert(isWasmFuncRef || definedEntries.isEmpty) + assert(elementType == .wasmFuncRef || definedEntries.isEmpty) - super.init(numInputs: isWasmFuncRef ? definedEntries.count : 0, + super.init(numInputs: elementType == .wasmFuncRef ? definedEntries.count : 0, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasm]) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index bcd7057b7..49cfb5a04 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1540,12 +1540,11 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let type: String switch op.tableType.elementType { - case .wasmExternRef(): + case .wasmExternRef: type = "externref" - case .wasmFuncRef(): + case .wasmFuncRef: type = "anyfunc" // TODO(mliedtke): add tables for i31ref. - // TODO(pawkra): add shared ref variants. default: fatalError("Unknown table type") } @@ -1580,21 +1579,21 @@ public class JavaScriptLifter: Lifter { return "\"i64\"" case .wasmSimd128: return "\"v128\"" - case ILType.wasmExternRef(): - return "\"externref\"" - case ILType.wasmFuncRef(): + case .wasmExternRef: + return "\"externref\"" + case .wasmFuncRef: return "\"anyfunc\"" - case ILType.wasmAnyRef(): + case .wasmAnyRef: return "\"anyref\"" - case ILType.wasmEqRef(): + case .wasmEqRef: return "\"eqref\"" - case ILType.wasmI31Ref(): + case .wasmI31Ref: return "\"i31ref\"" - case ILType.wasmStructRef(): + case .wasmStructRef: return "\"structref\"" - case ILType.wasmArrayRef(): + case .wasmArrayRef: return "\"arrayref\"" - case ILType.wasmExnRef(): + case .wasmExnRef: return "\"exnref\"" default: diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index a11ed0dbd..4944ac161 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -527,33 +527,39 @@ public class WasmLifter { self.bytecode += [0x1, 0x0, 0x0, 0x0] } - 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 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 encodeWasmGCType(_ description: WasmTypeDescription?) throws -> Data { guard let description else { throw WasmLifter.CompileError.missingTypeInformation } - // TODO(pawkra): encode shared bit return Leb128.unsignedEncode(typeDescToIndex[description]!) } @@ -562,22 +568,28 @@ public class WasmLifter { let isNullable = refType.nullability let nullabilityByte: UInt8 = isNullable ? 0x63 : 0x64 - return try Data([nullabilityByte]) + encodeHeapType(type) + switch refType.kind { + case .Index(let description): + return try Data([nullabilityByte]) + encodeWasmGCType(description.get()) + case .Abstract(let heapType): + return Data([nullabilityByte]) + encodeAbstractHeapType(heapType) + } } // 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) throws -> Data { + private func encodeHeapType(_ type: ILType, defaultType: ILType? = nil) throws -> Data { if let refType = type.wasmReferenceType { switch refType.kind { case .Index(let description): return try encodeWasmGCType(description.get()) - case .Abstract(let heapTypeInfo): - return encodeAbstractHeapType(heapTypeInfo) + case .Abstract(let heapType): + return encodeAbstractHeapType(heapType) } } - fatalError("This function supports only wasmReferenceType.") + // 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 { @@ -651,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) } } @@ -1064,14 +1076,14 @@ public class WasmLifter { temporaryInstruction = Instruction(Consti32(value: val), output: Variable()) case .wasmi64(let val): temporaryInstruction = Instruction(Consti64(value: val), output: Variable()) - case .externref(let shared): - temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef(shared: shared)) + Data([0x0B]) + case .externref: + temp += try! Data([0xD0]) + encodeHeapType(.wasmExternRef) + Data([0x0B]) continue - case .exnref(let shared): - temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef(shared: shared)) + Data([0x0B]) + case .exnref: + temp += try! Data([0xD0]) + encodeHeapType(.wasmExnRef) + Data([0x0B]) continue - case .i31ref(let shared): - temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref(shared: shared)) + Data([0x0B]) + case .i31ref: + temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref) + Data([0x0B]) continue case .refFunc(_), .imported(_): @@ -1494,8 +1506,7 @@ public class WasmLifter { self.exports.append(.global(instr)) case .wasmDefineTable(let tableDef): self.exports.append(.table(instr)) - // TODO(pawkra): support shared refs. - if tableDef.elementType == .wasmFuncRef() { + 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. diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4f8b7b843..94e7e297c 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -369,21 +369,23 @@ public class OperationMutator: BaseInstructionMutator { case .wasmDefineGlobal(let op): // We never change the type of the global, only the value as changing the type will break the following code pretty much instantly. - let wasmGlobal:WasmGlobal = - switch op.wasmGlobal.toType() { - case .wasmf32: - .wasmf32(Float32(b.randomFloat())) - case .wasmf64: - .wasmf64(b.randomFloat()) - case .wasmi32: - .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) - case .wasmi64: - .wasmi64(b.randomInt()) - case ILType.wasmExternRef(), ILType.wasmExnRef(), ILType.wasmI31Ref(): - op.wasmGlobal - default: - fatalError("unexpected/unimplemented Value Type!") - } + let wasmGlobal: WasmGlobal + switch op.wasmGlobal.toType() { + case .wasmf32: + wasmGlobal = .wasmf32(Float32(b.randomFloat())) + case .wasmf64: + wasmGlobal = .wasmf64(b.randomFloat()) + case .wasmi32: + wasmGlobal = .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) + case .wasmi64: + wasmGlobal = .wasmi64(b.randomInt()) + case .wasmExternRef, + .wasmExnRef, + .wasmI31Ref: + wasmGlobal = op.wasmGlobal + default: + fatalError("unexpected/unimplemented Value Type!") + } newOp = WasmDefineGlobal(wasmGlobal: wasmGlobal, isMutable: probability(0.5)) case .wasmDefineTable(let op): // TODO: change table size? diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index cdca77467..2b2248232 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4138,8 +4138,6 @@ public struct Fuzzilli_Protobuf_WasmReferenceType: Sendable { public var nullability: Bool = false - public var isShared: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -4714,10 +4712,10 @@ public struct Fuzzilli_Protobuf_WasmGlobal: Sendable { set {wasmGlobal = .valuef64(newValue)} } - public var nullref: Fuzzilli_Protobuf_WasmReferenceType { + public var nullref: Fuzzilli_Protobuf_WasmReferenceTypeKind { get { if case .nullref(let v)? = wasmGlobal {return v} - return Fuzzilli_Protobuf_WasmReferenceType() + return .index } set {wasmGlobal = .nullref(newValue)} } @@ -4745,7 +4743,7 @@ public struct Fuzzilli_Protobuf_WasmGlobal: Sendable { case valuei64(Int64) case valuef32(Float) case valuef64(Double) - case nullref(Fuzzilli_Protobuf_WasmReferenceType) + case nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind) case funcref(Int64) case imported(Fuzzilli_Protobuf_WasmILType) @@ -11564,7 +11562,7 @@ extension Fuzzilli_Protobuf_WasmReturn: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmReferenceType" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{1}nullability\0\u{1}isShared\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}kind\0\u{1}nullability\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11574,7 +11572,6 @@ extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProto switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.kind) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.nullability) }() - case 3: try { try decoder.decodeSingularBoolField(value: &self.isShared) }() default: break } } @@ -11587,16 +11584,12 @@ extension Fuzzilli_Protobuf_WasmReferenceType: SwiftProtobuf.Message, SwiftProto if self.nullability != false { try visitor.visitSingularBoolField(value: self.nullability, fieldNumber: 2) } - if self.isShared != false { - try visitor.visitSingularBoolField(value: self.isShared, fieldNumber: 3) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmReferenceType, rhs: Fuzzilli_Protobuf_WasmReferenceType) -> Bool { if lhs.kind != rhs.kind {return false} if lhs.nullability != rhs.nullability {return false} - if lhs.isShared != rhs.isShared {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -12859,15 +12852,10 @@ extension Fuzzilli_Protobuf_WasmGlobal: SwiftProtobuf.Message, SwiftProtobuf._Me } }() case 6: try { - var v: Fuzzilli_Protobuf_WasmReferenceType? - var hadOneofValue = false - if let current = self.wasmGlobal { - hadOneofValue = true - if case .nullref(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) + var v: Fuzzilli_Protobuf_WasmReferenceTypeKind? + try decoder.decodeSingularEnumField(value: &v) if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} + if self.wasmGlobal != nil {try decoder.handleConflictingOneOf()} self.wasmGlobal = .nullref(v) } }() @@ -12924,7 +12912,7 @@ extension Fuzzilli_Protobuf_WasmGlobal: SwiftProtobuf.Message, SwiftProtobuf._Me }() case .nullref?: try { guard case .nullref(let v)? = self.wasmGlobal else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + try visitor.visitSingularEnumField(value: v, fieldNumber: 6) }() case .funcref?: try { guard case .funcref(let v)? = self.wasmGlobal else { preconditionFailure() } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index a4feaf8f3..8ed578def 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -920,7 +920,6 @@ enum WasmReferenceTypeKind { message WasmReferenceType { WasmReferenceTypeKind kind = 1; bool nullability = 2; - bool isShared = 3; } message WasmILType { @@ -1101,7 +1100,7 @@ message WasmGlobal { int64 valuei64 = 3; float valuef32 = 4; double valuef64 = 5; - WasmReferenceType nullref = 6; + WasmReferenceTypeKind nullref = 6; int64 funcref = 7; WasmILType imported = 8; } diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index e8a5d66fa..967210b97 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -554,7 +554,7 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in } let table = wasmModule.addTable( - elementType: .wasmFuncRef(), + elementType: .wasmFuncRef, minSize: numCallees, definedEntries: (0.. 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 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) @@ -745,7 +745,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { var args = [ "--expose-gc", "--expose-externalize-string", - "--experimental-wasm-shared", "--omit-quit", "--allow-natives-syntax", "--fuzzing", diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index da45fc8c3..56ab52d11 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1534,7 +1534,7 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - let wasmSignature = [] => [.wasmExternRef()] + let wasmSignature = [] => [.wasmExternRef] let typeDesc = b.type(of: typeGroup[0]).wasmTypeDefinition!.description! @@ -1574,7 +1574,7 @@ 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)] } @@ -1585,7 +1585,7 @@ class JSTyperTests: XCTestCase { // 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)!] } @@ -1795,7 +1795,7 @@ class JSTyperTests: XCTestCase { let wasmTableConstructor = b.getProperty("Table", of: wasm) 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) diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 39a00c095..7758461d1 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3274,7 +3274,7 @@ class LifterTests: XCTestCase { 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 diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 8a6dce290..4ffb8c5d9 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -133,16 +133,15 @@ 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 ILType.wasmFuncRef(): + case .wasmFuncRef: return jsFunction - case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): + case .wasmNullExternRef, .wasmNullFuncRef, .wasmNullRef: return b.loadNull() - case ILType.wasmExternRef(), ILType.wasmAnyRef(): + case .wasmExternRef, .wasmAnyRef: return b.createObject(with: [:]) default: return b.loadInt(321) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 4478f3225..5a9c53b63 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2863,21 +2863,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(.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))) + 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))) 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(.WasmArray, nullability: false) + let refArrayType = ILType.wasmRef(.Abstract(.WasmArray), nullability: false) XCTAssertEqual(arrayI32Type.union(with: arrayI32BType), refArrayType) XCTAssertEqual(arrayI32BType.union(with: arrayI32Type), refArrayType) XCTAssertEqual(arrayI32Type.intersection(with: arrayI32BType), .nothing) @@ -2887,14 +2887,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(.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) + 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) XCTAssertEqual(structType.union(with: arrayI32Type), refEqType) XCTAssertEqual(arrayI32Type.union(with: structType), refEqType) XCTAssertEqual(structType.intersection(with: arrayI32Type), .nothing) @@ -2903,25 +2903,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(.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))) + 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))) 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(.WasmStruct, nullability: false) + let refStructType = ILType.wasmRef(.Abstract(.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(.WasmNone, nullability: false) + let refNone = ILType.wasmRef(.Abstract(.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 [] } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 073388a11..5e6f0fd77 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -1110,12 +1110,11 @@ class TypeSystemTests: XCTestCase { 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))") + let nullExn = ILType.wasmRef(.Abstract(.WasmExn), nullability: true) + let nonNullAny = ILType.wasmRef(.Abstract(.WasmAny), nullability: false) + XCTAssertEqual(nullExn.description, ".wasmRef(.Abstract(null WasmExn))") XCTAssertEqual(nonNullAny.description, ".wasmRef(.Abstract(WasmAny))") - // 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])") @@ -1149,11 +1148,11 @@ class TypeSystemTests: XCTestCase { ".wasmTypeDef(1 Struct[mutable .wasmf32, " + "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") let signatureDesc = WasmSignatureTypeDescription( - signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef(shared: true)], typeGroupIndex: 0) + signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef], typeGroupIndex: 0) let signatureDef = ILType.wasmTypeDef(description: signatureDesc) XCTAssertEqual(signatureDef.description, ".wasmTypeDef(0 Func[[.wasmi32, .wasmRef(null Index 0 Array)] => " + - "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null shared WasmNone))]])") + "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null WasmNone))]])") // A generic index type without a type description. // These are e.g. used by the element types for arrays and structs inside the operation as @@ -1164,7 +1163,7 @@ class TypeSystemTests: XCTestCase { } func testWasmSubsumptionRules() { - let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allWasmRefTypes() + let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmFuncRef, .wasmExternRef, .wasmI31Ref, .wasmExnRef] // Make sure that no Wasm type is subsumed by (JS-)anything. for t in wasmTypes { XCTAssertEqual(t <= .jsAnything, false) @@ -1210,16 +1209,14 @@ class TypeSystemTests: XCTestCase { // Test nullability rules for abstract Wasm types. for heapType: WasmAbstractHeapType in WasmAbstractHeapType.allCases { - 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) - } + 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) } } @@ -1279,6 +1276,7 @@ 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) @@ -1289,48 +1287,35 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(WasmAbstractHeapType.WasmAny.intersection(.WasmArray), .WasmArray) // Tests on the whole ILType. - for shared in [true, false] { - let ref: (WasmAbstractHeapType) -> ILType = {t in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t in ILType.wasmRef(t, shared: shared, nullability: true)} - - 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)) + 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) } - let ref = {t, shared in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t, shared in ILType.wasmRef(t, shared: shared, nullability: true)} - // Shared and unshared ref hierarchies are disjoint. - for (lhsShared, rhsShared) in [(true, false), (false, true)] { - for type in allTypes { - XCTAssertEqual(ref(type, lhsShared).union(with: ref(type, rhsShared)), .wasmGenericRef) - XCTAssertEqual(refNull(type, lhsShared).union(with: refNull(type, rhsShared)), .wasmGenericRef) - } - } + XCTAssertEqual(ref(.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)) } func testUnboundFunctionSubsumptionRules() { @@ -1448,10 +1433,15 @@ class TypeSystemTests: XCTestCase { .wasmf32, .wasmi64, .wasmf64, + .wasmFuncRef, + .wasmExternRef, + .wasmExnRef, + .wasmI31Ref, + .wasmRefI31, .wasmFunctionDef([.wasmi32] => [.wasmi64]), .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), + .wasmFunctionDef([.wasmExternRef] => [.wasmExternRef]), .wasmMemory(limits: Limits(min: 10)), .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + ILType.allWasmRefTypes() + ] } diff --git a/Tests/FuzzilliTests/WasmTableTests.swift b/Tests/FuzzilliTests/WasmTableTests.swift index 2e4f9335f..c3e59c9b7 100644 --- a/Tests/FuzzilliTests/WasmTableTests.swift +++ b/Tests/FuzzilliTests/WasmTableTests.swift @@ -22,7 +22,7 @@ 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 +31,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 8a78971bb..f7955e212 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -44,16 +44,16 @@ func testForErrorOutput(program: String, runner: JavaScriptExecutor, errorMessag class WasmSignatureConversionTests: XCTestCase { func testJsSignatureConversion() { - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmi32] => [.wasmi32]) - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmf32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmf32] => [.wasmi32]) + XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1), (.wasmFuncRef, 1), (.wasmExternRef, 1)])), [.wasmi32] => [.wasmi32]) + XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmf32, 1), (.wasmFuncRef, 1), (.wasmExternRef, 1)])), [.wasmf32] => [.wasmi32]) } func testWasmSignatureConversion() { XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmi64] => [.wasmf32]), [.integer, .bigint] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmExnRef()] => [.wasmf64]), [.integer, .jsAnything] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmExternRef(), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.Index(), nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.WasmExtern, nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) + XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .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) // TODO(cffsmith): Change this once we know how we want to represent .wasmSimd128 types in JS. XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmSimd128] => [.wasmSimd128]), [.jsAnything] => .jsAnything) } @@ -440,7 +440,7 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1338\n4242\n6.61e-321\n") } - func globalExnRef(sharedRef: Bool) throws { + func testGlobalExnRef() throws { let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -450,8 +450,8 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) 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(shared: sharedRef), isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExnRef(shared: sharedRef), isMutable: true))) + 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))) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let value = function.wasmLoadGlobal(globalVariable: global) @@ -460,12 +460,12 @@ class WasmFoundationTests: XCTestCase { // Throw an exception, catch it and store it in the global. wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef(shared: sharedRef)], args: []) { catchLabel, _ 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(shared: sharedRef))] + return [function.wasmRefNull(type: .wasmExnRef)] }[0] function.wasmStoreGlobal(globalVariable: global, to: exnref) return [] @@ -473,12 +473,12 @@ 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(shared: sharedRef)], args: []) { catchLabel, _ 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), sharedRef: sharedRef) + function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) return [] } - return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef(shared: sharedRef))] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef)] } return [caughtValues[0]] } @@ -509,12 +509,12 @@ 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(shared: sharedRef)], args: []) { catchLabel, _ 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), sharedRef: sharedRef) + function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) return [] } - return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef(shared: sharedRef))] + return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef)] } return [caughtValues[0]] } @@ -529,16 +529,7 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n42\nexception\n42\n") } - func testGlobalExnRefShared() throws { - // TODO(pawkra) - throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") - } - - func testGlobalExnRefUnshared() throws { - try globalExnRef(sharedRef: false) - } - - func globalExternRef(sharedRef: Bool) throws { + func testGlobalExternRef() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -546,14 +537,14 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let global = wasmModule.addGlobal(wasmGlobal: .externref(shared: sharedRef), isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(shared: sharedRef), isMutable: true))) + 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))) - wasmModule.addWasmFunction(with: [] => [.wasmExternRef(shared: sharedRef)]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [.wasmExternRef]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmExternRef(shared: sharedRef)] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmExternRef] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -579,15 +570,6 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\nHello!\nHello!\n") } - func testglobalExternRefShared() throws { - // TODO(pawkra) - throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") - } - - func testglobalExternRefUnshared() throws { - try globalExternRef(sharedRef: false) - } - func testGlobalExternRefFromJS() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -595,9 +577,8 @@ 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(shared: false), isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(), isMutable: true))) + 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))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "undefined" (because we didn't provide an explicit initialization). @@ -613,22 +594,22 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "undefined\nHello!\n") } - func globalI31Ref(sharedRef: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) + func testGlobalI31Ref() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let global = wasmModule.addGlobal(wasmGlobal: .i31ref(shared: sharedRef), isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(shared: sharedRef), isMutable: true))) + 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))) - wasmModule.addWasmFunction(with: [] => [.wasmI31Ref(shared: sharedRef)]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [.wasmI31Ref]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] } - wasmModule.addWasmFunction(with: [.wasmI31Ref(shared: sharedRef)] => []) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmI31Ref] => []) { function, label, args in function.wasmStoreGlobal(globalVariable: global, to: args[0]) return [] } @@ -653,14 +634,6 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\n-42\n-42\n") } - func testGlobalI31RefShared() throws { - try globalI31Ref(sharedRef: true) - } - - func testGlobalI31RefUnshared() throws { - try globalI31Ref(sharedRef: false) - } - func testGlobalI31RefFromJS() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -668,9 +641,8 @@ 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(shared: false), isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(), isMutable: true))) + 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))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "null" (because we didn't provide an explicit initialization). @@ -694,8 +666,8 @@ 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)]) @@ -703,9 +675,9 @@ class WasmFoundationTests: XCTestCase { 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) @@ -755,7 +727,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in [function.wasmi32BinOp(params[0], function.consti32(1), binOpKind: .Add)] } - wasmModule.addTable(elementType: .wasmFuncRef(), + wasmModule.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: [.init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), .init(indexInTable: 1, signature: [] => [.wasmi64])], definedEntryValues: [wasmFunction, jsFunction], @@ -773,7 +745,7 @@ class WasmFoundationTests: XCTestCase { 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: [ + 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]) @@ -821,7 +793,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), + 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], @@ -871,7 +843,7 @@ class WasmFoundationTests: XCTestCase { 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])], definedEntryValues: [wasmFunction, jsFunction], @@ -879,7 +851,7 @@ class WasmFoundationTests: XCTestCase { } let table = b.getProperty("wt0", of: module.loadExports()) - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, knownEntries: [ + 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]) ])) @@ -894,7 +866,7 @@ class WasmFoundationTests: XCTestCase { 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])] } @@ -909,7 +881,7 @@ 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: [ + 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]) @@ -1025,7 +997,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), + 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], @@ -3788,11 +3760,10 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let tagVoid = b.createWasmTag(parameterTypes: []) let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) - // TODO(pawkra): add shared ref variant. 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.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.WasmBuildThrow(tag: tagVoid, inputs: []) @@ -3801,10 +3772,10 @@ class WasmFoundationTests: XCTestCase { } 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)] } @@ -3894,8 +3865,10 @@ class WasmFoundationTests: XCTestCase { let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - // Assumption: All types apart from bottom (null) & shared types are supported in the JS API. - let supportedTypes = WasmAbstractHeapType.allNonBottomTypes().map {ILType.wasmRef($0, nullability: true)} + // 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) + } b.createWasmTag(parameterTypes: supportedTypes) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog, withOptions: [.includeComments]) @@ -3906,7 +3879,7 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "") } - func throwRef(sharedRef: Bool) throws { + func testThrowRef() throws { let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) @@ -3921,17 +3894,17 @@ class WasmFoundationTests: XCTestCase { 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(shared: sharedRef)], args: []) { catchRefLabel, _ 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(shared: sharedRef))] + return [function.consti32(0), function.wasmRefNull(type: .wasmExnRef)] } // Print the caught i32 value. 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], sharedRef: sharedRef) + function.wasmBuildThrowRef(exception: caughtValues[1]) return [] } @@ -3956,15 +3929,6 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n42\n") } - func testThrowRefShared() throws { - // TODO(pawkra) - throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") - } - - func testThrowRefUnshared() throws { - try throwRef(sharedRef: false) - } - func testUnreachable() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -4008,7 +3972,7 @@ class WasmFoundationTests: XCTestCase { 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])] } } @@ -4184,13 +4148,13 @@ class WasmFoundationTests: XCTestCase { let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(1)]} let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} - // TODO(pawkra): add shared ref variant. - module.addTable(elementType: .wasmFuncRef(), + + module.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: [], definedEntryValues: [], @@ -4232,13 +4196,12 @@ class WasmFoundationTests: XCTestCase { let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} - // TODO(pawkra): add shared ref variant. - let table1 = module.addTable(elementType: .wasmFuncRef(), + let table1 = module.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable(elementType: .wasmFuncRef, minSize: 10, definedEntries: (0..<4).map { WasmTableType.IndexInTableAndWasmSignature.init(indexInTable: $0, signature: [] => [.wasmi64]) }, definedEntryValues: [f3, f3, f1, f2], @@ -4505,9 +4468,8 @@ class WasmGCTests: XCTestCase { 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. @@ -4532,7 +4494,7 @@ class WasmGCTests: XCTestCase { let jsProg = buildAndLiftProgram { b in 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. @@ -4746,19 +4708,15 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n") } - func refNullAbstractTypes(sharedRef: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref", "--experimental-wasm-shared"]) + func testRefNullAbstractTypes() throws { + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - // TODO(pawkra): simplify once V8 adds support for shared references of type: func, exn - let unsupportedHeapType: Set = sharedRef ? [.WasmFunc, .WasmNoFunc, .WasmExn, .WasmNoExn] : [] - let supportedHeapTypes = Array(Set(WasmAbstractHeapType.allCases).subtracting(unsupportedHeapType)) - let module = b.buildWasmModule { wasmModule in - for heapType in supportedHeapTypes { - let valueType = ILType.wasmRef(heapType, shared: sharedRef, nullability: true) + for heapType in WasmAbstractHeapType.allCases { + let valueType = ILType.wasmRef(.Abstract(heapType), nullability: true) if heapType.isUsableInJS() { // ref.null wasmModule.addWasmFunction(with: [] => [valueType]) { function, label, args in @@ -4774,8 +4732,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let exportedFctCount = supportedHeapTypes.count - + supportedHeapTypes.count {$0.isUsableInJS()} + let exportedFctCount = WasmAbstractHeapType.allCases.count + + WasmAbstractHeapType.allCases.count {$0.isUsableInJS()} for i in 0.. [.wasmI31Ref()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmI31Ref]) { function, label, args in [function.wasmRefI31(args[0])] } - wasmModule.addWasmFunction(with: [.wasmI31Ref()] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true, shared: false), - function.wasmI31Get(args[0], isSigned: false, shared: false)] + wasmModule.addWasmFunction(with: [.wasmI31Ref] => [.wasmi32, .wasmi32]) { function, label, args in + [function.wasmI31Get(args[0], isSigned: true), + function.wasmI31Get(args[0], isSigned: false)] } } @@ -4830,75 +4780,36 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } - func i31Ref(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 module = b.buildWasmModule { wasmModule in - let f1 = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmI31Ref(shared: sharedRef)]) { function, label, args in - [function.wasmRefI31(args[0])] - } - let f2 = wasmModule.addWasmFunction(with: [.wasmI31Ref(shared: sharedRef)] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true, shared: sharedRef), - function.wasmI31Get(args[0], isSigned: false, shared: sharedRef)] - } - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, args in - let ref = function.wasmCallDirect(signature: [.wasmi32] => [.wasmI31Ref(shared: sharedRef)], function: f1, functionArgs: [function.consti32(-42)]) - return function.wasmCallDirect(signature: [.wasmI31Ref(shared: sharedRef)] => [.wasmi32, .wasmi32], function: f2, functionArgs: ref) - } - } - - let exports = module.loadExports() - let outputFunc = b.createNamedVariable(forBuiltin: "output") - let result = b.callMethod(module.getExportedMethod(at: 2), 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: "-42,2147483606\n") - } - - func testi31RefSharedRef() throws { - // TODO(pawkra) - throw XCTSkip("Enable the test once we are emit & support shared refs in ProgramBuilder.") - } - - func testi31RefUnsharedRef() throws { - try i31Ref(sharedRef: false) - } - - func externAnyConversions(sharedRef: Bool) throws { + func testExternAnyConversions() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern(shared: sharedRef)]) { 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]), shared: sharedRef) - XCTAssertEqual(b.type(of: result), .wasmRefExtern(shared: sharedRef)) + let result = function.wasmExternConvertAny(function.wasmRefI31(args[0])) + XCTAssertEqual(b.type(of: result), .wasmRefExtern) return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern(shared: sharedRef)] => [.wasmRefAny(shared: sharedRef)]) { function, label, args in - let result = function.wasmAnyConvertExtern(args[0], shared: sharedRef) - XCTAssertEqual(b.type(of: result), .wasmRefAny(shared: sharedRef)) + wasmModule.addWasmFunction(with: [.wasmRefExtern] => [.wasmRefAny]) { function, label, args in + let result = function.wasmAnyConvertExtern(args[0]) + XCTAssertEqual(b.type(of: result), .wasmRefAny) return [result] } - wasmModule.addWasmFunction(with: [] => [.wasmExternRef(shared: sharedRef)]) { function, label, args in - let result = function.wasmExternConvertAny(function.wasmRefNull(type: .wasmNullRef(shared: sharedRef)), shared: sharedRef) - XCTAssertEqual(b.type(of: result), .wasmExternRef(shared: sharedRef)) + 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(shared: sharedRef)]) { function, label, args in - let result = function.wasmAnyConvertExtern(function.wasmRefNull(type: .wasmNullExternRef(shared: sharedRef)), shared: sharedRef) - XCTAssertEqual(b.type(of: result), .wasmAnyRef(shared: sharedRef)) + wasmModule.addWasmFunction(with: [] => [.wasmAnyRef]) { function, label, args in + let result = function.wasmAnyConvertExtern(function.wasmRefNull(type: .wasmNullExternRef)) + XCTAssertEqual(b.type(of: result), .wasmAnyRef) return [result] } } @@ -4914,15 +4825,6 @@ class WasmGCTests: XCTestCase { let jsProg = fuzzer.lifter.lift(prog) testForOutput(program: jsProg, runner: runner, outputString: "42\n42\nnull\nnull\n") } - - func testExternAnyConversionsSharedRefs() throws { - // TODO(pawkra): double check that shared references can be converted to extern ref. - throw XCTSkip("Fix once we are able to emit shared i31, extern, null, and nullextern refs.") - } - - func testExternAnyConversionsUnsharedRefs() throws { - try externAnyConversions(sharedRef: false) - } } class WasmNumericalTests: XCTestCase { @@ -6457,10 +6359,9 @@ class WasmJSPITests: XCTestCase { XCTAssertEqual(b.type(of: importFunction), .object(ofGroup: "WasmSuspendingObject")) // Now lets build the module - // TODO(pawkra): add shared ref variant. 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])!] } } From d50f02e2e5dbc779ac75a5b2dbf3582860aa60df Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Tue, 2 Dec 2025 23:46:56 +0000 Subject: [PATCH 025/234] Enable inlining of Arrow Functions in JavaScript lifting This change allows the JavaScriptLifter to inline arrow functions (e.g., 'foo(() => 42)') by treating them as expressions. - Adds ArrowFunctionExpression to JSExpressions. - Updates JavaScriptLifter to detect recursive arrow functions and block boundaries. - Non-recursive arrow functions are buffered and assigned as expressions. - Recursive arrow functions retain the original variable declaration strategy. - Implements concise body syntax ('() => expr') for single-line returns without comments. - Updates JavaScriptWriter to use emitBlock for multi-line inlined expressions. Bug: 464228572, 456164925 Change-Id: Ic4618c2ba92ad96d95303e83f8551c13beef508c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8808456 Reviewed-by: Matthias Liedtke Commit-Queue: Dominik Klemba Auto-Submit: Dominik Klemba --- Sources/Fuzzilli/Lifting/JSExpressions.swift | 43 +-- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 131 ++++++++-- Tests/FuzzilliTests/LifterTest.swift | 245 +++++++++++++++++- 3 files changed, 374 insertions(+), 45 deletions(-) diff --git a/Sources/Fuzzilli/Lifting/JSExpressions.swift b/Sources/Fuzzilli/Lifting/JSExpressions.swift index 40a298a3d..e06d4f7fd 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,25 @@ 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/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 49cfb5a04..fd96d0caf 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -64,6 +64,17 @@ public class JavaScriptLifter: Lifter { } } + 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, @@ -77,6 +88,13 @@ 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 @@ -90,6 +108,18 @@ public class JavaScriptLifter: Lifter { var typer: JSTyper? = nil // The currently active WasmLifter, we can only have one of them. var wasmInstructions = Code() + + // 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 } @@ -820,12 +850,8 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "function", 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, parameters: op.parameters, isAsync: false, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "function*", using: &w) @@ -834,20 +860,43 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "async function", 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, parameters: op.parameters, isAsync: true, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginAsyncGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "async function*", using: &w) case .endArrowFunction(_), .endAsyncArrowFunction: - w.leaveCurrentBlock() - w.emit("};") + 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(_), @@ -1851,6 +1900,45 @@ public class JavaScriptLifter: Lifter { w.enterNewBlock() } + private func liftArrowFunctionDefinitionBegin( + _ instr: Instruction, + 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") + let params = liftParameters(parameters, as: vars) + + 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() { @@ -1991,6 +2079,7 @@ 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. @@ -2237,7 +2326,7 @@ public class JavaScriptLifter: Lifter { mutating func emit(_ line: String) { emitPendingExpressions() - writer.emit(line) + writer.emitBlock(line) } /// Emit a (potentially multi-line) comment. @@ -2262,6 +2351,8 @@ public class JavaScriptLifter: Lifter { mutating func pushTemporaryOutputBuffer(initialIndentionLevel: Int) { temporaryOutputBufferStack.push(writer) + pendingExpressionsStack.push(pendingExpressions) + pendingExpressions = [] writer = ScriptWriter(stripComments: writer.stripComments, includeLineNumbers: false, indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) } @@ -2269,6 +2360,7 @@ public class JavaScriptLifter: Lifter { assert(pendingExpressions.isEmpty) let code = writer.code writer = temporaryOutputBufferStack.pop() + pendingExpressions = pendingExpressionsStack.pop() return code } @@ -2314,12 +2406,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. @@ -2329,9 +2420,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/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 7758461d1..258ed4a02 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -1038,10 +1038,7 @@ class LifterTests: XCTestCase { return a1; } f0(13.37); - const v4 = () => { - return "foobar"; - }; - f0 = v4; + f0 = () => "foobar"; f0(); """ @@ -3398,4 +3395,244 @@ class LifterTests: XCTestCase { """ 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) + } } From c88fbb3914796aedab816acf1475435883749e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Gro=C3=9F?= Date: Wed, 3 Dec 2025 13:33:54 +0100 Subject: [PATCH 026/234] Add BytecodeFuzzer ProgramTemplate for the V8Sandbox profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a mini-fuzzer for the new BytecodeVerifier in V8. It uses %GetBytecode to obtain a JS representation of the BytecodeArray of an existing function, mutates it, then installs it back on the function using %InstallBytecode and finally executes the function. As the verifier only ensures that the bytecode does not cause a sandbox breakout (not general memory corruption), the mini-fuzzer is also specific to the V8Sandbox fuzzing profile. Bug: 461681036 Change-Id: Iac64f3c9532f47455c57cf4251197771b0663612 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8814316 Commit-Queue: Samuel Groß Reviewed-by: Matthias Liedtke --- .../Profiles/V8SandboxProfile.swift | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 3177c273e..1df53793d 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -51,6 +51,50 @@ fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { } } +let BytecodeFuzzer = ProgramTemplate("BytecodeFuzzer") { b in + b.buildPrefix() + + // Generate some random code to produce some values + b.build(n: 10) + + // Create a random function + let f = b.buildPlainFunction(with: b.randomParameters()) { args in + b.build(n: 25) + } + + // Invoke the function once to trigger bytecode compilation + b.callFunction(f, withArgs: b.randomArguments(forCalling: f)) + + // Get the Bytecode object + let bytecodeObj = b.eval("%GetBytecode(%@)", with: [f], hasOutput: true)! + + // Wrap the bytecode in a Uint8Array + let bytecode = b.getProperty("bytecode", of: bytecodeObj) + let Uint8Array = b.createNamedVariable(forBuiltin: "Uint8Array") + let u8 = b.construct(Uint8Array, withArgs: [bytecode]) + + // Mutate the bytecode + let numMutations = Int.random(in: 1...3) + for _ in 0..([ + (BytecodeFuzzer, 2) ]), disabledCodeGenerators: [], From b716b2f70f559cfa1ea5b7121d79919828d61998 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 4 Dec 2025 15:20:59 +0100 Subject: [PATCH 027/234] Enable a shard mode for transpile_tests.py This enables calling the script with the arguments --num-shards and --shard-index. The former defines on how many shards (bots) the overall task gets distributed, the latter the index n to deterministically determined the sub-task for the n'th shard. The test order is deterministic and we assume that this script is called from different shards with the same test archive. The sub task is then evenly divided with a simple modulo algorithm. Bug: 442444727 Change-Id: I32803d2bae14f9387e445b627363f4de7ac7efe4 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8817538 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Tools/transpile_tests/test_transpile_tests.py | 104 +++++++++++++----- Tools/transpile_tests/transpile_tests.py | 26 ++++- 2 files changed, 101 insertions(+), 29 deletions(-) diff --git a/Tools/transpile_tests/test_transpile_tests.py b/Tools/transpile_tests/test_transpile_tests.py index cc776ce27..a772cd9b6 100644 --- a/Tools/transpile_tests/test_transpile_tests.py +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -29,39 +29,41 @@ TEST_DATA = Path(__file__).parent / 'testdata' -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) +# 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'') - Process = namedtuple('Process', 'returncode stdout') - # Mock out the FuzzIL tool, but mimick writing the desired output file. - # Simulate one compilation failure for the test with "fail" in its name. - 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 - # 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 __enter__(self): - return self + def __exit__(self, *_): + pass - def __exit__(self, *_): - pass + def imap_unordered(self, *args): + return map(*args) - 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): @@ -107,5 +109,55 @@ def imap_unordered(self, *args): } 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 = { + 'num_tests': 2, + 'num_successes': 1, + 'percent_successes': 50.0, + 'failures': [ + { + 'output': 'Failed!', + 'path': 'test/test262/data/test/folder2/Test4_fail.js', + }, + ], + } + self.assertEqual(expected_results, actual_results) + if __name__ == '__main__': unittest.main() diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index 8deccb1a9..e7fee5f9e 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -122,6 +122,17 @@ 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.""" @@ -132,9 +143,10 @@ def transpile_suite(options, base_dir, output_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 abspath in list_test_filenames( - test_input_dir, metadata_parser.is_supported): - yield (abspath, output_dir / abspath.relative_to(base_dir)) + 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. num_tests = 0 @@ -185,6 +197,13 @@ def parse_args(args): '--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.') @@ -193,6 +212,7 @@ def 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) From e1bb49257a26a50b7015f42112bf45c7303b01d1 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Fri, 5 Dec 2025 02:44:27 -0800 Subject: [PATCH 028/234] Revert "Throw exception in TryCatchFinally blocks (with certain probability)." This reverts commit 8a542afbbf2c6b6dd5f62fdcf8361ec7f6979110. Reason for revert: V8/d8 is not seeded, therefore crashes are not reproducible (and the code is unstable). Original change's description: > Throw exception in TryCatchFinally blocks (with certain probability). > > Bug: 455512155,455513417 > Change-Id: I52dc1b9d27d02ee1e5d905eca3705d9a9c4a6661 > Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8796096 > Commit-Queue: Pawel Krawczyk > Reviewed-by: Dominik Klemba Bug: 455512155,455513417 Change-Id: I17514fcc50b60232faccd0a7b418fad0b187174d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8821316 Bot-Commit: Rubber Stamper Commit-Queue: Dominik Klemba Reviewed-by: Michael Achenbach Auto-Submit: Dominik Klemba Commit-Queue: Michael Achenbach --- .../CodeGen/CodeGeneratorWeights.swift | 1 - Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 32 ++----------------- 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index c60c853ce..1dff70aed 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -186,7 +186,6 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "TryFinallyGenerator": 5, "ThrowGenerator": 1, - "NondeterministiclyThrowGenerator": 1, "BlockStatementGenerator": 1, // Special generators diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 002b46b01..0c5442f4a 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2492,8 +2492,6 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), provides: [.javascript] ) { b in - if (probability(0.1)) { throwRandomJSVariable(b) } - else if (probability(0.3)) { nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.5)} b.emit(BeginCatch()) }, GeneratorStub( @@ -2526,8 +2524,6 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), provides: [.javascript] ) { b in - if (probability(0.1)) { throwRandomJSVariable(b) } - else if (probability(0.3)) { nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.5)} b.emit(BeginCatch()) }, GeneratorStub( @@ -2564,11 +2560,8 @@ public let CodeGenerators: [CodeGenerator] = [ ]), CodeGenerator("ThrowGenerator") { b in - throwRandomJSVariable(b) - }, - - CodeGenerator("NondeterministiclyThrowGenerator") { b in - nondeterministiclyThrowRandomJSVariable(b, withProbability: 0.3) + let v = b.randomJsVariable() + b.throwException(v) }, // @@ -3025,24 +3018,3 @@ public let CodeGenerators: [CodeGenerator] = [ }, catchBody: { _ in }) }, ] - -private func nondeterministiclyThrowRandomJSVariable(_ b: ProgramBuilder, withProbability probability: Double) { - assert(probability >= 0 && probability <= 1) - - let threshold = b.loadFloat(probability) - let Math = b.createNamedVariable(forBuiltin: "Math") - let randomNumber = b.callMethod("random", on: Math, withArgs: []) - // Let's not influence other generators with Math & randomly generated number. - b.hide(Math) - b.hide(randomNumber) - - let condition = b.compare(threshold, with: randomNumber, using: Comparator.greaterThan) - b.buildIf(condition) { - throwRandomJSVariable(b) - } -} - -private func throwRandomJSVariable(_ b: ProgramBuilder) { - let v = b.randomJsVariable() - b.throwException(v) -} From 9c370c32b942af893a51ed0e06dcf1bf6d41a7d4 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 5 Dec 2025 14:47:37 +0100 Subject: [PATCH 029/234] Find the FuzzILTool relative to the transpiler script This makes it possible to call the script from some nested work dir. Bug: 442444727 Change-Id: I5f6f4313b652cb09e4d168785e78a2334495ccd9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8821322 Auto-Submit: Michael Achenbach Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Tools/transpile_tests/transpile_tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index e7fee5f9e..ef82f11f2 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -30,6 +30,8 @@ from pathlib import Path +BASE_DIR = Path(__file__).parent.parent.parent + class DefaultMetaDataParser: """Class instantiated once per test configuration/suite, providing a @@ -96,7 +98,7 @@ def list_test_filenames(test_root, is_supported_fun): def run_transpile_tool(input_file, output_file): cmd = [ - '.build/debug/FuzzILTool', + BASE_DIR / '.build/debug/FuzzILTool', '--compile', input_file, f'--outputPathJS={output_file}', From 3b241b0b0ea992ce6e99433a44b18bdfdaa92ba1 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 24 Nov 2025 14:53:56 +0100 Subject: [PATCH 030/234] [wasm] Change loops to use wasm-gc signatures This allows using parameter types which are indexed types (things like `(ref null 1)`). Implementation: - Each WasmLoop instruction now takes its signature as the first input. - The static signature types are removed from the begin and endLoop. - The loop code generator emits an "ad hoc" signature in order to emit signatures for which we already have corresponding inputs available. Bug: 445356784 Change-Id: Ic58ab7d6a092a39de77c974142dd7f976786e8e1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8792956 Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 44 ++++++++--- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 71 +++++++++++------ Sources/Fuzzilli/FuzzIL/Instruction.swift | 11 +-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 35 +++++++-- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 9 +++ Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 21 +++-- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 10 +-- .../Fuzzilli/Minimization/BlockReducer.swift | 19 +++-- Sources/Fuzzilli/Mutators/InputMutator.swift | 5 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 31 +++----- Sources/Fuzzilli/Protobuf/operations.proto | 5 +- Tests/FuzzilliTests/WasmTests.swift | 78 ++++++++++++++++--- 13 files changed, 241 insertions(+), 102 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 6bc1dbd6b..c8de47c92 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1345,6 +1345,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]() @@ -3998,18 +4002,25 @@ public class ProgramBuilder { return Array(b.emit(WasmEndIf(outputTypes: signature.outputTypes), withInputs: falseResults, types: 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) } @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) } @discardableResult @@ -4637,8 +4648,20 @@ public class ProgramBuilder { /// Like wasmDefineSignatureType but instead of within a type group this defines a signature /// type directly inside a wasm function. + /// 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]) -> Variable { + func wasmDefineAdHocSignatureType(signature: WasmSignature) -> Variable { + let 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) return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes).output } @@ -4854,8 +4877,6 @@ public class ProgramBuilder { 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): @@ -4863,7 +4884,6 @@ public class ProgramBuilder { case .wasmBeginTryTable(let op): activeWasmModule!.blockSignatures.push(op.signature) case .wasmEndIf(_), - .wasmEndLoop(_), .wasmEndTry(_), .wasmEndTryDelegate(_), .wasmEndTryTable(_), diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 697f84d4a..6a37e6717 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1261,7 +1261,9 @@ 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) @@ -1275,38 +1277,59 @@ 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) + CodeGenerator("WasmLoopWithSignatureGenerator", [ + GeneratorStub("WasmBeginLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction]) { b in + let function = b.currentWasmModule.currentWasmFunction + // Count upwards here to make it slightly more different from the other loop generator. + // Also, instead of using reassign, this generator uses the signature to pass and update the loop counter. + let randomArgs = b.randomWasmBlockArguments(upTo: 5) + 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) + // Calculate index types for the dynamically created signature. + let indexTypes = (parameters + outputTypes) + .filter {$0.Is(.anyIndexRef)} + .map(b.getWasmTypeDef) + + // TODO(mliedtke): We need to cleanup the index types here! + let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) + let loopBegin = b.emit(WasmBeginLoop(parameterCount: parameters.count), + withInputs: [signature] + args) + let loopCounter = loopBegin.innerOutput(1) + assert(b.type(of: loopCounter).Is(.wasmi32)) + b.runtimeData.push("loopCounter", loopCounter) + b.runtimeData.push("loopSignature", signature) + b.runtimeData.push("loopLabel", loopBegin.innerOutput(0)) + }, + GeneratorStub("WasmEndLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction]) { b in + let signature = b.runtimeData.pop("loopSignature") + let function = b.currentWasmModule.currentWasmFunction - function.wasmBuildLoop(with: parameters => outputTypes, args: args) { - label, loopArgs in - b.buildRecursive(n: defaultCodeGenerationAmount) + // 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( - args[0], function.consti32(1), binOpKind: .Add) + b.runtimeData.pop("loopCounter"), 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)! } + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature + let backedgeArgs = [loopCtr] + wasmSignature.parameterTypes.dropFirst() + .map {b.randomVariable(ofType: $0)!} function.wasmBranchIf( - condition, to: label, args: backedgeArgs, + condition, to: b.runtimeData.pop("loopLabel"), args: backedgeArgs, hint: b.randomWasmBranchHint()) - return outputTypes.map(function.findOrGenerateWasmVar) - } - }, + let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) + b.emit(WasmEndLoop(outputCount: outputs.count), withInputs: [signature] + outputs) + }, + ]), // TODO Turn this into a multi-part Generator CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 6486e4603..86f98e4a7 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1395,12 +1395,11 @@ extension Instruction: ProtobufConvertible { } 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 { @@ -2456,11 +2455,9 @@ extension Instruction: ProtobufConvertible { case .wasmEndBlock(let p): op = WasmEndBlock(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) 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) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 054f242a2..ae3e96826 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -38,6 +38,8 @@ public struct JSTyper: Analyzer { private var typeGroupDependencies: [Int:Set] = [:] private var selfReferences: [Variable: [(inout JSTyper, Variable?) -> ()]] = [:] 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() @@ -401,6 +403,7 @@ public struct JSTyper: Analyzer { state.reset() signatures.removeAll() typeGroups.removeAll() + wasmTypeDefMap.removeAll() defUseAnalyzer = DefUseAnalyzer() isWithinTypeGroup = false dynamicObjectGroupManager = ObjectGroupManager() @@ -432,6 +435,20 @@ public struct JSTyper: Analyzer { } } + 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") + } + return wasmTypeDefMap[desc.get()!]! + } + mutating func addSignatureType(def: Variable, signature: WasmSignature, inputs: ArraySlice) { assert(isWithinTypeGroup) var inputs = inputs.makeIterator() @@ -445,7 +462,7 @@ 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 { @@ -809,16 +826,18 @@ public struct JSTyper: Analyzer { wasmTypeBeginBlock(instr, op.signature) case .wasmEndIf(let op): wasmTypeEndBlock(instr, op.outputTypes) - case .wasmBeginLoop(let op): + 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: .label(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 .wasmEndLoop(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, signature.outputTypes) case .wasmBeginTryTable(let op): wasmTypeBeginBlock(instr, op.signature) instr.inputs.forEach { input in @@ -903,6 +922,7 @@ public struct JSTyper: Analyzer { 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)") @@ -1886,6 +1906,9 @@ public struct JSTyper: Analyzer { 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) diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index 729550e9c..a0aa62eed 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -291,6 +291,7 @@ public struct ILType: Hashable { 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 @@ -596,6 +597,14 @@ 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 { let isPacked = Is(.wasmPackedI8) || Is(.wasmPackedI16) return isPacked diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 452dd9cc5..307ff0346 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1315,21 +1315,26 @@ final class WasmEndIf: WasmOperation { 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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 33d47fa16..f7985fe99 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1097,9 +1097,9 @@ 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): diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 4944ac161..bcfb03a07 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1268,8 +1268,7 @@ public class WasmLifter { self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginLoop(let op): - registerSignature(op.signature) + case .wasmBeginLoop(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1455,7 +1454,7 @@ 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) guard typeDesc.typeGroupIndex != -1 else { throw CompileError.fatalError("Missing type group index for \(input)") @@ -1912,8 +1911,9 @@ public class WasmLifter { // 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))) + 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 catchTable: Data = try op.catches.map { diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 5a1efac08..3fd0a0ad0 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -95,13 +95,20 @@ struct BlockReducer: Reducer { .wasmBeginTryTable: reduceGenericBlockGroup(group, with: helper) - case .wasmBeginBlock, - .wasmBeginLoop: + case .wasmBeginBlock: + // TODO(mliedtke): Deduplicate with .wasmBeginLoop once blocks also use wasm-gc + // signatures. let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper) if rewroteProgram { return } + case .wasmBeginLoop: + let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper, usesSignature: true) + if rewroteProgram { + return + } + case .wasmBeginCatchAll, .wasmBeginCatch: // These instructions are handled in the reduceWasmTryCatch. @@ -311,7 +318,7 @@ struct BlockReducer: Reducer { // Reduce a wasm block. In some cases this reduction fully rewrites the program // invalidating pre-computed BlockGroups. If that happens, the function returns true indicating // that following reductions need to rerun the Blockgroups analysis. - private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper) -> Bool { + private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper, usesSignature: Bool = false) -> Bool { // Try to remove just the block. var candidates = group.blockInstructionIndices if helper.tryNopping(candidates) { @@ -334,9 +341,11 @@ struct BlockReducer: Reducer { let beginInstr = helper.code[group.head] let endInstr = helper.code[group.tail] + let blockInputs = usesSignature ? beginInstr.inputs.dropFirst() : beginInstr.inputs + let endInstrInputs = usesSignature ? endInstr.inputs.dropFirst() : endInstr.inputs var varReplacements = Dictionary( - uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), beginInstr.inputs)) - varReplacements.merge(zip(endInstr.outputs, endInstr.inputs.map {varReplacements[$0] ?? $0}), + uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), blockInputs)) + varReplacements.merge(zip(endInstr.outputs, endInstrInputs.map {varReplacements[$0] ?? $0}), uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) var newCode = Code() for (i, instr) in helper.code.enumerated() { diff --git a/Sources/Fuzzilli/Mutators/InputMutator.swift b/Sources/Fuzzilli/Mutators/InputMutator.swift index 01398b3ac..7f03a9ffc 100644 --- a/Sources/Fuzzilli/Mutators/InputMutator.swift +++ b/Sources/Fuzzilli/Mutators/InputMutator.swift @@ -66,7 +66,10 @@ public class InputMutator: BaseInstructionMutator { 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: diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 2b2248232..883ab8d90 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5173,9 +5173,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 +5185,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() @@ -13718,7 +13716,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() { @@ -13726,26 +13724,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 } @@ -13753,7 +13746,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() { @@ -13761,21 +13754,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 8ed578def..d26a6d56b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1247,12 +1247,11 @@ message WasmEndBlock { } message WasmBeginLoop { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmEndLoop { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } enum WasmCatchKind { diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index f7955e212..987599fb4 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -324,13 +324,14 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let ctr = function.consti32(10) - function.wasmBuildLoop(with: [] => []) { label, args in + function.wasmBuildLoop(with: [] => [], args: []) { label, args in XCTAssert(b.type(of: label).Is(.anyLabel)) 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] } @@ -2684,7 +2685,7 @@ class WasmFoundationTests: XCTestCase { let max = function.consti32(10) let one = function.consti32(1) - function.wasmBuildLoop(with: [] => []) { label, args in + function.wasmBuildLoop(with: [] => [], args: []) { label, args in XCTAssert(b.type(of: label).Is(.anyLabel)) let result = function.wasmi32BinOp(ctr, one, binOpKind: .Add) let varUpdate = function.wasmi64BinOp(variable, function.consti64(2), binOpKind: .Add) @@ -2692,6 +2693,7 @@ class WasmFoundationTests: XCTestCase { 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. @@ -4489,17 +4491,35 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "null\n") } - func testAdHocSignature() throws { + 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: [] => [.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. - let signatureType = b.wasmDefineAdHocSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) - return [function.wasmRefNull(typeDef: signatureType)] + 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)] } } @@ -4509,7 +4529,45 @@ class WasmGCTests: XCTestCase { b.callFunction(outputFunc, withArgs: [wasmOut]) } - testForOutput(program: jsProg, runner: runner, outputString: "null\n") + 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 { From ea68e6435ba035d11b619fcdd07af72bbf65e45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= Date: Mon, 8 Dec 2025 15:18:38 +0100 Subject: [PATCH 031/234] Implement support for a number of recent JS language features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * JSON.parse source text access & RawJSON * Iterator helpers * upsert Change-Id: I1dad9b38c1a42ba8cfdb055651db06e0947dd184 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8814317 Reviewed-by: Matthias Liedtke Commit-Queue: Olivier Flückiger Auto-Submit: Olivier Flückiger --- .../Environment/JavaScriptEnvironment.swift | 172 ++++++++++++------ 1 file changed, 116 insertions(+), 56 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9ef54f216..83c2509bb 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -322,6 +322,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsStrings) registerObjectGroup(.jsArrays) registerObjectGroup(.jsArguments) + registerObjectGroup(.jsIterator) + registerObjectGroup(.jsIteratorPrototype) + registerObjectGroup(.jsIteratorConstructor) registerObjectGroup(.jsGenerators) registerObjectGroup(.jsPromises) registerObjectGroup(.jsRegExps) @@ -552,6 +555,7 @@ 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"] { @@ -1009,9 +1013,15 @@ public extension ILType { /// 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. + /// Type of a JavaScript function's arguments object. static let jsArguments = ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) + /// Type of a JavaScript Iterator object. + static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"]) + + /// Type of the JavaScript Iterator constructor builtin. + static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from"]) + /// Type of a JavaScript generator object. static let jsGenerator = ILType.iterable + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) @@ -1019,10 +1029,10 @@ public extension ILType { 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"]) + 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"]) + 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"]) @@ -1149,7 +1159,7 @@ public extension ILType { 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"]) + 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"]) @@ -1306,10 +1316,16 @@ public extension ObjectGroup { // 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 + // TODO(mliedtke): Find a nicer interface than manually excluding some + // magic combinations here. if receiver.name == "Intl.DateTimeFormat" || receiver.name == "Intl.NumberFormat" { properties.removeValue(forKey: "format") } else if receiver.name == "Intl.Collator" { properties.removeValue(forKey: "compare") + } else if receiver.name == "Iterator" { + properties.removeValue(forKey: "next") + properties.removeValue(forKey: "return") + properties.removeValue(forKey: "throw") } return ObjectGroup( name: name, @@ -1342,7 +1358,7 @@ public extension ObjectGroup { "indexOf" : [.jsAnything, .opt(.integer)] => .integer, "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, "match" : [.regexp] => .jsString, - "matchAll" : [.regexp] => .jsString, + "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, @@ -1399,7 +1415,7 @@ public extension ObjectGroup { methods: [ "at" : [.integer] => .jsAnything, "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsArray, - "entries" : [] => .jsArray, + "entries" : [] => .jsIterator, "every" : [.function(), .opt(.object())] => .boolean, "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined, "find" : [.function(), .opt(.object())] => .jsAnything, @@ -1410,14 +1426,14 @@ public extension ObjectGroup { "includes" : [.jsAnything, .opt(.integer)] => .boolean, "indexOf" : [.jsAnything, .opt(.integer)] => .integer, "join" : [.string] => .jsString, - "keys" : [] => .object(), // returns an array iterator + "keys" : [] => .jsIterator, "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(), + "values" : [] => .jsIterator, "pop" : [] => .jsAnything, "push" : [.jsAnything...] => .integer, "shift" : [] => .jsAnything, @@ -1477,14 +1493,52 @@ public extension ObjectGroup { methods: [:] ) + 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, + ] + ) + + static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator) + + static let jsIteratorConstructor = ObjectGroup( + name: "IteratorConstructor", + instanceType: .jsIteratorConstructor, + properties: [ + "prototype" : jsIteratorPrototype.instanceType + ], + methods: [ + "from" : [.jsAnything] => .jsIterator, + ] + ) + 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"]), ] ) @@ -1508,15 +1562,17 @@ public extension ObjectGroup { "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, ] ) @@ -1526,10 +1582,12 @@ public extension ObjectGroup { 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, ] ) @@ -1544,11 +1602,11 @@ public extension ObjectGroup { "add" : [.jsAnything] => .jsSet, "clear" : [] => .undefined, "delete" : [.jsAnything] => .boolean, - "entries" : [] => .object(), + "entries" : [] => .jsIterator, "forEach" : [.function(), .opt(.object())] => .undefined, "has" : [.jsAnything] => .boolean, - "keys" : [] => .object(), - "values" : [] => .object(), + "keys" : [] => .jsIterator, + "values" : [] => .jsIterator, ] ) @@ -1592,12 +1650,12 @@ public extension ObjectGroup { properties: [ "byteLength" : .integer, "maxByteLength" : .integer, - "resizable" : .boolean + "resizable" : .boolean, ], methods: [ - "resize" : [.integer] => .undefined, - "slice" : [.integer, .opt(.integer)] => .jsArrayBuffer, - "transfer" : [] => .jsArrayBuffer, + "resize" : [.integer] => .undefined, + "slice" : [.integer, .opt(.integer)] => .jsArrayBuffer, + "transfer" : [.opt(.integer)] => .jsArrayBuffer, ] ) @@ -1636,32 +1694,32 @@ public extension ObjectGroup { "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, + "at" : [.integer] => .jsAnything, + "copyWithin" : [.integer, .integer, .opt(.integer)] => .undefined, + "entries" : [] => .jsIterator, + "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), + "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" : [] => .undefined, + "set" : [.object(), .opt(.integer)] => .undefined, + "some" : [.function(), .opt(.jsAnything)] => .boolean, + "sort" : [.function()] => .undefined, + "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), @@ -2032,6 +2090,8 @@ public extension ObjectGroup { methods: [ "parse" : [.string, .opt(.function())] => .jsAnything, "stringify" : [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString, + "rawJSON" : [.plain(.string | .number | .boolean)] => .jsAnything, + "isRawJSON" : [.jsAnything] => .boolean, ] ) From 525e9ddc6e318015f0beb349f042d203d2f3a8cc Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 9 Dec 2025 10:22:09 +0100 Subject: [PATCH 032/234] Add merge script for transpile-tests results This adds a simple script to merge data from multiple sharded calls to transpile_tests.py. We keep the merge script side-by-side with the main script to ease changing details in the data later, e.g. adding additional keys. This also drops two redundant entries from the current format. Bug: 442444727 Change-Id: I774c078455028a01eb97276b90120a0f03c14f7a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8832116 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Tools/transpile_tests/merge_json_results.py | 65 ++++++++++++++++ Tools/transpile_tests/test_merge_results.py | 75 +++++++++++++++++++ Tools/transpile_tests/test_transpile_tests.py | 4 - Tools/transpile_tests/transpile_tests.py | 4 +- 4 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 Tools/transpile_tests/merge_json_results.py create mode 100644 Tools/transpile_tests/test_merge_results.py diff --git a/Tools/transpile_tests/merge_json_results.py b/Tools/transpile_tests/merge_json_results.py new file mode 100644 index 000000000..8aa66bb2d --- /dev/null +++ b/Tools/transpile_tests/merge_json_results.py @@ -0,0 +1,65 @@ +# 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 + + +def merge_test_results(inputs): + num_tests = 0 + failures = [] + for result in inputs: + num_tests += result["num_tests"] + failures += result["failures"] + + return { + 'num_tests': num_tests, + 'failures': failures, + } + + +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'Merged results for {result["num_tests"]} tests ' + f'and {len(result["failures"])} failures.') + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/Tools/transpile_tests/test_merge_results.py b/Tools/transpile_tests/test_merge_results.py new file mode 100644 index 000000000..cdc446fb2 --- /dev/null +++ b/Tools/transpile_tests/test_merge_results.py @@ -0,0 +1,75 @@ +# 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({ + 'num_tests': 2, + 'failures': [ + {'path': 'path/to/failure1', 'output': 'foo'}, + ] + }, f) + + with open('/in2.json', 'w') as f: + json.dump({ + 'num_tests': 3, + 'failures': [ + {'path': 'path/to/failure2', 'output': 'bar 42\nbar 43'}, + {'path': 'path/to/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( + 'Merged results for 5 tests and 3 failures.', + 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 = { + 'num_tests': 5, + 'failures': [ + {'path': 'path/to/failure1', 'output': 'foo'}, + {'path': 'path/to/failure2', 'output': 'bar 42\nbar 43'}, + {'path': 'path/to/failure3', 'output': 'baz'}, + ], + } + 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 index a772cd9b6..ef1c7b95e 100644 --- a/Tools/transpile_tests/test_transpile_tests.py +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -98,8 +98,6 @@ def test_full_run(self, fs): expected_results = { 'num_tests': 4, - 'num_successes': 3, - 'percent_successes': 75.0, 'failures': [ { 'output': 'Failed!', @@ -148,8 +146,6 @@ def test_shard_run(self, fs): expected_results = { 'num_tests': 2, - 'num_successes': 1, - 'percent_successes': 50.0, 'failures': [ { 'output': 'Failed!', diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index ef82f11f2..b9ba6ca95 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -172,15 +172,13 @@ def test_input_gen(): f'({num_successes} of {num_tests}) test cases.') return { 'num_tests': num_tests, - 'num_successes': num_successes, - 'percent_successes': ratio, 'failures': failures, } def write_json_output(path, results): with open(path, 'w') as f: - json.dump(results, f) + json.dump(results, f, sort_keys=True, indent=2) def parse_args(args): From e0c17b64984290afdf5bcfea3140d6184515aeb3 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 9 Dec 2025 12:50:40 +0100 Subject: [PATCH 033/234] Rename merge script test Bug: 442444727 Change-Id: I6bc7c8744a7237e6d7c7c4bb204aeb530ed272e5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8832418 Auto-Submit: Michael Achenbach Commit-Queue: Pawel Krawczyk Reviewed-by: Pawel Krawczyk --- .../{test_merge_results.py => test_merge_json_results.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tools/transpile_tests/{test_merge_results.py => test_merge_json_results.py} (100%) diff --git a/Tools/transpile_tests/test_merge_results.py b/Tools/transpile_tests/test_merge_json_results.py similarity index 100% rename from Tools/transpile_tests/test_merge_results.py rename to Tools/transpile_tests/test_merge_json_results.py From cb649fa38a977cd559c08d95af161082ccd23c87 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 9 Dec 2025 19:07:48 +0100 Subject: [PATCH 034/234] [v8] Add %AllocationTimeout generator Besides the existing --gc-interval=n flag, this can help finding bugs for a GC happening at a specific point in a builtin or runtime function. Bug: 467294029 Change-Id: I9d78d7d01d229ecd3e0c631f9d1e2f54a456b4ba Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8832419 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 7 +++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 1 + 2 files changed, 8 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 967210b97..3c65c893c 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -51,6 +51,13 @@ public let V8GcGenerator = CodeGenerator("GcGenerator") { b in 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. diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index ade2d87ac..3d3e60bf2 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -63,6 +63,7 @@ let v8Profile = Profile( (WorkerGenerator, 10), (V8GcGenerator, 5), + (V8AllocationTimeoutGenerator, 5), (V8MajorGcGenerator, 5), (WasmStructGenerator, 15), From 36d62582f60991d3194bd2e820440d503a7f3d07 Mon Sep 17 00:00:00 2001 From: Hendrik Wuethrich Date: Thu, 11 Dec 2025 09:54:18 +0000 Subject: [PATCH 035/234] Add ManyArgumentsCall CodeGenerator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling apply() with an array like this generator does will create a function call with as many arguments as the size of the array. It is meant to cover the discrepencies in max argument counts between turboshaft and maglev. Bug: b/455503442 Change-Id: Ia605368687970369e168796273486d75de4cc811 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8839116 Reviewed-by: Matthias Liedtke Commit-Queue: Hendrik Wüthrich --- .../CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 1dff70aed..f44c008ac 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -129,6 +129,7 @@ public let codeGeneratorWeights = [ "ComputedPropertyConfigurationGenerator": 10, "FunctionCallGenerator": 30, "FunctionCallWithSpreadGenerator": 3, + "ManyArgumentsCall": 3, "ConstructorCallGenerator": 20, "ConstructorCallWithSpreadGenerator": 3, "MethodCallGenerator": 30, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 0c5442f4a..f649e17d8 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1846,6 +1846,25 @@ public let CodeGenerators: [CodeGenerator] = [ f, withArgs: arguments, spreading: spreads, guard: needGuard) }, + + CodeGenerator("ManyArgumentsCall", inputs: .preferred(.function())) { b, f in + // These sizes are around the max arguments for maglev (2^16 - 10) + // and turboshaft (2^16). + let sizes: [Int64] = [65524, 65525, 65526, 65534, 65535, 65536] + let size = b.loadInt(chooseUniform(from: sizes)) + let constructor = b.createNamedVariable(forBuiltin: "Array") + let largeArray = b.construct(constructor, withArgs: [size]) + + let needGuard = b.type(of: f).MayNotBe(.function()) + + if probability(0.5) { + let receiver = probability(0.5) ? b.loadNull() : b.randomVariable(forUseAs: .object()) + b.callMethod("apply", on: f, withArgs: [receiver, largeArray], guard: needGuard) + } else { + b.callFunction(f, withArgs: [largeArray], spreading: [true], guard: needGuard) + } + }, + CodeGenerator( "ConstructorCallWithSpreadGenerator", inputs: .preferred(.constructor()) ) { b, c in From 60b6d27a24c64e6ba3ad92c64cc078a7f221453d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 12 Dec 2025 12:19:53 +0100 Subject: [PATCH 036/234] [v8] Drop SSE3 code gen flag for Wasm This flag is incomplete. Before fuzzing it, all V8 tests should pass. Recent fuzzer reports show that this is not the case. Bug: 468167782 Change-Id: I80d2cba60f1d553dd47cff338dee40a3b7c1ffbd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8843276 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Thibaud Michaud Commit-Queue: Thibaud Michaud --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 3c65c893c..d53a07dac 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -1061,7 +1061,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 From 62e4d2fda66f659c8d95abc17b5da7293475f7e2 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 11 Dec 2025 21:49:35 +0100 Subject: [PATCH 037/234] Make transpiler results format more fine-grained. This enhances the results format after test transpilation. Before, we had only one level of: {num_tests: int, failures: [{path: string, output: string}]} Now we'll key the two lowest directory levels in Test262, e.g. for a typical path like: language/literals/boolean/S7.8.2_A1_T1.js, the key would be language/literals. All results under this directory will be listed as a dict value, with numbers and failures as previously, further directories accordingly: { language/literals: {num_tests: ..., failures: ...}, language/identifiers: ... ... } We will now transpile all Test262 tests in one run and won't need to exclude any subdirectories, like staging, as we can now report separate numbers anyways. This also updates the merge script to the new format and adds additional unit tests for some helper functions. Bug: 442444727 Change-Id: Idf23c650c646bc970d81fc8a318d4a8c76797a4d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8841396 Commit-Queue: Michael Achenbach Reviewed-by: Liviu Rau --- Tools/transpile_tests/merge_json_results.py | 23 ++-- .../test_merge_json_results.py | 61 ++++++--- Tools/transpile_tests/test_transpile_tests.py | 119 +++++++++++++++--- Tools/transpile_tests/transpile_tests.py | 105 ++++++++++++---- 4 files changed, 242 insertions(+), 66 deletions(-) diff --git a/Tools/transpile_tests/merge_json_results.py b/Tools/transpile_tests/merge_json_results.py index 8aa66bb2d..0b0a38fab 100644 --- a/Tools/transpile_tests/merge_json_results.py +++ b/Tools/transpile_tests/merge_json_results.py @@ -20,18 +20,22 @@ import json import sys +from collections import defaultdict, Counter + def merge_test_results(inputs): - num_tests = 0 - failures = [] + num_tests = Counter() + failures = defaultdict(list) + for result in inputs: - num_tests += result["num_tests"] - failures += result["failures"] + for key, value in result.items(): + num_tests[key] += value["num_tests"] + failures[key] += value["failures"] - return { - 'num_tests': num_tests, - 'failures': failures, - } + return dict( + (key, {'num_tests': num_tests[key], 'failures': failures[key]}) + for key in sorted(num_tests.keys()) + ) def parse_args(args): @@ -57,8 +61,7 @@ def main(args): with open(options.json_output, 'w') as f: json.dump(result, f, sort_keys=True, indent=2) - print(f'Merged results for {result["num_tests"]} tests ' - f'and {len(result["failures"])} failures.') + print(f'Successfully merged results.') if __name__ == '__main__': diff --git a/Tools/transpile_tests/test_merge_json_results.py b/Tools/transpile_tests/test_merge_json_results.py index cdc446fb2..a297172f2 100644 --- a/Tools/transpile_tests/test_merge_json_results.py +++ b/Tools/transpile_tests/test_merge_json_results.py @@ -28,19 +28,37 @@ class TestMergeResults(fake_filesystem_unittest.TestCase): def test_full_run(self, fs): with open('/in1.json', 'w') as f: json.dump({ - 'num_tests': 2, - 'failures': [ - {'path': 'path/to/failure1', 'output': 'foo'}, - ] + '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({ - 'num_tests': 3, - 'failures': [ - {'path': 'path/to/failure2', 'output': 'bar 42\nbar 43'}, - {'path': 'path/to/failure3', 'output': 'baz'}, - ] + '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() @@ -53,7 +71,7 @@ def test_full_run(self, fs): # Verify the output. self.assertEqual( - 'Merged results for 5 tests and 3 failures.', + 'Successfully merged results.', f.getvalue().strip()) # Verify the results written to the json output file. @@ -61,13 +79,24 @@ def test_full_run(self, fs): actual_results = json.load(f) expected_results = { - 'num_tests': 5, - 'failures': [ - {'path': 'path/to/failure1', 'output': 'foo'}, - {'path': 'path/to/failure2', 'output': 'bar 42\nbar 43'}, - {'path': 'path/to/failure3', 'output': 'baz'}, - ], + '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) diff --git a/Tools/transpile_tests/test_transpile_tests.py b/Tools/transpile_tests/test_transpile_tests.py index ef1c7b95e..3e6277428 100644 --- a/Tools/transpile_tests/test_transpile_tests.py +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -97,13 +97,14 @@ def test_full_run(self, fs): actual_results = json.load(f) expected_results = { - 'num_tests': 4, - 'failures': [ - { - 'output': 'Failed!', - 'path': 'test/test262/data/test/folder2/Test4_fail.js', - }, - ], + 'folder1/subfolder1': { + 'failures': [], + 'num_tests': 2, + }, + 'folder2': { + 'failures': [{'output': 'Failed!', 'path': 'folder2/Test4_fail.js'}], + 'num_tests': 2, + }, } self.assertEqual(expected_results, actual_results) @@ -145,15 +146,105 @@ def test_shard_run(self, fs): actual_results = json.load(f) expected_results = { - 'num_tests': 2, - 'failures': [ - { - 'output': 'Failed!', - 'path': 'test/test262/data/test/folder2/Test4_fail.js', - }, - ], + '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_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): + counter = transpile_tests.TestCounter(2, 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') + + 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'}, + ]}, + '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/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index b9ba6ca95..106895e2e 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -28,6 +28,7 @@ import subprocess import sys +from collections import defaultdict, Counter from pathlib import Path BASE_DIR = Path(__file__).parent.parent.parent @@ -49,7 +50,6 @@ def __init__(self, base_dir): 'parseTestRecord', f'{tools_abs_path}/parseTestRecord.py') self.parse = loader.load_module().parseTestRecord self.excluded_suffixes = ['_FIXTURE.js'] - self.excluded_dirs = ['staging'] def is_supported(self, abspath, relpath): if not super().is_supported(abspath, relpath): @@ -59,10 +59,6 @@ def is_supported(self, abspath, relpath): for suffix in self.excluded_suffixes): return False - if any(str(relpath).startswith(directory) - for directory in self.excluded_dirs): - return False - with open(abspath, encoding='utf-8') as f: content = f.read() record = self.parse(content, relpath) @@ -74,15 +70,82 @@ def is_supported(self, abspath, relpath): 'test262': { 'path': 'test/test262/data/test', 'excluded_suffixes': ['_FIXTURE.js'], - # TODO(https://crbug.com/442444727): We might want to track the staging - # tests separately. Those typically address in-progress JS features with - # a high import-failure rate. - 'excluded_dirs': ['staging'], + 'levels': 2, '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'. + + 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, options): + self.levels = levels + 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 level_key(self, relpath): + parts = list(relpath.parts) + assert parts + assert parts[0] != '/' + + parts = parts[:-1] + parts = parts[:self.levels] + 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. @@ -151,29 +214,19 @@ def test_input_gen(): yield (abspath, output_dir / abspath.relative_to(base_dir)) # Iterate over all tests in parallel and collect stats. - num_tests = 0 - failures = [] + counter = TestCounter(test_config['levels'], options) with multiprocessing.Pool(multiprocessing.cpu_count()) as pool: for exit_code, abspath, stdout in pool.imap_unordered( transpile_test, test_input_gen()): - num_tests += 1 - if exit_code != 0: - relpath = abspath.relative_to(base_dir) - failures.append({'path': str(relpath), 'output': stdout}) - verbose_print(options, f'Failed to compile {relpath}') - if (num_tests + 1) % 500 == 0: - print(f'Processed {num_tests + 1} test cases.') + relpath = abspath.relative_to(test_input_dir) + counter.count(exit_code, relpath, stdout) # Render and return results. - assert num_tests, 'Failed to find any tests.' - num_successes = num_tests - len(failures) - ratio = float(num_successes) / num_tests * 100 + 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'({num_successes} of {num_tests}) test cases.') - return { - 'num_tests': num_tests, - 'failures': failures, - } + f'({counter.num_successes} of {counter.total_tests}) test cases.') + return counter.results() def write_json_output(path, results): From d9aa0f61142d1a4ea62f81b93a9eb0e845a916e5 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 12 Dec 2025 14:39:11 +0100 Subject: [PATCH 038/234] Preserve leading comments when transpiling JS JS files often contain meta data in leading comments. We require these comments to be able to execute JS code again after transpiling it with the FuzzILTool. This preserves such comments, whenever the `--outputPathJS` option is used. The comments are extracted using information from the Babel AST in the parser. Bug: 442444727 Change-Id: Ibc9fda5f99a69123672b75970f9b5801c2695074 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8839676 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/FuzzILTool/main.swift | 2 +- Sources/Fuzzilli/Compiler/Parser/parser.js | 15 +++++++++++++-- Sources/Fuzzilli/Protobuf/ast.pb.swift | 13 ++++++++++--- Sources/Fuzzilli/Protobuf/ast.proto | 3 ++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Sources/FuzzILTool/main.swift b/Sources/FuzzILTool/main.swift index a8a3b6009..bff607265 100644 --- a/Sources/FuzzILTool/main.swift +++ b/Sources/FuzzILTool/main.swift @@ -188,7 +188,7 @@ 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) } catch { diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 081449c34..9d31b61a1 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)); } @@ -667,7 +678,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/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 61f091cb1..da0503c8f 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -153,6 +153,8 @@ public struct Compiler_Protobuf_AST: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + public var leadingComments: String = String() + public var statements: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -2455,7 +2457,7 @@ extension Compiler_Protobuf_FunctionType: SwiftProtobuf._ProtoNameProviding { extension Compiler_Protobuf_AST: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".AST" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}statements\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}leadingComments\0\u{1}statements\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2463,20 +2465,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 diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index 56fd5fbdc..3a4545cde 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -16,7 +16,8 @@ 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. From f065d0ba226269bf13fae85e71708efeff06fc23 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Mon, 15 Dec 2025 06:59:52 +0000 Subject: [PATCH 039/234] RAB and GSAB Fuzzing Added generators for: - ResizableArrayBuffer (RAB) and GrowableSharedArrayBuffer (GSAB) operations (resize, grow). - Creating TypedArrays and DataViews from buffers (including fixed-length views). - Converting Wasm memory to RAB/GSAB. - Increasing chance of accessing last element Improved existing generators: - ResizableArrayBufferGenerator, GrowableSharedArrayBufferGenerator Added a program template testing the interaction between Wasm memory growth and JS buffer resizing. Change-Id: I2127a84796470efff4304402f8fd7a9cc3b8f008 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8836397 Commit-Queue: Dominik Klemba Reviewed-by: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 12 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 71 ++++++++++- .../CodeGen/ProgramTemplateWeights.swift | 2 + .../Fuzzilli/CodeGen/ProgramTemplates.swift | 118 ++++++++++++++++++ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 26 ++++ .../Environment/JavaScriptEnvironment.swift | 7 ++ Tests/FuzzilliTests/JSTyperTests.swift | 21 ++++ Tests/FuzzilliTests/ProgramBuilderTest.swift | 27 ++++ 8 files changed, 280 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index f44c008ac..18a364cd4 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -203,8 +203,13 @@ public let codeGeneratorWeights = [ "EvalGenerator": 3, "NumberComputationGenerator": 40, "ImitationGenerator": 30, - "ResizableArrayBufferGenerator": 5, - "GrowableSharedArrayBufferGenerator": 5, + "ResizableArrayBufferGenerator": 5*6, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. + "ResizableBufferResizeGenerator": 5*3, + "GrowableSharedArrayBufferGenerator": 5*6, + "GrowableSharedBufferGrowGenerator": 5*3, + "TypedArrayFromBufferGenerator": 10*3, + "DataViewFromBufferGenerator": 5*3, + "TypedArrayLastIndexGenerator": 5*3, "FastToSlowPropertiesGenerator": 10, "IteratorGenerator": 5, "ConstructWithDifferentNewTargetGenerator": 5, @@ -217,6 +222,9 @@ public let codeGeneratorWeights = [ // JS generators for wasm features (e.g. APIs on the WebAssembly global object). "WasmGlobalGenerator": 4, "WasmMemoryGenerator": 4, + "WasmMemoryToResizableBufferGenerator": 5*3, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. + "WasmMemoryToFixedLengthBufferGenerator": 5*3, + "WasmMemoryJSGrowGenerator": 5*3, "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index f649e17d8..40d6f737f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -276,6 +276,39 @@ public let CodeGenerators: [CodeGenerator] = [ b.construct(constructor, withArgs: [size]) }, + CodeGenerator("TypedArrayFromBufferGenerator", + inContext: .single(.javascript), + inputs: .required(.jsArrayBuffer | .jsSharedArrayBuffer) + ) { b, buffer in + let constructor = b.createNamedVariable( + forBuiltin: chooseUniform( + from: JavaScriptEnvironment.typedArrayConstructors + ) + ) + b.construct(constructor, withArgs: [buffer]) + // TODO(tacet): add Fixed length view. withArgs: [buffer, offset, length] + }, + + CodeGenerator("DataViewFromBufferGenerator", + inContext: .single(.javascript), + inputs: .required(.jsArrayBuffer | .jsSharedArrayBuffer), + produces: [.jsDataView] + ) { b, buffer in + let constructor = b.createNamedVariable(forBuiltin: "DataView") + b.construct(constructor, withArgs: [buffer]) + // TODO(tacet): add Fixed length view. withArgs: [buffer, offset, length] + }, + + CodeGenerator("TypedArrayLastIndexGenerator", + inContext: .single(.javascript), + inputs: .required(.object(withProperties: ["buffer", "length"])), + produces: [.integer, .jsAnything] + ) { b, view in + let len = b.getProperty("length", of: view) + let index = b.binary(len, b.loadInt(1), with: .Sub) + b.getComputedProperty(index, of: view) + }, + CodeGenerator("BuiltinIntlGenerator") { b in let _ = chooseUniform(from: [b.constructIntlDateTimeFormat, b.constructIntlCollator, b.constructIntlListFormat, b.constructIntlNumberFormat, b.constructIntlPluralRules, b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter])() }, @@ -2869,7 +2902,7 @@ public let CodeGenerators: [CodeGenerator] = [ // assert(b.type(of: imitation) == b.type(of: orig)) }, - CodeGenerator("ResizableArrayBufferGenerator", inputs: .one) { b, v in + CodeGenerator("ResizableArrayBufferGenerator", produces: [.jsArrayBuffer]) { b in let size = b.randomSize(upTo: 0x1000) var maxSize = b.randomSize() if maxSize < size { @@ -2894,7 +2927,7 @@ public let CodeGenerators: [CodeGenerator] = [ b.construct(View, withArgs: [ab]) }, - CodeGenerator("GrowableSharedArrayBufferGenerator", inputs: .one) { b, v in + CodeGenerator("GrowableSharedArrayBufferGenerator", produces: [.jsSharedArrayBuffer]) { b in let size = b.randomSize(upTo: 0x1000) var maxSize = b.randomSize() if maxSize < size { @@ -3036,4 +3069,38 @@ public let CodeGenerators: [CodeGenerator] = [ b.callFunction(f, withArgs: args) }, catchBody: { _ in }) }, + + 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)) + } + 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) + }, ] diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift index c57cf76b4..f642ceab8 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift @@ -27,4 +27,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..4f859ba4d 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -500,4 +500,122 @@ public let ProgramTemplates = [ // Generate some more random code to (hopefully) use the parsed JSON in some interesting way. b.build(n: 25) }, + + WasmProgramTemplate("WasmResizableMemory") { b in + b.buildPrefix() + b.build(n: 50) + + // 1. Define a Wasm module with a randomly configured memory and a single exported function. + let isMemory64 = probability(0.5) + let isShared = probability(0.5) + let signature = b.randomWasmSignature() + + let jsMemory = b.createWasmMemory(minPages: 1, maxPages: Int.random(in: 50...200), isShared: isShared, isMemory64: isMemory64) + + let module = b.buildWasmModule { m in + let internalMem = m.addMemory(minPages: 1, maxPages: Int.random(in: 50...200), isShared: isShared, isMemory64: isMemory64) + + m.addWasmFunction(with: signature) { f, _, args in + b.build(n: 30) + if probability(0.5), let memory = b.randomVariable(ofType: .object(ofGroup: "WasmMemory")) { + let numPagesToGrow = f.memoryArgument(Int64.random(in: 0..<5), b.type(of: memory).wasmMemoryType!) + f.wasmMemoryGrow(memory: memory, growByPages: numPagesToGrow) + b.build(n: 5) + } + return signature.outputTypes.map { f.findOrGenerateWasmVar(ofType: $0) } + } + } + + // 2. In JavaScript, obtain references to the exported Wasm function and memory. + let exports = module.loadExports() + let wasmFunc = b.getProperty("w0", of: exports) + let exportedMem = b.getProperty("wm0", of: exports) + + // 3. Create a ResizableArrayBuffer (RAB) and a random TypedArray view on the Wasm memory. + let rab = b.callMethod("toResizableBuffer", on: exportedMem) + let randomViewConstructor = b.createNamedVariable(forBuiltin: chooseUniform(from: JavaScriptEnvironment.typedArrayConstructors)) + let view = b.construct(randomViewConstructor, withArgs: [rab]) + + b.build(n: 10) + + // 4. Build a loop of mixed Wasm and JS operations. + b.buildRepeatLoop(n: 15) { i in + b.build(n: 5) + + // Call the Wasm function, which may modify the memory. + b.callFunction(wasmFunc, withArgs: b.randomArguments(forCalling: wasmFunc)) + b.build(n: 15) + + // Explicitly grow the Wasm memory from the JavaScript side. + if probability(0.5), let memory = b.randomVariable(ofType: .object(ofGroup: "WasmMemory")) { + b.callMethod("grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...5))], guard: true) + b.build(n: 5) + } + } + }, + + WasmProgramTemplate("WasmMemoryBufferReattachment") { b in + b.buildPrefix() + b.build(n: 15) + + let jsMemory = b.createWasmMemory(minPages: 1, maxPages: 256, isShared: false, isMemory64: probability(0.5)) + + // 1. Setup: Wasm Module with Memory and Grow export + let module = b.buildWasmModule { m in + let mem = m.addMemory(minPages: 1, maxPages: 256, isShared: false, isMemory64: probability(0.5)) + m.addWasmFunction(with: [.wasmi32] => [.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 6a37e6717..9ee6a3375 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1875,6 +1875,32 @@ 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))]) + }, ] fileprivate let wasmArrayTypeGenerator = GeneratorStub( diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 83c2509bb..ede66726a 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -18,6 +18,13 @@ public class JavaScriptEnvironment: ComponentBase { // Possible return values of the 'typeof' operator. 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", "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 diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 56ab52d11..181f128f3 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1904,4 +1904,25 @@ 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) + } } diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 5a9c53b63..938bde343 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3013,6 +3013,33 @@ class ProgramBuilderTests: XCTestCase { } } + func testTypedArrayFromBufferGenerator() { + let fuzzer = makeMockFuzzer() + let numPrograms = 50 + + for _ in 0...numPrograms { + let b = fuzzer.makeBuilder() + b.buildPrefix() + + let generator = fuzzer.codeGenerators.filter { + $0.name == "TypedArrayFromBufferGenerator" + }[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 _ = b.finalize() + + // XCTAssertGreaterThan(numGeneratedInstructions, 0) + // TODO(tacet): Fails in around 5% of times, we should figure out how to fix it. + } + } + func testArrayGetSchedulingTest() { let fuzzer = makeMockFuzzer() let numPrograms = 30 From d334575f8afc42adad7e364b919b42f0dc59a966 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 15 Dec 2025 14:12:25 +0100 Subject: [PATCH 040/234] Increase depth of configured test-transpilation results In the overall results directory tree, certain directories contain large and interesting subtrees (e.g. large directories with low import coverage). This change enables us listing such additional directories to expand their subdirectories in the results mapping. E.g. if now a directory is listed in this config, the directory itself and one level of subdirectories below are now also listed as single result entities. Bug: 442444727 Change-Id: Iba585221622c054985f2307389fccf35d3b10fec Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8845316 Commit-Queue: Michael Achenbach Reviewed-by: Pawel Krawczyk Reviewed-by: Liviu Rau --- Tools/transpile_tests/test_transpile_tests.py | 74 ++++++++++++++++++- Tools/transpile_tests/transpile_tests.py | 36 ++++++++- 2 files changed, 103 insertions(+), 7 deletions(-) diff --git a/Tools/transpile_tests/test_transpile_tests.py b/Tools/transpile_tests/test_transpile_tests.py index 3e6277428..a388763ec 100644 --- a/Tools/transpile_tests/test_transpile_tests.py +++ b/Tools/transpile_tests/test_transpile_tests.py @@ -162,12 +162,12 @@ def test_shard_run(self, fs): class UnitTests(unittest.TestCase): def test_level_key_0(self): - counter = transpile_tests.TestCounter(0, Options(False)) + 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)) + counter = transpile_tests.TestCounter(2, [], Options(False)) self.assertEqual( '', counter.level_key(Path('test.js'))) self.assertEqual( @@ -179,8 +179,69 @@ def test_level_key_2(self): '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)) + counter = transpile_tests.TestCounter(1, [], Options(False)) self.assertEqual({}, counter.results()) counter.count(0, Path('pass1.js'), 'good') @@ -210,7 +271,10 @@ def test_simple_counts(self): counter.results()) def test_complex_count(self): - counter = transpile_tests.TestCounter(2, Options(False)) + # 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') @@ -223,6 +287,7 @@ def test_complex_count(self): 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( { @@ -238,6 +303,7 @@ def test_complex_count(self): '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'}, ]}, diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index 106895e2e..02b913a18 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -71,6 +71,17 @@ def is_supported(self, abspath, relpath): '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, } } @@ -84,6 +95,10 @@ class TestCounter: 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': } @@ -101,8 +116,11 @@ class TestCounter: }, } """ - def __init__(self, levels, options): + 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) @@ -113,13 +131,24 @@ def __init__(self, levels, options): 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[:self.levels] + parts = parts[:max(self.levels, self.largest_expansion_level(relpath))] return '/'.join(parts) def count(self, exit_code, relpath, stdout): @@ -214,7 +243,8 @@ def test_input_gen(): yield (abspath, output_dir / abspath.relative_to(base_dir)) # Iterate over all tests in parallel and collect stats. - counter = TestCounter(test_config['levels'], options) + 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()): From d3450fa8ea46f385e3a547c9db4cfcee72f5b180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Gro=C3=9F?= Date: Mon, 15 Dec 2025 11:30:58 +0100 Subject: [PATCH 041/234] Abort runtime-assisted mutations on FuzzIL translation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, if we caught an error during translation of a RuntimeAssistedMutator's Actions back to FuzzIL instructions, we simply logged an error but otherwise continued the mutation. This, however, can lead to invalid programs as we're essentially deleting the current instruction (which may e.g. have produced an output needed later on). This might then lead to various other crashes later on. Instead, we should simply abort the mutation when we see such an error. Bug: 468928010 Change-Id: Iefd1010d9c7bd72444d5be1258f81b3063f7b39b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8849276 Reviewed-by: Michael Achenbach Commit-Queue: Samuel Groß --- Sources/Fuzzilli/Mutators/FixupMutator.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/Fuzzilli/Mutators/FixupMutator.swift b/Sources/Fuzzilli/Mutators/FixupMutator.swift index 957a59f14..fc9865bed 100644 --- a/Sources/Fuzzilli/Mutators/FixupMutator.swift +++ b/Sources/Fuzzilli/Mutators/FixupMutator.swift @@ -287,9 +287,18 @@ public class FixupMutator: RuntimeAssistedMutator { 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) } 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) { From 1b58e0c3ce5504b755a9b73f72e1fbd4235ed739 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 16 Dec 2025 10:21:10 +0100 Subject: [PATCH 042/234] Unwrap JS parser errors on import for better readability Without this, the wrapped error's text is later shown with encoded linebreaks ("\n"). Bug: 442444727 Change-Id: I2b0aa87d7582d83a8339b105f03ac87df59da873 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8852616 Reviewed-by: Pawel Krawczyk Commit-Queue: Michael Achenbach --- Sources/FuzzILTool/main.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzILTool/main.swift b/Sources/FuzzILTool/main.swift index bff607265..3843dbc1f 100644 --- a/Sources/FuzzILTool/main.swift +++ b/Sources/FuzzILTool/main.swift @@ -173,8 +173,12 @@ else if args.has("--compile") { 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) } From 11e6d6a9a6840337d9cf759dadf10b17cfd89b14 Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Mon, 15 Dec 2025 17:01:43 +0000 Subject: [PATCH 043/234] Shared reference - adjust type system. See https://github.com/WebAssembly/shared-everything-threads/blob/main/proposals/shared-everything-threads/Overview.md. Bug: 448349112 Change-Id: Ifcc6666c0f3c282078954902853dff23b72e43f9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8832117 Reviewed-by: Danylo Mocherniuk Commit-Queue: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 82 +++++---- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 6 +- .../Fuzzilli/CodeGen/ProgramTemplates.swift | 8 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 26 +-- .../Environment/JavaScriptEnvironment.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 39 +++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 13 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 122 +++++++++++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 17 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 23 +-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 87 +++++----- .../Fuzzilli/Mutators/OperationMutator.swift | 32 ++-- .../Profiles/V8CommonProfile.swift | 4 +- Tests/FuzzilliTests/JSTyperTests.swift | 8 +- Tests/FuzzilliTests/LifterTest.swift | 2 +- Tests/FuzzilliTests/LiveTests.swift | 7 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 52 +++--- Tests/FuzzilliTests/TypeSystemTest.swift | 107 ++++++------ Tests/FuzzilliTests/WasmTableTests.swift | 4 +- Tests/FuzzilliTests/WasmTests.swift | 159 ++++++++++-------- 20 files changed, 457 insertions(+), 343 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index c8de47c92..3a5080ca9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1217,7 +1217,6 @@ public class ProgramBuilder { numberOfHiddenVariables -= 1 } - /// Hides a variable containing a function from the function's body. /// /// For example, in @@ -1250,19 +1249,20 @@ public class ProgramBuilder { 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()] } } @@ -1272,6 +1272,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 @@ -1288,12 +1289,12 @@ 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 @@ -3885,8 +3886,9 @@ public class ProgramBuilder { b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) } + // TODO(pawkra): support shared tables and element segments. public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { - let elementSegmentType = ILType.wasmFuncRef + let elementSegmentType = ILType.wasmFuncRef() let tableElemType = b.type(of: table).wasmTableType!.elementType assert(elementSegmentType.Is(tableElemType)) @@ -4023,18 +4025,22 @@ public class ProgramBuilder { 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)}) #if DEBUG var argIndex = signature.parameterTypes.count + let assertLabelTypeData: (ILType) -> () = { labelType in + assert(labelType.Is(.anyLabel)) + 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"))) @@ -4042,8 +4048,7 @@ public class ProgramBuilder { 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)) @@ -4107,7 +4112,7 @@ public class ProgramBuilder { } public func wasmBuildThrowRef(exception: Variable) { - b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef]) + b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef()]) } public func wasmBuildLegacyRethrow(_ exceptionLabel: Variable) { @@ -4148,15 +4153,22 @@ public class ProgramBuilder { // 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) + } else { + return nil } - assert(type.wasmReferenceType!.nullability) - return self.wasmRefNull(type: type) case .Index(_), .none: break // Unimplemented @@ -4355,17 +4367,17 @@ public class ProgramBuilder { @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 } } @@ -4434,13 +4446,14 @@ public class ProgramBuilder { @discardableResult public func addElementSegment(elements: [Variable]) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef), count: elements.count) + 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: + case .wasmFuncRef(): return .wasmFunctionDef() | .function() default: return .object() @@ -4516,6 +4529,7 @@ public class ProgramBuilder { /// Produces a WasmGlobal that is valid to create in the given Context. public func randomWasmGlobal(forContext context: Context) -> 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. @@ -4545,21 +4559,23 @@ public class ProgramBuilder { // 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. + // TODO(pawkra): enable shared types. 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)) @@ -4574,9 +4590,10 @@ public class ProgramBuilder { // 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. + // TODO(pawkra): enable shared types. (0.. [Variable] { @@ -5339,3 +5356,4 @@ public class ProgramBuilder { } } + diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 174e72924..61d9e181e 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -105,7 +105,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmArrayTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmArrayRef) + type.Is(.wasmArrayRef()) } else { false } @@ -113,7 +113,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmStructTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmStructRef) + type.Is(.wasmStructRef()) } else { false } @@ -121,7 +121,7 @@ public class GeneratorStub: Contributor { if type.Is(.wasmTypeDef()) { type.wasmTypeDefinition?.description is WasmSignatureTypeDescription } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmFuncRef) + type.Is(.wasmFuncRef()) } else { false } diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 4f859ba4d..3c257d5f2 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -99,7 +99,7 @@ public let ProgramTemplates = [ 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) let wrapped = b.wrapSuspending(function: f!) @@ -152,7 +152,7 @@ public let ProgramTemplates = [ let tagToThrow = chooseUniform(from: wasmTags) let throwParamTypes = b.type(of: tagToThrow).wasmTagType!.parameters let tagToCatchForRethrow = chooseUniform(from: tags) - let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef] + let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef()] let module = b.buildWasmModule { wasmModule in // Wasm function that throws a tag, catches a tag (the same or a different one) to @@ -173,7 +173,7 @@ public let ProgramTemplates = [ return catchBlockOutputTypes.map(function.findOrGenerateWasmVar) } b.build(n: 10) - function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef)!) + function.wasmBuildThrowRef(exception: b.randomVariable(ofType: .wasmExnRef())!) return [] } } @@ -206,7 +206,7 @@ public let ProgramTemplates = [ return calleeSig.outputTypes.map(function.findOrGenerateWasmVar) }} - let table = wasmModule.addTable(elementType: .wasmFuncRef, + let table = wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, definedEntries: callees.enumerated().map { (index, callee) in .init(indexInTable: index, signature: calleeSig) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 9ee6a3375..9de2cbfaa 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -270,6 +270,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ value: newValue) }, + // TODO(pawkra): add shared variant. CodeGenerator("WasmRefNullGenerator", inContext: .single(.wasmFunction)) { b in let function = b.currentWasmModule.currentWasmFunction if let typeDef = (b.findVariable { b.type(of: $0).Is(.wasmTypeDef()) }), @@ -280,7 +281,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmRefNull( type: .wasmRef( .Abstract( - chooseUniform(from: WasmAbstractHeapType.allCases)), + HeapTypeInfo(chooseUniform(from: WasmAbstractHeapType.allCases), shared: false)), nullability: true)) } }, @@ -296,15 +297,18 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmRefI31(value) }, - CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref)) { b, ref in + // TODO(pawkra): add shared variant. + CodeGenerator("WasmI31GetGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmI31Ref())) { b, ref in b.currentWasmModule.currentWasmFunction.wasmI31Get(ref, isSigned: Bool.random()) }, - CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef)) { b, ref in + // TODO(pawkra): add shared variant. + CodeGenerator("WasmAnyConvertExternGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExternRef())) { b, ref in b.currentWasmModule.currentWasmFunction.wasmAnyConvertExtern(ref) }, - CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef)) { b, ref in + // TODO(pawkra): add shared variant. + CodeGenerator("WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmAnyRef())) { b, ref in b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) }, @@ -596,7 +600,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] = [] @@ -609,7 +613,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. @@ -638,7 +642,7 @@ 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 } @@ -669,7 +673,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 } @@ -729,7 +733,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 { @@ -1551,7 +1555,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmThrowRefGenerator", inContext: .single(.wasmFunction), - inputs: .required(.wasmExnRef) + inputs: .required(.wasmExnRef()) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction function.wasmBuildThrowRef(exception: exception) @@ -1647,7 +1651,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ [] } if withExnRef { - outputTypes.append(.wasmExnRef) + outputTypes.append(.wasmExnRef()) } function.wasmBeginBlock(with: [] => outputTypes, args: []) return outputTypes diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index ede66726a..03c0014ba 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -2282,7 +2282,7 @@ public extension 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, diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 86f98e4a7..9b3faab7d 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -388,8 +388,8 @@ extension Instruction: ProtobufConvertible { $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } } - case .Abstract(let heapType): - let kind = switch heapType { + case .Abstract(let heapTypeInfo): + let kind = switch heapTypeInfo.heapType { case .WasmExn: Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref case .WasmI31: @@ -1683,37 +1683,40 @@ extension Instruction: ProtobufConvertible { fatalError("Unrecognized wasm value type \(value)") } case .refType(_): - let refKind: WasmReferenceType.Kind = switch wasmType.refType.kind { - case .index: - .Index() + if wasmType.refType.kind == .index { + return .wasmRef(.Index(), nullability: wasmType.refType.nullability) + } + let heapType: WasmAbstractHeapType = switch wasmType.refType.kind { case .externref: - .Abstract(.WasmExtern) + .WasmExtern case .funcref: - .Abstract(.WasmFunc) + .WasmFunc case .exnref: - .Abstract(.WasmExn) + .WasmExn case .i31Ref: - .Abstract(.WasmI31) + .WasmI31 case .anyref: - .Abstract(.WasmAny) + .WasmAny case .eqref: - .Abstract(.WasmEq) + .WasmEq case .structref: - .Abstract(.WasmStruct) + .WasmStruct case .arrayref: - .Abstract(.WasmArray) + .WasmArray case .noneref: - .Abstract(.WasmNone) + .WasmNone case .noexternref: - .Abstract(.WasmNoExtern) + .WasmNoExtern case .nofuncref: - .Abstract(.WasmNoFunc) + .WasmNoFunc case .noexnref: - .Abstract(.WasmNoExn) + .WasmNoExn + case .index: + fatalError("Unexpected index type.") case .UNRECOGNIZED(let value): fatalError("Unrecognized wasm reference type \(value)") } - return .wasmRef(refKind, nullability: wasmType.refType.nullability) + return .wasmRef(heapType, nullability: wasmType.refType.nullability) case .none: fatalError("Absent wasm type") } diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index ae3e96826..1d2cbeec4 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -907,17 +907,20 @@ public struct JSTyper: Analyzer { case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) case .wasmRefI31(_): - setType(of: instr.output, to: .wasmRefI31) + // TODO(pawkra): support shared variant. + setType(of: instr.output, to: .wasmRefI31()) case .wasmI31Get(_): setType(of: instr.output, to: .wasmi32) 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) @@ -1854,7 +1857,7 @@ public struct JSTyper: Analyzer { 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))) diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index a0aa62eed..b463f8432 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -247,23 +247,33 @@ 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 @@ -275,6 +285,10 @@ public struct ILType: Hashable { 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, @@ -286,7 +300,7 @@ 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 @@ -1098,8 +1112,9 @@ extension ILType: CustomStringConvertible { } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapType): - return ".wasmRef(.Abstract(\(nullPrefix)\(heapType)))" + 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)))" @@ -1400,9 +1415,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 @@ -1484,8 +1498,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 @@ -1499,6 +1513,57 @@ 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. @@ -1523,7 +1588,7 @@ 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 { @@ -2077,10 +2142,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 } @@ -2110,7 +2175,8 @@ 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 { @@ -2131,7 +2197,8 @@ 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 { @@ -2162,7 +2229,8 @@ 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/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 307ff0346..e5e519fc8 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -695,6 +695,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 @@ -716,11 +717,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 @@ -729,7 +730,7 @@ public enum WasmGlobal { } } - func typeString() -> String { +func typeString() -> String { switch self { case .wasmi64(_): return "i64" @@ -750,8 +751,9 @@ public enum WasmGlobal { } } + // Returns a JS string representing the initial value. - func valueToString() -> String { +func valueToString() -> String { switch self { case .wasmi64(let val): return "\(val)n" @@ -801,9 +803,10 @@ final class WasmDefineTable: WasmOperation { 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, + super.init(numInputs: isWasmFuncRef ? definedEntries.count : 0, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasm]) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index fd96d0caf..040a3dc9d 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1589,11 +1589,12 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let type: String switch op.tableType.elementType { - case .wasmExternRef: + case .wasmExternRef(): type = "externref" - case .wasmFuncRef: + case .wasmFuncRef(): type = "anyfunc" // TODO(mliedtke): add tables for i31ref. + // TODO(pawkra): add shared ref variants. default: fatalError("Unknown table type") } @@ -1628,21 +1629,21 @@ public class JavaScriptLifter: Lifter { return "\"i64\"" case .wasmSimd128: return "\"v128\"" - case .wasmExternRef: - return "\"externref\"" - case .wasmFuncRef: + case ILType.wasmExternRef(): + return "\"externref\"" + case ILType.wasmFuncRef(): return "\"anyfunc\"" - case .wasmAnyRef: + case ILType.wasmAnyRef(): return "\"anyref\"" - case .wasmEqRef: + case ILType.wasmEqRef(): return "\"eqref\"" - case .wasmI31Ref: + case ILType.wasmI31Ref(): return "\"i31ref\"" - case .wasmStructRef: + case ILType.wasmStructRef(): return "\"structref\"" - case .wasmArrayRef: + case ILType.wasmArrayRef(): return "\"arrayref\"" - case .wasmExnRef: + case ILType.wasmExnRef(): return "\"exnref\"" default: diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index bcfb03a07..a13968ef1 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -527,33 +527,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 { @@ -568,28 +561,27 @@ 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) } - // HINT: If you crash here, you might not have specified an encoding for your new type in `ILTypeMapping`. - return ILTypeMapping[type] ?? ILTypeMapping[defaultType!]! + fatalError("This function supports only wasmReferenceType.") } private func buildTypeEntry(for desc: WasmTypeDescription, data: inout Data) throws { @@ -663,7 +655,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()) } } @@ -1077,13 +1069,13 @@ 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(_): @@ -1505,7 +1497,8 @@ 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. diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 94e7e297c..4f8b7b843 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -369,23 +369,21 @@ public class OperationMutator: BaseInstructionMutator { case .wasmDefineGlobal(let op): // We never change the type of the global, only the value as changing the type will break the following code pretty much instantly. - let wasmGlobal: WasmGlobal - switch op.wasmGlobal.toType() { - case .wasmf32: - wasmGlobal = .wasmf32(Float32(b.randomFloat())) - case .wasmf64: - wasmGlobal = .wasmf64(b.randomFloat()) - case .wasmi32: - wasmGlobal = .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) - case .wasmi64: - wasmGlobal = .wasmi64(b.randomInt()) - case .wasmExternRef, - .wasmExnRef, - .wasmI31Ref: - wasmGlobal = op.wasmGlobal - default: - fatalError("unexpected/unimplemented Value Type!") - } + let wasmGlobal:WasmGlobal = + switch op.wasmGlobal.toType() { + case .wasmf32: + .wasmf32(Float32(b.randomFloat())) + case .wasmf64: + .wasmf64(b.randomFloat()) + case .wasmi32: + .wasmi32(Int32(truncatingIfNeeded: b.randomInt())) + case .wasmi64: + .wasmi64(b.randomInt()) + case ILType.wasmExternRef(), ILType.wasmExnRef(), ILType.wasmI31Ref(): + op.wasmGlobal + default: + fatalError("unexpected/unimplemented Value Type!") + } newOp = WasmDefineGlobal(wasmGlobal: wasmGlobal, isMutable: probability(0.5)) case .wasmDefineTable(let op): // TODO: change table size? diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index d53a07dac..620302af2 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -561,7 +561,7 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in } let table = wasmModule.addTable( - elementType: .wasmFuncRef, + elementType: .wasmFuncRef(), minSize: numCallees, definedEntries: (0.. 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 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) diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 181f128f3..b5ebb6779 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1534,7 +1534,7 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - let wasmSignature = [] => [.wasmExternRef] + let wasmSignature = [] => [.wasmExternRef()] let typeDesc = b.type(of: typeGroup[0]).wasmTypeDefinition!.description! @@ -1574,7 +1574,7 @@ 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)] } @@ -1585,7 +1585,7 @@ class JSTyperTests: XCTestCase { // 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)!] } @@ -1795,7 +1795,7 @@ class JSTyperTests: XCTestCase { let wasmTableConstructor = b.getProperty("Table", of: wasm) 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) diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 258ed4a02..2744756fb 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3271,7 +3271,7 @@ class LifterTests: XCTestCase { 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 diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 4ffb8c5d9..8a6dce290 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -133,15 +133,16 @@ 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: + case ILType.wasmFuncRef(): return jsFunction - case .wasmNullExternRef, .wasmNullFuncRef, .wasmNullRef: + case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): return b.loadNull() - case .wasmExternRef, .wasmAnyRef: + case ILType.wasmExternRef(), ILType.wasmAnyRef(): return b.createObject(with: [:]) default: return b.loadInt(321) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 938bde343..97d2c1788 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2863,21 +2863,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) @@ -2887,14 +2887,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) @@ -2903,25 +2903,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 [] } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 5e6f0fd77..677032925 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -1110,11 +1110,12 @@ class TypeSystemTests: XCTestCase { 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 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))") + // 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])") @@ -1148,11 +1149,11 @@ class TypeSystemTests: XCTestCase { ".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))]])") + "[.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 +1164,7 @@ 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) @@ -1209,14 +1210,16 @@ class TypeSystemTests: XCTestCase { // 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) + } } } @@ -1276,7 +1279,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 +1289,47 @@ 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() { @@ -1433,15 +1447,10 @@ class TypeSystemTests: XCTestCase { .wasmf32, .wasmi64, .wasmf64, - .wasmFuncRef, - .wasmExternRef, - .wasmExnRef, - .wasmI31Ref, - .wasmRefI31, .wasmFunctionDef([.wasmi32] => [.wasmi64]), .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef] => [.wasmExternRef]), + .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), .wasmMemory(limits: Limits(min: 10)), .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + ] + ILType.allNullableAbstractWasmRefTypes() } diff --git a/Tests/FuzzilliTests/WasmTableTests.swift b/Tests/FuzzilliTests/WasmTableTests.swift index c3e59c9b7..2e4f9335f 100644 --- a/Tests/FuzzilliTests/WasmTableTests.swift +++ b/Tests/FuzzilliTests/WasmTableTests.swift @@ -22,7 +22,7 @@ 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 +31,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 987599fb4..5fad1a6d9 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -44,16 +44,16 @@ func testForErrorOutput(program: String, runner: JavaScriptExecutor, errorMessag 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, .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) } @@ -452,7 +452,7 @@ 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) @@ -461,12 +461,12 @@ class WasmFoundationTests: XCTestCase { // Throw an exception, catch it and store it in the global. wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef], args: []) { catchLabel, _ in + 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 [] @@ -474,12 +474,12 @@ 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 + 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]] } @@ -510,12 +510,12 @@ 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 + 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]] } @@ -539,13 +539,13 @@ 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 [] } @@ -578,8 +578,9 @@ 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). @@ -604,13 +605,13 @@ 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 [] } @@ -642,8 +643,9 @@ 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). @@ -667,8 +669,8 @@ 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)]) @@ -676,9 +678,9 @@ class WasmFoundationTests: XCTestCase { 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) @@ -728,7 +730,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in [function.wasmi32BinOp(params[0], function.consti32(1), binOpKind: .Add)] } - wasmModule.addTable(elementType: .wasmFuncRef, + wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, definedEntries: [.init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), .init(indexInTable: 1, signature: [] => [.wasmi64])], definedEntryValues: [wasmFunction, jsFunction], @@ -746,7 +748,7 @@ class WasmFoundationTests: XCTestCase { 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: [ + 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]) @@ -794,7 +796,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef, + 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], @@ -844,7 +846,7 @@ class WasmFoundationTests: XCTestCase { 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])], definedEntryValues: [wasmFunction, jsFunction], @@ -852,7 +854,7 @@ class WasmFoundationTests: XCTestCase { } let table = b.getProperty("wt0", of: module.loadExports()) - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef, limits: Limits(min: 10), isTable64: false, knownEntries: [ + 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]) ])) @@ -867,7 +869,7 @@ class WasmFoundationTests: XCTestCase { 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])] } @@ -882,7 +884,7 @@ 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: [ + 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]) @@ -998,7 +1000,7 @@ class WasmFoundationTests: XCTestCase { let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef, + 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], @@ -3764,8 +3766,8 @@ 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.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.WasmBuildThrow(tag: tagVoid, inputs: []) @@ -3774,10 +3776,10 @@ class WasmFoundationTests: XCTestCase { } 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)] } @@ -3867,10 +3869,8 @@ class WasmFoundationTests: XCTestCase { 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() let jsProg = fuzzer.lifter.lift(prog, withOptions: [.includeComments]) @@ -3896,12 +3896,12 @@ class WasmFoundationTests: XCTestCase { 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 + 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] => []) @@ -3974,7 +3974,7 @@ class WasmFoundationTests: XCTestCase { 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])] } } @@ -4150,13 +4150,13 @@ class WasmFoundationTests: XCTestCase { 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, + // 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: [], @@ -4198,12 +4198,13 @@ class WasmFoundationTests: XCTestCase { 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]) }, definedEntryValues: [f3, f3, f1, f2], @@ -4470,8 +4471,9 @@ class WasmGCTests: XCTestCase { 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. @@ -4766,15 +4768,18 @@ 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-exnref", "--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 @@ -4790,8 +4795,8 @@ 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 + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmI31Ref()]) { function, label, args in [function.wasmRefI31(args[0])] } - wasmModule.addWasmFunction(with: [.wasmI31Ref] => [.wasmi32, .wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmI31Ref()] => [.wasmi32, .wasmi32]) { function, label, args in [function.wasmI31Get(args[0], isSigned: true), function.wasmI31Get(args[0], isSigned: false)] } @@ -4845,29 +4858,29 @@ 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] } } @@ -6418,8 +6431,8 @@ 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])!] } } From 125ad0c7bbc47138a28b27e35cebc42bed320116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Gro=C3=9F?= Date: Wed, 17 Dec 2025 15:34:07 +0100 Subject: [PATCH 044/234] Add testcases for recently added SIGILL-related crashers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See crrev.com/c/7269586 for context. Here we add the fuzzilli-side testcases for the new crash types and also extend the ASAN_OPTIONS with `handle_sigill=1` so we get ASAN splats for non-ud2 SIGILL crashes. Bug: 42202821 Change-Id: I08d7d42e8ef9869cd1a228ce15654b23c956ded3 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8857196 Reviewed-by: Michael Achenbach Commit-Queue: Samuel Groß --- Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 1df53793d..dce89be75 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -102,9 +102,10 @@ let v8SandboxProfile = Profile( // ASan options. // - abort_on_error=true: We need asan to exit in a way that's detectable for Fuzzilli as a crash + // - handle_sigill=true: It seems by default ASAN doesn't handle SIGILL, but we want that to have stack traces // - symbolize=false: Symbolization can tak a _very_ long time (> 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"], + 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, @@ -503,6 +504,8 @@ let v8SandboxProfile = Profile( ("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. @@ -511,6 +514,8 @@ let v8SandboxProfile = Profile( ("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: [ From 676f94c36f076f6ec58e5ebe998ea9829fd38af5 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 18 Dec 2025 11:46:04 +0100 Subject: [PATCH 045/234] Add a test with semi-conditional returns in inlined function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 468928010 Change-Id: I00d34c83bf727b1efece464787910ecfdc3a61fe Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8861036 Commit-Queue: Michael Achenbach Reviewed-by: Samuel Groß --- Tests/FuzzilliTests/MinimizerTest.swift | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 8d9a29664..cae11e8de 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -651,6 +651,79 @@ 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(r, to: a2) + }) + b.reassign(r, to: 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) + } + func testMultiInlining() { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) From a776a26b5b5d3f8b653cde0adbc951d6d35319c7 Mon Sep 17 00:00:00 2001 From: Pawel Krawczyk Date: Thu, 18 Dec 2025 12:53:46 +0000 Subject: [PATCH 046/234] Shared references - wasmRefI31 Bug: 448349112 Change-Id: Icef73c9f72668e31b48d6c71699b0392f20a5fb2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8832118 Auto-Submit: Pawel Krawczyk Reviewed-by: Danylo Mocherniuk Commit-Queue: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 3 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 +++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 +-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 4 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 ++++++-- Sources/Fuzzilli/Protobuf/operations.proto | 1 + Tests/FuzzilliTests/ProgramBuilderTest.swift | 1 + Tests/FuzzilliTests/WasmTests.swift | 43 ++++++++++++++++++- 10 files changed, 77 insertions(+), 17 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 3a5080ca9..5957975e2 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4361,8 +4361,8 @@ public class ProgramBuilder { } @discardableResult - public func wasmRefI31(_ number: Variable) -> Variable { - return b.emit(WasmRefI31(), withInputs: [number], types: [.wasmi32]).output + public func wasmRefI31(_ number: Variable, shared: Bool = false) -> Variable { + return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]).output } @discardableResult diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 9de2cbfaa..130545440 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -293,8 +293,9 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmRefIsNull(ref) }, + // TODO(pawkra): add shared variant. CodeGenerator("WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32)) { b, value in - b.currentWasmModule.currentWasmFunction.wasmRefI31(value) + b.currentWasmModule.currentWasmFunction.wasmRefI31(value, shared: false) }, // TODO(pawkra): add shared variant. diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 9b3faab7d..cc52480ec 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1617,8 +1617,10 @@ extension Instruction: ProtobufConvertible { } case .wasmRefIsNull(_): $0.wasmRefIsNull = Fuzzilli_Protobuf_WasmRefIsNull() - case .wasmRefI31(_): - $0.wasmRefI31 = Fuzzilli_Protobuf_WasmRefI31() + 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 @@ -2601,8 +2603,8 @@ extension Instruction: ProtobufConvertible { op = p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) case .wasmRefIsNull(_): op = WasmRefIsNull() - case .wasmRefI31(_): - op = WasmRefI31() + case .wasmRefI31(let p): + op = WasmRefI31(isShared: p.isShared) case .wasmI31Get(let p): op = WasmI31Get(isSigned: p.isSigned) case .wasmAtomicLoad(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 1d2cbeec4..29e75d80e 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -906,9 +906,8 @@ public struct JSTyper: Analyzer { } case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) - case .wasmRefI31(_): - // TODO(pawkra): support shared variant. - setType(of: instr.output, to: .wasmRefI31()) + case .wasmRefI31(let op): + setType(of: instr.output, to: .wasmRefI31(shared: op.isShared)) case .wasmI31Get(_): setType(of: instr.output, to: .wasmi32) case .wasmAnyConvertExtern(_): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index e5e519fc8..508922c58 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2276,8 +2276,10 @@ class WasmRefIsNull: WasmOperation { 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]) } } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index a13968ef1..56eaddcfe 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -2181,8 +2181,8 @@ 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 .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]) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 883ab8d90..4cbf6f735 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5923,6 +5923,8 @@ public struct Fuzzilli_Protobuf_WasmRefI31: Sendable { // `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() {} @@ -15427,18 +15429,29 @@ 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" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}isShared\0") public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + 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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index d26a6d56b..247ba5c8e 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1563,6 +1563,7 @@ message WasmRefIsNull { } message WasmRefI31 { + bool isShared = 1; } message WasmI31Get { diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 97d2c1788..52f339565 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2828,6 +2828,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) diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 5fad1a6d9..c219e6175 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4817,7 +4817,7 @@ class WasmGCTests: XCTestCase { try refNullAbstractTypes(sharedRef: false) } - func testi31Ref() throws { + func testi31RefFromJs() 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()) @@ -4851,6 +4851,47 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } + func i31Ref(shared: Bool) throws { + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: shared ? ["--experimental-wasm-shared", "--experimental-wasm-stringref"] : []) + let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) + let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) + let b: ProgramBuilder = fuzzer.makeBuilder() + let i31RefType = ILType.wasmI31Ref(shared: shared) + + let module = b.buildWasmModule { wasmModule in + let createReferenceOf = wasmModule.addWasmFunction(with: [.wasmi32] => [i31RefType]) { function, label, args in + [function.wasmRefI31(args[0], shared: shared)] + } + let dereference = wasmModule.addWasmFunction(with: [i31RefType] => [.wasmi32, .wasmi32]) { function, label, args in + [function.wasmI31Get(args[0], isSigned: true), + function.wasmI31Get(args[0], isSigned: false)] + } + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, args in + let const = function.consti32(-42) + let constRef = function.wasmCallDirect(signature: [.wasmi32] => [i31RefType], function: createReferenceOf, functionArgs: [const]) + let dereferencedConst = function.wasmCallDirect(signature: [i31RefType] => [.wasmi32, .wasmi32], function: dereference, functionArgs: constRef) + return dereferencedConst + } + } + + let exports = module.loadExports() + let outputFunc = b.createNamedVariable(forBuiltin: "output") + let result = b.callMethod(module.getExportedMethod(at: 2), 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: "-42,2147483606\n") + } + + func testi31RefShared() throws { + try i31Ref(shared: true) + } + + func testi31RefUnshared() throws { + try i31Ref(shared: false) + } + func testExternAnyConversions() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) From 34c9d61e9bd98dc3b19082e98ae3f24e01e45308 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Wed, 17 Dec 2025 16:39:43 +0100 Subject: [PATCH 047/234] Escape double quotes when lifting string literals to JS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Though Fuzzilli has no way to introduce a double quote character into a string, it can get them when tests are imported from JS. We assume the string representations in FuzzIL are raw (i.e. not escaped) and now escape the double quote character when lifting to JS. Bug: 469712158 Change-Id: I33e843b39959538fc5a1f0aacaae522af63ec1c0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8857197 Reviewed-by: Samuel Groß Reviewed-by: Pawel Krawczyk Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Lifting/JavaScriptLifter.swift | 3 ++- Tests/FuzzilliTests/LifterTest.swift | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 040a3dc9d..d299c10f2 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -302,7 +302,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() diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 2744756fb..0af2c8a0e 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3635,4 +3635,21 @@ class LifterTests: XCTestCase { """ 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) + } } From beddc758c4fcc37d363afbac3c76680983e74959 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 30 Dec 2025 14:54:55 +0100 Subject: [PATCH 048/234] Add assertion to detect inconsistent code generators This guards an optional unwrapping that frequently fails in production with an assertion with more debug output. Bug: 470273473 Change-Id: I17cbc86c698ff629708d9fd893e2bec80a79b6d8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8888616 Commit-Queue: Michael Achenbach Reviewed-by: Danylo Mocherniuk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 5957975e2..627f5bcb6 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -841,11 +841,11 @@ public class ProgramBuilder { 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)! + let variable = self.randomVariable(ofTypeOrSubtype: type) + assert(variable != nil, + "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. From 51dcc33c0a8be424c3fe0a7f232233ddc6c1616b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 5 Jan 2026 08:41:33 +0100 Subject: [PATCH 049/234] Convert assertion to fatalError to catch issues with generators This is a follow-up to commit beddc758c4fcc37d363afbac3c76680983e74959 Bug: 470273473 Change-Id: Ia3bc85a8632efe75a009f5c11ec47b3611f42998 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8901816 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 10 +++++----- Sources/Fuzzilli/Protobuf/gen_programproto.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 627f5bcb6..959f91aa8 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -841,11 +841,11 @@ public class ProgramBuilder { if generators.count > 0 { let generator = generators.randomElement() let _ = self.complete(generator: generator, withBudget: 10) - let variable = self.randomVariable(ofTypeOrSubtype: type) - assert(variable != nil, - "The generator \(generator.name) is supposed to generate type \(type). " + - "Either the generator or its annotation is wrong.") - return variable! + 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. diff --git a/Sources/Fuzzilli/Protobuf/gen_programproto.py b/Sources/Fuzzilli/Protobuf/gen_programproto.py index 0018ac2a6..7447d6caf 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"); From b71ac3d72cac9ad7b9f152034f98c5f6d4c97ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hendrik=20W=C3=BCthrich?= Date: Thu, 8 Jan 2026 01:47:05 -0800 Subject: [PATCH 050/234] Revert "Add ManyArgumentsCall CodeGenerator" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 36d62582f60991d3194bd2e820440d503a7f3d07. Reason for revert: The code we want to target is unreachable due to hitting syntax errors from the parser before we could ever compile and bailout. Original change's description: > Add ManyArgumentsCall CodeGenerator > > Calling apply() with an array like this generator does will create a > function call with as many arguments as the size of the array. > It is meant to cover the discrepencies in max argument counts between > turboshaft and maglev. > > Bug: b/455503442 > Change-Id: Ia605368687970369e168796273486d75de4cc811 > Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8839116 > Reviewed-by: Matthias Liedtke > Commit-Queue: Hendrik Wüthrich Bug: b/455503442 Change-Id: Ie18ec8668485fe8518b14a7d95ba6dea74886364 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8910656 Reviewed-by: Matthias Liedtke Commit-Queue: Hendrik Wüthrich --- .../CodeGen/CodeGeneratorWeights.swift | 1 - Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 19 ------------------- 2 files changed, 20 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 18a364cd4..9da0a7720 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -129,7 +129,6 @@ public let codeGeneratorWeights = [ "ComputedPropertyConfigurationGenerator": 10, "FunctionCallGenerator": 30, "FunctionCallWithSpreadGenerator": 3, - "ManyArgumentsCall": 3, "ConstructorCallGenerator": 20, "ConstructorCallWithSpreadGenerator": 3, "MethodCallGenerator": 30, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 40d6f737f..6b387d0ab 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1879,25 +1879,6 @@ public let CodeGenerators: [CodeGenerator] = [ f, withArgs: arguments, spreading: spreads, guard: needGuard) }, - - CodeGenerator("ManyArgumentsCall", inputs: .preferred(.function())) { b, f in - // These sizes are around the max arguments for maglev (2^16 - 10) - // and turboshaft (2^16). - let sizes: [Int64] = [65524, 65525, 65526, 65534, 65535, 65536] - let size = b.loadInt(chooseUniform(from: sizes)) - let constructor = b.createNamedVariable(forBuiltin: "Array") - let largeArray = b.construct(constructor, withArgs: [size]) - - let needGuard = b.type(of: f).MayNotBe(.function()) - - if probability(0.5) { - let receiver = probability(0.5) ? b.loadNull() : b.randomVariable(forUseAs: .object()) - b.callMethod("apply", on: f, withArgs: [receiver, largeArray], guard: needGuard) - } else { - b.callFunction(f, withArgs: [largeArray], spreading: [true], guard: needGuard) - } - }, - CodeGenerator( "ConstructorCallWithSpreadGenerator", inputs: .preferred(.constructor()) ) { b, c in From c97d5f61685f0719bea5990365309847c0e73c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= Date: Mon, 5 Jan 2026 11:36:37 +0100 Subject: [PATCH 051/234] Enable experimental features in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6d1d5fad1fee59368e3b277e43db96f56e8ff903 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8902196 Commit-Queue: Olivier Flückiger Reviewed-by: Matthias Liedtke --- Tests/FuzzilliTests/EnvironmentTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index d8dbcf271..736164e73 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -25,7 +25,7 @@ class EnvironmentTests: XCTestCase { /// Test all the builtin objects that are reachable from the global this. /// (This does not include anything that needs a constructor to be called.) func testJSEnvironmentLive() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--experimental-wasm-rab-integration", "--wasm-test-streaming"]) + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--experimental-wasm-rab-integration", "--wasm-test-streaming", "--js-staging"]) let jsProg = buildAndLiftProgram(withLiftingOptions: [.includeComments]) { b in let jsEnvironment = b.fuzzer.environment var seenTypeGroups = Set() From 972d56028be3bd5623b6ed51d7a3967a28293802 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 8 Jan 2026 13:45:53 +0100 Subject: [PATCH 052/234] Fix inlining of functions also used as disposable variables. Inlining can crash if a function is also used as a disposable variable in some other function. This also adds a minimizer test that demonstrates the crash in patchset 10. Bug: 468928010 Change-Id: Ic9554163e536b0cfb909783ec401062014270cf8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8861857 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- .../Minimization/InliningReducer.swift | 8 +++- Tests/FuzzilliTests/MinimizerTest.swift | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index be6bed5d6..c9555538d 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -118,10 +118,14 @@ struct InliningReducer: Reducer { // Can't inline functions that are passed as arguments to other functions. deleteCandidates(instr.inputs.dropFirst()) + case .loadDisposableVariable: + // 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) } diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index cae11e8de..497508250 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -724,6 +724,51 @@ class MinimizerTests: XCTestCase { 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) From 948e9fdcbe3dfe156f07641d2aeac819cc8b8811 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Thu, 8 Jan 2026 14:47:28 +0000 Subject: [PATCH 053/234] [bugfix] Remove incorrect produced type from the list We cannot guarantee that `.integer` is produced because the `.length` property could be overwritten, and nothing else produces integers. We don't want `produces: [.jsAnything]` as it doesn't have value. Bug: 470273473 Change-Id: Ib3c78e05ea2845ed3e7966b1e10aaa51f3a0e5b5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8911216 Reviewed-by: Matthias Liedtke Auto-Submit: Dominik Klemba Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 6b387d0ab..9d814ac62 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -301,8 +301,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("TypedArrayLastIndexGenerator", inContext: .single(.javascript), - inputs: .required(.object(withProperties: ["buffer", "length"])), - produces: [.integer, .jsAnything] + inputs: .required(.object(withProperties: ["buffer", "length"])) ) { b, view in let len = b.getProperty("length", of: view) let index = b.binary(len, b.loadInt(1), with: .Sub) From d37a8ed52d349593d065c814415e866673a6e9e5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 26 Dec 2025 11:05:41 -0800 Subject: [PATCH 054/234] [intl] Add fuzz support for Intl.Locale This fills in some support for Intl.Locale. There's still work to be done, but this covers most of the API. Bug: 450083673 Change-Id: I7b2f899b7d2a8ff44a10a7ecea5f8a906a6a6964 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8881013 Reviewed-by: Matthias Liedtke Commit-Queue: Manish Goregaokar --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 66 +++++++++++++ Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 2 +- .../Environment/JavaScriptEnvironment.swift | 93 +++++++++++++++++-- 3 files changed, 153 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 959f91aa8..fae586123 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -5286,12 +5286,24 @@ 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"] + // 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" @discardableResult static func constructIntlUnit() -> String { @@ -5304,6 +5316,60 @@ 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 String((0..<2).map { _ in allAlpha.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") diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 9d814ac62..07943c72a 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -309,7 +309,7 @@ public let CodeGenerators: [CodeGenerator] = [ }, CodeGenerator("BuiltinIntlGenerator") { b in - let _ = chooseUniform(from: [b.constructIntlDateTimeFormat, b.constructIntlCollator, b.constructIntlListFormat, b.constructIntlNumberFormat, b.constructIntlPluralRules, b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter])() + let _ = chooseUniform(from: [b.constructIntlDateTimeFormat, b.constructIntlCollator, b.constructIntlListFormat, b.constructIntlLocale, b.constructIntlNumberFormat, b.constructIntlPluralRules, b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter])() }, CodeGenerator("HexGenerator") { b in diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 03c0014ba..562009562 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -433,6 +433,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsIntlListFormat) registerObjectGroup(.jsIntlListFormatConstructor) registerObjectGroup(.jsIntlListFormatPrototype) + registerObjectGroup(.jsIntlLocale) + registerObjectGroup(.jsIntlLocaleConstructor) + registerObjectGroup(.jsIntlLocalePrototype) registerObjectGroup(.jsIntlNumberFormat) registerObjectGroup(.jsIntlNumberFormatConstructor) registerObjectGroup(.jsIntlNumberFormatPrototype) @@ -476,6 +479,7 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlFullLongMediumShort) registerEnumeration(OptionsBag.jsIntlCollatorUsageEnum) registerEnumeration(OptionsBag.jsIntlCollationEnum) + registerEnumeration(OptionsBag.jsIntlCollationTypeEnum) registerEnumeration(OptionsBag.jsIntlCaseFirstEnum) registerEnumeration(OptionsBag.jsIntlCollatorSensitivityEnum) registerEnumeration(OptionsBag.jsIntlListFormatTypeEnum) @@ -511,6 +515,7 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsIntlDateTimeFormatSettings) registerOptionsBag(.jsIntlCollatorSettings) registerOptionsBag(.jsIntlListFormatSettings) + registerOptionsBag(.jsIntlLocaleSettings) registerOptionsBag(.jsIntlNumberFormatSettings) registerOptionsBag(.jsIntlPluralRulesSettings) registerOptionsBag(.jsIntlRelativeTimeFormatSettings) @@ -536,8 +541,12 @@ public class JavaScriptEnvironment: ComponentBase { return ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: true) } }) - addNamedStringGenerator(forType: .jsIntlLocaleLike, with: { ProgramBuilder.constructIntlLocaleString() }) - addNamedStringGenerator(forType: .jsIntlUnit, with: { ProgramBuilder.constructIntlUnit() }) + 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, @@ -3012,7 +3021,10 @@ 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 jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "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"]) @@ -3037,8 +3049,14 @@ extension ILType { 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 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 { @@ -3051,6 +3069,7 @@ extension ObjectGroup { "Collator" : .jsIntlCollatorConstructor, "DateTimeFormat" : .jsIntlDateTimeFormatConstructor, "ListFormat" : .jsIntlListFormatConstructor, + "Locale" : .jsIntlLocaleConstructor, "NumberFormat" : .jsIntlNumberFormatConstructor, "PluralRules" : .jsIntlPluralRulesConstructor, "RelativeTimeFormat" : .jsIntlRelativeTimeFormatConstructor, @@ -3157,6 +3176,48 @@ extension ObjectGroup { ] ) + 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) + + 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 { @@ -3301,6 +3362,7 @@ extension OptionsBag { 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 jsIntlListFormatTypeEnum = ILType.enumeration(ofName: "IntlListFormatTypeEnum", withValues: ["conjunction", "disjunction", "unit"]) @@ -3319,7 +3381,7 @@ extension OptionsBag { // 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, @@ -3371,6 +3433,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", @@ -3383,7 +3462,7 @@ extension OptionsBag { "currency": jsIntlCurrencySystemEnum, "currencyDisplay": jsIntlCurrencyDisplayEnum, "currencySign": jsIntlCurrencySignEnum, - "unit": .jsIntlUnit, + "unit": .jsIntlUnitString, "unitDisplay": jsIntlLongShortNarrowEnum, // digit options "minimumIntegerDigits": .integer, From 7b9f695a9e56008850ef0c03698c0ff14cdc055d Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Fri, 9 Jan 2026 09:25:14 +0000 Subject: [PATCH 055/234] [dumpling] Add RelateTool and DiffOracle DiffOracle is a library that allows to see if there was a difference between optimized and unoptimized runs. RelateTool is designed as a CLI tool to compare optimized vs unoptimized runs. Usage: swift run -c release RelateTool --d8=... --poc=... Bug: 441467877 Change-Id: Ie8850e8534ae3a890f93be77ba2d0961f51a129e Co-authored-by: Mathias Payer Co-authored-by: Liam Wachter Co-authored-by: Flavio Toffalini Co-authored-by: Christian Wressnegger Co-authored-by: Julian Gremminger Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8759816 Reviewed-by: Matthias Liedtke Commit-Queue: Danylo Mocherniuk --- Package.swift | 8 + .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 229 +++++++++++++ Sources/RelateTool/main.swift | 114 +++++++ Tests/FuzzilliTests/DiffOracleTests.swift | 314 ++++++++++++++++++ 4 files changed, 665 insertions(+) create mode 100644 Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift create mode 100644 Sources/RelateTool/main.swift create mode 100644 Tests/FuzzilliTests/DiffOracleTests.swift diff --git a/Package.swift b/Package.swift index 216cf67c3..62f6609c4 100644 --- a/Package.swift +++ b/Package.swift @@ -70,6 +70,14 @@ let package = Package( .executableTarget(name: "FuzzILTool", dependencies: ["Fuzzilli"]), + // Tool that runs d8 in Dumpling mode. First time it runs with Maglev + // and Turbofan. Second time without. In both runs frames are dumped + // in certain points to the files. The dumps are later compared for + // equality. If they are not equal, it means that there's likely a bug + // in V8. + .executableTarget(name: "RelateTool", + dependencies: ["Fuzzilli"]), + .testTarget(name: "FuzzilliTests", dependencies: ["Fuzzilli"], resources: [.copy("CompilerTests")]), diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift new file mode 100644 index 000000000..74a988db3 --- /dev/null +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -0,0 +1,229 @@ +// 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 { + let bytecodeOffset: Int + let accumulator: String + let arguments: [String] + let registers: [String] + let functionId: Int + let frameType: FrameType + + // '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 "". + func isMatch(_ optValue: String, unoptValue: String) -> Bool { + return 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?) -> 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, totalCount: Int, oldValues: [String]) -> [String] { + var newValues = oldValues + + if newValues.count > totalCount { + newValues.removeLast(newValues.count - totalCount) + } else if newValues.count < totalCount { + let missingCount = totalCount - newValues.count + let defaults = Array(repeating: "", count: missingCount) + newValues.append(contentsOf: defaults) + } + + while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { + let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1) + let number = Int(data[0])! + let value = String(data[1]) + newValues[number] = value + i += 1 + } + return newValues + + } + + let arguments = updateValues(prefix: "a", totalCount: argCount, oldValues: prevFrame?.arguments ?? []) + let registers = updateValues(prefix: "r", totalCount: regCount, oldValues: prevFrame?.registers ?? []) + + 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 + + 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) + 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 as AnyObject) + print("--------------------------") + print("[") + for unoptFrame in unoptFrames { + if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset { + print(unoptFrame as AnyObject) + } + } + print("]") + return false + } + // Remove all skipped frames and the found frame. + unoptFramesLeft = unoptFramesLeft[(unoptIndex + 1)...] + } + return true + } +} diff --git a/Sources/RelateTool/main.swift b/Sources/RelateTool/main.swift new file mode 100644 index 000000000..33a9e718a --- /dev/null +++ b/Sources/RelateTool/main.swift @@ -0,0 +1,114 @@ +// 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/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift new file mode 100644 index 000000000..4b6176aa7 --- /dev/null +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -0,0 +1,314 @@ +// 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 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)) + } +} From 954de4ec5362e79130ab2ac5795a2d7e2fa22cf3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 5 Jan 2026 08:38:44 +0100 Subject: [PATCH 056/234] [test] Cleanup i31 tests Change-Id: I63cb4c1f7aef06240729a3879eb20ab3ef452549 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8911776 Auto-Submit: Matthias Liedtke Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- Tests/FuzzilliTests/WasmTests.swift | 42 ++++------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index c219e6175..0b291643f 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4817,17 +4817,18 @@ class WasmGCTests: XCTestCase { try refNullAbstractTypes(sharedRef: false) } - func testi31RefFromJs() throws { + 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] => [.wasmI31Ref()]) { function, label, args in - [function.wasmRefI31(args[0])] + wasmModule.addWasmFunction(with: [.wasmi32] => [i31RefT]) { function, label, args in + [function.wasmRefI31(args[0], shared: shared)] } - wasmModule.addWasmFunction(with: [.wasmI31Ref()] => [.wasmi32, .wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [i31RefT] => [.wasmi32, .wasmi32]) { function, label, args in [function.wasmI31Get(args[0], isSigned: true), function.wasmI31Get(args[0], isSigned: false)] } @@ -4851,39 +4852,6 @@ class WasmGCTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } - func i31Ref(shared: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: shared ? ["--experimental-wasm-shared", "--experimental-wasm-stringref"] : []) - let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) - let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) - let b: ProgramBuilder = fuzzer.makeBuilder() - let i31RefType = ILType.wasmI31Ref(shared: shared) - - let module = b.buildWasmModule { wasmModule in - let createReferenceOf = wasmModule.addWasmFunction(with: [.wasmi32] => [i31RefType]) { function, label, args in - [function.wasmRefI31(args[0], shared: shared)] - } - let dereference = wasmModule.addWasmFunction(with: [i31RefType] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true), - function.wasmI31Get(args[0], isSigned: false)] - } - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, args in - let const = function.consti32(-42) - let constRef = function.wasmCallDirect(signature: [.wasmi32] => [i31RefType], function: createReferenceOf, functionArgs: [const]) - let dereferencedConst = function.wasmCallDirect(signature: [i31RefType] => [.wasmi32, .wasmi32], function: dereference, functionArgs: constRef) - return dereferencedConst - } - } - - let exports = module.loadExports() - let outputFunc = b.createNamedVariable(forBuiltin: "output") - let result = b.callMethod(module.getExportedMethod(at: 2), 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: "-42,2147483606\n") - } - func testi31RefShared() throws { try i31Ref(shared: true) } From 0785e9ecc881b0efb64fb32e6fffecdf5be77df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= Date: Mon, 12 Jan 2026 17:49:28 +0100 Subject: [PATCH 057/234] Add support for iterator sequencing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 434977727 Change-Id: I24617b4353f7205c8654ce9f555ed043fb5e4b8c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8902197 Reviewed-by: Michael Achenbach Commit-Queue: Olivier Flückiger --- Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 562009562..05d07890c 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1036,7 +1036,7 @@ public extension ILType { static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"]) /// Type of the JavaScript Iterator constructor builtin. - static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from"]) + static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from", "concat"]) /// Type of a JavaScript generator object. static let jsGenerator = ILType.iterable + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) @@ -1544,6 +1544,7 @@ public extension ObjectGroup { ], methods: [ "from" : [.jsAnything] => .jsIterator, + "concat" : [.jsAnything...] => .jsIterator, ] ) From da6f981650637848a31ce74bd2f4af21385e08dc Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 13 Jan 2026 17:09:39 +0100 Subject: [PATCH 058/234] Make transpilator script support mjsunit Bug: 442444727 Change-Id: Ia254954f25df8284a58d43cce0c27383027e01db Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926738 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Tools/transpile_tests/transpile_tests.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Tools/transpile_tests/transpile_tests.py b/Tools/transpile_tests/transpile_tests.py index 02b913a18..6ee3959d5 100644 --- a/Tools/transpile_tests/transpile_tests.py +++ b/Tools/transpile_tests/transpile_tests.py @@ -38,6 +38,9 @@ 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']) @@ -67,6 +70,13 @@ def is_supported(self, abspath, relpath): 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'], @@ -83,7 +93,7 @@ def is_supported(self, abspath, relpath): 'language/statements/class', ], 'metadata_parser': Test262MetaDataParser, - } + }, } From 614a606f3f11d33e611d43a0301f2ccadf910d0a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 15:40:35 +0100 Subject: [PATCH 059/234] [environment] Refactor excluded properties on prototype There is an ever-growing list of properties that exist on a receiver which don't exist on the corresponding prototype object of the constructor or are not usable on it. So far, there are two cases for it: 1) They simply do not come from the prototype, e.g. iterator instances have properties that are part of the Iterator protocol, like `next`, while Iterator.prototype.next does not exist. 2) The property does exist on the prototype object, however it is not usable on it. There are a few properties that aren't actually regular properties but get accessors. These get accessors cannot be used on the prototype object as they will throw on access, e.g. `Intl.Collator.prototype.compare`. For nicer documentation, move these excluded properties to the call that registers the prototype object on the environment. Change-Id: I6e6163e0424a3e1f7e213ea2700d2dc8c883cd31 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926737 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- .../Environment/JavaScriptEnvironment.swift | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 05d07890c..921e07878 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1324,24 +1324,17 @@ public extension ObjectGroup { // them. Instead Fuzzilli generates GetProperty operations for them which will then be typed as // an `ILType.unboundFunction` which knows the required receiver type (in the example `Date`), // so Fuzzilli can generate sequences like `Date.prototype.getTime.call(new Date())`. - static func createPrototypeObjectGroup(_ receiver: ObjectGroup) -> ObjectGroup { + static func createPrototypeObjectGroup(_ receiver: ObjectGroup, excludeProperties: [String] = []) -> 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 - // TODO(mliedtke): Find a nicer interface than manually excluding some - // magic combinations here. - if receiver.name == "Intl.DateTimeFormat" || receiver.name == "Intl.NumberFormat" { - properties.removeValue(forKey: "format") - } else if receiver.name == "Intl.Collator" { - properties.removeValue(forKey: "compare") - } else if receiver.name == "Iterator" { - properties.removeValue(forKey: "next") - properties.removeValue(forKey: "return") - properties.removeValue(forKey: "throw") + // 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, @@ -1534,7 +1527,9 @@ public extension ObjectGroup { ] ) - static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator) + // next, return and throw are part of the Iterator protocol, not Iterator.prototype. + static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator, + excludeProperties: ["next", "return", "throw"]) static let jsIteratorConstructor = ObjectGroup( name: "IteratorConstructor", @@ -3092,7 +3087,10 @@ 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, + excludeProperties: ["compare"]) static let jsIntlCollatorConstructor = ObjectGroup( name: "IntlCollatorConstructor", @@ -3136,7 +3134,10 @@ 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, + excludeProperties: ["format"]) static let jsIntlDateTimeFormatConstructor = ObjectGroup( name: "IntlDateTimeFormatConstructor", @@ -3246,7 +3247,10 @@ 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, + excludeProperties: ["format"]) static let jsIntlNumberFormatConstructor = ObjectGroup( name: "IntlNumberFormatConstructor", From a63c74073085d4e619a5622cf563ce7755f4ff3e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 9 Jan 2026 16:19:01 +0100 Subject: [PATCH 060/234] [wasm] Use a wasm-gc signature as input for if-else-endif Similar to commit 3b241b0b0ea992ce6e99433a44b18bdfdaa92ba1 this change makes wasm's if-else control flow blocks use wasm-gc signatures as inputs instead of having the signature stored as a property inside the operation. This allows using wasm-gc index types inside these signatures. Bug: 445356784 Change-Id: I8315f64be536a1882ab9d4d39a3b7b72eb690456 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8914456 Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 50 +++++++++++------ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 45 ++++++++-------- Sources/Fuzzilli/FuzzIL/Instruction.swift | 19 +++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 17 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 27 +++++----- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 6 +-- .../Fuzzilli/Minimization/BlockReducer.swift | 18 ++++--- .../Fuzzilli/Mutators/OperationMutator.swift | 4 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 53 ++++++++----------- Sources/Fuzzilli/Protobuf/operations.proto | 9 ++-- 11 files changed, 131 insertions(+), 121 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index fae586123..ed04ebae9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3973,35 +3973,53 @@ public class ProgramBuilder { withInputs: labels + args + [on]) } + // TODO(mliedtke): It would be nice to remove this overload to simplify the codebase. public func wasmBuildIfElse(_ condition: Variable, hint: WasmBranchHint = .None, ifBody: () -> Void, elseBody: (() -> Void)? = nil) { - b.emit(WasmBeginIf(hint: hint), withInputs: [condition]) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: [] => []) + b.emit(WasmBeginIf(hint: hint), withInputs: [signatureDef, condition]) ifBody() if let elseBody { - b.emit(WasmBeginElse()) + b.emit(WasmBeginElse(), withInputs: [signatureDef]) elseBody() } - b.emit(WasmEndIf()) + b.emit(WasmEndIf(), withInputs: [signatureDef]) } 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]) + 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 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(with: signature), withInputs: trueResults, types: signature.outputTypes) + 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(outputTypes: signature.outputTypes), withInputs: falseResults, types: signature.outputTypes).outputs) + return Array(b.emit( + WasmEndIf(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + falseResults, + types: [.wasmTypeDef()] + signature.outputTypes).outputs) } @discardableResult @@ -4010,6 +4028,7 @@ public class ProgramBuilder { return wasmBuildLoopImpl(signature: signature, signatureDef: signatureDef, args: args, body: body) } + // TODO(mliedtke): Also use this inside the code generator. @discardableResult public func wasmBuildLoop(with signatureDef: Variable, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { let signature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature @@ -4596,11 +4615,11 @@ public class ProgramBuilder { + WasmAbstractHeapType.allCases.map {.wasmRef($0, nullability: true)})} } - public func randomWasmBlockArguments(upTo n: Int) -> [Variable] { + public func randomWasmBlockArguments(upTo n: Int, allowingGcTypes: Bool = false) -> [Variable] { (0.. outputTypes) let loopBegin = b.emit(WasmBeginLoop(parameterCount: parameters.count), withInputs: [signature] + args) @@ -1455,22 +1449,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.popAndPush("ifSignature")]) }, GeneratorStub( "WasmEndIfElseGenerator", inContext: .single(.wasmFunction) ) { b in - b.emit(WasmEndIf()) + b.emit(WasmEndIf(), withInputs: [b.runtimeData.pop("ifSignature")]) }, ]), @@ -1483,14 +1479,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", @@ -1498,22 +1496,23 @@ 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.popAndPush("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) - b.emit( - WasmEndIf(outputTypes: signature.outputTypes), - withInputs: falseResults) + let signature = b.runtimeData.pop("ifSignature") + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature + let falseResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) + b.emit(WasmEndIf(outputCount: wasmSignature.outputTypes.count), + withInputs: [signature] + falseResults) }, ]), diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index cc52480ec..728619b03 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1466,19 +1466,18 @@ extension Instruction: ProtobufConvertible { } 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") @@ -2503,15 +2502,11 @@ extension Instruction: ProtobufConvertible { case .wasmBranchTable(let p): op = WasmBranchTable(labelTypes: p.parameters.map(WasmTypeEnumToILType), 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(_): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 29e75d80e..4cf4888e2 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -818,14 +818,17 @@ public struct JSTyper: Analyzer { 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 .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) + 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 diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 508922c58..3f47b2d30 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1277,43 +1277,46 @@ 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 { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index f7985fe99..4df1a6fce 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1219,14 +1219,12 @@ public class FuzzILLifter: Lifter { 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.increaseIndentionLevel() diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 56eaddcfe..754a12795 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1235,8 +1235,7 @@ public class WasmLifter { self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginIf(let op): - registerSignature(op.signature) + case .wasmBeginIf(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1970,7 +1969,8 @@ public class WasmLifter { 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(_): diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 3fd0a0ad0..a25e18d12 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -479,8 +479,9 @@ struct BlockReducer: Reducer { let ifBlock = group.block(0) let beginIf = helper.code[ifBlock.head].op as! WasmBeginIf + let endIf = helper.code[group.tail].op as! WasmEndIf // Now try to turn if-else into just if. - if group.numBlocks == 2 && beginIf.signature.outputTypes.isEmpty { + if group.numBlocks == 2 && endIf.outputCount == 0 { // First try to remove the else block. let elseBlock = group.block(1) let rangeToNop = Array(elseBlock.head ..< elseBlock.tail) @@ -490,7 +491,7 @@ struct BlockReducer: Reducer { } // Then try to remove the if block. This requires inverting the condition of the if. - let invertedIf = WasmBeginIf(with: beginIf.signature, inverted: !beginIf.inverted) + let invertedIf = WasmBeginIf(parameterCount: beginIf.parameterCount, inverted: !beginIf.inverted) var replacements = [(Int, Instruction)]() // The new WasmBeginIf will take the original inputs but produces the inner outputs // of the original WasmBeginElse block, so that users of them are rewired correctly. @@ -509,7 +510,7 @@ struct BlockReducer: Reducer { } // If we have outputs or the innerOutputs of the WasmBeginIf / WasmBeginElse are used, // a more "sophisticated" reduction is needed. - if group.numBlocks == 2 && (!beginIf.signature.parameterTypes.isEmpty || !beginIf.signature.outputTypes.isEmpty) { + if group.numBlocks == 2 && (beginIf.parameterCount != 0 || endIf.outputCount != 0) { let elseBlock = group.block(1) let beginIfInstr = helper.code[ifBlock.head] @@ -522,11 +523,11 @@ struct BlockReducer: Reducer { do { // First try to replace the if-else with the if body. // "Shortcut" bypassing the WasmBeginIf by directly using its inputs. var varReplacements = Dictionary( - uniqueKeysWithValues: zip(beginIfInstr.innerOutputs.dropFirst(), beginIfInstr.inputs)) + uniqueKeysWithValues: zip(beginIfInstr.innerOutputs.dropFirst(), beginIfInstr.inputs.dropFirst())) // Replace all usages of the WasmEndIf outputs with the results of the if true // block which are the inputs into the WasmBeginElse block. varReplacements.merge( - zip(helper.code[elseBlock.tail].outputs, helper.code[elseBlock.head].inputs.map {varReplacements[$0] ?? $0}), + zip(helper.code[elseBlock.tail].outputs, helper.code[elseBlock.head].inputs.dropFirst().map {varReplacements[$0] ?? $0}), uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) var newCode = Code() for (i, instr) in helper.code.enumerated() { @@ -547,10 +548,13 @@ struct BlockReducer: Reducer { // "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")}) + 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() for (i, instr) in helper.code.enumerated() { if i == elseBlock.tail || (i >= ifBlock.head && i <= ifBlock.tail) { diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4f8b7b843..1098ea1b3 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -369,7 +369,7 @@ public class OperationMutator: BaseInstructionMutator { case .wasmDefineGlobal(let op): // We never change the type of the global, only the value as changing the type will break the following code pretty much instantly. - let wasmGlobal:WasmGlobal = + let wasmGlobal:WasmGlobal = switch op.wasmGlobal.toType() { case .wasmf32: .wasmf32(Float32(b.randomFloat())) @@ -499,7 +499,7 @@ public class OperationMutator: BaseInstructionMutator { case .wasmBranchIf(let op): newOp = WasmBranchIf(labelTypes: op.labelTypes, hint: chooseUniform(from: WasmBranchHint.allCases)) case .wasmBeginIf(let op): - newOp = WasmBeginIf(with: op.signature, hint: chooseUniform(from: WasmBranchHint.allCases), inverted: Bool.random()) + newOp = WasmBeginIf(parameterCount: op.parameterCount, hint: chooseUniform(from: WasmBranchHint.allCases), inverted: Bool.random()) case .wasmArrayGet(let op): // Switch signedness. (This only matters for packed types i8 and i16.) newOp = WasmArrayGet(isSigned: !op.isSigned) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 4cbf6f735..00cd84c4e 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5408,9 +5408,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 @@ -5426,9 +5424,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() @@ -5440,7 +5438,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() @@ -14275,7 +14273,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() { @@ -14283,8 +14281,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 @@ -14293,11 +14290,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) @@ -14309,8 +14303,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} @@ -14320,7 +14313,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() { @@ -14328,26 +14321,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 } @@ -14355,7 +14348,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() { @@ -14363,21 +14356,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 247ba5c8e..a369be39d 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1337,19 +1337,18 @@ message WasmReassign { } 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 { From 492e592032a25b56522a5860d283fe32a327f48d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 9 Jan 2026 18:21:27 +0100 Subject: [PATCH 061/234] [wasm] Use a wasm-gc signature for wasm blocks Bug: 445356784 Change-Id: Ic309942aac909ffa6397fc889fd4cd8fe86e6b4e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8914596 Commit-Queue: Matthias Liedtke Reviewed-by: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 34 +++++------ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 57 ++++++++++--------- Sources/Fuzzilli/FuzzIL/Instruction.swift | 11 ++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 10 ++-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 18 +++--- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 8 +-- .../Fuzzilli/Minimization/BlockReducer.swift | 18 ++---- Sources/Fuzzilli/Protobuf/operations.pb.swift | 31 ++++------ Sources/Fuzzilli/Protobuf/operations.proto | 5 +- Tests/FuzzilliTests/MinimizerTest.swift | 2 +- 11 files changed, 91 insertions(+), 107 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index ed04ebae9..4c285c31e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3921,25 +3921,28 @@ public class ProgramBuilder { // The first innerOutput of this block is a label variable, which is just there to explicitly mark control-flow and allow branches. public func wasmBuildBlock(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> ()) { 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) + 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]) { @@ -4909,8 +4912,6 @@ public class ProgramBuilder { break case .beginWasmFunction(let op): activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) - case .wasmBeginBlock(let op): - activeWasmModule!.blockSignatures.push(op.signature) case .wasmBeginTry(let op): activeWasmModule!.blockSignatures.push(op.signature) case .wasmBeginTryDelegate(let op): @@ -4919,8 +4920,7 @@ public class ProgramBuilder { activeWasmModule!.blockSignatures.push(op.signature) case .wasmEndTry(_), .wasmEndTryDelegate(_), - .wasmEndTryTable(_), - .wasmEndBlock(_): + .wasmEndTryTable(_): activeWasmModule!.blockSignatures.pop() default: diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index a5ae351b6..eefef55ec 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1216,13 +1216,15 @@ 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")]) }, ]), @@ -1234,24 +1236,22 @@ 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) }, ]), @@ -1607,8 +1607,9 @@ 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: .label(b.type(of: signatureDef).wasmFunctionSignatureDefSignature.outputTypes))! } let catches = zip(tags, withExnRef).map { tag, withExnRef -> WasmBeginTryTable.CatchKind in @@ -1682,12 +1684,11 @@ 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) } } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 728619b03..19e2f917b 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1386,12 +1386,11 @@ extension Instruction: ProtobufConvertible { } 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 { @@ -2453,11 +2452,9 @@ extension Instruction: ProtobufConvertible { let outputs = p.outputTypes.map(WasmTypeEnumToILType) op = EndWasmFunction(signature: parameters => outputs) 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): op = WasmBeginLoop(parameterCount: Int(p.parameterCount)) case .wasmEndLoop(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 4cf4888e2..99a0e3216 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -814,10 +814,12 @@ public struct JSTyper: Analyzer { dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(op.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 .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) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 3f47b2d30..e0424b20a 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1250,22 +1250,20 @@ 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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 4df1a6fce..f88825865 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1081,10 +1081,10 @@ public class FuzzILLifter: Lifter { let inputs = instr.inputs.map(lift).joined(separator: ", ") w.emit("WasmReturnCallIndirect(\(op.signature)) \(inputs)") - case .wasmBeginBlock(let op): + case .wasmBeginBlock(_): // TODO(cffsmith): Maybe lift labels as e.g. L7 or something like that? let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginBlock (\(op.signature)) [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit("WasmBeginBlock [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") w.increaseIndentionLevel() case .wasmEndBlock(let op): diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 754a12795..ec001c82e 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1230,8 +1230,7 @@ public class WasmLifter { assert(instr.op is WasmOperation) switch instr.op.opcode { - case .wasmBeginBlock(let op): - registerSignature(op.signature) + case .wasmBeginBlock(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1899,10 +1898,11 @@ public class WasmLifter { } 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))) + 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]!)) diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index a25e18d12..aec2abf3c 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -95,20 +95,13 @@ struct BlockReducer: Reducer { .wasmBeginTryTable: reduceGenericBlockGroup(group, with: helper) - case .wasmBeginBlock: - // TODO(mliedtke): Deduplicate with .wasmBeginLoop once blocks also use wasm-gc - // signatures. + case .wasmBeginBlock, + .wasmBeginLoop: let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper) if rewroteProgram { return } - case .wasmBeginLoop: - let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper, usesSignature: true) - if rewroteProgram { - return - } - case .wasmBeginCatchAll, .wasmBeginCatch: // These instructions are handled in the reduceWasmTryCatch. @@ -318,7 +311,7 @@ struct BlockReducer: Reducer { // Reduce a wasm block. In some cases this reduction fully rewrites the program // invalidating pre-computed BlockGroups. If that happens, the function returns true indicating // that following reductions need to rerun the Blockgroups analysis. - private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper, usesSignature: Bool = false) -> Bool { + private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper) -> Bool { // Try to remove just the block. var candidates = group.blockInstructionIndices if helper.tryNopping(candidates) { @@ -341,8 +334,9 @@ struct BlockReducer: Reducer { let beginInstr = helper.code[group.head] let endInstr = helper.code[group.tail] - let blockInputs = usesSignature ? beginInstr.inputs.dropFirst() : beginInstr.inputs - let endInstrInputs = usesSignature ? endInstr.inputs.dropFirst() : endInstr.inputs + // 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(), blockInputs)) varReplacements.merge(zip(endInstr.outputs, endInstrInputs.map {varReplacements[$0] ?? $0}), diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 00cd84c4e..aca566377 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5147,9 +5147,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 +5159,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() @@ -13651,7 +13649,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() { @@ -13659,26 +13657,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 } @@ -13686,7 +13679,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() { @@ -13694,21 +13687,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index a369be39d..d55891336 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1238,12 +1238,11 @@ 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 { diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 497508250..b70df09bf 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1947,7 +1947,7 @@ 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 From df38fe33220688ac156d3891563113e156fe680f Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 9 Jan 2026 18:37:38 +0100 Subject: [PATCH 062/234] [cleanup] Remove one of the wasmBuildIfElse overloads Change-Id: Id1322a5847527125d3282da5d80e861422bd7f45 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8914597 Commit-Queue: Matthias Liedtke Reviewed-by: Pawel Krawczyk --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 14 +--------- Tests/FuzzilliTests/MinimizerTest.swift | 4 +-- Tests/FuzzilliTests/WasmTests.swift | 32 +++++++++++----------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 4c285c31e..286204b1c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3976,19 +3976,7 @@ public class ProgramBuilder { withInputs: labels + args + [on]) } - // TODO(mliedtke): It would be nice to remove this overload to simplify the codebase. - public func wasmBuildIfElse(_ condition: Variable, hint: WasmBranchHint = .None, ifBody: () -> Void, elseBody: (() -> Void)? = nil) { - let signatureDef = b.wasmDefineAdHocSignatureType(signature: [] => []) - b.emit(WasmBeginIf(hint: hint), withInputs: [signatureDef, condition]) - ifBody() - if let elseBody { - b.emit(WasmBeginElse(), withInputs: [signatureDef]) - elseBody() - } - b.emit(WasmEndIf(), withInputs: [signatureDef]) - } - - public func wasmBuildIfElse(_ condition: Variable, signature: WasmSignature, args: [Variable], inverted: Bool, ifBody: (Variable, [Variable]) -> Void, elseBody: ((Variable, [Variable]) -> Void)? = nil) { + public func wasmBuildIfElse(_ condition: Variable, signature: WasmSignature = [] => [], args: [Variable] = [], hint: WasmBranchHint = .None, inverted: Bool = false, ifBody: (Variable, [Variable]) -> Void, elseBody: ((Variable, [Variable]) -> Void)? = nil) { assert(signature.outputTypes.count == 0) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let beginBlock = b.emit(WasmBeginIf(parameterCount: signature.parameterTypes.count, inverted: inverted), diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index b70df09bf..22807afe5 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1672,10 +1672,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) } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 0b291643f..21ac40213 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -2731,7 +2731,7 @@ class WasmFoundationTests: XCTestCase { 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]] @@ -2762,13 +2762,13 @@ class WasmFoundationTests: XCTestCase { 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] } @@ -2897,13 +2897,13 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { _, _ 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( @@ -3190,9 +3190,9 @@ 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.wasmBuildIfElse(param[0], hint: .None) { _, _ in function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) - } elseBody: { + } elseBody: { _, _ in function.WasmBuildThrow(tag: importedTag, inputs: [function.consti32(123)]) } function.wasmUnreachable() @@ -3280,13 +3280,13 @@ class WasmFoundationTests: XCTestCase { 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.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq), hint: .None) { + 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), hint: .None) { + function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq)) { _, _ in function.WasmBuildThrow(tag: tagi32Other, inputs: [function.consti32(200)]) } return [args[0], contant42] @@ -3302,7 +3302,7 @@ class WasmFoundationTests: XCTestCase { ], catchAllBody: { _ in return [function.consti32(900), contant42] }) - function.wasmBuildIfElse(function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None) { + function.wasmBuildIfElse(function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None) { _, _ in function.wasmUnreachable() } return [result[0]] @@ -3730,9 +3730,9 @@ class WasmFoundationTests: XCTestCase { 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) { + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) - } elseBody: { + } elseBody: { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) } return [] @@ -3769,9 +3769,9 @@ class WasmFoundationTests: XCTestCase { 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.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) - } elseBody: { + } elseBody: { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) } return [] From fcd3227ad23db2141b233b1916e48d89a229d7f9 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 12 Jan 2026 17:14:11 +0100 Subject: [PATCH 063/234] [cleanup] Rename GeneratorRuntimeData.popAndPush() to peek() Change-Id: Ia6616629177ee5f941377471a998d59e1ab31d06 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8922297 Reviewed-by: Pawel Krawczyk Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 +++-- Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift | 4 ++-- Tests/FuzzilliTests/ProgramBuilderTest.swift | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 286204b1c..e392e7d95 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -35,8 +35,9 @@ 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 } diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index eefef55ec..f4c36b7b1 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1460,7 +1460,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inContext: .single(.wasmFunction), provides: [.wasmFunction] ) { b in - b.emit(WasmBeginElse(), withInputs: [b.runtimeData.popAndPush("ifSignature")]) + b.emit(WasmBeginElse(), withInputs: [b.runtimeData.peek("ifSignature")]) }, GeneratorStub( "WasmEndIfElseGenerator", @@ -1496,7 +1496,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ provides: [.wasmFunction] ) { b in let function = b.currentWasmFunction - let signature = b.runtimeData.popAndPush("ifSignature") + 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, diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 52f339565..473a33590 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3237,7 +3237,7 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { counter += 1 }, GeneratorStub("AddOne") { b in - let value = b.runtimeData.popAndPush("value") + let value = b.runtimeData.peek("value") b.binary(value, b.loadInt(1), with: .Add) }, GeneratorStub("SubOne") { b in From 47c7c39a2d201c9f9ac76877bddce5a868c57344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doga=20Y=C3=BCksel?= Date: Tue, 13 Jan 2026 10:39:14 +0000 Subject: [PATCH 064/234] Add WasmStructNew operation and generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for wasm struct.new operation to be able to generate structs with initial non-default values. Bug: 474940922 Change-Id: Ic8f1cc8d7f9dc24dc73b342fb3d55c35e1a33446 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8921896 Reviewed-by: Matthias Liedtke Reviewed-by: Dominik Klemba Commit-Queue: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 16 +++++++-- .../CodeGen/CodeGeneratorWeights.swift | 1 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 19 +++++++++++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 4 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 3 +- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 8 +++++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 1 + Sources/Fuzzilli/Lifting/WasmLifter.swift | 4 +++ .../Fuzzilli/Mutators/OperationMutator.swift | 3 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 29 ++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 3 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 29 ++++++++++++++-- Sources/Fuzzilli/Protobuf/program.proto | 1 + Tests/FuzzilliTests/WasmTests.swift | 34 +++++++++++++++++++ 16 files changed, 153 insertions(+), 7 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index e392e7d95..33e887a0a 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4180,9 +4180,14 @@ public class ProgramBuilder { } else { return nil } - case .Index(_), - .none: - break // Unimplemented + case .Index(_): + if (type.wasmReferenceType!.nullability) { + return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) + } else { + break + } + case .none: + break } } else { return nil @@ -4338,6 +4343,11 @@ public class ProgramBuilder { 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 public func wasmStructNewDefault(structType: Variable) -> Variable { return b.emit(WasmStructNewDefault(), withInputs: [structType]).output diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 9da0a7720..22596f473 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -365,6 +365,7 @@ public let codeGeneratorWeights = [ "WasmArrayLengthGenerator": 5, "WasmArrayGetGenerator": 5, "WasmArraySetGenerator": 5, + "WasmStructNewGenerator": 5, "WasmStructNewDefaultGenerator": 5, "WasmStructGetGenerator": 5, "WasmStructSetGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index f4c36b7b1..0fdbc2ab0 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -210,6 +210,25 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmArraySet(array: array, index: index, element: element) }, + CodeGenerator( + "WasmStructNewGenerator", inContext: .single(.wasmFunction), + inputs: .requiredComplex(.init(.wasmTypeDef(), .IsWasmStruct)), + producesComplex: [.init(.anyNonNullableIndexRef, .IsWasmStruct)] + ) { b, structType in + guard let typeDesc = b.type(of: structType).wasmTypeDefinition?.description as? WasmStructTypeDescription + else { + fatalError("Invalid type description for \(b.type(of: structType))") + } + let function = b.currentWasmModule.currentWasmFunction + var initial_fields: [Variable] = [] + for field in typeDesc.fields { + let fieldType = field.type.unpacked() + let fieldValue = function.findOrGenerateWasmVar(ofType: fieldType) + initial_fields.append(fieldValue) + } + function.wasmStructNew(structType: structType, fields: initial_fields) + }, + CodeGenerator( "WasmStructNewDefaultGenerator", inContext: .single(.wasmFunction), inputs: .requiredComplex(.init(.wasmTypeDef(), .IsWasmStruct)), diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 19e2f917b..36dc2e9be 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1598,6 +1598,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) @@ -2585,6 +2587,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): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 99a0e3216..1fd9f2377 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -896,7 +896,8 @@ 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 diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index d28dd189f..8e2110cae 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -364,4 +364,5 @@ enum Opcode { case createNamedDisposableVariable(CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(CreateNamedAsyncDisposableVariable) case wasmDefineAdHocSignatureType(WasmDefineAdHocSignatureType) + case wasmStructNew(WasmStructNew) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index e0424b20a..6df5b99c1 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2224,6 +2224,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) } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index f88825865..f6c7cfc5b 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1310,6 +1310,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))]") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index d299c10f2..1d74e006a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1783,6 +1783,7 @@ public class JavaScriptLifter: Lifter { .wasmArrayLen(_), .wasmArrayGet(_), .wasmArraySet(_), + .wasmStructNew(_), .wasmStructNewDefault(_), .wasmStructGet(_), .wasmStructSet(_), diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index ec001c82e..a97485fec 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -2162,6 +2162,10 @@ 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]!) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 1098ea1b3..af493a681 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -727,7 +727,8 @@ public class OperationMutator: BaseInstructionMutator { .wasmDefineElementSegment(_), .wasmDropElementSegment(_), .wasmTableInit(_), - .wasmTableCopy(_): + .wasmTableCopy(_), + .wasmStructNew(_): let mutability = instr.isOperationMutable ? "mutable" : "immutable" fatalError("Unexpected operation \(instr.op.opcode), marked as \(mutability)") } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index aca566377..2632630b4 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5857,6 +5857,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 @@ -15295,6 +15305,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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index d55891336..46758340b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1544,6 +1544,9 @@ message WasmArraySet { message WasmStructNewDefault { } +message WasmStructNew { +} + message WasmStructGet { int32 fieldIndex = 1; bool isSigned = 2; diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 293a03607..c85ec56f6 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2729,6 +2729,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3067,7 +3075,7 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case createNamedDisposableVariable(Fuzzilli_Protobuf_CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable) case wasmDefineAdHocSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocSignatureType) - + case wasmStructNew(Fuzzilli_Protobuf_WasmStructNew) } public init() {} @@ -3115,7 +3123,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7474,6 +7482,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocSignatureType(v) } }() + case 337: 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) + } + }() default: break } } @@ -8828,6 +8849,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmDefineAdHocSignatureType(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 336) }() + case .wasmStructNew?: try { + guard case .wasmStructNew(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 337) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index db2587934..1c6d2fbba 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -360,6 +360,7 @@ message Instruction { CreateNamedDisposableVariable createNamedDisposableVariable = 334; CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 335; WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; + WasmStructNew wasmStructNew = 337; } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 21ac40213..23ef57bb6 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4417,6 +4417,40 @@ 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) From 1f1871962fbf8cdb86099a9fb72c41ab5e13111f Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 14:44:34 +0100 Subject: [PATCH 065/234] [cleanup] Simplify ProgramBuilder.generateRandomWasmVar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id6f1609bf09df512aced5db86f979e3709647446 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926736 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 33e887a0a..5f39ab5e3 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4177,20 +4177,14 @@ public class ProgramBuilder { // TODO(pawkra): support other non-nullable types. if (type.wasmReferenceType!.nullability) { return self.wasmRefNull(type: type) - } else { - return nil } case .Index(_): if (type.wasmReferenceType!.nullability) { return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) - } else { - break } case .none: break } - } else { - return nil } return nil } From f418a5e040e090b9453b74f77644da701450e8a2 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 15 Jan 2026 13:53:56 +0100 Subject: [PATCH 066/234] [wasm] Print better error message when failing in findOrGenerateWasmVar Bug: 475996631 Change-Id: I2fed02882da99abdaaca11d5bed21ebd0f0ff833 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8932836 Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 5f39ab5e3..9f1ccbe64 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4191,7 +4191,10 @@ public class ProgramBuilder { } 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() { From c3fe975530af5307fd770c69537639b8c2b1c525 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 14 Jan 2026 16:20:40 +0100 Subject: [PATCH 067/234] [js] Fix input requirements resolution for JS types So far we didn't try to resolve input requirements for JS types by scheduling code generators that produce these inputs. This change fixes that and also fixes the test case and the compile warning it produces for the unused Swift variable due to commented out code. Change-Id: I7c090fc164b00df5ef31353447ae4f993538c437 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8929438 Reviewed-by: Dominik Klemba Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 38 +++++++++----------- Tests/FuzzilliTests/ProgramBuilderTest.swift | 16 +++++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 9f1ccbe64..1e0956bf9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2225,31 +2225,27 @@ public class ProgramBuilder { private func createRequiredInputVariables(for requirements: Set) { for requirement in requirements { let type = requirement.type - 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 (findVariable {requirement.fulfilled(by: self.type(of: $0))} == nil) { - // Check for other CodeGenerators that can produce the given type in this context. - let usableGenerators = fuzzer.codeGenerators.filter { - $0.requiredContext.isSubset(of: context) && - $0.produces.contains(where: requirement.fulfilled) - } - - // 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 {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) } } } diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 473a33590..69ef921eb 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3016,11 +3016,13 @@ class ProgramBuilderTests: XCTestCase { func testTypedArrayFromBufferGenerator() { let fuzzer = makeMockFuzzer() - let numPrograms = 50 + 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 == "TypedArrayFromBufferGenerator" @@ -3033,11 +3035,13 @@ 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() - - // XCTAssertGreaterThan(numGeneratedInstructions, 0) - // TODO(tacet): Fails in around 5% of times, we should figure out how to fix it. } } From 8fe974b63af7bb0650d43d86c3a020c2bdcd3057 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 15 Jan 2026 15:51:42 +0100 Subject: [PATCH 068/234] [wasm] Fix generateRandomWasmVar for wasm index ref in cases where it doesn't have a wasmReferenceType WasmTypeExtension. The better printing in commit f418a5e040e090b9453b74f77644da701450e8a2 doesn't do anything if we don't ever reach it because we already crash earlier. This change adapts generateRandomWasmVar to return nil if it receives an index reference type without the expected type extension. If this still causes crashes, we'd then get the better error message from above. Bug: 475996631 Change-Id: I86f89855724f09de3875770e2380257c07d54062 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8932837 Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 1e0956bf9..7c51c954b 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4175,7 +4175,7 @@ public class ProgramBuilder { return self.wasmRefNull(type: type) } case .Index(_): - if (type.wasmReferenceType!.nullability) { + if (type.wasmReferenceType?.nullability ?? false) { return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) } case .none: From 1968a9719129f4f84aa71cf603e48c342548a67d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 16 Jan 2026 11:22:41 +0100 Subject: [PATCH 069/234] [wasm] Add one more fatalError to investigate recent failures Bug: 475996631 Change-Id: If8b92877f88b5852184d69477bc508d6c039c294 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8932857 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 1fd9f2377..e78852875 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -446,7 +446,10 @@ public struct JSTyper: Analyzer { guard case .Index(let desc) = type.wasmReferenceType!.kind else { fatalError("\(type) is not an index type") } - return wasmTypeDefMap[desc.get()!]! + 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) { From 86744448158e49a294c0ae993ee962f265a9e045 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 16 Jan 2026 15:46:46 +0100 Subject: [PATCH 070/234] [wasm] Fix WasmTypeGroupReducer to expose all unremoved types While the WasmTypeGroupReducer shall remove all inputs which are not used from the WasmEndTypeGroup (so that these types can be removed in a following iteration), it should still expose all types which are used inside the type group, so that the JSTyper still continues to handle them correctly. This will hopefully fix the current crashes we are observing for types missing the linkage from a wasm index reference type to the corresponding type definition variable in the JSTyper. Bug: 475996631 Change-Id: I571a44fabee3f302c8f53fad14d6f62263d0a8ca Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8935617 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke --- .../Minimization/WasmTypeGroupReducer.swift | 16 +++++- Tests/FuzzilliTests/MinimizerTest.swift | 49 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 96d6d4870..df6c149db 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -22,12 +22,24 @@ struct WasmTypeGroupReducer: Reducer { uses[input]? += 1 } + + guard instr.op is WasmTypeOperation else { continue } + // Define the usages for all WasmTypeOperation so that we also count usages of a type + // inside a type group (i.e. by other type operations). + for output in instr.outputs { + uses[output] = 0 + } + // 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 + for (input, output) in zip(instr.inputs, instr.outputs) { + // Subtract 1 as the input in the WasmEndTypeGroup itself is not a reason to keep + // the type. However, if the type is used inside the type group, it also needs to be + // exposed by the type group. Right now the JSTyper requires that all types defined + // in a type group are exposed by their WasmEndTypeGroup instruction. + uses[output]! += uses[input]! - 1 } } diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 22807afe5..58dd10ec7 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -2126,6 +2126,55 @@ class MinimizerTests: XCTestCase { } + 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) From 83d4faca2511e3810ac261647810fc46a01d3eb6 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 16 Jan 2026 16:14:09 +0100 Subject: [PATCH 071/234] Print corpus import durations Bug: 442444727 Change-Id: I2b829da00393a63f40ac2791091ff73bd288aa24 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8935636 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/FuzzilliCli/main.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 10612275b..89c2e87e9 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -641,6 +641,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 +651,10 @@ 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 +663,19 @@ 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).") + + 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) } From 6faf7876262188452399fc43be4015018f12f7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doga=20Y=C3=BCksel?= Date: Fri, 16 Jan 2026 11:22:09 +0000 Subject: [PATCH 072/234] [wasm] Add WasmRefEq operation and generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for ref.eq instruction to be generated Bug: 474940922 Change-Id: I7b88ceffed5252878132406da30a570be01f13ad Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8933276 Reviewed-by: Matthias Liedtke Commit-Queue: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 6 +++ .../CodeGen/CodeGeneratorWeights.swift | 1 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 8 ++++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 4 ++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 2 + Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 8 ++++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 3 ++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 1 + Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 + .../Fuzzilli/Mutators/OperationMutator.swift | 3 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 29 ++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 3 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 29 +++++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 1 + Tests/FuzzilliTests/WasmTests.swift | 38 +++++++++++++++++++ 16 files changed, 137 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 7c51c954b..0322618a1 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4374,6 +4374,12 @@ public class ProgramBuilder { return b.emit(WasmRefIsNull(), withInputs: [ref], types: [.wasmGenericRef]).output } + @discardableResult + // TODO(pawkra): Support shared references. + public func wasmRefEq(_ lhs: Variable, _ rhs: Variable) -> Variable { + return b.emit(WasmRefEq(), withInputs: [lhs, rhs], types: [.wasmEqRef(), .wasmEqRef()]).output + } + @discardableResult public func wasmRefI31(_ number: Variable, shared: Bool = false) -> Variable { return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]).output diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 22596f473..6d8698fc6 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -371,6 +371,7 @@ public let codeGeneratorWeights = [ "WasmStructSetGenerator": 5, "WasmRefNullGenerator": 5, "WasmRefIsNullGenerator": 5, + "WasmRefEqGenerator": 5, "WasmRefI31Generator": 5, "WasmI31GetGenerator": 5, "WasmAnyConvertExternGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 0fdbc2ab0..ee8abfc22 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -312,6 +312,14 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmRefIsNull(ref) }, + CodeGenerator( + "WasmRefEqGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmEqRef(), .wasmEqRef()), + produces: [.wasmi32] + ) { b, lhs, rhs in + b.currentWasmModule.currentWasmFunction.wasmRefEq(lhs, rhs) + }, + // TODO(pawkra): add shared variant. CodeGenerator("WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32)) { b, value in b.currentWasmModule.currentWasmFunction.wasmRefI31(value, shared: false) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 36dc2e9be..bb3d4b0f6 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1617,6 +1617,8 @@ extension Instruction: ProtobufConvertible { } case .wasmRefIsNull(_): $0.wasmRefIsNull = Fuzzilli_Protobuf_WasmRefIsNull() + case .wasmRefEq(_): + $0.wasmRefEq = Fuzzilli_Protobuf_WasmRefEq() case .wasmRefI31(let op): $0.wasmRefI31 = Fuzzilli_Protobuf_WasmRefI31.with { $0.isShared = op.isShared @@ -2599,6 +2601,8 @@ extension Instruction: ProtobufConvertible { op = p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) case .wasmRefIsNull(_): op = WasmRefIsNull() + case .wasmRefEq(_): + op = WasmRefEq() case .wasmRefI31(let p): op = WasmRefI31(isShared: p.isShared) case .wasmI31Get(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index e78852875..eeff27465 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -915,6 +915,8 @@ public struct JSTyper: Analyzer { } case .wasmRefIsNull(_): setType(of: instr.output, to: .wasmi32) + case .wasmRefEq(_): + setType(of: instr.output, to: .wasmi32) case .wasmRefI31(let op): setType(of: instr.output, to: .wasmRefI31(shared: op.isShared)) case .wasmI31Get(_): diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 8e2110cae..6faff452a 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -365,4 +365,5 @@ enum Opcode { case createNamedAsyncDisposableVariable(CreateNamedAsyncDisposableVariable) case wasmDefineAdHocSignatureType(WasmDefineAdHocSignatureType) case wasmStructNew(WasmStructNew) + case wasmRefEq(WasmRefEq) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 6df5b99c1..dfe1fd6f1 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2283,6 +2283,14 @@ 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 diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index f6c7cfc5b..8fbb32fb6 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1330,6 +1330,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))") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 1d74e006a..9fb9ba5fe 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1789,6 +1789,7 @@ public class JavaScriptLifter: Lifter { .wasmStructSet(_), .wasmRefNull(_), .wasmRefIsNull(_), + .wasmRefEq(_), .wasmRefI31(_), .wasmI31Get(_), .wasmAnyConvertExtern(_), diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index a97485fec..d3cbe2635 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -2185,6 +2185,8 @@ public class WasmLifter { return try Data([0xD0]) + encodeHeapType(typer.type(of: wasmInstruction.output)) case .wasmRefIsNull(_): return Data([0xD1]) + case .wasmRefEq(_): + return Data([0xD3]) case .wasmRefI31(let op): return Data([Prefix.GC.rawValue, op.isShared ? 0x1F : 0x1C]) case .wasmI31Get(let op): diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index af493a681..cefbf9d92 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -728,7 +728,8 @@ public class OperationMutator: BaseInstructionMutator { .wasmDropElementSegment(_), .wasmTableInit(_), .wasmTableCopy(_), - .wasmStructNew(_): + .wasmStructNew(_), + .wasmRefEq(_): let mutability = instr.isOperationMutable ? "mutable" : "immutable" fatalError("Unexpected operation \(instr.op.opcode), marked as \(mutability)") } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 2632630b4..a6011ecc8 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5924,6 +5924,16 @@ 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_WasmRefI31: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -15442,6 +15452,25 @@ extension Fuzzilli_Protobuf_WasmRefIsNull: SwiftProtobuf.Message, SwiftProtobuf. } } +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 { + // 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_WasmRefEq, rhs: Fuzzilli_Protobuf_WasmRefEq) -> Bool { + 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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 46758340b..f761715e1 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1563,6 +1563,9 @@ message WasmRefNull { message WasmRefIsNull { } +message WasmRefEq { +} + message WasmRefI31 { bool isShared = 1; } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index c85ec56f6..11b662941 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2737,6 +2737,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3076,6 +3084,8 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case createNamedAsyncDisposableVariable(Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable) case wasmDefineAdHocSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocSignatureType) case wasmStructNew(Fuzzilli_Protobuf_WasmStructNew) + case wasmRefEq(Fuzzilli_Protobuf_WasmRefEq) + } public init() {} @@ -3123,7 +3133,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7495,6 +7505,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructNew(v) } }() + case 338: 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) + } + }() default: break } } @@ -8853,6 +8876,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmStructNew(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 337) }() + case .wasmRefEq?: try { + guard case .wasmRefEq(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 338) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 1c6d2fbba..6fc3e2981 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -361,6 +361,7 @@ message Instruction { CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 335; WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; WasmStructNew wasmStructNew = 337; + WasmRefEq wasmRefEq = 338; } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 23ef57bb6..b2b51e9d3 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4851,6 +4851,44 @@ class WasmGCTests: XCTestCase { try refNullAbstractTypes(sharedRef: false) } + func testRefEq() 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: true)}[0] + + let module = b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmEqRef(), .wasmEqRef()] => [.wasmi32]) { function, label, args in + return [function.wasmRefEq(args[0], args[1])] + } + wasmModule.addWasmFunction(with: [] => [.wasmEqRef()]) { function, label, args in + 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) From 00086f688fe42450174e4e517e9ba4989544b06e Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Mon, 19 Jan 2026 09:06:09 +0000 Subject: [PATCH 073/234] Actually emit variables for unused expressions. Seems like the previous change didn't do that because configuration objects never got this boolean. Bug: 422361840 Change-Id: I9a4fd2af616b7dd5dd27126fe10004374a41992a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8940976 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/FuzzilliCli/main.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 89c2e87e9..08be33264 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -547,7 +547,8 @@ let mainConfig = Configuration(arguments: CommandLine.arguments, staticCorpus: staticCorpus, tag: tag, isWasmEnabled: enableWasm, - storagePath: storagePath) + storagePath: storagePath, + forDifferentialFuzzing: forDifferentialFuzzing) let fuzzer = makeFuzzer(with: mainConfig) @@ -699,7 +700,8 @@ let workerConfig = Configuration(arguments: CommandLine.arguments, staticCorpus: staticCorpus, tag: tag, isWasmEnabled: enableWasm, - storagePath: storagePath) + storagePath: storagePath, + forDifferentialFuzzing: forDifferentialFuzzing) for _ in 1.. Date: Mon, 19 Jan 2026 12:26:06 +0000 Subject: [PATCH 074/234] [dumpling] Implement differential fuzzing Bug: 441467877 Change-Id: I7278380605e40ca79b4dc889cb8b6734aa7c4327 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8908076 Reviewed-by: Matthias Liedtke Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/Base/Contributor.swift | 16 ++- Sources/Fuzzilli/Base/Events.swift | 14 +++ Sources/Fuzzilli/Configuration.swift | 38 +++++- Sources/Fuzzilli/Engines/FuzzEngine.swift | 4 + Sources/Fuzzilli/Engines/HybridEngine.swift | 3 + .../Evaluation/ProgramCoverageEvaluator.swift | 4 +- Sources/Fuzzilli/Execution/Execution.swift | 67 +++++++++++ Sources/Fuzzilli/Fuzzer.swift | 86 ++++++++++++- Sources/Fuzzilli/Modules/Storage.swift | 16 +++ .../Mutators/RuntimeAssistedMutator.swift | 4 +- Sources/Fuzzilli/Util/MockFuzzer.swift | 1 + .../FuzzilliCli/Profiles/DuktapeProfile.swift | 2 + Sources/FuzzilliCli/Profiles/JSCProfile.swift | 2 + .../Profiles/JerryscriptProfile.swift | 2 + Sources/FuzzilliCli/Profiles/NjsProfile.swift | 2 + Sources/FuzzilliCli/Profiles/Profile.swift | 7 ++ Sources/FuzzilliCli/Profiles/QjsProfile.swift | 2 + .../FuzzilliCli/Profiles/QtjsProfile.swift | 2 + Sources/FuzzilliCli/Profiles/Serenity.swift | 1 + .../Profiles/SpidermonkeyProfile.swift | 2 + .../Profiles/V8DumplingProfile.swift | 113 ++++++++++++++++++ .../Profiles/V8HoleFuzzingProfile.swift | 2 + Sources/FuzzilliCli/Profiles/V8Profile.swift | 2 + .../Profiles/V8SandboxProfile.swift | 2 + Sources/FuzzilliCli/Profiles/XSProfile.swift | 2 + Sources/FuzzilliCli/main.swift | 41 +++++-- 26 files changed, 423 insertions(+), 14 deletions(-) create mode 100644 Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift diff --git a/Sources/Fuzzilli/Base/Contributor.swift b/Sources/Fuzzilli/Base/Contributor.swift index c0e23bd2f..87b668464 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,12 @@ 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 +161,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..84a6832ec 100644 --- a/Sources/Fuzzilli/Base/Events.swift +++ b/Sources/Fuzzilli/Base/Events.swift @@ -55,6 +55,9 @@ 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)>() + /// 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() @@ -140,4 +143,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/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 121e9cbb8..28c7eaad4 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] @@ -91,7 +120,9 @@ public struct Configuration { tag: String? = nil, isWasmEnabled: Bool = false, storagePath: String? = nil, - forDifferentialFuzzing: Bool = false) { + forDifferentialFuzzing: Bool = false, + instanceId: Int = -1, + dumplingEnabled: Bool = false) { self.arguments = arguments self.timeout = timeout self.logLevel = logLevel @@ -106,6 +137,11 @@ public struct Configuration { self.isWasmEnabled = isWasmEnabled self.storagePath = storagePath 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/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift index 815caad30..1a8602312 100644 --- a/Sources/Fuzzilli/Engines/FuzzEngine.swift +++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift @@ -44,6 +44,10 @@ public class FuzzEngine: ComponentBase { 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 diff --git a/Sources/Fuzzilli/Engines/HybridEngine.swift b/Sources/Fuzzilli/Engines/HybridEngine.swift index b59aa1ed4..214ff67cb 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" @@ -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/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift index c365ff1ef..ed17d6d43 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift @@ -192,8 +192,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 } diff --git a/Sources/Fuzzilli/Execution/Execution.swift b/Sources/Fuzzilli/Execution/Execution.swift index 5d23c70a2..9297ef296 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,54 @@ 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/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 3a7f9f605..51aa6a308 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -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 @@ -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 @@ -175,7 +182,7 @@ 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, referenceScriptRunner: ScriptRunner?, engine: FuzzEngine, mutators: WeightedList, codeGenerators: WeightedList, programTemplates: WeightedList, evaluator: ProgramEvaluator, environment: JavaScriptEnvironment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, queue: DispatchQueue? = nil ) { @@ -196,6 +203,7 @@ 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) @@ -265,6 +273,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) @@ -465,6 +476,8 @@ 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.stdout, origin: origin) case .succeeded: if let aspects = evaluator.evaluate(execution) { @@ -700,6 +713,10 @@ 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 } @@ -815,6 +832,42 @@ public class Fuzzer { } } + /// 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) + } + } + /// Constructs a new ProgramBuilder using this fuzzing context. public func makeBuilder(forMutating parent: Program? = nil) -> ProgramBuilder { dispatchPrecondition(condition: .onQueue(queue)) @@ -1063,6 +1116,35 @@ 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) + + return DiffExecution.diff(optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, unoptDumpOut: unoptimizedDump) + + } 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] @@ -1124,7 +1206,7 @@ public class Fuzzer { numberOfProgramsRequiringWasmButDisabled += 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/Modules/Storage.swift b/Sources/Fuzzilli/Modules/Storage.swift index 9c9860d57..72c5ad49f 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 @@ -52,6 +58,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 { @@ -59,6 +66,10 @@ public class Storage: Module { 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?") } @@ -95,6 +106,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) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index a99c33f21..baad473fa 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -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. @@ -386,7 +388,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/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift index 2f9558208..bd524bcf2 100644 --- a/Sources/Fuzzilli/Util/MockFuzzer.swift +++ b/Sources/Fuzzilli/Util/MockFuzzer.swift @@ -129,6 +129,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // Construct the fuzzer instance. let fuzzer = Fuzzer(configuration: configuration, scriptRunner: runner, + referenceScriptRunner: nil, engine: engine, mutators: mutators, codeGenerators: codeGenerators, diff --git a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift b/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift index 001ce27a8..bdc685193 100644 --- a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift +++ b/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift @@ -19,6 +19,8 @@ let duktapeProfile = Profile( ["--reprl"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/JSCProfile.swift b/Sources/FuzzilliCli/Profiles/JSCProfile.swift index d79b85360..23305fc90 100644 --- a/Sources/FuzzilliCli/Profiles/JSCProfile.swift +++ b/Sources/FuzzilliCli/Profiles/JSCProfile.swift @@ -69,6 +69,8 @@ let jscProfile = Profile( return args }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift b/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift index acc18406d..427a3eea5 100644 --- a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift +++ b/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift @@ -19,6 +19,8 @@ let jerryscriptProfile = Profile( ["--reprl-fuzzilli"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/NjsProfile.swift b/Sources/FuzzilliCli/Profiles/NjsProfile.swift index 040ef711d..b286196ef 100644 --- a/Sources/FuzzilliCli/Profiles/NjsProfile.swift +++ b/Sources/FuzzilliCli/Profiles/NjsProfile.swift @@ -19,6 +19,8 @@ let njsProfile = Profile( ["fuzz"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/Profile.swift b/Sources/FuzzilliCli/Profiles/Profile.swift index 0947d9559..8d9d7dcd5 100644 --- a/Sources/FuzzilliCli/Profiles/Profile.swift +++ b/Sources/FuzzilliCli/Profiles/Profile.swift @@ -16,6 +16,8 @@ import Fuzzilli struct Profile { let processArgs: (_ randomize: Bool) -> [String] + // if not nil, then this is profile for differential fuzzing + let processArgsReference: [String]? let processEnv: [String : String] let maxExecsBeforeRespawn: Int // Timeout either by value or interval in milliseconds. @@ -39,6 +41,10 @@ struct Profile { // An optional post-processor that is executed for every sample generated for fuzzing and can modify it. let optionalPostProcessor: FuzzingPostProcessor? + + var isDifferential: Bool { + return processArgsReference != nil + } } let profiles = [ @@ -48,6 +54,7 @@ let profiles = [ "spidermonkey": spidermonkeyProfile, "v8": v8Profile, "v8Sandbox": v8SandboxProfile, + "v8Dumpling": v8DumplingProfile, "duktape": duktapeProfile, "jerryscript": jerryscriptProfile, "xs": xsProfile, diff --git a/Sources/FuzzilliCli/Profiles/QjsProfile.swift b/Sources/FuzzilliCli/Profiles/QjsProfile.swift index aa521f001..dae0ee932 100644 --- a/Sources/FuzzilliCli/Profiles/QjsProfile.swift +++ b/Sources/FuzzilliCli/Profiles/QjsProfile.swift @@ -19,6 +19,8 @@ let qjsProfile = Profile( ["--reprl"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift b/Sources/FuzzilliCli/Profiles/QtjsProfile.swift index c536f529b..656a5022c 100644 --- a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift +++ b/Sources/FuzzilliCli/Profiles/QtjsProfile.swift @@ -27,6 +27,8 @@ let qtjsProfile = Profile( ["-reprl"] }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/Serenity.swift b/Sources/FuzzilliCli/Profiles/Serenity.swift index 496e833b9..e98f41fd5 100644 --- a/Sources/FuzzilliCli/Profiles/Serenity.swift +++ b/Sources/FuzzilliCli/Profiles/Serenity.swift @@ -16,6 +16,7 @@ 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", diff --git a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift b/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift index ec131d243..46dc022b8 100644 --- a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift +++ b/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift @@ -70,6 +70,8 @@ let spidermonkeyProfile = Profile( return args }, + processArgsReference: nil, + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift new file mode 100644 index 000000000..0abcb0cf7 --- /dev/null +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -0,0 +1,113 @@ +// 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 Fuzzilli + +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", + "--turbofan-dumping-print-deopt-frames" + ] + + 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: """ + """, + + codeSuffix: """ + """, + + ecmaVersion: ECMAScriptVersion.es6, + + startupTests: [ + + ], + + additionalCodeGenerators: [ + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 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: nil +) diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift index c7c72aa09..218ea99fe 100644 --- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift @@ -36,6 +36,8 @@ let v8HoleFuzzingProfile = Profile( return args }, + processArgsReference: nil, + processEnv: [:], maxExecsBeforeRespawn: 1000, diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 3d3e60bf2..9f0c47588 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -19,6 +19,8 @@ let v8Profile = Profile( 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: [:], diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index dce89be75..9a171dfd6 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -100,6 +100,8 @@ let v8SandboxProfile = Profile( v8ProcessArgs(randomize: randomize, forSandbox: true) }, + processArgsReference: nil, + // ASan options. // - abort_on_error=true: We need asan to exit in a way that's detectable for Fuzzilli as a crash // - handle_sigill=true: It seems by default ASAN doesn't handle SIGILL, but we want that to have stack traces diff --git a/Sources/FuzzilliCli/Profiles/XSProfile.swift b/Sources/FuzzilliCli/Profiles/XSProfile.swift index 1cb64c0f1..3de2abb17 100644 --- a/Sources/FuzzilliCli/Profiles/XSProfile.swift +++ b/Sources/FuzzilliCli/Profiles/XSProfile.swift @@ -290,6 +290,8 @@ let xsProfile = Profile( ["-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", diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 08be33264..f49dde3b6 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -328,6 +328,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") @@ -408,8 +412,26 @@ let jsShellArguments = profile.processArgs(argumentRandomization) + additionalAr 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) + 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) @@ -525,6 +547,7 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { // Construct the fuzzer instance. return Fuzzer(configuration: configuration, scriptRunner: runner, + referenceScriptRunner: referenceRunner, engine: engine, mutators: mutators, codeGenerators: codeGenerators, @@ -548,7 +571,9 @@ let mainConfig = Configuration(arguments: CommandLine.arguments, tag: tag, isWasmEnabled: enableWasm, storagePath: storagePath, - forDifferentialFuzzing: forDifferentialFuzzing) + forDifferentialFuzzing: forDifferentialFuzzing, + instanceId: 0, + dumplingEnabled: profile.isDifferential) let fuzzer = makeFuzzer(with: mainConfig) @@ -688,9 +713,10 @@ 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, +for i in 1.. Date: Tue, 13 Jan 2026 12:21:01 +0100 Subject: [PATCH 075/234] [wasm] Prepare WasmThrow to use wasm-gc types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By removing the types from the WasmThrow, this prepares Fuzzilli to adapt the tags as a next step to use wasm-gc signatures instead of static parameter types (there might be more dependencies for that). Bug: 445356784 Change-Id: I852a84efd928ed593bbb84105a95ab7a09cde9a7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926696 Commit-Queue: Matthias Liedtke Reviewed-by: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 ++++------ Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 6 ++---- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 +++---------------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 5 files changed, 10 insertions(+), 28 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 0322618a1..28aa9d0c9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4115,7 +4115,7 @@ public class ProgramBuilder { 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) { diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index bb3d4b0f6..2b3fcb2eb 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1437,10 +1437,8 @@ extension Instruction: ProtobufConvertible { $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) - } + case .wasmThrow(_): + $0.wasmThrow = Fuzzilli_Protobuf_WasmThrow() case .wasmThrowRef(_): $0.wasmThrowRef = Fuzzilli_Protobuf_WasmThrowRef() case .wasmRethrow(_): @@ -2488,8 +2486,8 @@ extension Instruction: ProtobufConvertible { op = WasmBeginTryDelegate(with: parameters => outputs) case .wasmEndTryDelegate(let p): op = WasmEndTryDelegate(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) - case .wasmThrow(let p): - op = WasmThrow(parameterTypes: p.parameterTypes.map(WasmTypeEnumToILType)) + case .wasmThrow(_): + op = WasmThrow(parameterCount: inouts.count - 1) case .wasmThrowRef(_): op = WasmThrowRef() case .wasmRethrow(_): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index dfe1fd6f1..469ea073a 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1467,12 +1467,10 @@ final class WasmEndTryDelegate: WasmOperation { 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]) } } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index a6011ecc8..64b1fbb19 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5301,8 +5301,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() {} @@ -14054,29 +14052,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index f761715e1..8398460e6 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1298,7 +1298,6 @@ message WasmEndTryDelegate { } message WasmThrow { - repeated WasmILType parameterTypes = 1; } message WasmThrowRef { From 66f0b84c97e654dc4626e62fcd215efe670e498e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 12:33:12 +0100 Subject: [PATCH 076/234] [wasm] Remove parameterTypes from WasmBranch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: I960d64621c3faac93083b44935382a05dee93d84 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926697 Commit-Queue: Matthias Liedtke Reviewed-by: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 ++++------ Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 9 ++++----- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 +++---------------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 6 files changed, 13 insertions(+), 30 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 28aa9d0c9..5d64d2872 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3954,7 +3954,7 @@ public class ProgramBuilder { 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) { diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 2b3fcb2eb..aca5175b8 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1447,10 +1447,8 @@ extension Instruction: ProtobufConvertible { $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 .wasmBranch(_): + $0.wasmBranch = Fuzzilli_Protobuf_WasmBranch() case .wasmBranchIf(let op): $0.wasmBranchIf = Fuzzilli_Protobuf_WasmBranchIf.with { $0.parameters = op.labelTypes.map(ILTypeToWasmTypeEnum) @@ -2494,8 +2492,8 @@ extension Instruction: ProtobufConvertible { 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 .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)) case .wasmBranchTable(let p): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 469ea073a..7ce96b954 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1494,13 +1494,12 @@ 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 { diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index d3cbe2635..8c81feaa6 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1957,7 +1957,7 @@ 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)) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 64b1fbb19..4f3d7604b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5343,8 +5343,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() {} @@ -14139,29 +14137,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 8398460e6..19154bdbc 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1311,7 +1311,6 @@ message WasmDefineTag { } message WasmBranch { - repeated WasmILType parameters = 1; } enum WasmBranchHint { From 9cc25ac6452c452c0ceafe641bf393a653c739f6 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 12:42:09 +0100 Subject: [PATCH 077/234] [wasm] Remove paramterTypes from WasmBranchIf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: I5d827c480f633e4efe565ac139f91c4fb5e04e79 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926698 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 +++- Sources/Fuzzilli/FuzzIL/Instruction.swift | 3 +-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 8 ++++---- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- Sources/Fuzzilli/Mutators/OperationMutator.swift | 2 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 9 +-------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 7 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 5d64d2872..3a535ae1e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3961,7 +3961,9 @@ public class ProgramBuilder { 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]) { diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index aca5175b8..fde29d97b 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1451,7 +1451,6 @@ extension Instruction: ProtobufConvertible { $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): @@ -2495,7 +2494,7 @@ extension Instruction: ProtobufConvertible { 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)) case .wasmBeginIf(let p): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 7ce96b954..525af229d 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1504,15 +1504,15 @@ final class WasmBranch: WasmOperation { 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 { diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 8c81feaa6..6012ccab0 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1961,7 +1961,7 @@ public class WasmLifter { 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)) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index cefbf9d92..4ebe42be3 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -497,7 +497,7 @@ public class OperationMutator: BaseInstructionMutator { : Int64.random(in: Int64.min...Int64.max) // most likely out of bounds newOp = WasmSimdLoad(kind: kind, staticOffset: staticOffset) case .wasmBranchIf(let op): - newOp = WasmBranchIf(labelTypes: op.labelTypes, hint: chooseUniform(from: WasmBranchHint.allCases)) + newOp = WasmBranchIf(parameterCount: op.parameterCount, hint: chooseUniform(from: WasmBranchHint.allCases)) case .wasmBeginIf(let op): newOp = WasmBeginIf(parameterCount: op.parameterCount, hint: chooseUniform(from: WasmBranchHint.allCases), inverted: Bool.random()) case .wasmArrayGet(let op): diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 4f3d7604b..92b565f79 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5353,8 +5353,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() @@ -14156,7 +14154,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() { @@ -14164,7 +14162,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 } @@ -14172,9 +14169,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) } @@ -14182,7 +14176,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 diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 19154bdbc..52397695e 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1320,7 +1320,6 @@ enum WasmBranchHint { } message WasmBranchIf { - repeated WasmILType parameters = 1; WasmBranchHint hint = 2; } From d53f176a3d5ef1c8bba3a2281fae0d60a7ffb020 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 13:42:42 +0100 Subject: [PATCH 078/234] [wasm] Remove parameter types from wasmBranchTable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: Ia1a6b4606ba85e5c6f0093cc8c43cc4726a7b907 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926699 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 7 ++----- Sources/Fuzzilli/FuzzIL/Instruction.swift | 3 +-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 9 +++++---- Sources/Fuzzilli/Protobuf/operations.pb.swift | 9 +-------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 3a535ae1e..94a0a0039 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3967,11 +3967,8 @@ public class ProgramBuilder { } 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]) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index fde29d97b..22b3c7c97 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1455,7 +1455,6 @@ extension Instruction: ProtobufConvertible { } 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): @@ -2496,7 +2495,7 @@ extension Instruction: ProtobufConvertible { case .wasmBranchIf(let p): 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): op = WasmBeginIf(parameterCount: Int(p.parameterCount), hint: try convertEnum(p.hint, WasmBranchHint.allCases), inverted: p.inverted) case .wasmBeginElse(let p): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 525af229d..d3112ac60 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1517,16 +1517,17 @@ final class WasmBranchIf: WasmOperation { 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. diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 92b565f79..ffbb23a80 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5365,8 +5365,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() @@ -14184,7 +14182,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() { @@ -14192,7 +14190,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 } @@ -14200,9 +14197,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) } @@ -14210,7 +14204,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 diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 52397695e..83d5f156b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1324,7 +1324,6 @@ message WasmBranchIf { } message WasmBranchTable { - repeated WasmILType parameters = 1; uint32 valueCount = 2; } From 39b3f84825a71a9e7f90c6dea1652daba7d2bc00 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 14:21:12 +0100 Subject: [PATCH 079/234] [wasm] Remove parameter types from wasmReassign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: If6049b20eb2a77ce27c04412f571af7626b4216b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926700 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 +-- Sources/Fuzzilli/FuzzIL/Instruction.swift | 8 ++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 5 +-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 32 ++----------------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 6 files changed, 11 insertions(+), 41 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 94a0a0039..f9d300212 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3906,8 +3906,8 @@ public class ProgramBuilder { } 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]) + assert(b.type(of: to).Is(b.type(of: variable))) + b.emit(WasmReassign(), withInputs: [variable, to]) } public enum wasmBlockType { diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 22b3c7c97..cbd060da5 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1234,8 +1234,8 @@ extension Instruction: ProtobufConvertible { case .wasmTruncateSatf64Toi64(let op): $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 @@ -2369,8 +2369,8 @@ 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) case .wasmDefineTable(let p): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index d3112ac60..94fd8e67e 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1535,10 +1535,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]) } } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 6012ccab0..b5b32b646 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1980,7 +1980,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)) { diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index ffbb23a80..c6d2e9321 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5377,20 +5377,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 { @@ -14212,33 +14201,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 83d5f156b..d7e6b28c6 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1328,7 +1328,6 @@ message WasmBranchTable { } message WasmReassign { - WasmILType variableType = 1; } message WasmBeginIf { From d9c265b6f8176a08d1a51f18f01deda1af3d510d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 13 Jan 2026 15:05:44 +0100 Subject: [PATCH 080/234] [wasm] Remove return types from wasmReturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: Ia9ced154e6f1ce465c257e0e17c53782ec13f442 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8926836 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 7 +++---- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 ++++------ Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 6 ++---- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 +++---------------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 5 files changed, 12 insertions(+), 31 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index f9d300212..c21a0d402 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4203,17 +4203,16 @@ public class ProgramBuilder { } 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 diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index cbd060da5..ccc76a04c 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1127,10 +1127,8 @@ 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) @@ -2279,8 +2277,8 @@ 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) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 94fd8e67e..5db0e28c3 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -74,11 +74,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]) } } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index c6d2e9321..38f5660b6 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4122,8 +4122,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() {} @@ -11529,29 +11527,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index d7e6b28c6..98beea01d 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -884,7 +884,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. From 226938a27cb4ac261fdae1bd7ae68cc6f7ac1d6f Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 14 Jan 2026 14:56:34 +0100 Subject: [PATCH 081/234] [wasm] Remove parameter and return types from WasmCallDirect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 445356784 Change-Id: Idbe0b038ecd47b371639219edababaf7e33d1054 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8929536 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 8 +++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 +++-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 8 +++---- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 8 +++---- Sources/Fuzzilli/Protobuf/operations.pb.swift | 22 +++++++++---------- Sources/Fuzzilli/Protobuf/operations.proto | 4 ++-- 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index c21a0d402..1f12d1bae 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3766,7 +3766,7 @@ public class ProgramBuilder { @discardableResult public func wasmCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) -> [Variable] { - return Array(b.emit(WasmCallDirect(signature: signature), + return Array(b.emit(WasmCallDirect(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), withInputs: [function] + functionArgs, types: [.wasmFunctionDef(signature)] + signature.parameterTypes ).outputs) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ccc76a04c..6a7cec37a 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1313,8 +1313,8 @@ 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 { @@ -2408,9 +2408,7 @@ extension Instruction: ProtobufConvertible { 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) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index eeff27465..0b48a7bf7 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -878,8 +878,9 @@ public struct JSTyper: Analyzer { 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 .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. diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 5db0e28c3..5b792bc7c 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -963,12 +963,12 @@ final class WasmCallIndirect: WasmOperation { 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 { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 8fbb32fb6..c86becf21 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1064,13 +1064,13 @@ public class FuzzILLifter: Lifter { w.emit("\(outputs) <- WasmCallIndirect(\(op.signature)) \(inputs)") } - case .wasmCallDirect(let op): + case .wasmCallDirect(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - if op.signature.outputTypes.isEmpty { - w.emit("WasmCallDirect(\(op.signature)) \(inputs)") + if instr.outputs.isEmpty { + w.emit("WasmCallDirect \(inputs)") } else { let outputs = instr.outputs.map(lift).joined(separator: ", ") - w.emit("\(outputs) <- WasmCallDirect(\(op.signature)) \(inputs)") + w.emit("\(outputs) <- WasmCallDirect \(inputs)") } case .wasmReturnCallDirect(let op): diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 38f5660b6..d9bb295f0 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5045,9 +5045,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() @@ -13405,7 +13405,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() { @@ -13413,26 +13413,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 98beea01d..4968018e3 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1173,8 +1173,8 @@ message WasmCallIndirect { } message WasmCallDirect { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; + int32 outputCount = 2; } message WasmReturnCallDirect { From 411f1dcc96abc4b219c2287bf84c6132c3defc42 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 20 Jan 2026 16:14:43 +0100 Subject: [PATCH 082/234] [wasm] Deduplicate WasmLegacyTryCatchWithResultGenerator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of them should be enough. :) Bug: 445356784 Change-Id: Ib0f215bcd41c2801d2b5d43c6255b17a5d979dd2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8944236 Auto-Submit: Matthias Liedtke Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index ee8abfc22..1a724a3a1 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1381,40 +1381,6 @@ public let WasmCodeGenerators: [CodeGenerator] = [ } }, - 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) - }, - catchClauses: tags.enumerated().map { i, tag in - ( - tag, - { _, _, _ in - b.buildRecursive(n: 4) - return outputTypes.map(function.findOrGenerateWasmVar) - } - ) - }, - 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) From 951080adca25d954c668a85c7df3745ea2ecc664 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Wed, 21 Jan 2026 18:15:33 +0100 Subject: [PATCH 083/234] Whitespace change to test builders Bug: 442444727 Change-Id: I4639df028436c02f59a26e12e3930bee209ab506 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8949196 Bot-Commit: Rubber Stamper --- WHITESPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WHITESPACE b/WHITESPACE index 657b7d229..18c219b08 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. From 93b589914dde4b5e4a1bf7cb7d2b7c6862342ceb Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 22 Jan 2026 12:37:57 +0100 Subject: [PATCH 084/234] Whitespace change to test builders Bug: 442444727 Change-Id: I77dc4619f6eba65bf7417fbb36609eb42993121c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8952396 Bot-Commit: Rubber Stamper --- WHITESPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WHITESPACE b/WHITESPACE index 18c219b08..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. From 65c0f459e106208df635d30c984b061b00e794ee Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 22 Jan 2026 09:58:36 +0000 Subject: [PATCH 085/234] [dumpling] Delete patch file. Main functionality was merged into codebase by now. Bug: 441467877 Change-Id: Ibcd2c7873188e52cf0db0dcdfacf8150ee694107 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8947917 Commit-Queue: Dominik Klemba Reviewed-by: Dominik Klemba Commit-Queue: Danylo Mocherniuk --- Sources/Dumpling/dumpling_fuzzilli.patch | 13010 --------------------- 1 file changed, 13010 deletions(-) delete mode 100644 Sources/Dumpling/dumpling_fuzzilli.patch 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}; From 7e668c9db862eab62b85fb59e792f2e650f2a983 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 26 Jan 2026 14:38:14 +0100 Subject: [PATCH 086/234] [github] Also test the Compiler/Parser functionality Change-Id: I947059c23b71448a97b58a3f36f79f8fef0b8ff7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956180 Commit-Queue: Danylo Mocherniuk Auto-Submit: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .github/workflows/swift.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 19f5536db..951fa3872 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -35,6 +35,9 @@ jobs: # 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 + - 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 From debc47a3f6808a18aebe17d01c8e7cb29cd42fe0 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 26 Jan 2026 17:11:34 +0100 Subject: [PATCH 087/234] Fix assertion in InliningReducer for explicit resource management This fixes https://github.com/googleprojectzero/fuzzilli/issues/545 (by just doing the same for the other kinds of disposable variables that we already do for `loadDisposableVariable`) Change-Id: I11ddb6323124deb7f99dbf110fee214be62b33a9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956877 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Minimization/InliningReducer.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index c9555538d..9704f81d9 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -118,7 +118,10 @@ struct InliningReducer: Reducer { // Can't inline functions that are passed as arguments to other functions. deleteCandidates(instr.inputs.dropFirst()) - case .loadDisposableVariable: + case .loadDisposableVariable, + .createNamedDisposableVariable, + .loadAsyncDisposableVariable, + .createNamedAsyncDisposableVariable: // Can't inline functions that are also used as a disposable variable. deleteCandidates(instr.inputs) fallthrough From 948c97b9e4d420c51f100a861cff87a6ff23461c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= Date: Mon, 26 Jan 2026 15:09:58 +0100 Subject: [PATCH 088/234] Add immutable ArrayBuffer support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 450237486 Change-Id: I30de85f87ca170a998fc17a72e15c4579db37774 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8901996 Auto-Submit: Olivier Flückiger Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../Fuzzilli/Environment/JavaScriptEnvironment.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 921e07878..595e5f985 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1063,7 +1063,7 @@ public extension ILType { static let jsFinalizationRegistry = ILType.object(ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) /// Type of a JavaScript ArrayBuffer object. - static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "transfer"]) + static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "transfer", "transferToFixedLength", "transferToImmutable"]) /// Type of a JavaScript SharedArrayBuffer object. static let jsSharedArrayBuffer = ILType.object(ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], withMethods: ["grow", "slice"]) @@ -1665,9 +1665,11 @@ public extension ObjectGroup { "resizable" : .boolean, ], methods: [ - "resize" : [.integer] => .undefined, - "slice" : [.integer, .opt(.integer)] => .jsArrayBuffer, - "transfer" : [.opt(.integer)] => .jsArrayBuffer, + "resize" : [.integer] => .undefined, + "slice" : [.integer, .opt(.integer)] => .jsArrayBuffer, + "transfer" : [.opt(.integer)] => .jsArrayBuffer, + "transferToFixedLength" : [.opt(.integer)] => .jsArrayBuffer, + "transferToImmutable" : [] => .jsArrayBuffer, ] ) From 4ac378c3c06376b9c7e798fdddc228620a03c1b0 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 26 Jan 2026 14:19:40 +0100 Subject: [PATCH 089/234] [parser] Support rest parameters on transpiling JS -> FuzzIL This fixes https://github.com/googleprojectzero/fuzzilli/issues/546 Change-Id: I8331dd909c05a51bfe73749e8677b18501e261bd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956179 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Compiler.swift | 24 +-- Sources/Fuzzilli/Compiler/Parser/parser.js | 17 +- Sources/Fuzzilli/Protobuf/ast.pb.swift | 183 ++++++++++++++---- Sources/Fuzzilli/Protobuf/ast.proto | 17 +- Tests/FuzzilliTests/CompilerTests.swift | 4 +- .../CompilerTests/rest_parameter.js | 28 +++ 6 files changed, 213 insertions(+), 60 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/rest_parameter.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 21264dc68..09999ce35 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -238,7 +238,8 @@ public class JavaScriptCompiler { 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) } @@ -511,7 +512,7 @@ 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){ emit(LoopBreak()) @@ -565,14 +566,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 +590,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()) } @@ -896,7 +897,8 @@ public class JavaScriptCompiler { try enterNewScope { var parameters = instr.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) } @@ -1251,15 +1253,15 @@ 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 convertParameters(_ parameters: Compiler_Protobuf_Parameters) -> Parameters { + return Parameters(count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) } /// Convenience accessor for the currently active scope. diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 9d31b61a1..372af3fbc 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -84,13 +84,22 @@ 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 '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) { diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index da0503c8f..92ba974ad 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -252,6 +252,20 @@ public struct Compiler_Protobuf_DisposableVariableDeclaration: Sendable { public init() {} } +public struct Compiler_Protobuf_Parameters: 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: [Compiler_Protobuf_Parameter] = [] + + public var hasRestElement_p: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Compiler_Protobuf_FunctionDeclaration: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -261,13 +275,22 @@ public struct Compiler_Protobuf_FunctionDeclaration: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain - public var parameters: [Compiler_Protobuf_Parameter] = [] + public var parameters: Compiler_Protobuf_Parameters { + get {return _parameters ?? Compiler_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 body: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } public struct Compiler_Protobuf_PropertyKey: Sendable { @@ -358,13 +381,22 @@ public struct Compiler_Protobuf_ClassConstructor: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameters: [Compiler_Protobuf_Parameter] = [] + public var parameters: Compiler_Protobuf_Parameters { + get {return _parameters ?? Compiler_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 body: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } public struct Compiler_Protobuf_ClassMethod: Sendable { @@ -383,7 +415,14 @@ public struct Compiler_Protobuf_ClassMethod: Sendable { public var isStatic: Bool = false - public var parameters: [Compiler_Protobuf_Parameter] = [] + public var parameters: Compiler_Protobuf_Parameters { + get {return _parameters ?? Compiler_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 body: [Compiler_Protobuf_Statement] = [] @@ -392,6 +431,7 @@ public struct Compiler_Protobuf_ClassMethod: Sendable { public init() {} fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil + fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } public struct Compiler_Protobuf_ClassGetter: Sendable { @@ -1516,7 +1556,14 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain - public var parameters: [Compiler_Protobuf_Parameter] = [] + public var parameters: Compiler_Protobuf_Parameters { + get {return _parameters ?? Compiler_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 body: [Compiler_Protobuf_Statement] = [] @@ -1529,6 +1576,8 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { } public init() {} + + fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } public struct Compiler_Protobuf_ObjectGetter: Sendable { @@ -1701,13 +1750,22 @@ public struct Compiler_Protobuf_FunctionExpression: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain - public var parameters: [Compiler_Protobuf_Parameter] = [] + public var parameters: Compiler_Protobuf_Parameters { + get {return _parameters ?? Compiler_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 body: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } public struct Compiler_Protobuf_ArrowFunctionExpression: @unchecked Sendable { @@ -1720,10 +1778,14 @@ public struct Compiler_Protobuf_ArrowFunctionExpression: @unchecked Sendable { set {_uniqueStorage()._type = newValue} } - public var parameters: [Compiler_Protobuf_Parameter] { - get {return _storage._parameters} + public var parameters: Compiler_Protobuf_Parameters { + get {return _storage._parameters ?? Compiler_Protobuf_Parameters()} set {_uniqueStorage()._parameters = newValue} } + /// Returns true if `parameters` has been explicitly set. + public var hasParameters: Bool {return _storage._parameters != nil} + /// Clears the value of `parameters`. Subsequent reads from it will return its default value. + public mutating func clearParameters() {_uniqueStorage()._parameters = nil} /// The body can either be an expression or a block statement. public var body: OneOf_Body? { @@ -2716,6 +2778,41 @@ extension Compiler_Protobuf_DisposableVariableDeclaration: SwiftProtobuf.Message } } +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() { + // 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) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRestElement_p) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.parameters.isEmpty { + try visitor.visitRepeatedMessageField(value: self.parameters, fieldNumber: 1) + } + 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_Parameters, rhs: Compiler_Protobuf_Parameters) -> Bool { + if lhs.parameters != rhs.parameters {return false} + if lhs.hasRestElement_p != rhs.hasRestElement_p {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + 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") @@ -2728,7 +2825,7 @@ extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftPro 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 } @@ -2736,15 +2833,19 @@ extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftPro } 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) } @@ -2754,7 +2855,7 @@ extension Compiler_Protobuf_FunctionDeclaration: SwiftProtobuf.Message, SwiftPro 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._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -2889,7 +2990,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 } @@ -2897,9 +2998,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) } @@ -2907,7 +3012,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 @@ -2926,7 +3031,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 } @@ -2944,9 +3049,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) } @@ -2956,7 +3061,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 @@ -5378,7 +5483,7 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ } }() case 3: try { try decoder.decodeSingularEnumField(value: &self.type) }() - case 4: try { try decoder.decodeRepeatedMessageField(value: &self.parameters) }() + case 4: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() case 5: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } @@ -5404,9 +5509,9 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ 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 { if let v = self._parameters { + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + } }() if !self.body.isEmpty { try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 5) } @@ -5416,7 +5521,7 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ public static func ==(lhs: Compiler_Protobuf_ObjectMethod, rhs: Compiler_Protobuf_ObjectMethod) -> Bool { 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 @@ -5735,7 +5840,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 } @@ -5743,15 +5848,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) } @@ -5761,7 +5870,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 @@ -5774,7 +5883,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. @@ -5808,7 +5917,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 @@ -5850,9 +5959,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 3a4545cde..a3e0bffed 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -66,10 +66,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; } @@ -92,14 +97,14 @@ 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; } @@ -330,7 +335,7 @@ message ObjectMethod { Expression expression = 2; } FunctionType type = 3; - repeated Parameter parameters = 4; + Parameters parameters = 4; repeated Statement body = 5; } @@ -373,13 +378,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/Tests/FuzzilliTests/CompilerTests.swift b/Tests/FuzzilliTests/CompilerTests.swift index b8f017ad9..a45e52bd3 100644 --- a/Tests/FuzzilliTests/CompilerTests.swift +++ b/Tests/FuzzilliTests/CompilerTests.swift @@ -47,7 +47,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,7 +65,7 @@ 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 } 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)); From 4b76603435e81d9a9df1705dd457567bfb37d560 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Tue, 27 Jan 2026 15:25:42 +0000 Subject: [PATCH 090/234] Add Maglev assert types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the `--maglev-assert-types` flag to the list of possible flags, with a 10% probability. This flag is enabled only when sandbox-fuzzing is disabled. Change-Id: Ic710d8b6c185af79979b50bb991672e6e1563dd3 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8963977 Reviewed-by: Matthias Liedtke Commit-Queue: Dominik Klemba Reviewed-by: Michael Achenbach Reviewed-by: Marja Hölttä --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 620302af2..abb06961a 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -931,6 +931,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") } From 5b936a6243a151dba6e0d146e0565ccd16a6adf5 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Fri, 30 Jan 2026 13:47:14 +0000 Subject: [PATCH 091/234] [dumpling] Add differential statistics to logs. Had some logs about them, but removed them for review. Now it is time to add proper reporting. Bug:441467877 Change-Id: I03bf6a6ae447caa4bc3eae202709fb2976a017c0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8969557 Reviewed-by: Matthias Liedtke Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/Protobuf/sync.pb.swift | 15 ++++++++++++++- Sources/Fuzzilli/Protobuf/sync.proto | 3 +++ Sources/FuzzilliCli/TerminalUI.swift | 6 +++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift index 0c64d22da..d59ac9658 100644 --- a/Sources/Fuzzilli/Protobuf/sync.pb.swift +++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift @@ -177,6 +177,12 @@ public struct Fuzzilli_Protobuf_Statistics: @unchecked Sendable { set {_uniqueStorage()._timeoutRate = newValue} } + //// The number of programs resulting in valid differential produced. + public var differentialSamples: UInt64 { + get {return _storage._differentialSamples} + set {_uniqueStorage()._differentialSamples = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -275,7 +281,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 +301,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 +329,7 @@ extension Fuzzilli_Protobuf_Statistics: SwiftProtobuf.Message, SwiftProtobuf._Me _coverage = source._coverage _correctnessRate = source._correctnessRate _timeoutRate = source._timeoutRate + _differentialSamples = source._differentialSamples } } @@ -357,6 +365,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 +425,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 +454,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..39a18a115 100644 --- a/Sources/Fuzzilli/Protobuf/sync.proto +++ b/Sources/Fuzzilli/Protobuf/sync.proto @@ -82,4 +82,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/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift index 1bb5f1c84..c81343ab0 100644 --- a/Sources/FuzzilliCli/TerminalUI.swift +++ b/Sources/FuzzilliCli/TerminalUI.swift @@ -125,6 +125,10 @@ class TerminalUI { } else { print("Fuzzer Statistics") } + let differentialsLine = fuzzer.isDifferentialFuzzing + ? "\nDifferentials Found: \(stats.differentialSamples)" + : "" + print(""" ----------------- Fuzzer state: \(state) @@ -136,7 +140,7 @@ class TerminalUI { 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) + Crashes Found: \(stats.crashingSamples)\(differentialsLine) Timeouts Hit: \(stats.timedOutSamples) Coverage: \(String(format: "%.2f%%", stats.coverage * 100)) Avg. program size: \(String(format: "%.2f", stats.avgProgramSize)) From d3a70f9676270f20f5e376d69bf8cf1f02a1705e Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Fri, 30 Jan 2026 14:17:43 +0000 Subject: [PATCH 092/234] [dumpling] Now actually add differential count. Before we were printing 0 always. Bug: 441467877 Change-Id: Icacd9310f8cd845695d2a83e5eb297ce2e60882b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8977177 Reviewed-by: Matthias Liedtke Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/Modules/Statistics.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/Fuzzilli/Modules/Statistics.swift b/Sources/Fuzzilli/Modules/Statistics.swift index e974e7648..54ccfe84f 100644 --- a/Sources/Fuzzilli/Modules/Statistics.swift +++ b/Sources/Fuzzilli/Modules/Statistics.swift @@ -136,6 +136,9 @@ public class Statistics: Module { fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { _ in self.ownData.crashingSamples += 1 } + fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { _ in + self.ownData.differentialSamples += 1 + } fuzzer.registerEventListener(for: fuzzer.events.TimeOutFound) { _ in self.ownData.timedOutSamples += 1 self.correctnessRate.add(0.0) From 45507ee563d32146a86ab87216bd49df3bf19e49 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Fri, 30 Jan 2026 14:09:01 +0000 Subject: [PATCH 093/234] [dumpling] Print differential to console. Bug: 441467877 Change-Id: Id3793d3065384bfb2e190c626ed014782d9ebb63 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8977176 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- Sources/FuzzilliCli/TerminalUI.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift index c81343ab0..7d8682088 100644 --- a/Sources/FuzzilliCli/TerminalUI.swift +++ b/Sources/FuzzilliCli/TerminalUI.swift @@ -52,6 +52,13 @@ class TerminalUI { } } + fuzzer.registerEventListener(for: fuzzer.events.DifferentialFound) { differential in + if differential.isUnique { + print("########## Unique Differential Found ##########") + print(fuzzer.lifter.lift(differential.program, withOptions: .includeComments)) + } + } + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { crash in if crash.isUnique { print("########## Unique Crash Found ##########") From f75d3ed9f29dc662256e8469a6d90bd12fb4ff0f Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sat, 31 Jan 2026 14:53:40 +0000 Subject: [PATCH 094/234] Add more recent builtin additions (#544) Adds builtins from the following stage 4 proposals: - https://github.com/tc39/proposal-array-from-async - https://github.com/tc39/proposal-float16array - https://github.com/tc39/proposal-math-sum - https://github.com/tc39/proposal-promise-try - https://github.com/tc39/proposal-regex-escaping --- .../Environment/JavaScriptEnvironment.swift | 113 +++++++++++------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 595e5f985..05d76a2d0 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -21,7 +21,7 @@ public class JavaScriptEnvironment: ComponentBase { // TODO: use it in all places where it can be used. public static let typedArrayConstructors = [ "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", - "Uint32Array", "Int32Array", "Float32Array", "Float64Array", + "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array", ] @@ -345,7 +345,7 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsFinalizationRegistrys) 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(.jsUint8ArrayConstructor) @@ -360,6 +360,7 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsStringPrototype) registerObjectGroup(.jsSymbolConstructor) registerObjectGroup(.jsBigIntConstructor) + registerObjectGroup(.jsRegExpConstructor) registerObjectGroup(.jsBooleanConstructor) registerObjectGroup(.jsNumberConstructor) registerObjectGroup(.jsMathObject) @@ -581,7 +582,7 @@ public class JavaScriptEnvironment: ComponentBase { 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 ["Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { registerBuiltin(variant, ofType: .jsTypedArrayConstructor(variant)) } registerBuiltin("Uint8Array", ofType: .jsUint8ArrayConstructor) @@ -1069,7 +1070,7 @@ public extension ILType { 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"]) + static let jsDataView = ILType.object(ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], withMethods: ["getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", "getFloat32", "getFloat64", "getBigInt64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", "setFloat64", "setBigInt64"]) /// Type of a JavaScript TypedArray object of the given variant. static func jsTypedArray(_ variant: String) -> ILType { @@ -1090,7 +1091,7 @@ public extension ILType { 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"]) /// Type of the JavaScript Array constructor builtin. - static let jsArrayConstructor = .functionAndConstructor([.integer] => .jsArray) + .object(ofGroup: "ArrayConstructor", withProperties: ["prototype"], withMethods: ["from", "of", "isArray"]) + 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)) @@ -1111,7 +1112,7 @@ public extension ILType { 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) + static let jsRegExpConstructor = ILType.functionAndConstructor([.string] => .jsRegExp) + .object(ofGroup: "RegExpConstructor", withProperties: ["prototype"], withMethods: ["escape"]) /// Type of a JavaScript Error object of the given variant. static func jsError(_ variant: String) -> ILType { @@ -1120,6 +1121,7 @@ public extension ILType { /// Type of the JavaScript Error constructor builtin static func jsErrorConstructor(_ variant: String) -> ILType { + // TODO: Add `Error.isError()` return .functionAndConstructor([.opt(.string)] => .jsError(variant)) } @@ -1142,7 +1144,7 @@ public extension ILType { static let jsDataViewConstructor = ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) /// 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"]) + static let jsPromiseConstructor = ILType.constructor([.function()] => .jsPromise) + .object(ofGroup: "PromiseConstructor", withProperties: ["prototype"], withMethods: ["resolve", "reject", "all", "any", "race", "allSettled", "try"]) /// Type of the JavaScript Proxy constructor builtin. static let jsProxyConstructor = ILType.constructor([.object(), .object()] => .jsAnything) @@ -1166,7 +1168,7 @@ public extension ILType { static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) /// 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"]) + 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", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) /// 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"]) @@ -1773,6 +1775,7 @@ public extension ObjectGroup { "getUint16" : [.integer] => .integer, "getInt32" : [.integer] => .integer, "getUint32" : [.integer] => .integer, + "getFloat16" : [.integer] => .float, "getFloat32" : [.integer] => .float, "getFloat64" : [.integer] => .float, "getBigInt64": [.integer] => .bigint, @@ -1782,6 +1785,7 @@ public extension ObjectGroup { "setUint16" : [.integer, .integer] => .undefined, "setInt32" : [.integer, .integer] => .undefined, "setUint32" : [.integer, .integer] => .undefined, + "setFloat16" : [.integer, .float] => .undefined, "setFloat32" : [.integer, .float] => .undefined, "setFloat64" : [.integer, .float] => .undefined, "setBigInt64": [.integer, .bigint] => .undefined, @@ -1805,6 +1809,7 @@ public extension ObjectGroup { "any" : [.jsPromise...] => .jsPromise, "race" : [.jsPromise...] => .jsPromise, "allSettled" : [.jsPromise...] => .jsPromise, + "try" : [.function(), .jsAnything...] => .jsPromise, ] ) @@ -1922,9 +1927,10 @@ public extension ObjectGroup { "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, ] ) @@ -2013,6 +2019,19 @@ public extension ObjectGroup { ] ) + /// Object group modelling the JavaScript RegExp constructor builtin + static let jsRegExpConstructor = ObjectGroup( + name: "RegExpConstructor", + constructorPath: "RegExp", + instanceType: .jsRegExpConstructor, + properties: [ + "prototype" : .object() + ], + methods: [ + "escape" : [.string] => .jsString, + ] + ) + /// Object group modelling the JavaScript Boolean constructor builtin static let jsBooleanConstructor = ObjectGroup( name: "BooleanConstructor", @@ -2058,41 +2077,43 @@ public extension ObjectGroup { "PI" : .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...] => .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, + "sumPrecise" : [.jsAnything] => .number, + "tan" : [.jsAnything] => .number, + "tanh" : [.jsAnything] => .number, + "trunc" : [.jsAnything] => .number, ] ) From 0e686ca94616ce7f7c0d3af7b4a9850c44a9f52c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Sun, 1 Feb 2026 14:22:07 +0100 Subject: [PATCH 095/234] [dumpling] Remove invalid flag from profile Change-Id: I00ec85b51048e0bc9dc90f96610c293c5d7f3089 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8977237 Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach --- Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index 0abcb0cf7..f02190aec 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -32,7 +32,6 @@ let v8DumplingProfile = Profile( "--no-sparkplug", "--maglev-dumping", "--turbofan-dumping", - "--turbofan-dumping-print-deopt-frames" ] return args From b3b7a7135c7663ad4adced8a11c0937782aa404e Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Tue, 3 Feb 2026 13:29:02 +0000 Subject: [PATCH 096/234] [dumpling] fix frame skipping Interpreter dumping produces 1 frame at a single offset, for optimized compilers we might dump the same frame many times on a single offset, because there might be many deopt points on a single offset. Bug: 441467877 Change-Id: Iaff7dd987d9352d0b95c1c53ffd54ef0ae7e8f1d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8986716 Commit-Queue: Dominik Klemba Commit-Queue: Danylo Mocherniuk Reviewed-by: Dominik Klemba --- Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 74a988db3..fb845bd8d 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -221,8 +221,8 @@ public final class DiffOracle { print("]") return false } - // Remove all skipped frames and the found frame. - unoptFramesLeft = unoptFramesLeft[(unoptIndex + 1)...] + // Remove all skipped frames but keep the found frame, because we might have multiple deopt points on same offset. + unoptFramesLeft = unoptFramesLeft[unoptIndex...] } return true } From f38a5e1c08fb9e44f165337bbade7e220e49615c Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Wed, 4 Feb 2026 13:41:08 +0000 Subject: [PATCH 097/234] Add ConditionalThrowGenerator New generator is able to create two patterns (with 50/50 probability): 1) if(boolean_variable){throw random_variable;} 2) if(!boolean_variable){throw random_variable;} Bug: 455512155, 455513417 Change-Id: Ief3ddeef21653cdda3fd1fdd154c0d248dc77631 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8991196 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke Auto-Submit: Dominik Klemba --- Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 6d8698fc6..31d9c0059 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -186,6 +186,7 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "TryFinallyGenerator": 5, "ThrowGenerator": 1, + "ConditionalThrowGenerator": 1, "BlockStatementGenerator": 1, // Special generators diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 07943c72a..3a782fc36 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2596,6 +2596,14 @@ public let CodeGenerators: [CodeGenerator] = [ b.throwException(v) }, + CodeGenerator("ConditionalThrowGenerator", inputs: .preferred(.boolean)) { b, cond in + let v = b.randomJsVariable() + let condition = probability(0.5) ? cond : b.unary(.LogicalNot, cond) + b.buildIf(condition) { + b.throwException(v) + } + }, + // // Language-specific Generators // From a9a1a99f73c92a15ab2f4b873f767edb4c6cea7f Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Thu, 5 Feb 2026 16:13:21 +0000 Subject: [PATCH 098/234] Add HoleyArrayGenerator NOTE: `undefined` is lifted to holes in that case (which is unintuitive). Adds HoleyArrayGenerator to create arrays with holes. Adds testHoleyArrayLifting to verify intended lifting of holey arrays. Generated hole types (can be in dictionary mode): - Holey Smi - Holey Double - Holey Elements Adds ArrayIntegrityLevelGenerator to freeze/seal/preventExtensions objects. There is a chance of transitioning the hole type with ArrayIntegrityLevelGenerator to: - HOLEY_SEALED_ELEMENTS - HOLEY_FROZEN_ELEMENTS - HOLEY_NONEXTENSIBLE_ELEMENTS Bug: 476158042, 455513417 Change-Id: Id396b72183f70ce98d0c97b4c202efffc1c31cbe Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956876 Reviewed-by: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Dominik Klemba --- .../CodeGen/CodeGeneratorWeights.swift | 2 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 42 +++++++++++++++++++ Tests/FuzzilliTests/LifterTest.swift | 24 +++++++++++ 3 files changed, 68 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 31d9c0059..12f86ff1e 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -28,6 +28,8 @@ public let codeGeneratorWeights = [ "NamedVariableGenerator": 10, "ArrayGenerator": 10, "FloatArrayGenerator": 10, + "HoleyArrayGenerator": 10, + "ObjectIntegrityLevelGenerator": 1, "IntArrayGenerator": 10, "TypedArrayGenerator": 20, "BuiltinObjectInstanceGenerator": 10, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 3a782fc36..9767d2f95 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -214,6 +214,48 @@ 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.. Date: Tue, 10 Feb 2026 09:04:57 +0000 Subject: [PATCH 099/234] [dumpling] Keep running args/regs. This change fixes a bug in DiffOracle where register and argument values were lost when transitioning between frame types with different register counts. In original-original code (in Dumpling GitHub), DiffOracle relied on prevFrame to reconstruct the state. We removed prevFrame, erroneously thinking that it is not needed. Now if a frame reports fewer registers than the preceding frame, the parser would shrink the register array to match. This causes data loss for the higher-index registers. When execution later has a higher count of register and was expecting them to still exist, they are erroneously reported as missing or reset, causing false positive mismatches. Thus we go back to have runningRegs/Args (same stuff as prevFrame in original-original code but still more refactored and simplified). Bug: 441467877 Change-Id: Ic85d7d8b9ef19d359ca9cc7e4af8bb6c36468c2b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8995239 Commit-Queue: Danylo Mocherniuk Reviewed-by: Dominik Klemba --- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 33 +++-- Tests/FuzzilliTests/DiffOracleTests.swift | 113 ++++++++++++++++++ 2 files changed, 133 insertions(+), 13 deletions(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index fb845bd8d..62be6f02c 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -121,7 +121,13 @@ public final class DiffOracle { } } - private static func parseDiffFrame(_ frameArr: ArraySlice, _ prevFrame: Frame?) -> Frame { + 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)) @@ -153,30 +159,28 @@ public final class DiffOracle { 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, totalCount: Int, oldValues: [String]) -> [String] { - var newValues = oldValues + func updateValues(prefix: String, requiredCount: Int, buffer: inout [String]) -> [String] { - if newValues.count > totalCount { - newValues.removeLast(newValues.count - totalCount) - } else if newValues.count < totalCount { - let missingCount = totalCount - newValues.count + if buffer.count < requiredCount { + let missingCount = requiredCount - buffer.count let defaults = Array(repeating: "", count: missingCount) - newValues.append(contentsOf: defaults) + buffer.append(contentsOf: defaults) } while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1) let number = Int(data[0])! let value = String(data[1]) - newValues[number] = value + + buffer[number] = value i += 1 } - return newValues + return Array(buffer.prefix(requiredCount)) } - let arguments = updateValues(prefix: "a", totalCount: argCount, oldValues: prevFrame?.arguments ?? []) - let registers = updateValues(prefix: "r", totalCount: regCount, oldValues: prevFrame?.registers ?? []) + 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, @@ -191,13 +195,16 @@ public final class DiffOracle { 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) + prevFrame = parseDiffFrame(frame, prevFrame, &runningArgs, &runningRegs) frameArray.append(prevFrame!) } return frameArray diff --git a/Tests/FuzzilliTests/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift index 4b6176aa7..674d443f8 100644 --- a/Tests/FuzzilliTests/DiffOracleTests.swift +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -311,4 +311,117 @@ final class DiffOracleTests: XCTestCase { 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)) + } } From 9ed1f847823d0a0ab11d94d836aff51990746801 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Wed, 11 Feb 2026 10:51:19 +0000 Subject: [PATCH 100/234] [dumpling] Improve debug printing a bit. My eyes hurt. Bug: 441467877 Change-Id: Ib8522847f46e1c0dd72bef19904a4fcd7d744f93 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012356 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 62be6f02c..142ba9f53 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -82,7 +82,7 @@ public final class DiffOracle { case deoptTurbofan } - private struct Frame: Equatable { + private struct Frame: Equatable, CustomStringConvertible { let bytecodeOffset: Int let accumulator: String let arguments: [String] @@ -90,6 +90,39 @@ public final class DiffOracle { 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 { @@ -217,12 +250,12 @@ public final class DiffOracle { for optFrame in optFrames { guard let unoptIndex = unoptFramesLeft.firstIndex(where: optFrame.matches) else { - print(optFrame as AnyObject) + print(optFrame) print("--------------------------") print("[") for unoptFrame in unoptFrames { if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset { - print(unoptFrame as AnyObject) + print(unoptFrame) } } print("]") From 22477a39c4f2771540ca501ac0084e701539ba97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doga=20Y=C3=BCksel?= Date: Mon, 9 Feb 2026 14:55:27 +0000 Subject: [PATCH 101/234] [wasm] Added ref.test instruction and code generators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wasmRefTest operation was added which can work with either concrete or abstract wasm types. Since concrete types need a type definition there are two code generators; one where we need such a type definition to already exist and a more generic one that tests against abstract types. Bug: 474940922 Change-Id: I148c1bc44c8649fcdb92d0afc52efa3af8d34b33 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8952838 Commit-Queue: Doga Yüksel Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 7 ++ .../CodeGen/CodeGeneratorWeights.swift | 2 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 47 +++++++++++++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 6 ++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 2 + Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 10 +++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 3 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 10 +++ .../Fuzzilli/Mutators/OperationMutator.swift | 15 +++++ Sources/Fuzzilli/Protobuf/operations.pb.swift | 55 +++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 4 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 28 +++++++- Sources/Fuzzilli/Protobuf/program.proto | 1 + Tests/FuzzilliTests/WasmTests.swift | 67 +++++++++++++++++++ 16 files changed, 260 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 1f12d1bae..ba4271dad 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4397,6 +4397,13 @@ public class ProgramBuilder { public func wasmExternConvertAny(_ ref: Variable) -> Variable { b.emit(WasmExternConvertAny(), withInputs: [ref]).output } + + @discardableResult + public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { + typeDef == nil + ? b.emit(WasmRefTest(refType: refType), withInputs: [ref]).output + : b.emit(WasmRefTest(refType: refType), withInputs: [ref, typeDef!]).output + } } public class WasmModule { diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 12f86ff1e..179a0d9cd 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -379,4 +379,6 @@ public let codeGeneratorWeights = [ "WasmI31GetGenerator": 5, "WasmAnyConvertExternGenerator": 5, "WasmExternConvertAnyGenerator": 5, + "WasmRefTestGenerator": 5, + "WasmRefTestAbstractGenerator": 5, ] diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 1a724a3a1..254b18e13 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -340,6 +340,53 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) }, + CodeGenerator( + "WasmRefTestGenerator", inContext: .single(.wasmFunction), + inputs: .requiredComplex(.init(.wasmTypeDef())), + produces: [.wasmi32] + ) { 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.wasmRefTest(variable, refType: refType, typeDef: typeDef) + }, + + CodeGenerator( + "WasmRefTestAbstractGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmGenericRef), + produces: [.wasmi32] + ) { b, ref in + let function = b.currentWasmModule.currentWasmFunction + let abstractType = switch b.type(of: ref).wasmReferenceType!.kind { + case .Abstract(let heapTypeInfo): + heapTypeInfo.heapType + case .Index(let desc): + desc.get()!.abstractHeapSupertype!.heapType + } + let sameHierarchy = WasmAbstractHeapType.allCases.filter { + $0 != abstractType && $0.inSameHierarchy(abstractType) + } + guard sameHierarchy.count > 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()) + ) + }, + // Primitive Value Generators CodeGenerator( diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 6a7cec37a..c58ffb788 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1611,6 +1611,10 @@ extension Instruction: ProtobufConvertible { $0.wasmRefIsNull = Fuzzilli_Protobuf_WasmRefIsNull() case .wasmRefEq(_): $0.wasmRefEq = Fuzzilli_Protobuf_WasmRefEq() + case .wasmRefTest(let op): + $0.wasmRefTest = Fuzzilli_Protobuf_WasmRefTest.with { + $0.type = ILTypeToWasmTypeEnum(op.type) + } case .wasmRefI31(let op): $0.wasmRefI31 = Fuzzilli_Protobuf_WasmRefI31.with { $0.isShared = op.isShared @@ -2593,6 +2597,8 @@ extension Instruction: ProtobufConvertible { op = WasmRefIsNull() case .wasmRefEq(_): op = WasmRefEq() + case .wasmRefTest(let p): + op = WasmRefTest(refType: WasmTypeEnumToILType(p.type)) case .wasmRefI31(let p): op = WasmRefI31(isShared: p.isShared) case .wasmI31Get(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 0b48a7bf7..341bd6c8b 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -922,6 +922,8 @@ public struct JSTyper: Analyzer { 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 .wasmAnyConvertExtern(_): // TODO(pawkra): forward shared bit & update the comment // any.convert_extern forwards the nullability bit from the input. diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 6faff452a..5d9ff5d11 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -366,4 +366,5 @@ enum Opcode { case wasmDefineAdHocSignatureType(WasmDefineAdHocSignatureType) case wasmStructNew(WasmStructNew) case wasmRefEq(WasmRefEq) + case wasmRefTest(WasmRefTest) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 5b792bc7c..243a373af 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2320,6 +2320,16 @@ 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]) + } +} + /// An atomic load from Wasm memory. /// The accessed address is base + offset. final class WasmAtomicLoad: WasmOperation { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index c86becf21..44103a423 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1345,6 +1345,10 @@ 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 .wasmBeginTypeGroup(_): w.emit("WasmBeginTypeGroup") w.increaseIndentionLevel() diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 9fb9ba5fe..e5a8fe020 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1793,7 +1793,8 @@ public class JavaScriptLifter: Lifter { .wasmRefI31(_), .wasmI31Get(_), .wasmAnyConvertExtern(_), - .wasmExternConvertAny(_): + .wasmExternConvertAny(_), + .wasmRefTest(_): fatalError("unreachable") } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index b5b32b646..ab88eba27 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -2196,6 +2196,16 @@ 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 = if refType.isAbstract() { + try encodeHeapType(op.type) + } else { + try encodeWasmGCType(typer.getTypeDescription(of: wasmInstruction.input(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. diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4ebe42be3..4d639d213 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -508,6 +508,21 @@ public class OperationMutator: BaseInstructionMutator { newOp = WasmStructGet(fieldIndex: op.fieldIndex, isSigned: !op.isSigned) case .wasmI31Get(let op): newOp = WasmI31Get(isSigned: !op.isSigned) + case .wasmRefTest(let op): + let newType: ILType + switch op.type.wasmReferenceType!.kind { + case .Abstract(let heapTypeInfo): + let chosenType = chooseUniform( + from: WasmAbstractHeapType.allCases.filter { + $0 != heapTypeInfo.heapType && $0.inSameHierarchy(heapTypeInfo.heapType) + } + ) + newType = ILType.wasmRef(.Abstract(HeapTypeInfo(chosenType, shared: false)), nullability: Bool.random()) + case .Index(_): + let nullable = op.type.wasmReferenceType!.nullability + newType = ILType.wasmRef(.Index(), nullability: !nullable) + } + newOp = WasmRefTest(refType: newType) // Unexpected operations to make the switch fully exhaustive. case .nop(_), .loadUndefined(_), diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index d9bb295f0..d20ce24be 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5913,6 +5913,27 @@ public struct Fuzzilli_Protobuf_WasmRefEq: Sendable { 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 {return _type ?? Fuzzilli_Protobuf_WasmILType()} + set {_type = newValue} + } + /// Returns true if `type` has been explicitly set. + public var hasType: Bool {return 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 @@ -15392,6 +15413,40 @@ extension Fuzzilli_Protobuf_WasmRefEq: SwiftProtobuf.Message, SwiftProtobuf._Mes } } +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_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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 4968018e3..e00e8905f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1560,6 +1560,10 @@ message WasmRefIsNull { message WasmRefEq { } +message WasmRefTest { + WasmILType type = 1; +} + message WasmRefI31 { bool isShared = 1; } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 11b662941..13322cb90 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2745,6 +2745,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3085,6 +3093,7 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmDefineAdHocSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocSignatureType) case wasmStructNew(Fuzzilli_Protobuf_WasmStructNew) case wasmRefEq(Fuzzilli_Protobuf_WasmRefEq) + case wasmRefTest(Fuzzilli_Protobuf_WasmRefTest) } @@ -3133,7 +3142,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7518,6 +7527,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefEq(v) } }() + case 339: 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) + } + }() default: break } } @@ -8880,6 +8902,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmRefEq(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 338) }() + case .wasmRefTest?: try { + guard case .wasmRefTest(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 339) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 6fc3e2981..54fb415c4 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -362,6 +362,7 @@ message Instruction { WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; WasmStructNew wasmStructNew = 337; WasmRefEq wasmRefEq = 338; + WasmRefTest wasmRefTest = 339; } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index b2b51e9d3..96c07452c 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -4977,6 +4977,73 @@ 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") + } } class WasmNumericalTests: XCTestCase { From 5bb4ccc28adb058ce81c0c7d611398bd25aca3cc Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Wed, 11 Feb 2026 13:53:38 +0000 Subject: [PATCH 102/234] Add guards to function calls in optimization patterns With 0.5 probability, adds guard try/catch blocks around calls in ForceTurboFanCompilationGenerator, ForceMaglevCompilationGenerator, LazyDeoptFuzzer, and FastApiCallFuzzer. Bug: 483578451 Change-Id: Iecaededb94c0dfbf6e49f20c6b69ddf38e500cb0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012916 Reviewed-by: Michael Achenbach Commit-Queue: Dominik Klemba --- .../Profiles/V8CommonProfile.swift | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index abb06961a..3c3c25375 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -77,32 +77,36 @@ public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompi assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) - b.callFunction(f, withArgs: arguments) + let guardCalls = probability(0.5) + + b.callFunction(f, withArgs: arguments, guard: guardCalls) b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - b.callFunction(f, withArgs: arguments) - b.callFunction(f, withArgs: arguments) + b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: arguments, guard: guardCalls) b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); - b.callFunction(f, withArgs: arguments) + b.callFunction(f, withArgs: arguments, guard: guardCalls) } public 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) + let guardCalls = probability(0.5) + + b.callFunction(f, withArgs: arguments, guard: guardCalls) b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - b.callFunction(f, withArgs: arguments) - b.callFunction(f, withArgs: arguments) + b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: arguments, guard: guardCalls) b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); - b.callFunction(f, withArgs: arguments) + b.callFunction(f, withArgs: arguments, guard: guardCalls) } public let TurbofanVerifyTypeGenerator = CodeGenerator("TurbofanVerifyTypeGenerator", inputs: .one) { b, v in @@ -525,11 +529,12 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in // Turn the call into a recursive call. b.reassign(dummyFct, to: realFct) let args = b.randomArguments(forCalling: realFct) + let guardCalls = probability(0.5) b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); - b.callFunction(realFct, withArgs: args) + 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 @@ -685,16 +690,17 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in } 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.callFunction(f, withArgs: args) - b.callFunction(f, withArgs: args) + b.callFunction(f, withArgs: args, guard: guardCalls) + b.callFunction(f, withArgs: args, guard: guardCalls) b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); - b.callFunction(f, withArgs: args) + b.callFunction(f, withArgs: args, guard: guardCalls) b.build(n: 10) } From f29eaa84e767f60ab697f4f67e3e7f0194ad9b5f Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 12 Feb 2026 08:51:09 +0100 Subject: [PATCH 103/234] Add unregistered built-in to TODOs Bug: 481610393 Change-Id: I815e16a598e7c0d3eafc39608fea1e41f96096d9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012919 Commit-Queue: Michael Achenbach Auto-Submit: Michael Achenbach Reviewed-by: Leszek Swirski Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk Commit-Queue: Leszek Swirski --- Tests/FuzzilliTests/EnvironmentTest.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index 736164e73..e180f869c 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -106,6 +106,7 @@ class EnvironmentTests: XCTestCase { "setTimeout", "console", "escape", + "onerror", "unescape", "encodeURIComponent", "encodeURI", From 597241fb250414dcf19360d193e3ca97b4f3c1ae Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Wed, 11 Feb 2026 15:56:56 +0000 Subject: [PATCH 104/234] [dumpling] Disable timestamp non-determinism. Quoting Leszek: "--predictable basically disables any concurrency so that everything is scheduled on the main thread. --verify-predictable additionally adds a synthetic clock so that things like timestamps have a fixed value, for being able to verify predictability by hashing" Additionally --verify-predictable implies --predictable. Bug: 441467877 Change-Id: I7c47d00b8de8242f4b029e60fe79816713756a2f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012917 Reviewed-by: Dominik Klemba Commit-Queue: Danylo Mocherniuk --- Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index f02190aec..b7117dd7d 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -28,7 +28,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--predictable", + "--verify-predictable", "--no-sparkplug", "--maglev-dumping", "--turbofan-dumping", @@ -56,7 +56,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--predictable" + "--verify-predictable" ], processEnv: [:], From 6ba00cfc9721ac046055da4af9a7b03d1d1c9e3f Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 12 Feb 2026 10:21:35 +0000 Subject: [PATCH 105/234] [dumpling] Add a bit more output. There are a few more steps to actually report a thing as differential but I don't want to miss anything, so I will print it here too. Bug: 441467877 Change-Id: I009ed1792ae486e55cbd65bf63c0863077a6a375 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012880 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/Fuzzer.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 51aa6a308..a00495f20 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -1138,7 +1138,20 @@ public class Fuzzer { let unoptimizedDump = try String(contentsOfFile: unoptPath, encoding: .utf8) - return DiffExecution.diff(optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, unoptDumpOut: unoptimizedDump) + // 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)") From 1769f9f8dfa6973fdd6ee6367bee2b8e20c87c6d Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 12 Feb 2026 01:30:02 -0800 Subject: [PATCH 106/234] Revert "[dumpling] Disable timestamp non-determinism." This reverts commit 597241fb250414dcf19360d193e3ca97b4f3c1ae. Reason for revert: it didn't help with all timestamps, adding code prefix to mock date looks more promising. Additionally this flag does a bunch of other stuff and requires a build flag to work properly, so let's ditch it. Original change's description: > [dumpling] Disable timestamp non-determinism. > > Quoting Leszek: "--predictable basically disables any concurrency so > that everything is scheduled on the main thread. --verify-predictable > additionally adds a synthetic clock so that things like timestamps have > a fixed value, for being able to verify predictability by hashing" > > Additionally --verify-predictable implies --predictable. > > Bug: 441467877 > Change-Id: I7c47d00b8de8242f4b029e60fe79816713756a2f > Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012917 > Reviewed-by: Dominik Klemba > Commit-Queue: Danylo Mocherniuk Bug: 441467877 No-Presubmit: true No-Tree-Checks: true No-Try: true Change-Id: I8ed49d648aa34a7c75f1ebb220d52a16ee396259 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9014817 Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk Reviewed-by: Michael Achenbach Bot-Commit: Rubber Stamper --- Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index b7117dd7d..f02190aec 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -28,7 +28,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--verify-predictable", + "--predictable", "--no-sparkplug", "--maglev-dumping", "--turbofan-dumping", @@ -56,7 +56,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--verify-predictable" + "--predictable" ], processEnv: [:], From 836950b06ffa56beca2cc194db353de73cc5dc4a Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 12 Feb 2026 10:56:49 +0000 Subject: [PATCH 107/234] [dumpling] filter for func id in debug print Bug: 441467877 Change-Id: I0ae0f1e833dfbc6a590d5dfe8d83a6e16836311f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9016616 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 142ba9f53..0cdb44569 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -254,7 +254,7 @@ public final class DiffOracle { print("--------------------------") print("[") for unoptFrame in unoptFrames { - if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset { + if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset && unoptFrame.functionId == optFrame.functionId { print(unoptFrame) } } From 816329edaf867681b7fd0fcd3ebdf97c9e0e2b0e Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 12 Feb 2026 10:11:02 +0000 Subject: [PATCH 108/234] [dumpling] Support empty string parsing in oracle. Bug: 441467877 Change-Id: I8346b2e0eba7877d86e2db1ceb35a236c4bf0545 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012879 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 2 +- Tests/FuzzilliTests/DiffOracleTests.swift | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 0cdb44569..499dd4c96 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -201,7 +201,7 @@ public final class DiffOracle { } while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { - let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1) + let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1, omittingEmptySubsequences: false) let number = Int(data[0])! let value = String(data[1]) diff --git a/Tests/FuzzilliTests/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift index 674d443f8..fe047a8e4 100644 --- a/Tests/FuzzilliTests/DiffOracleTests.swift +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -424,4 +424,30 @@ final class DiffOracleTests: XCTestCase { 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") + } } From d89698001e5f788b6aeb4ca5e4a510add8296124 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Thu, 12 Feb 2026 10:03:12 +0000 Subject: [PATCH 109/234] [dumpling] Mock some funcs to achieve determinism. Bug: 441467877 Change-Id: I104bc80f10573790e0a4c81ba99d70dcc1bac99e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9012959 Commit-Queue: Danylo Mocherniuk Reviewed-by: Michael Achenbach Reviewed-by: Dominik Klemba --- .../Profiles/V8DumplingProfile.swift | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index f02190aec..9cd0b7496 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -66,6 +66,33 @@ let v8DumplingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ + // --- Determinism Shim --- + (function() { + const originalDate = Date; + const FIXED_TIME = 1767225600000; + const FIXED_STRING = new originalDate(FIXED_TIME).toString(); + + Date.now = function() { return FIXED_TIME; }; + globalThis.Date = new Proxy(originalDate, { + construct(target, args) { + if (args.length === 0) return new target(FIXED_TIME); + return new target(...args); + }, + apply(target, thisArg, args) { return FIXED_STRING; } + }); + globalThis.Date.prototype = originalDate.prototype; + + // Math.random shim + const rng = function() { + let s = 0x12345678; + return function() { + s ^= s << 13; s ^= s >> 17; s ^= s << 5; + return (s >>> 0) / 4294967296; + }; + }(); + Math.random = rng; + })(); + // --- End Determinism Shim --- """, codeSuffix: """ From b7df82801213bf36ee3d1f06ea15ba1b2f98721a Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 13 Feb 2026 17:11:26 +0100 Subject: [PATCH 110/234] Diversify argument patterns for optimized function generators This diversifies the arguments for the function calls in V8's typical function-optimization shortcuts. Often, reproducers have an argument pattern across the functions that is not all equal. For getting polymorphic feedback or a type deviation in the optimized function call, we see patterns like: f(a); f(a); %Opt(f); f(b); Or: f(a); f(b); %Opt(f); f(c); Though Fuzzilli will eventually mutate the arguments, this change attempts to tickle out this diversity a bit more. With the largest percentage we retain the old behavior. Change-Id: I58c8e7361aa3ce122a034417708dcedb8b4d7888 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9020237 Reviewed-by: Dominik Klemba Commit-Queue: Michael Achenbach --- .../Profiles/V8CommonProfile.swift | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 3c3c25375..b3e83685d 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -73,40 +73,62 @@ public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITComp } } +// Choose argument lists for four function calls of the same function with +// interesting optimization patterns. +func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Variable], [Variable], [Variable], [Variable]) { + var pool: [[Variable]?] = [nil, nil, nil] + + let getArg = { (i: Int) -> [Variable] in + if pool[i] == nil { + pool[i] = b.randomArguments(forCalling: f) + } + return pool[i]! + } + + let keepRates = [1.0, 0.97, 0.85, 0.75] + + let args = (0..<4).map { i in + probability(keepRates[i]) ? getArg(0) : getArg(probability(0.5) ? 1 : 2) + } + + assert(args.count == 4) + return (args[0], args[1], args[2], args[3]) +} + public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) - let arguments = b.randomArguments(forCalling: f) + let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) let guardCalls = probability(0.5) - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args1, guard: guardCalls) b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - b.callFunction(f, withArgs: arguments, guard: guardCalls) - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args2, guard: guardCalls) + b.callFunction(f, withArgs: args3, guard: guardCalls) b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args4, guard: guardCalls) } public let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) - let arguments = b.randomArguments(forCalling: f) + let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) let guardCalls = probability(0.5) - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args1, guard: guardCalls) b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - b.callFunction(f, withArgs: arguments, guard: guardCalls) - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args2, guard: guardCalls) + b.callFunction(f, withArgs: args3, guard: guardCalls) b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); - b.callFunction(f, withArgs: arguments, guard: guardCalls) + b.callFunction(f, withArgs: args4, guard: guardCalls) } public let TurbofanVerifyTypeGenerator = CodeGenerator("TurbofanVerifyTypeGenerator", inputs: .one) { b, v in From 57da3abf03d1f2a4957dc4256a450e57ffad941e Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 13 Feb 2026 15:13:12 +0100 Subject: [PATCH 111/234] Simplify force-compilation generator This merges the code of the two generators forcing Maglev or Turbofan compilation. The separation is probably not adding any value. This also doubles the weight of the resulting generator as local experiments show that it's called a bit too rarely. Probably due to other generators being added over time. Fly-by: Remove a counter-productive generator for Dumpling. Bug: 465497343 Change-Id: I208fc1ba47caa3b3d0f2d672b72b527e001a0f45 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9020158 Reviewed-by: Dominik Klemba Commit-Queue: Michael Achenbach --- .../Profiles/V8CommonProfile.swift | 23 +++---------------- .../Profiles/V8DumplingProfile.swift | 5 +--- .../Profiles/V8HoleFuzzingProfile.swift | 3 +-- Sources/FuzzilliCli/Profiles/V8Profile.swift | 3 +-- .../Profiles/V8SandboxProfile.swift | 3 +-- 5 files changed, 7 insertions(+), 30 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index b3e83685d..9426d7c8f 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -95,7 +95,7 @@ func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Varia return (args[0], args[1], args[2], args[3]) } -public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in +public let ForceCompilationGenerator = CodeGenerator("ForceCompilationGenerator", inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) @@ -108,25 +108,8 @@ public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompi b.callFunction(f, withArgs: args2, guard: guardCalls) b.callFunction(f, withArgs: args3, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); - - b.callFunction(f, withArgs: args4, guard: guardCalls) -} - -public let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in - assert(b.type(of: f).Is(.function())) - let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) - - let guardCalls = probability(0.5) - - b.callFunction(f, withArgs: args1, guard: guardCalls) - - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - - b.callFunction(f, withArgs: args2, guard: guardCalls) - b.callFunction(f, withArgs: args3, guard: guardCalls) - - b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); + let optimizer = chooseUniform(from: ["OptimizeFunctionOnNextCall", "OptimizeMaglevOnNextCall"]) + b.eval("%\(optimizer)(%@)", with: [f]); b.callFunction(f, withArgs: args4, guard: guardCalls) } diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index 9cd0b7496..259edac5b 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -106,10 +106,7 @@ let v8DumplingProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), - + (ForceCompilationGenerator, 20), (V8GcGenerator, 10), ], diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift index 218ea99fe..350d3fed5 100644 --- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift @@ -70,8 +70,7 @@ let v8HoleFuzzingProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), + (ForceCompilationGenerator, 20), (V8GcGenerator, 10), (HoleLeakGenerator, 25), ], diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 9f0c47588..9ad2e52d6 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -59,8 +59,7 @@ let v8Profile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), + (ForceCompilationGenerator, 20), (TurbofanVerifyTypeGenerator, 10), (WorkerGenerator, 10), diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 9a171dfd6..efd50481c 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -522,8 +522,7 @@ let v8SandboxProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), + (ForceCompilationGenerator, 20), (V8GcGenerator, 10), (WasmStructGenerator, 5), (WasmArrayGenerator, 5), From f9cacf41d7ca5fc5129b4ea651c0b01bbfd42504 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Mon, 16 Feb 2026 08:19:50 +0000 Subject: [PATCH 112/234] [dumpling] add non-materialized option to Oracle Until non-materialized printing is implemented for everything, we will allow it to match anything similar to . Bug: 441467877 Change-Id: I681ceba56a88e66220ee00d65a7f8f4166042cd5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9026356 Commit-Queue: Danylo Mocherniuk Reviewed-by: Michael Achenbach --- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 4 +-- Tests/FuzzilliTests/DiffOracleTests.swift | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 499dd4c96..677256f53 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -133,9 +133,9 @@ public final class DiffOracle { return false } - // Logic: 'self' is the Optimized frame. It is allowed to have "". + // Logic: 'self' is the Optimized frame. It is allowed to have "" or "". func isMatch(_ optValue: String, unoptValue: String) -> Bool { - return optValue == "" || optValue == unoptValue + return optValue == "" || optValue == "" || optValue == unoptValue } if !isMatch(self.accumulator, unoptValue: reference.accumulator) { diff --git a/Tests/FuzzilliTests/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift index fe047a8e4..00d0e52c9 100644 --- a/Tests/FuzzilliTests/DiffOracleTests.swift +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -132,6 +132,34 @@ final class DiffOracleTests: XCTestCase { 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 From 4e27e7421fd44c19115b9994adeb13439d3bb8be Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Mon, 16 Feb 2026 08:56:41 +0000 Subject: [PATCH 113/234] [dumpling] Add temporal determinism. Similar to Date, we also need to mock Temporal Bug: 441467877 Change-Id: I72f44575b2c9c08c9067f55518259727b8cb10b1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9026357 Reviewed-by: Michael Achenbach Commit-Queue: Danylo Mocherniuk --- .../Profiles/V8DumplingProfile.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index 259edac5b..dc3d207c8 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -91,6 +91,25 @@ let v8DumplingProfile = Profile( }; }(); 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 --- """, From be671ee525af282cdfcfc8b9e6aec06180997d2d Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 16 Feb 2026 01:07:57 -0800 Subject: [PATCH 114/234] Revert "Simplify force-compilation generator" This reverts commit 57da3abf03d1f2a4957dc4256a450e57ffad941e. Reason for revert: The simplification doesn't take the swarm mode into account. Original change's description: > Simplify force-compilation generator > > This merges the code of the two generators forcing Maglev or > Turbofan compilation. The separation is probably not adding any > value. > > This also doubles the weight of the resulting generator as local > experiments show that it's called a bit too rarely. Probably > due to other generators being added over time. > > Fly-by: Remove a counter-productive generator for Dumpling. > > Bug: 465497343 > Change-Id: I208fc1ba47caa3b3d0f2d672b72b527e001a0f45 > Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9020158 > Reviewed-by: Dominik Klemba > Commit-Queue: Michael Achenbach Bug: 465497343 Change-Id: I98fdb06431c296b7a516502899b6a94712cb3dcd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9026358 Bot-Commit: Rubber Stamper Commit-Queue: Michael Achenbach --- .../Profiles/V8CommonProfile.swift | 23 ++++++++++++++++--- .../Profiles/V8DumplingProfile.swift | 5 +++- .../Profiles/V8HoleFuzzingProfile.swift | 3 ++- Sources/FuzzilliCli/Profiles/V8Profile.swift | 3 ++- .../Profiles/V8SandboxProfile.swift | 3 ++- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 9426d7c8f..b3e83685d 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -95,7 +95,7 @@ func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Varia return (args[0], args[1], args[2], args[3]) } -public let ForceCompilationGenerator = CodeGenerator("ForceCompilationGenerator", inputs: .required(.function())) { b, f in +public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) @@ -108,8 +108,25 @@ public let ForceCompilationGenerator = CodeGenerator("ForceCompilationGenerator" b.callFunction(f, withArgs: args2, guard: guardCalls) b.callFunction(f, withArgs: args3, guard: guardCalls) - let optimizer = chooseUniform(from: ["OptimizeFunctionOnNextCall", "OptimizeMaglevOnNextCall"]) - b.eval("%\(optimizer)(%@)", with: [f]); + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); + + b.callFunction(f, withArgs: args4, guard: guardCalls) +} + +public let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in + assert(b.type(of: f).Is(.function())) + let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) + + let guardCalls = probability(0.5) + + b.callFunction(f, withArgs: args1, guard: guardCalls) + + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + + b.callFunction(f, withArgs: args2, guard: guardCalls) + b.callFunction(f, withArgs: args3, guard: guardCalls) + + b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); b.callFunction(f, withArgs: args4, guard: guardCalls) } diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift index dc3d207c8..89418e8ce 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift @@ -125,7 +125,10 @@ let v8DumplingProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceCompilationGenerator, 20), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), + (V8GcGenerator, 10), ], diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift index 350d3fed5..218ea99fe 100644 --- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift @@ -70,7 +70,8 @@ let v8HoleFuzzingProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceCompilationGenerator, 20), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), (V8GcGenerator, 10), (HoleLeakGenerator, 25), ], diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 9ad2e52d6..9f0c47588 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -59,7 +59,8 @@ let v8Profile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceCompilationGenerator, 20), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), (TurbofanVerifyTypeGenerator, 10), (WorkerGenerator, 10), diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index efd50481c..9a171dfd6 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -522,7 +522,8 @@ let v8SandboxProfile = Profile( additionalCodeGenerators: [ (ForceJITCompilationThroughLoopGenerator, 5), - (ForceCompilationGenerator, 20), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), (V8GcGenerator, 10), (WasmStructGenerator, 5), (WasmArrayGenerator, 5), From a5ef634a9d7b8b8e1b1e1299cf76519f1aa54b55 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 16 Feb 2026 11:18:45 +0100 Subject: [PATCH 115/234] Partial reland: Simplify force-compilation generator Share the generator code, but keep the separate generator instances. Bug: 465497343 Change-Id: Ie31c5b0fd8e1853a93dc26664ac863c28ac567ff Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9026476 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- .../Profiles/V8CommonProfile.swift | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index b3e83685d..db2746e2b 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -95,41 +95,31 @@ func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Varia return (args[0], args[1], args[2], args[3]) } -public let ForceTurboFanCompilationGenerator = CodeGenerator("ForceTurboFanCompilationGenerator", inputs: .required(.function())) { b, f in - assert(b.type(of: f).Is(.function())) - let (args1, args2, args3, args4) = chooseArgumentLists(b, 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) - let guardCalls = probability(0.5) + let guardCalls = probability(0.5) - b.callFunction(f, withArgs: args1, guard: guardCalls) + b.callFunction(f, withArgs: args1, guard: guardCalls) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - b.callFunction(f, withArgs: args2, guard: guardCalls) - b.callFunction(f, withArgs: args3, guard: guardCalls) + b.callFunction(f, withArgs: args2, guard: guardCalls) + b.callFunction(f, withArgs: args3, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); + b.eval("%\(optimizeName)(%@)", with: [f]); - b.callFunction(f, withArgs: args4, guard: guardCalls) + b.callFunction(f, withArgs: args4, guard: guardCalls) + } } -public let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in - assert(b.type(of: f).Is(.function())) - let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) +public let ForceTurboFanCompilationGenerator = forceCompilationGenerator( + "ForceTurboFanCompilationGenerator", optimizeName: "OptimizeFunctionOnNextCall") - let guardCalls = probability(0.5) - - b.callFunction(f, withArgs: args1, guard: guardCalls) - - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); - - b.callFunction(f, withArgs: args2, guard: guardCalls) - b.callFunction(f, withArgs: args3, guard: guardCalls) - - b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f]); - - b.callFunction(f, withArgs: args4, guard: guardCalls) -} +public let ForceMaglevCompilationGenerator = forceCompilationGenerator( + "ForceMaglevCompilationGenerator", optimizeName: "OptimizeMaglevOnNextCall") public let TurbofanVerifyTypeGenerator = CodeGenerator("TurbofanVerifyTypeGenerator", inputs: .one) { b, v in b.eval("%VerifyType(%@)", with: [v]) From afeb461454902520955c629292f54328d1bccddb Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Feb 2026 21:53:58 +0100 Subject: [PATCH 116/234] [v8] Randomize --jit-fuzzing which implies --no-lazy Also sometimes explicitly enable or disable lazy compilation. Bug: 475707969 Change-Id: Ic13b6843ae0d478f0d9e6ce77a0d7318d1f47e03 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8999276 Commit-Queue: Matthias Liedtke Reviewed-by: Leszek Swirski Auto-Submit: Matthias Liedtke --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index db2746e2b..a8d391f14 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -773,7 +773,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { "--omit-quit", "--allow-natives-syntax", "--fuzzing", - "--jit-fuzzing", "--future", "--harmony", "--experimental-fuzzing", @@ -813,6 +812,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. @@ -1033,6 +1036,8 @@ 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") From 6c606342e03b44d74740540d2854833abdbb6155 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Mon, 16 Feb 2026 15:21:28 +0000 Subject: [PATCH 117/234] Refactor chooseArgumentLists to use arguments history list The goal is to improve readability. It affects probability distribution: - Allows up to 4 distinct argument sets (previously capped at 3). - When reusing arguments, selects uniformly from all previously generated sets, eliminating the bias towards the first set found in the previous implementation. Original implementation added in: crrev/i/9020237 Change-Id: I590149d3d0cf7f1889c68c30fc8d4b0f0d71e6e5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9022358 Commit-Queue: Dominik Klemba Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach Reviewed-by: Matthias Liedtke Auto-Submit: Dominik Klemba --- .../Profiles/V8CommonProfile.swift | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index a8d391f14..9c3c27e67 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -76,23 +76,20 @@ public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITComp // Choose argument lists for four function calls of the same function with // interesting optimization patterns. func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Variable], [Variable], [Variable], [Variable]) { - var pool: [[Variable]?] = [nil, nil, nil] + var reusePool: [[Variable]] = [b.randomArguments(forCalling: f)] + let reuseProbabilities = [1.0, 0.9, 0.9, 0.5] - let getArg = { (i: Int) -> [Variable] in - if pool[i] == nil { - pool[i] = b.randomArguments(forCalling: f) + let argumentLists = reuseProbabilities.map { p in + if probability(p) { + return reusePool.randomElement()! + } else { + reusePool.append(b.randomArguments(forCalling: f)) + return reusePool.last! } - return pool[i]! - } - - let keepRates = [1.0, 0.97, 0.85, 0.75] - - let args = (0..<4).map { i in - probability(keepRates[i]) ? getArg(0) : getArg(probability(0.5) ? 1 : 2) } - assert(args.count == 4) - return (args[0], args[1], args[2], args[3]) + assert(argumentLists.count == 4) + return (argumentLists[0], argumentLists[1], argumentLists[2], argumentLists[3]) } private func forceCompilationGenerator(_ generatorName: String, optimizeName: String) -> CodeGenerator { From 7235a53c7886b19b8bc6788350c87d40ecd798dc Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 16 Feb 2026 17:35:27 +0100 Subject: [PATCH 118/234] [clean-up] Remove unused program reference for adoption Bug: 465497343 Change-Id: I0b136da11c15bd83353c76fae8d1c168f92f5d34 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9026976 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 16 ++++++++-------- Sources/Fuzzilli/Fuzzer.swift | 4 ++-- .../Mutators/BaseInstructionMutator.swift | 2 +- .../Fuzzilli/Mutators/ExplorationMutator.swift | 4 ++-- Sources/Fuzzilli/Mutators/ProbingMutator.swift | 4 ++-- .../FuzzilliCli/Profiles/V8SandboxProfile.swift | 2 +- Tests/FuzzilliTests/LifterTest.swift | 2 +- Tests/FuzzilliTests/MutatorTests.swift | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index ba4271dad..e27b5882e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1397,15 +1397,15 @@ public class ProgramBuilder { /// /// Adoption of variables from a different program. - /// Required when copying instructions between program. + /// Required when copying instructions between programs. /// private var varMaps = [VariableMap]() - /// Prepare for adoption of variables from the given program. + /// Prepare for adoption of variables from another 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 +1414,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() } @@ -1453,7 +1453,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) } diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index a00495f20..c54a1dc97 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -547,7 +547,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 { @@ -644,7 +644,7 @@ public class Fuzzer { // 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) { + b.adopting() { for instr in program.code { b.adopt(instr) } diff --git a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift index d769dd0de..4ad73bccb 100644 --- a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift +++ b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift @@ -40,7 +40,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) diff --git a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift index 34450e8fc..24e6a9551 100644 --- a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift +++ b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift @@ -106,7 +106,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) @@ -205,7 +205,7 @@ 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 { diff --git a/Sources/Fuzzilli/Mutators/ProbingMutator.swift b/Sources/Fuzzilli/Mutators/ProbingMutator.swift index d3173eb65..b6dade48e 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) @@ -143,7 +143,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] { diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift index 9a171dfd6..50c7669dd 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift @@ -37,7 +37,7 @@ fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { } } - b.adopting(from: program) { + b.adopting() { for instr in program.code { b.adopt(instr) diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 81d567403..f771b802c 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3322,7 +3322,7 @@ class LifterTests: XCTestCase { let _ = lifter.lift(prog) // Now we build the mutated Program. - b.beginAdoption(from: prog) + b.beginAdoption() for i in 0.. Date: Tue, 17 Feb 2026 10:22:36 +0100 Subject: [PATCH 119/234] [clean-up] Properly reset the program builder Bug: 465497343 Change-Id: I37625a7b5dc60ea9fc60efb083b36a8b92720588 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9028516 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index e27b5882e..8ce75582d 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -144,6 +144,12 @@ public class ProgramBuilder { // 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() @@ -210,8 +216,13 @@ public class ProgramBuilder { 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. @@ -1395,12 +1406,6 @@ public class ProgramBuilder { return argumentTypes } - /// - /// Adoption of variables from a different program. - /// Required when copying instructions between programs. - /// - private var varMaps = [VariableMap]() - /// Prepare for adoption of variables from another program. /// /// This sets up a mapping for variables from another program to the From e9a114a1f1b65e86aeaf0ef051a1f43276075c26 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 16 Feb 2026 17:59:13 +0100 Subject: [PATCH 120/234] [clean-up] Fix an assert in the DefUseAnalyzer Bug: 465497343 Change-Id: Ic5371de6093189b8519c7491037acd38e2774a11 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9027056 Commit-Queue: Michael Achenbach Reviewed-by: Dominik Klemba Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index 2274e044f..782f27e11 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -95,9 +95,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 +107,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 From 6e80d8029a1ed0cce538306d96ad992770f88b9c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 19 Jan 2026 14:47:11 +0100 Subject: [PATCH 121/234] [wasm] Introduce WasmDefineAdHocModuleSignatureType MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to commit 72dd5d7d9fcb648881543cd31bbac0d1baaa106f but on a wasm module level instead of inside a wasm function. This is a conservative workaround to ensure that we don't lose any chances of emitting operations that previously used static ILTypes but will depend on a signature input for the migration to wasm-gc. Bug: 448860865 Change-Id: Ife60126cabb8c49a0493736603611b9b2dd3e67b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8938986 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 38 ++++++++++++-- .../CodeGen/CodeGeneratorWeights.swift | 1 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 9 ++++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 7 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 ++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 17 +++++++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 1 + Sources/Fuzzilli/Lifting/WasmLifter.swift | 9 +++- .../Fuzzilli/Mutators/OperationMutator.swift | 1 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 49 +++++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 5 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 28 ++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 1 + 15 files changed, 170 insertions(+), 6 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 8ce75582d..739ca4fb1 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4615,6 +4615,29 @@ public class ProgramBuilder { return params => returnTypes } + public func randomWasmGcSignature() -> (signature: WasmSignature, indexTypes: [Variable]) { + let typeCount = Int.random(in: 0...10) + let returnCount = Int.random(in: 0...typeCount) + let parameterCount = typeCount - returnCount + + var indexTypes: [Variable] = [] + let chooseType = { + if let elementType = self.randomVariable(ofType: .wasmTypeDef()), probability(0.25) { + let nullability = + self.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.. [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 @@ -4694,12 +4717,12 @@ public class ProgramBuilder { } /// Like wasmDefineSignatureType but instead of within a type group this defines a signature - /// type directly inside a wasm function. + /// 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) -> Variable { - let indexTypes = (signature.parameterTypes + signature.outputTypes) + 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 @@ -4709,7 +4732,12 @@ public class ProgramBuilder { } let signature = signature.parameterTypes.map(cleanIndexTypes) => signature.outputTypes.map(cleanIndexTypes) - return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes).output + 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 @@ -4930,6 +4958,8 @@ public class ProgramBuilder { .wasmEndTryDelegate(_), .wasmEndTryTable(_): activeWasmModule!.blockSignatures.pop() + case .wasmDefineAdHocModuleSignatureType(_): + break default: assert(!instr.op.requiredContext.contains(.objectLiteral)) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 179a0d9cd..c192e3911 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -263,6 +263,7 @@ public let codeGeneratorWeights = [ "WasmGlobalLoadGenerator": 2, "WasmReassignmentGenerator": 2, "WasmDefineTagGenerator": 4, + "WasmAdHocModuleSignature": 2, // Primitive Value Generators "WasmLoadi32Generator": 4, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 254b18e13..5c1435161 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1601,6 +1601,15 @@ public let WasmCodeGenerators: [CodeGenerator] = [ 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")] diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index c58ffb788..5f104e616 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1553,6 +1553,11 @@ extension Instruction: ProtobufConvertible { $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) @@ -2565,6 +2570,8 @@ extension Instruction: ProtobufConvertible { 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) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 341bd6c8b..d03696473 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -939,6 +939,11 @@ public struct JSTyper: Analyzer { 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)") diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 5d9ff5d11..2d400bd87 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -367,4 +367,5 @@ enum Opcode { case wasmStructNew(WasmStructNew) case wasmRefEq(WasmRefEq) case wasmRefTest(WasmRefTest) + case wasmDefineAdHocModuleSignatureType(WasmDefineAdHocModuleSignatureType) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 243a373af..1217e4fef 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2433,3 +2433,20 @@ final class WasmDefineAdHocSignatureType: WasmOperation { 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/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 44103a423..09479866d 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1367,6 +1367,10 @@ public class FuzzILLifter: Lifter { 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)") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index e5a8fe020..d039bb894 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1774,6 +1774,7 @@ public class JavaScriptLifter: Lifter { .wasmEndTypeGroup(_), .wasmDefineSignatureType(_), .wasmDefineAdHocSignatureType(_), + .wasmDefineAdHocModuleSignatureType(_), .wasmDefineArrayType(_), .wasmDefineStructType(_), .wasmDefineForwardOrSelfReference(_), diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index ab88eba27..c2977ef99 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1224,7 +1224,12 @@ 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) @@ -1321,6 +1326,8 @@ public class WasmLifter { assert(self.exports.contains(where: { $0.isTag && $0.getDefInstr()!.output == instr.output })) + case .wasmDefineAdHocModuleSignatureType(_): + break default: return true } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4d639d213..e69cc62f9 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -726,6 +726,7 @@ public class OperationMutator: BaseInstructionMutator { .wasmDefineStructType(_), .wasmDefineSignatureType(_), .wasmDefineAdHocSignatureType(_), + .wasmDefineAdHocModuleSignatureType(_), .wasmDefineForwardOrSelfReference(_), .wasmResolveForwardReference(_), .wasmArrayNewFixed(_), diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index d20ce24be..5fd382bd3 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5696,6 +5696,20 @@ public struct Fuzzilli_Protobuf_WasmDefineAdHocSignatureType: Sendable { 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 @@ -14986,6 +15000,41 @@ extension Fuzzilli_Protobuf_WasmDefineAdHocSignatureType: SwiftProtobuf.Message, } } +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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index e00e8905f..ee68f9f1b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1499,6 +1499,11 @@ message WasmDefineAdHocSignatureType { repeated WasmILType outputTypes = 2; } +message WasmDefineAdHocModuleSignatureType { + repeated WasmILType parameterTypes = 1; + repeated WasmILType outputTypes = 2; +} + message WasmDefineArrayType { WasmILType elementType = 1; bool mutability = 2; diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 13322cb90..8a02b84ab 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2753,6 +2753,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3094,6 +3102,7 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmStructNew(Fuzzilli_Protobuf_WasmStructNew) case wasmRefEq(Fuzzilli_Protobuf_WasmRefEq) case wasmRefTest(Fuzzilli_Protobuf_WasmRefTest) + case wasmDefineAdHocModuleSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType) } @@ -3142,7 +3151,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7540,6 +7549,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefTest(v) } }() + case 340: 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) + } + }() default: break } } @@ -8906,6 +8928,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmRefTest(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 339) }() + case .wasmDefineAdHocModuleSignatureType?: try { + guard case .wasmDefineAdHocModuleSignatureType(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 340) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 54fb415c4..50121d9cc 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -363,6 +363,7 @@ message Instruction { WasmStructNew wasmStructNew = 337; WasmRefEq wasmRefEq = 338; WasmRefTest wasmRefTest = 339; + WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 340; } } From 782f3997823b196da8ec4fb525438d359b19ff25 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 23 Jan 2026 12:50:28 +0100 Subject: [PATCH 122/234] [wasm] Migrate legacy try-catch to use wasm-gc signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 448860865 Change-Id: Ifd01ae66b862e844bfbdb781dac36b3a8ba2d0bd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956316 Commit-Queue: Matthias Liedtke Reviewed-by: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 76 +++++---- .../CodeGen/CodeGeneratorWeights.swift | 1 - .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 33 +--- Sources/Fuzzilli/FuzzIL/Instruction.swift | 24 ++- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 46 ++++-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 39 ++--- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 10 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 65 ++++---- Sources/Fuzzilli/Protobuf/operations.proto | 11 +- Tests/FuzzilliTests/JSTyperTests.swift | 7 +- Tests/FuzzilliTests/MinimizerTest.swift | 65 ++++---- Tests/FuzzilliTests/WasmTests.swift | 152 +++++++++--------- 13 files changed, 267 insertions(+), 266 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 739ca4fb1..018135cc8 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4072,49 +4072,70 @@ public class ProgramBuilder { return Array(b.emit(WasmEndTryTable(outputTypes: signature.outputTypes), withInputs: results).outputs) } - 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)) + // 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) + let instr = b.emit(WasmBeginTry( + parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) + assert(instr.innerOutputs.count == 1) + body(instr.innerOutput(0)) + for (tag, generator) in catchClauses { + 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( + blockOutputCount: signature.outputTypes.count, + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + withInputs: [signatureDef, tag], + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + 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], + public func wasmBuildLegacyTryWithResult( + signature: WasmSignature, + signatureDef: Variable, + args: [Variable], body: (Variable, [Variable]) -> [Variable], - catchClauses: [(tag: Variable, body: (Variable, 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) + let parameterCount = signature.parameterTypes.count + 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) + let instr = b.emit(WasmBeginCatch( + blockOutputCount: signature.outputTypes.count, + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + withInputs: [signatureDef, tag] + result, + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes) 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]) { @@ -4948,14 +4969,13 @@ public class ProgramBuilder { break case .beginWasmFunction(let op): activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) - case .wasmBeginTry(let op): - activeWasmModule!.blockSignatures.push(op.signature) + case .wasmBeginTry(_): + break case .wasmBeginTryDelegate(let op): activeWasmModule!.blockSignatures.push(op.signature) case .wasmBeginTryTable(let op): activeWasmModule!.blockSignatures.push(op.signature) - case .wasmEndTry(_), - .wasmEndTryDelegate(_), + case .wasmEndTryDelegate(_), .wasmEndTryTable(_): activeWasmModule!.blockSignatures.pop() case .wasmDefineAdHocModuleSignatureType(_): diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index c192e3911..b598b4490 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -321,7 +321,6 @@ public let codeGeneratorWeights = [ "WasmLoopGenerator": 8, "WasmLoopWithSignatureGenerator": 8, "WasmLegacyTryCatchGenerator": 8, - "WasmLegacyTryCatchWithResultGenerator": 8, "WasmLegacyTryDelegateGenerator": 8, "WasmThrowGenerator": 2, "WasmLegacyRethrowGenerator": 10, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 5c1435161..d1919475c 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1404,46 +1404,21 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ]), - // 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) - } - }, - // 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) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 5f104e616..99e78ab84 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1410,21 +1410,20 @@ extension Instruction: ProtobufConvertible { } 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 { @@ -2470,17 +2469,14 @@ extension Instruction: ProtobufConvertible { case .wasmEndTryTable(let p): op = WasmEndTryTable(outputTypes: p.outputTypes.map(WasmTypeEnumToILType)) 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) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index d03696473..2ab94fca3 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -856,24 +856,44 @@ public struct JSTyper: Analyzer { } 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)) + 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: .label(signature.outputTypes)) + case .wasmBeginCatch(_): + let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + // Type the label (used for branch instructions). + setType(of: instr.innerOutput(0), to: .label(blockSignature.outputTypes)) + // 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: .exceptionLabel) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), op.signature.parameterTypes) { + // Type the tag parameters. + guard let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters else { + // TODO(mliedtke): I believe that sooner or later we will run into this fatal + // error. A tag can be defined in JavaScript and then be used in Wasm. Later on + // the varaible defining the tag can be reassigned to with a different type, + // loosening the inferred type information suddenly not being a tag any more. + fatalError("Input into WasmBeginCatch not a tag type, actual " + + "\(type(of: instr.input(1))), defined in \(definingInstruction)") + } + for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), labelParameters) { 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 .wasmEndTry(_): + let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeEndBlock(instr, blockSignature.outputTypes) case .wasmBeginTryDelegate(let op): wasmTypeBeginBlock(instr, op.signature) case .wasmEndTryDelegate(let op): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 1217e4fef..55a2255a0 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1375,23 +1375,24 @@ final class WasmEndTryTable: WasmOperation { 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 { 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, + numInputs: 1 + blockOutputCount, numInnerOutputs: 1, // the label attributes: [ .isBlockEnd, @@ -1406,10 +1407,8 @@ final class WasmBeginCatchAll : 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 @@ -1417,9 +1416,11 @@ final class WasmBeginCatch : WasmOperation { // the usage. For now, we just emit a label for branching and the ".exceptionLabel" for // rethrows. super.init( - numInputs: 1 + signature.outputTypes.count, + // Inputs: The block signature, the tag and the outputs of the preceding try or catch + // (all) block. + numInputs: 2 + 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, @@ -1427,15 +1428,17 @@ final class WasmBeginCatch : WasmOperation { ], requiredContext: [.wasmFunction]) } + + var blockOutputCount: Int {numInputs - 2} + 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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 09479866d..1c3b82878 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1139,9 +1139,9 @@ 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(_): diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index c2977ef99..6ea84331d 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1253,8 +1253,7 @@ public class WasmLifter { self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginTry(let op): - registerSignature(op.signature) + case .wasmBeginTry(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1933,14 +1932,15 @@ public class WasmLifter { + Leb128.unsignedEncode(signatureIndexMap[op.signature]!) + Leb128.unsignedEncode(op.catches.count) + catchTable - case .wasmBeginTry(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 op): return Data([0x06] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) 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(_), diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 5fd382bd3..6c5a1a091 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5221,9 +5221,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() @@ -5235,7 +5233,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() @@ -5247,9 +5245,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() @@ -5261,7 +5259,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() @@ -13862,7 +13860,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() { @@ -13870,26 +13868,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 } @@ -13897,7 +13890,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() { @@ -13905,21 +13898,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 } @@ -13927,7 +13920,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() { @@ -13935,26 +13928,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 } @@ -13962,7 +13955,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() { @@ -13970,21 +13963,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index ee68f9f1b..c803e8cfa 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1270,21 +1270,20 @@ message WasmEndTryTable { } 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 { diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index b5ebb6779..9599398fe 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1551,11 +1551,8 @@ 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 [] } diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 58dd10ec7..32db2dd78 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1550,8 +1550,9 @@ 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) @@ -1565,7 +1566,7 @@ class MinimizerTests: XCTestCase { } 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)] @@ -1582,18 +1583,18 @@ 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 - } - } + 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.consti32(-1)] } } @@ -1602,12 +1603,12 @@ 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.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: []) + }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmReturn(function.consti64(42)) - } - } + })]) return [function.consti32(-1)] } } @@ -1620,14 +1621,11 @@ 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) - evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - function.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmUnreachable() - } - } + function.wasmBuildLegacyTryVoid(body: { label in + let val = function.consti64(42) + evaluator.nextInstructionIsImportant(in: b) + function.wasmReturn(val) + }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) return [function.consti32(-1)] } } @@ -1648,12 +1646,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)] } @@ -2288,6 +2283,10 @@ class MinimizerTests: XCTestCase { 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) } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 96c07452c..ba70c793d 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -338,15 +338,14 @@ class WasmFoundationTests: XCTestCase { let tag = wasmModule.addTag(parameterTypes: [.wasmi32, .wasmi32]) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { _, _ in + function.wasmBuildLegacyTryVoid(body: { _ in function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123), function.consti32(456)]) - function.WasmBuildLegacyCatch(tag: tag) { _, _, e in + }, 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)] } @@ -2938,7 +2937,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid { label in XCTAssert(b.type(of: label).Is(.anyLabel)) function.wasmReturn(function.consti64(42)) } @@ -2971,7 +2970,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid { label in XCTAssert(b.type(of: label).Is(.anyLabel)) // Manually set the availableTypes here for testing. let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) @@ -3014,17 +3013,16 @@ class WasmFoundationTests: XCTestCase { b.buildIfElse(supportsJSTag) { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid(body: { label in XCTAssert(b.type(of: label).Is(.anyLabel)) let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) function.wasmJsCall(function: functionA, withArgs: [], withWasmSignature: wasmSignature) function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: jstag) { label, exception, args in - function.wasmReturn(function.consti64(123)) - } - } catchAllBody: { label in + }, catchClauses: [(tag: jstag, body: { label, exception, args in + function.wasmReturn(function.consti64(123)) + })], catchAllBody: { label in function.wasmUnreachable() - } + }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3070,20 +3068,21 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid(body: { label in XCTAssert(b.type(of: label).Is(.anyLabel)) function.WasmBuildThrow(tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: otherTag) { label, exception, args in + }, catchClauses: [ + (tag: otherTag, body: { label, exception, args in function.wasmUnreachable() - } - function.WasmBuildLegacyCatch(tag: throwTag) { label, exception, args in + }), + (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 + }) + ], catchAllBody: { label in function.wasmUnreachable() - } + }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3106,12 +3105,11 @@ 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.wasmBuildLegacyTryVoid(body: { tryLabel in function.WasmBuildThrow(tag: tag, inputs: []) - function.WasmBuildLegacyCatch(tag: tag) { catchLabel, exceptionLabel, args in - function.wasmBranch(to: catchLabel) - } - } + }, catchClauses: [(tag: tag, body: { catchLabel, exceptionLabel, args in + function.wasmBranch(to: catchLabel) + })]) return [function.consti32(42)] } } @@ -3134,7 +3132,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) @@ -3189,22 +3187,23 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, param in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid(body: { label in function.wasmBuildIfElse(param[0], hint: .None) { _, _ in function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) } elseBody: { _, _ in function.WasmBuildThrow(tag: importedTag, inputs: [function.consti32(123)]) } function.wasmUnreachable() - function.WasmBuildLegacyCatch(tag: importedTag) { label, exception, args in + }, catchClauses: [ + (tag: importedTag, body: { label, exception, args in function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(1), binOpKind: .Add)) - } - function.WasmBuildLegacyCatch(tag: definedTag) { label, exception, args in + }), + (tag: definedTag, body: { label, exception, args in function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(4), binOpKind: .Add)) - } - } catchAllBody: { label in + }) + ], catchAllBody: { label in function.wasmUnreachable() - } + }) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3240,16 +3239,20 @@ 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 + let signature = [.wasmi64, .wasmi32] => [] + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + function.wasmBuildLegacyTryWithResult(signature: signature, signatureDef: signatureDef, + args: [argI64, argI32], body: { label, args in XCTAssert(b.type(of: label).Is(.anyLabel)) XCTAssertEqual(b.type(of: args[0]), .wasmi64) XCTAssertEqual(b.type(of: args[1]), .wasmi32) function.WasmBuildThrow(tag: tag, inputs: args) - 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) - } - } + 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)] } @@ -3279,7 +3282,10 @@ 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 + 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: []) } @@ -3366,23 +3372,22 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { tryLabel, _ 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.wasmBuildLegacyTry(with: [] => [], args: []) { unusedLabel, _ in + 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 + }, catchAllBody: { label in 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)] } @@ -3452,18 +3457,16 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid(body: { 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]) - } - } + }, 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)] } @@ -3505,26 +3508,23 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in - function.wasmBuildLegacyTry(with: [] => [], args: []) { label, _ in + function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid(body: { 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.WasmBuildLegacyCatch(tag: tag) { label, exception, args in - function.wasmReturn(args[0]) - } - } + }, catchClauses: [(tag: tag, body: { label, outerException, args in + function.wasmBuildLegacyTryVoid(body: { label in + function.WasmBuildThrow(tag: tag, inputs: [function.consti32(456)]) + function.wasmUnreachable() + }, catchClauses: [(tag: tag, body: { label, innerException, args in + // There are two "active" exceptions: + // outerException: [123: i32] + // innerException: [456: i32] + function.wasmBuildLegacyRethrow(outerException) + })]) + })]) + }, catchClauses: [(tag: tag, body: { label, exception, args in + function.wasmReturn(args[0]) + })]) function.wasmUnreachable() return [function.consti32(-1)] } From f890d789485a9a2e6fd9cb1a4e2fa59be2b87fb2 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 23 Jan 2026 13:19:12 +0100 Subject: [PATCH 123/234] [wasm] Migrate legacy try-delegate to use wasm-gc signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 448860865 Change-Id: I89bdc92e1757a68dec64da8a7ab90e7c397694eb Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956317 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 27 +++++++++------- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 11 +++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 10 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 20 ++++++------ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 10 +++--- Sources/Fuzzilli/Protobuf/operations.pb.swift | 31 +++++++------------ Sources/Fuzzilli/Protobuf/operations.proto | 5 ++- 9 files changed, 59 insertions(+), 61 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 018135cc8..cbbef1d8d 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4153,18 +4153,24 @@ public class ProgramBuilder { 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) + 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 + return Array(b.emit(WasmEndTryDelegate(outputCount: signature.outputTypes.count), + withInputs: [signatureDef, delegate] + results, + types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes ).outputs) } @@ -4969,14 +4975,13 @@ public class ProgramBuilder { break case .beginWasmFunction(let op): activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) - case .wasmBeginTry(_): + case .wasmBeginTry(_), + .wasmEndTryDelegate(_), + .wasmBeginTryDelegate(_): break - case .wasmBeginTryDelegate(let op): - activeWasmModule!.blockSignatures.push(op.signature) case .wasmBeginTryTable(let op): activeWasmModule!.blockSignatures.push(op.signature) - case .wasmEndTryDelegate(_), - .wasmEndTryTable(_): + case .wasmEndTryTable(_): activeWasmModule!.blockSignatures.pop() case .wasmDefineAdHocModuleSignatureType(_): break diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index d1919475c..4ac64c605 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1444,7 +1444,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ ) { 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( diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 99e78ab84..d947b1787 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1427,12 +1427,11 @@ extension Instruction: ProtobufConvertible { } 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) + $0.outputCount = Int32(op.numOutputs) } case .wasmThrow(_): $0.wasmThrow = Fuzzilli_Protobuf_WasmThrow() @@ -2478,11 +2477,9 @@ extension Instruction: ProtobufConvertible { case .wasmEndTry(let p): 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)) + op = WasmEndTryDelegate(outputCount: Int(p.outputCount)) case .wasmThrow(_): op = WasmThrow(parameterCount: inouts.count - 1) case .wasmThrowRef(_): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 2ab94fca3..569627678 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -894,10 +894,12 @@ public struct JSTyper: Analyzer { case .wasmEndTry(_): let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, blockSignature.outputTypes) - case .wasmBeginTryDelegate(let op): - wasmTypeBeginBlock(instr, op.signature) - case .wasmEndTryDelegate(let op): - wasmTypeEndBlock(instr, op.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) { diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 55a2255a0..a16276aa2 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1445,11 +1445,13 @@ final class WasmEndTry: WasmOperation { /// 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]) } } @@ -1457,12 +1459,12 @@ 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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 1c3b82878..a93ef4500 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1176,8 +1176,8 @@ 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(_): diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 6ea84331d..69737900c 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1257,8 +1257,7 @@ public class WasmLifter { self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true - case .wasmBeginTryDelegate(let op): - registerSignature(op.signature) + case .wasmBeginTryDelegate(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1935,8 +1934,9 @@ public class WasmLifter { case .wasmBeginTry(_): let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) return Data([0x06] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) - case .wasmBeginTryDelegate(let op): - return Data([0x06] + Leb128.unsignedEncode(getSignatureIndexStrict(op.signature))) + case .wasmBeginTryDelegate(_): + let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) + return Data([0x06] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) case .wasmBeginCatchAll(_): return Data([0x19]) case .wasmBeginCatch(_): @@ -1949,7 +1949,7 @@ public class WasmLifter { // 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 diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 6c5a1a091..9459d581b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5271,9 +5271,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() @@ -5285,7 +5283,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() @@ -13985,7 +13983,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() { @@ -13993,26 +13991,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 } @@ -14020,7 +14013,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() { @@ -14028,21 +14021,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index c803e8cfa..6e94da109 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1287,12 +1287,11 @@ message WasmEndTry { } message WasmBeginTryDelegate { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmEndTryDelegate { - repeated WasmILType outputTypes = 1; + int32 outputCount = 1; } message WasmThrow { From 59e7a3dca960cc3f5e99bdf3197d17e6c3888b6c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 23 Jan 2026 15:39:01 +0100 Subject: [PATCH 124/234] [wasm] Migrate try-table to use wasm-gc signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 448860865 Change-Id: I01de000a5ae5fae47634ca64edad7dfd9d028695 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956318 Commit-Queue: Matthias Liedtke Reviewed-by: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 19 +++++----- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 11 +++--- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 10 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 18 +++++----- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 6 ++-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 8 ++--- Sources/Fuzzilli/Protobuf/operations.pb.swift | 35 ++++++++----------- Sources/Fuzzilli/Protobuf/operations.proto | 7 ++-- 9 files changed, 55 insertions(+), 61 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index cbbef1d8d..11052b10e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4067,9 +4067,13 @@ public class ProgramBuilder { } } #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 @@ -4977,13 +4981,10 @@ public class ProgramBuilder { activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) case .wasmBeginTry(_), .wasmEndTryDelegate(_), - .wasmBeginTryDelegate(_): - break - case .wasmBeginTryTable(let op): - activeWasmModule!.blockSignatures.push(op.signature) - case .wasmEndTryTable(_): - activeWasmModule!.blockSignatures.pop() - case .wasmDefineAdHocModuleSignatureType(_): + .wasmBeginTryDelegate(_), + .wasmBeginTryTable(_), + .wasmEndTryTable(_), + .wasmDefineAdHocModuleSignatureType(_): break default: diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 4ac64c605..d9a5031c4 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1695,7 +1695,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 diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index d947b1787..db2e27754 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1400,13 +1400,12 @@ extension Instruction: ProtobufConvertible { } 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 { @@ -2461,12 +2460,10 @@ extension Instruction: ProtobufConvertible { case .wasmEndLoop(let p): 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): op = WasmBeginTry(parameterCount: Int(p.parameterCount)) case .wasmBeginCatchAll(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 569627678..c96032a59 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -846,16 +846,18 @@ public struct JSTyper: Analyzer { case .wasmEndLoop(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, signature.outputTypes) - case .wasmBeginTryTable(let op): - wasmTypeBeginBlock(instr, op.signature) + 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) } } - case .wasmEndTryTable(let op): - wasmTypeEndBlock(instr, op.outputTypes) + 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) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index a16276aa2..3350c2ff5 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1351,25 +1351,27 @@ 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 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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index a93ef4500..c262a11ce 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1114,10 +1114,10 @@ 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])") diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 69737900c..1e902dc46 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1248,8 +1248,7 @@ public class WasmLifter { self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true - case .wasmBeginTryTable(let op): - registerSignature(op.signature) + case .wasmBeginTryTable(_): self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true @@ -1912,7 +1911,8 @@ public class WasmLifter { 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: @@ -1928,7 +1928,7 @@ public class WasmLifter { } }.reduce(Data(), +) return [0x1F] - + Leb128.unsignedEncode(signatureIndexMap[op.signature]!) + + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!) + Leb128.unsignedEncode(op.catches.count) + catchTable case .wasmBeginTry(_): diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 9459d581b..0d528b3f8 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5193,9 +5193,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] = [] @@ -5209,7 +5207,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() @@ -13788,7 +13786,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() { @@ -13796,30 +13794,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 @@ -13828,7 +13821,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() { @@ -13836,21 +13829,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 6e94da109..e15852d6d 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1260,13 +1260,12 @@ 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 { From 0043c8b58c5f2c6d778ce21a0001a8674dfdcb8a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 23 Jan 2026 16:54:41 +0100 Subject: [PATCH 125/234] [wasm] Migrate tags to use wasm-gc signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With all instructions interacting with Wasm tags switched over to using wasm-gc signatures in previous changes, tags can now also be adapted to use wasm-gc types in their signature (their parameter types). Note that it is also possible to define tags from JS, e.g.: > new WebAssembly.Tag({parameters: ['i32']}) However, these tags do not support index types in the JS API spec, so they can continue using the current mechanism for their type information. Bug: 448860865 Change-Id: If558f0562609d7a26a0119a4055184506351bd52 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956197 Reviewed-by: Doga Yüksel Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 21 +++++++++++++------ .../Fuzzilli/CodeGen/ProgramTemplates.swift | 2 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 10 +++++++-- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 ++++----- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 +++-- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 7 +++---- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 10 ++------- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 +++-------------- Sources/Fuzzilli/Protobuf/operations.proto | 1 - 10 files changed, 41 insertions(+), 48 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 11052b10e..c4c76128d 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4534,9 +4534,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 { @@ -4616,7 +4623,8 @@ public class ProgramBuilder { } } - 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. @@ -4646,16 +4654,17 @@ public class ProgramBuilder { return params => returnTypes } - public func randomWasmGcSignature() -> (signature: WasmSignature, indexTypes: [Variable]) { + public func randomWasmGcSignature(withResults: Bool = true, allowNonNullable: Bool = true) + -> (signature: WasmSignature, indexTypes: [Variable]) { let typeCount = Int.random(in: 0...10) - let returnCount = Int.random(in: 0...typeCount) + 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 = - self.type(of: elementType).wasmTypeDefinition!.description == .selfReference + let nullability = !allowNonNullable + || self.type(of: elementType).wasmTypeDefinition!.description == .selfReference || probability(0.5) indexTypes.append(elementType) return ILType.wasmRef(.Index(), nullability: nullability) diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 3c257d5f2..9fce1cfd4 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -146,7 +146,7 @@ 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) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index d9a5031c4..3311b897a 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -52,7 +52,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ if probability(0.5) { b.createWasmJSTag() } else { - b.createWasmTag(parameterTypes: b.randomTagParameters()) + b.createWasmTag(parameterTypes: b.randomTagParametersJs()) } }, // @@ -1589,7 +1589,13 @@ public let WasmCodeGenerators: [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( diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index db2e27754..c176aed92 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1438,10 +1438,8 @@ extension Instruction: ProtobufConvertible { $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 .wasmDefineTag(_): + $0.wasmDefineTag = Fuzzilli_Protobuf_WasmDefineTag() case .wasmBranch(_): $0.wasmBranch = Fuzzilli_Protobuf_WasmBranch() case .wasmBranchIf(let op): @@ -2483,8 +2481,8 @@ extension Instruction: ProtobufConvertible { op = WasmThrowRef() case .wasmRethrow(_): op = WasmRethrow() - case .wasmDefineTag(let p): - op = WasmDefineTag(parameterTypes: p.parameterTypes.map(WasmTypeEnumToILType)) + case .wasmDefineTag(_): + op = WasmDefineTag() case .wasmBranch(_): op = WasmBranch(parameterCount: inouts.count - 1) case .wasmBranchIf(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index c96032a59..f67f99030 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -754,8 +754,9 @@ 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))) + 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)) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 3350c2ff5..9dbc9da1e 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -877,11 +877,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]) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index c262a11ce..3b8d29dff 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -873,8 +873,8 @@ public class FuzzILLifter: Lifter { 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))") diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 1e902dc46..754643e9e 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -622,12 +622,6 @@ public class WasmLifter { 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 { registerSignature(functionInfo!.signature) @@ -1142,9 +1136,9 @@ 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 => [] + 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)) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 0d528b3f8..d1cd191a1 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5323,8 +5323,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() {} @@ -14093,29 +14091,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) - } 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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index e15852d6d..ce4bbbad2 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1303,7 +1303,6 @@ message WasmRethrow { } message WasmDefineTag { - repeated WasmILType parameterTypes = 1; } message WasmBranch { From 9f9c3710e9979f3d10317612cb3f27c42f9491f7 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 18 Feb 2026 16:13:01 +0100 Subject: [PATCH 126/234] Update swift-protobuf version and pin it to a strict version The pinning ensures that our presubmit-check and all developers working on Fuzzilli have a consistent version used for regenerating the *.bp.swift files. The non-exact version caused the GitHub run to fail as a newer swift-protobuf version now resulted in diffs in the generated files. Change-Id: I4edeae1a38e0b912a45e17b20b950066db4b24d4 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9032256 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach --- Package.swift | 6 +- Sources/Fuzzilli/Protobuf/ast.pb.swift | 258 +++++++++--------- Sources/Fuzzilli/Protobuf/operations.pb.swift | 148 +++++----- Sources/Fuzzilli/Protobuf/program.pb.swift | 10 +- Sources/Fuzzilli/Protobuf/sync.pb.swift | 36 +-- 5 files changed, 231 insertions(+), 227 deletions(-) diff --git a/Package.swift b/Package.swift index 62f6609c4..35a5128d1 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,11 @@ let package = Package( .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") diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 92ba974ad..8eddca120 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -203,17 +203,17 @@ public struct Compiler_Protobuf_VariableDeclarator: @unchecked Sendable { // methods supported on all messages. public var name: String { - get {return _storage._name} + get {_storage._name} set {_uniqueStorage()._name = newValue} } /// The value is optional public var value: Compiler_Protobuf_Expression { - get {return _storage._value ?? Compiler_Protobuf_Expression()} + get {_storage._value ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._value = newValue} } /// Returns true if `value` has been explicitly set. - public var hasValue: Bool {return _storage._value != nil} + public var hasValue: Bool {_storage._value != nil} /// Clears the value of `value`. Subsequent reads from it will return its default value. public mutating func clearValue() {_uniqueStorage()._value = nil} @@ -276,11 +276,11 @@ public struct Compiler_Protobuf_FunctionDeclaration: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain public var parameters: Compiler_Protobuf_Parameters { - get {return _parameters ?? Compiler_Protobuf_Parameters()} + get {_parameters ?? Compiler_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} @@ -348,11 +348,11 @@ public struct Compiler_Protobuf_ClassProperty: Sendable { // methods supported on all messages. public var key: Compiler_Protobuf_PropertyKey { - get {return _key ?? Compiler_Protobuf_PropertyKey()} + get {_key ?? Compiler_Protobuf_PropertyKey()} set {_key = newValue} } /// Returns true if `key` has been explicitly set. - public var hasKey: Bool {return self._key != nil} + public var hasKey: Bool {self._key != nil} /// Clears the value of `key`. Subsequent reads from it will return its default value. public mutating func clearKey() {self._key = nil} @@ -360,11 +360,11 @@ public struct Compiler_Protobuf_ClassProperty: Sendable { /// The value is optional public var value: Compiler_Protobuf_Expression { - get {return _value ?? Compiler_Protobuf_Expression()} + get {_value ?? Compiler_Protobuf_Expression()} set {_value = newValue} } /// Returns true if `value` has been explicitly set. - public var hasValue: Bool {return self._value != nil} + public var hasValue: Bool {self._value != nil} /// Clears the value of `value`. Subsequent reads from it will return its default value. public mutating func clearValue() {self._value = nil} @@ -382,11 +382,11 @@ public struct Compiler_Protobuf_ClassConstructor: Sendable { // methods supported on all messages. public var parameters: Compiler_Protobuf_Parameters { - get {return _parameters ?? Compiler_Protobuf_Parameters()} + get {_parameters ?? Compiler_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} @@ -405,22 +405,22 @@ public struct Compiler_Protobuf_ClassMethod: Sendable { // methods supported on all messages. public var key: Compiler_Protobuf_PropertyKey { - get {return _key ?? Compiler_Protobuf_PropertyKey()} + get {_key ?? Compiler_Protobuf_PropertyKey()} set {_key = newValue} } /// Returns true if `key` has been explicitly set. - public var hasKey: Bool {return self._key != nil} + public var hasKey: Bool {self._key != nil} /// Clears the value of `key`. Subsequent reads from it will return its default value. public mutating func clearKey() {self._key = nil} public var isStatic: Bool = false public var parameters: Compiler_Protobuf_Parameters { - get {return _parameters ?? Compiler_Protobuf_Parameters()} + get {_parameters ?? Compiler_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} @@ -460,11 +460,11 @@ public struct Compiler_Protobuf_ClassSetter: Sendable { public var isStatic: Bool = false public var parameter: Compiler_Protobuf_Parameter { - get {return _parameter ?? Compiler_Protobuf_Parameter()} + get {_parameter ?? Compiler_Protobuf_Parameter()} set {_parameter = newValue} } /// Returns true if `parameter` has been explicitly set. - public var hasParameter: Bool {return self._parameter != nil} + public var hasParameter: Bool {self._parameter != nil} /// Clears the value of `parameter`. Subsequent reads from it will return its default value. public mutating func clearParameter() {self._parameter = nil} @@ -565,22 +565,22 @@ public struct Compiler_Protobuf_ClassDeclaration: @unchecked Sendable { // methods supported on all messages. public var name: String { - get {return _storage._name} + get {_storage._name} set {_uniqueStorage()._name = newValue} } /// The superclass is optional public var superClass: Compiler_Protobuf_Expression { - get {return _storage._superClass ?? Compiler_Protobuf_Expression()} + get {_storage._superClass ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._superClass = newValue} } /// Returns true if `superClass` has been explicitly set. - public var hasSuperClass: Bool {return _storage._superClass != nil} + public var hasSuperClass: Bool {_storage._superClass != nil} /// Clears the value of `superClass`. Subsequent reads from it will return its default value. public mutating func clearSuperClass() {_uniqueStorage()._superClass = nil} public var fields: [Compiler_Protobuf_ClassField] { - get {return _storage._fields} + get {_storage._fields} set {_uniqueStorage()._fields = newValue} } @@ -598,22 +598,22 @@ public struct Compiler_Protobuf_ClassExpression: @unchecked Sendable { /// The name is optional public var name: String { - get {return _storage._name} + get {_storage._name} set {_uniqueStorage()._name = newValue} } /// The superclass is optional public var superClass: Compiler_Protobuf_Expression { - get {return _storage._superClass ?? Compiler_Protobuf_Expression()} + get {_storage._superClass ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._superClass = newValue} } /// Returns true if `superClass` has been explicitly set. - public var hasSuperClass: Bool {return _storage._superClass != nil} + public var hasSuperClass: Bool {_storage._superClass != nil} /// Clears the value of `superClass`. Subsequent reads from it will return its default value. public mutating func clearSuperClass() {_uniqueStorage()._superClass = nil} public var fields: [Compiler_Protobuf_ClassField] { - get {return _storage._fields} + get {_storage._fields} set {_uniqueStorage()._fields = newValue} } @@ -631,11 +631,11 @@ public struct Compiler_Protobuf_ReturnStatement: @unchecked Sendable { /// The argument is optional public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -664,11 +664,11 @@ public struct Compiler_Protobuf_ExpressionStatement: @unchecked Sendable { // methods supported on all messages. public var expression: Compiler_Protobuf_Expression { - get {return _storage._expression ?? Compiler_Protobuf_Expression()} + get {_storage._expression ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._expression = newValue} } /// Returns true if `expression` has been explicitly set. - public var hasExpression: Bool {return _storage._expression != nil} + public var hasExpression: Bool {_storage._expression != nil} /// Clears the value of `expression`. Subsequent reads from it will return its default value. public mutating func clearExpression() {_uniqueStorage()._expression = nil} @@ -685,30 +685,30 @@ public struct Compiler_Protobuf_IfStatement: @unchecked Sendable { // methods supported on all messages. public var test: Compiler_Protobuf_Expression { - get {return _storage._test ?? Compiler_Protobuf_Expression()} + get {_storage._test ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._test = newValue} } /// Returns true if `test` has been explicitly set. - public var hasTest: Bool {return _storage._test != nil} + public var hasTest: Bool {_storage._test != nil} /// Clears the value of `test`. Subsequent reads from it will return its default value. public mutating func clearTest() {_uniqueStorage()._test = nil} public var ifBody: Compiler_Protobuf_Statement { - get {return _storage._ifBody ?? Compiler_Protobuf_Statement()} + get {_storage._ifBody ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._ifBody = newValue} } /// Returns true if `ifBody` has been explicitly set. - public var hasIfBody: Bool {return _storage._ifBody != nil} + public var hasIfBody: Bool {_storage._ifBody != nil} /// Clears the value of `ifBody`. Subsequent reads from it will return its default value. public mutating func clearIfBody() {_uniqueStorage()._ifBody = nil} /// The else body is optional public var elseBody: Compiler_Protobuf_Statement { - get {return _storage._elseBody ?? Compiler_Protobuf_Statement()} + get {_storage._elseBody ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._elseBody = newValue} } /// Returns true if `elseBody` has been explicitly set. - public var hasElseBody: Bool {return _storage._elseBody != nil} + public var hasElseBody: Bool {_storage._elseBody != nil} /// Clears the value of `elseBody`. Subsequent reads from it will return its default value. public mutating func clearElseBody() {_uniqueStorage()._elseBody = nil} @@ -725,20 +725,20 @@ public struct Compiler_Protobuf_WhileLoop: @unchecked Sendable { // methods supported on all messages. public var test: Compiler_Protobuf_Expression { - get {return _storage._test ?? Compiler_Protobuf_Expression()} + get {_storage._test ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._test = newValue} } /// Returns true if `test` has been explicitly set. - public var hasTest: Bool {return _storage._test != nil} + public var hasTest: Bool {_storage._test != nil} /// Clears the value of `test`. Subsequent reads from it will return its default value. public mutating func clearTest() {_uniqueStorage()._test = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -755,20 +755,20 @@ public struct Compiler_Protobuf_DoWhileLoop: @unchecked Sendable { // methods supported on all messages. public var test: Compiler_Protobuf_Expression { - get {return _storage._test ?? Compiler_Protobuf_Expression()} + get {_storage._test ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._test = newValue} } /// Returns true if `test` has been explicitly set. - public var hasTest: Bool {return _storage._test != nil} + public var hasTest: Bool {_storage._test != nil} /// Clears the value of `test`. Subsequent reads from it will return its default value. public mutating func clearTest() {_uniqueStorage()._test = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -808,30 +808,30 @@ public struct Compiler_Protobuf_ForLoop: @unchecked Sendable { /// This field is optional public var condition: Compiler_Protobuf_Expression { - get {return _storage._condition ?? Compiler_Protobuf_Expression()} + get {_storage._condition ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._condition = newValue} } /// Returns true if `condition` has been explicitly set. - public var hasCondition: Bool {return _storage._condition != nil} + public var hasCondition: Bool {_storage._condition != nil} /// Clears the value of `condition`. Subsequent reads from it will return its default value. public mutating func clearCondition() {_uniqueStorage()._condition = nil} /// This field is optional public var afterthought: Compiler_Protobuf_Expression { - get {return _storage._afterthought ?? Compiler_Protobuf_Expression()} + get {_storage._afterthought ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._afterthought = newValue} } /// Returns true if `afterthought` has been explicitly set. - public var hasAfterthought: Bool {return _storage._afterthought != nil} + public var hasAfterthought: Bool {_storage._afterthought != nil} /// Clears the value of `afterthought`. Subsequent reads from it will return its default value. public mutating func clearAfterthought() {_uniqueStorage()._afterthought = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -855,29 +855,29 @@ public struct Compiler_Protobuf_ForInLoop: @unchecked Sendable { // methods supported on all messages. public var left: Compiler_Protobuf_VariableDeclarator { - get {return _storage._left ?? Compiler_Protobuf_VariableDeclarator()} + get {_storage._left ?? Compiler_Protobuf_VariableDeclarator()} set {_uniqueStorage()._left = newValue} } /// Returns true if `left` has been explicitly set. - public var hasLeft: Bool {return _storage._left != nil} + public var hasLeft: Bool {_storage._left != nil} /// Clears the value of `left`. Subsequent reads from it will return its default value. public mutating func clearLeft() {_uniqueStorage()._left = nil} public var right: Compiler_Protobuf_Expression { - get {return _storage._right ?? Compiler_Protobuf_Expression()} + get {_storage._right ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._right = newValue} } /// Returns true if `right` has been explicitly set. - public var hasRight: Bool {return _storage._right != nil} + public var hasRight: Bool {_storage._right != nil} /// Clears the value of `right`. Subsequent reads from it will return its default value. public mutating func clearRight() {_uniqueStorage()._right = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -894,29 +894,29 @@ public struct Compiler_Protobuf_ForOfLoop: @unchecked Sendable { // methods supported on all messages. public var left: Compiler_Protobuf_VariableDeclarator { - get {return _storage._left ?? Compiler_Protobuf_VariableDeclarator()} + get {_storage._left ?? Compiler_Protobuf_VariableDeclarator()} set {_uniqueStorage()._left = newValue} } /// Returns true if `left` has been explicitly set. - public var hasLeft: Bool {return _storage._left != nil} + public var hasLeft: Bool {_storage._left != nil} /// Clears the value of `left`. Subsequent reads from it will return its default value. public mutating func clearLeft() {_uniqueStorage()._left = nil} public var right: Compiler_Protobuf_Expression { - get {return _storage._right ?? Compiler_Protobuf_Expression()} + get {_storage._right ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._right = newValue} } /// Returns true if `right` has been explicitly set. - public var hasRight: Bool {return _storage._right != nil} + public var hasRight: Bool {_storage._right != nil} /// Clears the value of `right`. Subsequent reads from it will return its default value. public mutating func clearRight() {_uniqueStorage()._right = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -954,11 +954,11 @@ public struct Compiler_Protobuf_CatchClause: Sendable { /// The parameter is optional public var parameter: Compiler_Protobuf_Parameter { - get {return _parameter ?? Compiler_Protobuf_Parameter()} + get {_parameter ?? Compiler_Protobuf_Parameter()} set {_parameter = newValue} } /// Returns true if `parameter` has been explicitly set. - public var hasParameter: Bool {return self._parameter != nil} + public var hasParameter: Bool {self._parameter != nil} /// Clears the value of `parameter`. Subsequent reads from it will return its default value. public mutating func clearParameter() {self._parameter = nil} @@ -992,21 +992,21 @@ public struct Compiler_Protobuf_TryStatement: Sendable { /// The catch clause is optional public var `catch`: Compiler_Protobuf_CatchClause { - get {return _catch ?? Compiler_Protobuf_CatchClause()} + get {_catch ?? Compiler_Protobuf_CatchClause()} set {_catch = newValue} } /// Returns true if ``catch`` has been explicitly set. - public var hasCatch: Bool {return self._catch != nil} + public var hasCatch: Bool {self._catch != nil} /// Clears the value of ``catch``. Subsequent reads from it will return its default value. public mutating func clearCatch() {self._catch = nil} /// The finally clause is optional public var finally: Compiler_Protobuf_FinallyClause { - get {return _finally ?? Compiler_Protobuf_FinallyClause()} + get {_finally ?? Compiler_Protobuf_FinallyClause()} set {_finally = newValue} } /// Returns true if `finally` has been explicitly set. - public var hasFinally: Bool {return self._finally != nil} + public var hasFinally: Bool {self._finally != nil} /// Clears the value of `finally`. Subsequent reads from it will return its default value. public mutating func clearFinally() {self._finally = nil} @@ -1024,11 +1024,11 @@ public struct Compiler_Protobuf_ThrowStatement: @unchecked Sendable { // methods supported on all messages. public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -1045,20 +1045,20 @@ public struct Compiler_Protobuf_WithStatement: @unchecked Sendable { // methods supported on all messages. public var object: Compiler_Protobuf_Expression { - get {return _storage._object ?? Compiler_Protobuf_Expression()} + get {_storage._object ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._object = newValue} } /// Returns true if `object` has been explicitly set. - public var hasObject: Bool {return _storage._object != nil} + public var hasObject: Bool {_storage._object != nil} /// Clears the value of `object`. Subsequent reads from it will return its default value. public mutating func clearObject() {_uniqueStorage()._object = nil} public var body: Compiler_Protobuf_Statement { - get {return _storage._body ?? Compiler_Protobuf_Statement()} + get {_storage._body ?? Compiler_Protobuf_Statement()} set {_uniqueStorage()._body = newValue} } /// Returns true if `body` has been explicitly set. - public var hasBody: Bool {return _storage._body != nil} + public var hasBody: Bool {_storage._body != nil} /// Clears the value of `body`. Subsequent reads from it will return its default value. public mutating func clearBody() {_uniqueStorage()._body = nil} @@ -1075,16 +1075,16 @@ public struct Compiler_Protobuf_SwitchStatement: @unchecked Sendable { // methods supported on all messages. public var discriminant: Compiler_Protobuf_Expression { - get {return _storage._discriminant ?? Compiler_Protobuf_Expression()} + get {_storage._discriminant ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._discriminant = newValue} } /// Returns true if `discriminant` has been explicitly set. - public var hasDiscriminant: Bool {return _storage._discriminant != nil} + public var hasDiscriminant: Bool {_storage._discriminant != nil} /// Clears the value of `discriminant`. Subsequent reads from it will return its default value. public mutating func clearDiscriminant() {_uniqueStorage()._discriminant = nil} public var cases: [Compiler_Protobuf_SwitchCase] { - get {return _storage._cases} + get {_storage._cases} set {_uniqueStorage()._cases = newValue} } @@ -1101,11 +1101,11 @@ public struct Compiler_Protobuf_SwitchCase: Sendable { // methods supported on all messages. public var test: Compiler_Protobuf_Expression { - get {return _test ?? Compiler_Protobuf_Expression()} + get {_test ?? Compiler_Protobuf_Expression()} set {_test = newValue} } /// Returns true if `test` has been explicitly set. - public var hasTest: Bool {return self._test != nil} + public var hasTest: Bool {self._test != nil} /// Clears the value of `test`. Subsequent reads from it will return its default value. public mutating func clearTest() {self._test = nil} @@ -1442,25 +1442,25 @@ public struct Compiler_Protobuf_AssignmentExpression: @unchecked Sendable { // methods supported on all messages. public var `operator`: String { - get {return _storage._operator} + get {_storage._operator} set {_uniqueStorage()._operator = newValue} } public var lhs: Compiler_Protobuf_Expression { - get {return _storage._lhs ?? Compiler_Protobuf_Expression()} + get {_storage._lhs ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._lhs = newValue} } /// Returns true if `lhs` has been explicitly set. - public var hasLhs: Bool {return _storage._lhs != nil} + public var hasLhs: Bool {_storage._lhs != nil} /// Clears the value of `lhs`. Subsequent reads from it will return its default value. public mutating func clearLhs() {_uniqueStorage()._lhs = nil} public var rhs: Compiler_Protobuf_Expression { - get {return _storage._rhs ?? Compiler_Protobuf_Expression()} + get {_storage._rhs ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._rhs = newValue} } /// Returns true if `rhs` has been explicitly set. - public var hasRhs: Bool {return _storage._rhs != nil} + public var hasRhs: Bool {_storage._rhs != nil} /// Clears the value of `rhs`. Subsequent reads from it will return its default value. public mutating func clearRhs() {_uniqueStorage()._rhs = nil} @@ -1506,11 +1506,11 @@ public struct Compiler_Protobuf_ObjectProperty: Sendable { } public var value: Compiler_Protobuf_Expression { - get {return _value ?? Compiler_Protobuf_Expression()} + get {_value ?? Compiler_Protobuf_Expression()} set {_value = newValue} } /// Returns true if `value` has been explicitly set. - public var hasValue: Bool {return self._value != nil} + public var hasValue: Bool {self._value != nil} /// Clears the value of `value`. Subsequent reads from it will return its default value. public mutating func clearValue() {self._value = nil} @@ -1557,11 +1557,11 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain public var parameters: Compiler_Protobuf_Parameters { - get {return _parameters ?? Compiler_Protobuf_Parameters()} + get {_parameters ?? Compiler_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} @@ -1640,11 +1640,11 @@ public struct Compiler_Protobuf_ObjectSetter: Sendable { } public var parameter: Compiler_Protobuf_Parameter { - get {return _parameter ?? Compiler_Protobuf_Parameter()} + get {_parameter ?? Compiler_Protobuf_Parameter()} set {_parameter = newValue} } /// Returns true if `parameter` has been explicitly set. - public var hasParameter: Bool {return self._parameter != nil} + public var hasParameter: Bool {self._parameter != nil} /// Clears the value of `parameter`. Subsequent reads from it will return its default value. public mutating func clearParameter() {self._parameter = nil} @@ -1751,11 +1751,11 @@ public struct Compiler_Protobuf_FunctionExpression: Sendable { public var type: Compiler_Protobuf_FunctionType = .plain public var parameters: Compiler_Protobuf_Parameters { - get {return _parameters ?? Compiler_Protobuf_Parameters()} + get {_parameters ?? Compiler_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} @@ -1774,16 +1774,16 @@ public struct Compiler_Protobuf_ArrowFunctionExpression: @unchecked Sendable { // methods supported on all messages. public var type: Compiler_Protobuf_FunctionType { - get {return _storage._type} + get {_storage._type} set {_uniqueStorage()._type = newValue} } public var parameters: Compiler_Protobuf_Parameters { - get {return _storage._parameters ?? Compiler_Protobuf_Parameters()} + get {_storage._parameters ?? Compiler_Protobuf_Parameters()} set {_uniqueStorage()._parameters = newValue} } /// Returns true if `parameters` has been explicitly set. - public var hasParameters: Bool {return _storage._parameters != nil} + public var hasParameters: Bool {_storage._parameters != nil} /// Clears the value of `parameters`. Subsequent reads from it will return its default value. public mutating func clearParameters() {_uniqueStorage()._parameters = nil} @@ -1829,21 +1829,21 @@ public struct Compiler_Protobuf_CallExpression: @unchecked Sendable { // methods supported on all messages. public var callee: Compiler_Protobuf_Expression { - get {return _storage._callee ?? Compiler_Protobuf_Expression()} + get {_storage._callee ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._callee = newValue} } /// Returns true if `callee` has been explicitly set. - public var hasCallee: Bool {return _storage._callee != nil} + public var hasCallee: Bool {_storage._callee != nil} /// Clears the value of `callee`. Subsequent reads from it will return its default value. public mutating func clearCallee() {_uniqueStorage()._callee = nil} public var arguments: [Compiler_Protobuf_Expression] { - get {return _storage._arguments} + get {_storage._arguments} set {_uniqueStorage()._arguments = newValue} } public var isOptional: Bool { - get {return _storage._isOptional} + get {_storage._isOptional} set {_uniqueStorage()._isOptional = newValue} } @@ -1860,16 +1860,16 @@ public struct Compiler_Protobuf_NewExpression: @unchecked Sendable { // methods supported on all messages. public var callee: Compiler_Protobuf_Expression { - get {return _storage._callee ?? Compiler_Protobuf_Expression()} + get {_storage._callee ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._callee = newValue} } /// Returns true if `callee` has been explicitly set. - public var hasCallee: Bool {return _storage._callee != nil} + public var hasCallee: Bool {_storage._callee != nil} /// Clears the value of `callee`. Subsequent reads from it will return its default value. public mutating func clearCallee() {_uniqueStorage()._callee = nil} public var arguments: [Compiler_Protobuf_Expression] { - get {return _storage._arguments} + get {_storage._arguments} set {_uniqueStorage()._arguments = newValue} } @@ -1886,11 +1886,11 @@ public struct Compiler_Protobuf_MemberExpression: @unchecked Sendable { // methods supported on all messages. public var object: Compiler_Protobuf_Expression { - get {return _storage._object ?? Compiler_Protobuf_Expression()} + get {_storage._object ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._object = newValue} } /// Returns true if `object` has been explicitly set. - public var hasObject: Bool {return _storage._object != nil} + public var hasObject: Bool {_storage._object != nil} /// Clears the value of `object`. Subsequent reads from it will return its default value. public mutating func clearObject() {_uniqueStorage()._object = nil} @@ -1918,7 +1918,7 @@ public struct Compiler_Protobuf_MemberExpression: @unchecked Sendable { } public var isOptional: Bool { - get {return _storage._isOptional} + get {_storage._isOptional} set {_uniqueStorage()._isOptional = newValue} } @@ -1943,16 +1943,16 @@ public struct Compiler_Protobuf_UnaryExpression: @unchecked Sendable { // methods supported on all messages. public var `operator`: String { - get {return _storage._operator} + get {_storage._operator} set {_uniqueStorage()._operator = newValue} } public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -1969,25 +1969,25 @@ public struct Compiler_Protobuf_BinaryExpression: @unchecked Sendable { // methods supported on all messages. public var `operator`: String { - get {return _storage._operator} + get {_storage._operator} set {_uniqueStorage()._operator = newValue} } public var lhs: Compiler_Protobuf_Expression { - get {return _storage._lhs ?? Compiler_Protobuf_Expression()} + get {_storage._lhs ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._lhs = newValue} } /// Returns true if `lhs` has been explicitly set. - public var hasLhs: Bool {return _storage._lhs != nil} + public var hasLhs: Bool {_storage._lhs != nil} /// Clears the value of `lhs`. Subsequent reads from it will return its default value. public mutating func clearLhs() {_uniqueStorage()._lhs = nil} public var rhs: Compiler_Protobuf_Expression { - get {return _storage._rhs ?? Compiler_Protobuf_Expression()} + get {_storage._rhs ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._rhs = newValue} } /// Returns true if `rhs` has been explicitly set. - public var hasRhs: Bool {return _storage._rhs != nil} + public var hasRhs: Bool {_storage._rhs != nil} /// Clears the value of `rhs`. Subsequent reads from it will return its default value. public mutating func clearRhs() {_uniqueStorage()._rhs = nil} @@ -2004,21 +2004,21 @@ public struct Compiler_Protobuf_UpdateExpression: @unchecked Sendable { // methods supported on all messages. public var `operator`: String { - get {return _storage._operator} + get {_storage._operator} set {_uniqueStorage()._operator = newValue} } public var isPrefix: Bool { - get {return _storage._isPrefix} + get {_storage._isPrefix} set {_uniqueStorage()._isPrefix = newValue} } public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -2036,11 +2036,11 @@ public struct Compiler_Protobuf_YieldExpression: @unchecked Sendable { /// The argument is optional public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -2057,11 +2057,11 @@ public struct Compiler_Protobuf_SpreadElement: @unchecked Sendable { // methods supported on all messages. public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -2103,31 +2103,31 @@ public struct Compiler_Protobuf_TernaryExpression: @unchecked Sendable { /// The test condition of the ternary expression. public var condition: Compiler_Protobuf_Expression { - get {return _storage._condition ?? Compiler_Protobuf_Expression()} + get {_storage._condition ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._condition = newValue} } /// Returns true if `condition` has been explicitly set. - public var hasCondition: Bool {return _storage._condition != nil} + public var hasCondition: Bool {_storage._condition != nil} /// Clears the value of `condition`. Subsequent reads from it will return its default value. public mutating func clearCondition() {_uniqueStorage()._condition = nil} /// The expression executed if the test is true. public var consequent: Compiler_Protobuf_Expression { - get {return _storage._consequent ?? Compiler_Protobuf_Expression()} + get {_storage._consequent ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._consequent = newValue} } /// Returns true if `consequent` has been explicitly set. - public var hasConsequent: Bool {return _storage._consequent != nil} + public var hasConsequent: Bool {_storage._consequent != nil} /// Clears the value of `consequent`. Subsequent reads from it will return its default value. public mutating func clearConsequent() {_uniqueStorage()._consequent = nil} /// The expression executed if the test is false. public var alternate: Compiler_Protobuf_Expression { - get {return _storage._alternate ?? Compiler_Protobuf_Expression()} + get {_storage._alternate ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._alternate = newValue} } /// Returns true if `alternate` has been explicitly set. - public var hasAlternate: Bool {return _storage._alternate != nil} + public var hasAlternate: Bool {_storage._alternate != nil} /// Clears the value of `alternate`. Subsequent reads from it will return its default value. public mutating func clearAlternate() {_uniqueStorage()._alternate = nil} @@ -2144,11 +2144,11 @@ public struct Compiler_Protobuf_AwaitExpression: @unchecked Sendable { // methods supported on all messages. public var argument: Compiler_Protobuf_Expression { - get {return _storage._argument ?? Compiler_Protobuf_Expression()} + get {_storage._argument ?? Compiler_Protobuf_Expression()} set {_uniqueStorage()._argument = newValue} } /// Returns true if `argument` has been explicitly set. - public var hasArgument: Bool {return _storage._argument != nil} + public var hasArgument: Bool {_storage._argument != nil} /// Clears the value of `argument`. Subsequent reads from it will return its default value. public mutating func clearArgument() {_uniqueStorage()._argument = nil} @@ -2187,7 +2187,7 @@ public struct Compiler_Protobuf_SuperMemberExpression: @unchecked Sendable { } public var isOptional: Bool { - get {return _storage._isOptional} + get {_storage._isOptional} set {_uniqueStorage()._isOptional = newValue} } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index d1cd191a1..d312a189c 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1655,11 +1655,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 +1828,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 +1859,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} @@ -1958,11 +1958,11 @@ public struct Fuzzilli_Protobuf_BeginClassConstructor: 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} @@ -2031,11 +2031,11 @@ public struct Fuzzilli_Protobuf_BeginClassInstanceMethod: 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} @@ -2062,11 +2062,11 @@ public struct Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: 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} @@ -2199,11 +2199,11 @@ public struct Fuzzilli_Protobuf_BeginClassStaticMethod: 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} @@ -2230,11 +2230,11 @@ public struct Fuzzilli_Protobuf_BeginClassStaticComputedMethod: 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} @@ -2321,11 +2321,11 @@ public struct Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: 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} @@ -2368,11 +2368,11 @@ 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} @@ -2721,11 +2721,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 +2755,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 +2786,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 +2820,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 +2854,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 +2885,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 +2919,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 +3934,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 +3955,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 +3976,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} @@ -4758,11 +4758,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} @@ -4783,11 +4783,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} @@ -4820,11 +4820,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} @@ -4841,22 +4841,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} @@ -4878,11 +4878,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} @@ -4899,11 +4899,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} @@ -4920,11 +4920,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} @@ -4942,22 +4942,22 @@ public struct Fuzzilli_Protobuf_WasmTableGet: 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} @@ -4977,22 +4977,22 @@ public struct Fuzzilli_Protobuf_WasmTableSet: 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} @@ -5708,11 +5708,11 @@ public struct Fuzzilli_Protobuf_WasmDefineArrayType: 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} @@ -5731,11 +5731,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} @@ -5884,11 +5884,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} @@ -5925,11 +5925,11 @@ public struct Fuzzilli_Protobuf_WasmRefTest: 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} diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 8a02b84ab..a632bad38 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -3115,26 +3115,26 @@ 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} diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift index d59ac9658..f17c236ce 100644 --- a/Sources/Fuzzilli/Protobuf/sync.pb.swift +++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift @@ -77,109 +77,109 @@ 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 {return _storage._differentialSamples} + get {_storage._differentialSamples} set {_uniqueStorage()._differentialSamples = newValue} } From 98e2354bc779d452188458913973673731514e2b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 18 Feb 2026 14:25:48 +0100 Subject: [PATCH 127/234] [tools] presubmit.py: Print actual diff on presubmit failure Change-Id: I174dd958c7854b0fa59228085bd23fe01cdf1fa0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9032276 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke --- Tools/presubmit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tools/presubmit.py b/Tools/presubmit.py index df04798e6..7c6efa58e 100644 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -20,7 +20,10 @@ def check_git_clean(): 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: {output}\n== Diff ==\n{diff_result.stdout.decode()}" def check_proto(): """Check that program.proto is up-to-date.""" From 45786b5654fb2b15f4b11b4f77a210b67d0cb58b Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Wed, 18 Feb 2026 20:47:26 +0000 Subject: [PATCH 128/234] Fix DestructArray simplification logic Change the loop condition to compare the iteration index against 'indices.count - 1' instead of 'indices.last!'. Also added regression test testDestructuringSimplificationWithRest, which reproduces the original bug using sparse indices with 'lastIsRest' set to true, ensuring that DestructArray is simplified into GetElement and a residual DestructArray for the rest elements. Change-Id: Ic630615bb85231d703046be4dc669e4314927db2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9027276 Reviewed-by: Matthias Liedtke Auto-Submit: Dominik Klemba Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- .../Minimization/InstructionSimplifier.swift | 2 +- Tests/FuzzilliTests/MinimizerTest.swift | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 6c6c60d5b..858b39003 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -143,7 +143,7 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, idx) in op.indices.enumerated() { - if i == op.indices.last! && op.lastIsRest { + 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)])) diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 32db2dd78..74b14a786 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1434,6 +1434,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) From 3a8d55941c0c897a271b6a59c4ccf3a418865825 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 19 Feb 2026 15:33:12 +0100 Subject: [PATCH 129/234] [v8] Enable fuzzing of Turbofan's instruction scheduling While this feature is disabled by default, it is a non-experimental feature and other fuzzers already create exposure of this feature (see https://source.chromium.org/chromium/chromium/src/+/main:v8/tools/clusterfuzz/trials/clusterfuzz_trials_config.json;l=60;drc=84a1682b877e88c8912cebf44a8513c7d84206ed) Bug: 485657212 Change-Id: I899357c64d4e2dfd9385d3da5f445f0edc447765 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9035976 Reviewed-by: Darius Mercadier Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 9c3c27e67..9a782ef34 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -795,6 +795,10 @@ 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) { From e65520d7c05bdee58b54a07184af13dbeb9d390d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 18 Feb 2026 14:00:30 +0100 Subject: [PATCH 130/234] [v8] Add ProgramTemplate for tierup with non-inlined function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Icee437b92f284e7f9f7dc339d31ee157c6f876ae Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9032277 Reviewed-by: Samuel Groß Commit-Queue: Matthias Liedtke --- .../Profiles/V8CommonProfile.swift | 31 +++++++++++++++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 19 ++++++------ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index 9a782ef34..ceafa1351 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -760,6 +760,37 @@ public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") b.build(n: 10) } +public let TurbofanTierUpNonInlinedCallFuzzer = + ProgramTemplate("TurbofanTierUpNonInlinedCallFuzzer") { b in + b.buildPrefix() + b.build(n: 50) + // Find a function (or generate a new one) to be marked as "never optimize". + let unoptimizedFunction = b.randomVariable(ofType: .function()) + ?? b.buildPlainFunction(with: .parameters(n: 2)) { _ in + b.build(n: 20) + b.doReturn(b.randomJsVariable()) + } + b.eval("%NeverOptimizeFunction(%@)", with: [unoptimizedFunction]) + // Create another function that calls the unoptimized function. This will always create a real + // call instead of inlining it. + let optimizedFunction = b.buildPlainFunction(with: .parameters(n: 0)) { _ in + // This should be able to generate interesting things including calls to the unoptimized + // function in all kinds of control flow. + b.build(n: 30) + // Also explicitly emit a call to the unoptimized function. + b.callFunction(unoptimizedFunction, withArgs: b.randomArguments(forCalling: unoptimizedFunction)) + b.build(n: 10) + } + // Collect feedback and optimize the function. + // Guard all calls. The path where they throw is still interesting as there are + // optimizations that affect the unwinding logic which we'd like to get coverage for as well. + b.eval("%PrepareFunctionForOptimization(%@)", with: [optimizedFunction]); + b.callFunction(optimizedFunction, guard: true) + b.callFunction(optimizedFunction, guard: true) + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [optimizedFunction]); + b.callFunction(optimizedFunction, guard: true) +} + // Configure V8 invocation arguments. `forSandbox` is used by the V8SandboxProfile. As the sandbox // fuzzer does not crash on regular assertions, most validation flags do not make sense in that // configuraiton. diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 9f0c47588..8402dbd76 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -78,15 +78,16 @@ let v8Profile = Profile( ], additionalProgramTemplates: WeightedList([ - (MapTransitionFuzzer, 1), - (ValueSerializerFuzzer, 1), - (V8RegExpFuzzer, 1), - (WasmFastCallFuzzer, 1), - (FastApiCallFuzzer, 1), - (LazyDeoptFuzzer, 1), - (WasmDeoptFuzzer, 1), - (WasmTurbofanFuzzer, 1), - (ProtoAssignSeqOptFuzzer, 1), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (WasmFastCallFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), + (WasmDeoptFuzzer, 1), + (WasmTurbofanFuzzer, 1), + (ProtoAssignSeqOptFuzzer, 1), + (TurbofanTierUpNonInlinedCallFuzzer, 1), ]), disabledCodeGenerators: [], From fe372e7dd13dc2171c9d8ed93161571c28bd0fa3 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 23 Feb 2026 10:18:22 +0100 Subject: [PATCH 131/234] [clean-up] Fix a typo Bug: 465497343 Change-Id: I81b857dc9dac3fb95f8cd3b0f45be04b396626d8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9043816 Commit-Queue: Michael Achenbach Auto-Submit: Michael Achenbach Reviewed-by: Danylo Mocherniuk Commit-Queue: Danylo Mocherniuk --- Sources/Fuzzilli/Fuzzer.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index c54a1dc97..f7ef762d7 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -167,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. @@ -753,7 +753,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 From 621f98c84d94c304ce721dda85d766b2c97fa63e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 12:23:40 +0100 Subject: [PATCH 132/234] [environment] Fix Math.sumPrecise argument type Change-Id: I7351c40670430f5b21ecff521eb5d419dc3ce2ac Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9051356 Reviewed-by: Dominik Klemba Auto-Submit: Matthias Liedtke Commit-Queue: Dominik Klemba --- Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 05d76a2d0..e7f351167 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -2110,7 +2110,7 @@ public extension ObjectGroup { "sin" : [.jsAnything] => .number, "sinh" : [.jsAnything] => .number, "sqrt" : [.jsAnything] => .number, - "sumPrecise" : [.jsAnything] => .number, + "sumPrecise" : [.iterable] => .number, "tan" : [.jsAnything] => .number, "tanh" : [.jsAnything] => .number, "trunc" : [.jsAnything] => .number, From 7fcba01a8f0b245cb31307bee5700361491cb86d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 24 Feb 2026 14:52:38 +0100 Subject: [PATCH 133/234] JavaScriptExecutor: Support large outputs This is needed for a tool that uses the JavaScriptExecutor and produces a large amount of output (the list of all builtins available in the global scope). Bug: 487347678 Change-Id: Ib83ee2ae33a609e5b8ce1598b14892a8cedfd0a4 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9047637 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .../Fuzzilli/Util/JavaScriptExecutor.swift | 47 ++++++++++++++----- Tests/FuzzilliTests/TestUtils.swift | 14 ++++++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift index c67e411ea..286ac1064 100644 --- a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift +++ b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift @@ -19,6 +19,30 @@ import WinSDK #endif /* os(Windows) */ public class JavaScriptExecutor { + // helper to support program output larger than the Pipe()'s buffer. + private final class OutputBuffer: @unchecked Sendable { + private var data = Data() + private let lock = NSLock() + + func append(_ newData: Data) { + lock.lock() + defer { lock.unlock() } + data.append(newData) + } + + var count: Int { + lock.lock() + defer { lock.unlock() } + return data.count + } + + var currentData: Data { + lock.lock() + defer { lock.unlock() } + return data + } + } + /// Path to the js shell binary. let executablePath: String @@ -84,6 +108,11 @@ public class JavaScriptExecutor { 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) @@ -138,19 +167,11 @@ 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" diff --git a/Tests/FuzzilliTests/TestUtils.swift b/Tests/FuzzilliTests/TestUtils.swift index 887f0e1e9..414d1fbfa 100644 --- a/Tests/FuzzilliTests/TestUtils.swift +++ b/Tests/FuzzilliTests/TestUtils.swift @@ -85,3 +85,17 @@ func buildAndLiftProgram(buildFunc: (ProgramBuilder) -> ()) -> 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) + } +} From 80923338d928c84ffedc3a5a2df32d0bad08dd3c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 11:49:30 +0100 Subject: [PATCH 134/234] [environment] Add .prototype.constructor for most builtins See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor Change-Id: Iaa324d06653a8dfeb2cc5e48b8357f5e4d2670c2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9051196 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 99 ++++++++++++++----- Tests/FuzzilliTests/JSTyperTests.swift | 4 +- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index e7f351167..a93cbfc3e 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1326,10 +1326,18 @@ 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, excludeProperties: [String] = []) -> ObjectGroup { + static func createPrototypeObjectGroup( + _ receiver: ObjectGroup, + constructor: ILType = .object(), + excludeProperties: [String] = []) -> ObjectGroup { let name = receiver.name + ".prototype" var properties = Dictionary(uniqueKeysWithValues: receiver.methods.map { ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) }) + + // 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 @@ -1531,6 +1539,7 @@ public extension ObjectGroup { // next, return and throw are part of the Iterator protocol, not Iterator.prototype. static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator, + constructor: .jsIteratorConstructor, excludeProperties: ["next", "return", "throw"]) static let jsIteratorConstructor = ObjectGroup( @@ -1792,7 +1801,8 @@ public extension ObjectGroup { ] ) - static let jsPromisePrototype = createPrototypeObjectGroup(jsPromises) + static let jsPromisePrototype = + createPrototypeObjectGroup(jsPromises, constructor: .jsPromiseConstructor) /// ObjectGroup modelling the JavaScript Promise constructor builtin static let jsPromiseConstructor = ObjectGroup( @@ -1867,7 +1877,7 @@ public extension ObjectGroup { ] ) - static let jsDatePrototype = createPrototypeObjectGroup(jsDate) + static let jsDatePrototype = createPrototypeObjectGroup(jsDate, constructor: .jsDateConstructor) /// ObjectGroup modelling the JavaScript Date constructor static let jsDateConstructor = ObjectGroup( @@ -1934,7 +1944,8 @@ public extension ObjectGroup { ] ) - static let jsArrayBufferPrototype = createPrototypeObjectGroup(jsArrayBuffers) + static let jsArrayBufferPrototype = + createPrototypeObjectGroup(jsArrayBuffers, constructor: .jsArrayBufferConstructor) static let jsArrayBufferConstructor = ObjectGroup( name: "ArrayBufferConstructor", @@ -1948,7 +1959,8 @@ public extension ObjectGroup { ] ) - static let jsSharedArrayBufferPrototype = createPrototypeObjectGroup(jsSharedArrayBuffers) + static let jsSharedArrayBufferPrototype = + createPrototypeObjectGroup(jsSharedArrayBuffers, constructor: .jsSharedArrayBufferConstructor) static let jsSharedArrayBufferConstructor = ObjectGroup( name: "SharedArrayBufferConstructor", @@ -1960,7 +1972,8 @@ public extension ObjectGroup { methods: [:] ) - static let jsStringPrototype = createPrototypeObjectGroup(jsStrings) + static let jsStringPrototype = + createPrototypeObjectGroup(jsStrings, constructor: .jsStringConstructor) /// Object group modelling the JavaScript String constructor builtin static let jsStringConstructor = ObjectGroup( @@ -2208,7 +2221,8 @@ public extension ObjectGroup { ] ) - static let jsWebAssemblyGlobalPrototype = createPrototypeObjectGroup(jsWasmGlobal) + static let jsWebAssemblyGlobalPrototype = + createPrototypeObjectGroup(jsWasmGlobal, constructor: .jsWebAssemblyGlobalConstructor) static let jsWebAssemblyGlobalConstructor = ObjectGroup( name: "WebAssemblyGlobalConstructor", @@ -2239,7 +2253,8 @@ public extension ObjectGroup { methods: [:] ) - static let jsWebAssemblyMemoryPrototype = createPrototypeObjectGroup(jsWasmMemory) + static let jsWebAssemblyMemoryPrototype = + createPrototypeObjectGroup(jsWasmMemory, constructor: .jsWebAssemblyMemoryConstructor) static let jsWebAssemblyMemoryConstructor = ObjectGroup( name: "WebAssemblyMemoryConstructor", @@ -2251,7 +2266,8 @@ public extension ObjectGroup { methods: [:] ) - static let jsWebAssemblyTablePrototype = createPrototypeObjectGroup(wasmTable) + static let jsWebAssemblyTablePrototype = + createPrototypeObjectGroup(wasmTable, constructor: .jsWebAssemblyTableConstructor) static let jsWebAssemblyTableConstructor = ObjectGroup( name: "WebAssemblyTableConstructor", @@ -2263,7 +2279,8 @@ public extension ObjectGroup { methods: [:] ) - static let jsWebAssemblyTagPrototype = createPrototypeObjectGroup(jsWasmTag) + static let jsWebAssemblyTagPrototype = + createPrototypeObjectGroup(jsWasmTag, constructor: .jsWebAssemblyTagConstructor) static let jsWebAssemblyTagConstructor = ObjectGroup( name: "WebAssemblyTagConstructor", @@ -2287,7 +2304,9 @@ public extension ObjectGroup { ] ) - static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup(jsWebAssemblyException) + static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup( + jsWebAssemblyException, + constructor: .jsWebAssemblyExceptionConstructor) static let jsWebAssemblyExceptionConstructor = ObjectGroup( name: "WebAssemblyExceptionConstructor", @@ -2498,7 +2517,8 @@ public extension ObjectGroup { ] ) - static let jsTemporalInstantPrototype = createPrototypeObjectGroup(jsTemporalInstant) + static let jsTemporalInstantPrototype = + createPrototypeObjectGroup(jsTemporalInstant, constructor: .jsTemporalInstantConstructor) /// ObjectGroup modelling the JavaScript Temporal.Instant constructor static let jsTemporalInstantConstructor = ObjectGroup( @@ -2547,7 +2567,8 @@ public extension ObjectGroup { ] ) - static let jsTemporalDurationPrototype = createPrototypeObjectGroup(jsTemporalDuration) + static let jsTemporalDurationPrototype = + createPrototypeObjectGroup(jsTemporalDuration, constructor: .jsTemporalDurationConstructor) /// ObjectGroup modelling the JavaScript Temporal.Duration constructor static let jsTemporalDurationConstructor = ObjectGroup( @@ -2588,7 +2609,8 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainTimePrototype = createPrototypeObjectGroup(jsTemporalPlainTime) + static let jsTemporalPlainTimePrototype = + createPrototypeObjectGroup(jsTemporalPlainTime, constructor: .jsTemporalPlainTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainTime constructor static let jsTemporalPlainTimeConstructor = ObjectGroup( @@ -2635,7 +2657,9 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup(jsTemporalPlainYearMonth) + static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup( + jsTemporalPlainYearMonth, + constructor: .jsTemporalPlainYearMonthConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainYearMonth constructor static let jsTemporalPlainYearMonthConstructor = ObjectGroup( @@ -2669,7 +2693,9 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup(jsTemporalPlainMonthDay) + static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup( + jsTemporalPlainMonthDay, + constructor: .jsTemporalPlainMonthDayConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainMonthDay constructor. static let jsTemporalPlainMonthDayConstructor = ObjectGroup( @@ -2715,7 +2741,9 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup(jsTemporalPlainDate) + static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup( + jsTemporalPlainDate, + constructor: .jsTemporalPlainDateConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDate constructor static let jsTemporalPlainDateConstructor = ObjectGroup( @@ -2754,7 +2782,9 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup(jsTemporalPlainDateTime) + static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup( + jsTemporalPlainDateTime, + constructor: .jsTemporalPlainDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDateTime constructor static let jsTemporalPlainDateTimeConstructor = ObjectGroup( @@ -2804,7 +2834,9 @@ public extension ObjectGroup { ] ) - static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup(jsTemporalZonedDateTime) + static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup( + jsTemporalZonedDateTime, + constructor: .jsTemporalZonedDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.ZonedDateTime constructor static let jsTemporalZonedDateTimeConstructor = ObjectGroup( @@ -3112,7 +3144,9 @@ extension ObjectGroup { // 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, + static let jsIntlCollatorPrototype = createPrototypeObjectGroup( + jsIntlCollator, + constructor: .jsIntlCollatorConstructor, excludeProperties: ["compare"]) static let jsIntlCollatorConstructor = ObjectGroup( @@ -3159,7 +3193,9 @@ extension ObjectGroup { // 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, + static let jsIntlDateTimeFormatPrototype = createPrototypeObjectGroup( + jsIntlDateTimeFormat, + constructor: .jsIntlDateTimeFormatConstructor, excludeProperties: ["format"]) static let jsIntlDateTimeFormatConstructor = ObjectGroup( @@ -3186,7 +3222,9 @@ extension ObjectGroup { ] ) - static let jsIntlListFormatPrototype = createPrototypeObjectGroup(jsIntlListFormat) + static let jsIntlListFormatPrototype = createPrototypeObjectGroup( + jsIntlListFormat, + constructor: .jsIntlListFormatConstructor) static let jsIntlListFormatConstructor = ObjectGroup( name: "IntlListFormatConstructor", @@ -3231,7 +3269,8 @@ extension ObjectGroup { ] ) - static let jsIntlLocalePrototype = createPrototypeObjectGroup(jsIntlLocale) + static let jsIntlLocalePrototype = + createPrototypeObjectGroup(jsIntlLocale, constructor: .jsIntlLocaleConstructor) static let jsIntlLocaleConstructor = ObjectGroup( name: "IntlLocaleConstructor", @@ -3272,7 +3311,9 @@ extension ObjectGroup { // 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, + static let jsIntlNumberFormatPrototype = createPrototypeObjectGroup( + jsIntlNumberFormat, + constructor: .jsIntlNumberFormatConstructor, excludeProperties: ["format"]) static let jsIntlNumberFormatConstructor = ObjectGroup( @@ -3299,7 +3340,8 @@ extension ObjectGroup { ] ) - static let jsIntlPluralRulesPrototype = createPrototypeObjectGroup(jsIntlPluralRules) + static let jsIntlPluralRulesPrototype = + createPrototypeObjectGroup(jsIntlPluralRules, constructor: .jsIntlPluralRulesConstructor) static let jsIntlPluralRulesConstructor = ObjectGroup( name: "IntlPluralRulesConstructor", @@ -3327,7 +3369,9 @@ extension ObjectGroup { ] ) - static let jsIntlRelativeTimeFormatPrototype = createPrototypeObjectGroup(jsIntlRelativeTimeFormat) + static let jsIntlRelativeTimeFormatPrototype = createPrototypeObjectGroup( + jsIntlRelativeTimeFormat, + constructor: .jsIntlRelativeTimeFormatConstructor) static let jsIntlRelativeTimeFormatConstructor = ObjectGroup( name: "IntlRelativeTimeFormatConstructor", @@ -3352,7 +3396,8 @@ extension ObjectGroup { ] ) - static let jsIntlSegmenterPrototype = createPrototypeObjectGroup(jsIntlSegmenter) + static let jsIntlSegmenterPrototype = + createPrototypeObjectGroup(jsIntlSegmenter, constructor: .jsIntlSegmenterConstructor) static let jsIntlSegmenterConstructor = ObjectGroup( name: "IntlSegmenterConstructor", diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 9599398fe..ebc6a7fe3 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -1805,8 +1805,8 @@ class JSTyperTests: XCTestCase { 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. From a350d0f4aa58814e465310a687e740f8c78487c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Doga=20Y=C3=BCksel?= Date: Tue, 24 Feb 2026 15:24:15 +0000 Subject: [PATCH 135/234] [wasm] Added ref.cast instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fuzzilli functionality for ref.cast added similarly to ref.test Bug: 474940922 Change-Id: I7cd3a28b05b7289c8ea0836be0c6d1024556e24c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8995238 Commit-Queue: Doga Yüksel Reviewed-by: Danylo Mocherniuk Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 14 +++- .../CodeGen/CodeGeneratorWeights.swift | 2 + .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 50 +++++++++++++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 6 ++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 7 ++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 9 +++ Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 3 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 22 ++++-- .../Fuzzilli/Mutators/OperationMutator.swift | 3 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 55 ++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 4 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 28 +++++++- Sources/Fuzzilli/Protobuf/program.proto | 1 + Tests/FuzzilliTests/WasmTests.swift | 71 +++++++++++++++++++ 16 files changed, 268 insertions(+), 12 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index c4c76128d..b0759e21c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4436,10 +4436,18 @@ public class ProgramBuilder { @discardableResult public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { - typeDef == nil - ? b.emit(WasmRefTest(refType: refType), withInputs: [ref]).output - : b.emit(WasmRefTest(refType: refType), withInputs: [ref, typeDef!]).output + 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 { diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index b598b4490..32540cfc0 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -381,4 +381,6 @@ public let codeGeneratorWeights = [ "WasmExternConvertAnyGenerator": 5, "WasmRefTestGenerator": 5, "WasmRefTestAbstractGenerator": 5, + "WasmRefCastGenerator": 5, + "WasmRefCastAbstractGenerator": 5, ] diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 3311b897a..493247c29 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -387,6 +387,56 @@ public let WasmCodeGenerators: [CodeGenerator] = [ ) }, + 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( diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index c176aed92..ee607f6ff 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1615,6 +1615,10 @@ extension Instruction: ProtobufConvertible { $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 @@ -2594,6 +2598,8 @@ extension Instruction: ProtobufConvertible { 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): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index f67f99030..9007fc91f 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -949,6 +949,13 @@ public struct JSTyper: Analyzer { 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. diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 2d400bd87..b50931649 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -368,4 +368,5 @@ enum Opcode { case wasmRefEq(WasmRefEq) case wasmRefTest(WasmRefTest) case wasmDefineAdHocModuleSignatureType(WasmDefineAdHocModuleSignatureType) + case wasmRefCast(WasmRefCast) } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 9dbc9da1e..d72ca4822 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -2336,6 +2336,15 @@ class WasmRefTest: WasmOperation { } } +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 { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 3b8d29dff..c9ac5520b 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1349,6 +1349,10 @@ public class FuzzILLifter: Lifter { 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() diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index d039bb894..86617754c 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1795,7 +1795,8 @@ public class JavaScriptLifter: Lifter { .wasmI31Get(_), .wasmAnyConvertExtern(_), .wasmExternConvertAny(_), - .wasmRefTest(_): + .wasmRefTest(_), + .wasmRefCast(_): fatalError("unreachable") } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 754643e9e..bc18db0e6 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -584,6 +584,16 @@ public class WasmLifter { 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))) + } + } + private func buildTypeEntry(for desc: WasmTypeDescription, data: inout Data) throws { if let arrayDesc = desc as? WasmArrayTypeDescription { data += [0x5E] @@ -2200,13 +2210,13 @@ public class WasmLifter { case .wasmRefTest(let op): let refType = op.type.wasmReferenceType! let opCode: UInt8 = refType.nullability ? 0x15 : 0x14 - let typeData = if refType.isAbstract() { - try encodeHeapType(op.type) - } else { - try encodeWasmGCType(typer.getTypeDescription(of: wasmInstruction.input(1))) - } + 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. diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index e69cc62f9..2e73465e0 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -745,7 +745,8 @@ public class OperationMutator: BaseInstructionMutator { .wasmTableInit(_), .wasmTableCopy(_), .wasmStructNew(_), - .wasmRefEq(_): + .wasmRefEq(_), + .wasmRefCast(_): let mutability = instr.isOperationMutable ? "mutable" : "immutable" fatalError("Unexpected operation \(instr.op.opcode), marked as \(mutability)") } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index d312a189c..98d1b86cb 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5940,6 +5940,27 @@ public struct Fuzzilli_Protobuf_WasmRefTest: Sendable { 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 {return _type ?? Fuzzilli_Protobuf_WasmILType()} + set {_type = newValue} + } + /// Returns true if `type` has been explicitly set. + public var hasType: Bool {return 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 @@ -15462,6 +15483,40 @@ extension Fuzzilli_Protobuf_WasmRefTest: SwiftProtobuf.Message, SwiftProtobuf._M } } +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") diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index ce4bbbad2..9575ffb0b 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1565,6 +1565,10 @@ message WasmRefTest { WasmILType type = 1; } +message WasmRefCast { + WasmILType type = 1; +} + message WasmRefI31 { bool isShared = 1; } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index a632bad38..2b13319ad 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2761,6 +2761,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { 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 unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3103,6 +3111,7 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmRefEq(Fuzzilli_Protobuf_WasmRefEq) case wasmRefTest(Fuzzilli_Protobuf_WasmRefTest) case wasmDefineAdHocModuleSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType) + case wasmRefCast(Fuzzilli_Protobuf_WasmRefCast) } @@ -3151,7 +3160,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7562,6 +7571,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocModuleSignatureType(v) } }() + case 341: 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) + } + }() default: break } } @@ -8932,6 +8954,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmDefineAdHocModuleSignatureType(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 340) }() + case .wasmRefCast?: try { + guard case .wasmRefCast(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 341) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 50121d9cc..1ae505cf7 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -364,6 +364,7 @@ message Instruction { WasmRefEq wasmRefEq = 338; WasmRefTest wasmRefTest = 339; WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 340; + WasmRefCast wasmRefCast = 341; } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index ba70c793d..7556b873b 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -5044,6 +5044,77 @@ class WasmGCTests: XCTestCase { 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 { From 01ae8ac7fbe7e759083c9f6c29b595bd6c43ac83 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 12:41:25 +0100 Subject: [PATCH 136/234] [environment] Register DisposableStack and its properties, methods and instance type See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack Bug: 487347678 Change-Id: I85e523864482d16d5b1f2a1c9d0cd3ba0cb77613 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9051796 Commit-Queue: Rezvan Mahdavi Hezaveh Auto-Submit: Matthias Liedtke Reviewed-by: Rezvan Mahdavi Hezaveh --- .../Environment/JavaScriptEnvironment.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index a93cbfc3e..5124246f4 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -343,6 +343,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsWeakSets) registerObjectGroup(.jsWeakRefs) registerObjectGroup(.jsFinalizationRegistrys) + registerObjectGroup(.jsDisposableStacks) + registerObjectGroup(.jsDisposableStackPrototype) + registerObjectGroup(.jsDisposableStackConstructor) registerObjectGroup(.jsArrayBuffers) registerObjectGroup(.jsSharedArrayBuffers) for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { @@ -596,6 +599,7 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("WeakSet", ofType: .jsWeakSetConstructor) registerBuiltin("WeakRef", ofType: .jsWeakRefConstructor) registerBuiltin("FinalizationRegistry", ofType: .jsFinalizationRegistryConstructor) + registerBuiltin("DisposableStack", ofType: .jsDisposableStackConstructor) registerBuiltin("Math", ofType: .jsMathObject) registerBuiltin("JSON", ofType: .jsJSONObject) registerBuiltin("Reflect", ofType: .jsReflectObject) @@ -1063,6 +1067,9 @@ public extension ILType { /// Type of a JavaScript FinalizationRegistry object. static let jsFinalizationRegistry = ILType.object(ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) + /// Type of a JavaScript DisposableStack object. + static let jsDisposableStack = ILType.object(ofGroup: "DisposableStack", withProperties: ["disposed"], withMethods: ["dispose", "use", "adopt", "defer", "move"]) + /// Type of a JavaScript ArrayBuffer object. static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "transfer", "transferToFixedLength", "transferToImmutable"]) @@ -1167,6 +1174,9 @@ public extension ILType { /// Type of the JavaScript FinalizationRegistry constructor builtin. static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + /// Type of the JavaScript DisposableStack constructor builtin. + static let jsDisposableStackConstructor = ILType.constructor([] => .jsDisposableStack) + .object(ofGroup: "DisposableStackConstructor", 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", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) @@ -1666,6 +1676,35 @@ public extension ObjectGroup { ] ) + /// ObjectGroup modelling JavaScript DisposableStack objects + 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, + ] + ) + + static let jsDisposableStackPrototype = createPrototypeObjectGroup(jsDisposableStacks, + constructor: .jsDisposableStackConstructor) + + static let jsDisposableStackConstructor = ObjectGroup( + name: "DisposableStackConstructor", + constructorPath: "DisposableStack", + instanceType: .jsDisposableStackConstructor, + properties: [ + "prototype" : jsDisposableStackPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript ArrayBuffer objects static let jsArrayBuffers = ObjectGroup( name: "ArrayBuffer", From c9971336662247101b26bf2b2381634d50b7171f Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 14:14:36 +0100 Subject: [PATCH 137/234] [environment] Register AsyncDisposableStack and its properties, methods and instance types See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack Bug: 487347678 Change-Id: I6a0506f0e09c8597c8f24a22833083a99c0c4472 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9051797 Reviewed-by: Rezvan Mahdavi Hezaveh Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 5124246f4..45687d0d2 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -346,6 +346,9 @@ public class JavaScriptEnvironment: ComponentBase { 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", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { @@ -600,6 +603,7 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("WeakRef", ofType: .jsWeakRefConstructor) registerBuiltin("FinalizationRegistry", ofType: .jsFinalizationRegistryConstructor) registerBuiltin("DisposableStack", ofType: .jsDisposableStackConstructor) + registerBuiltin("AsyncDisposableStack", ofType: .jsAsyncDisposableStackConstructor) registerBuiltin("Math", ofType: .jsMathObject) registerBuiltin("JSON", ofType: .jsJSONObject) registerBuiltin("Reflect", ofType: .jsReflectObject) @@ -1070,6 +1074,9 @@ public extension ILType { /// Type of a JavaScript DisposableStack object. static let jsDisposableStack = ILType.object(ofGroup: "DisposableStack", withProperties: ["disposed"], withMethods: ["dispose", "use", "adopt", "defer", "move"]) + /// Type of a JavaScript AsyncDisposableStack object. + static let jsAsyncDisposableStack = ILType.object(ofGroup: "AsyncDisposableStack", withProperties: ["disposed"], withMethods: ["disposeAsync", "use", "adopt", "defer", "move"]) + /// Type of a JavaScript ArrayBuffer object. static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "transfer", "transferToFixedLength", "transferToImmutable"]) @@ -1177,6 +1184,9 @@ public extension ILType { /// Type of the JavaScript DisposableStack constructor builtin. static let jsDisposableStackConstructor = ILType.constructor([] => .jsDisposableStack) + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) + /// Type of the JavaScript AsyncDisposableStack constructor builtin. + static let jsAsyncDisposableStackConstructor = ILType.constructor([] => .jsAsyncDisposableStack) + .object(ofGroup: "AsyncDisposableStackConstructor", withProperties: ["prototype"]) + /// 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", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) @@ -1705,6 +1715,35 @@ public extension ObjectGroup { methods: [:] ) + /// ObjectGroup modelling JavaScript AsyncDisposableStack objects + 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, + ] + ) + + static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup(jsAsyncDisposableStacks, + constructor: .jsAsyncDisposableStackConstructor) + + static let jsAsyncDisposableStackConstructor = ObjectGroup( + name: "AsyncDisposableStackConstructor", + constructorPath: "AsyncDisposableStack", + instanceType: .jsAsyncDisposableStackConstructor, + properties: [ + "prototype" : jsAsyncDisposableStackPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript ArrayBuffer objects static let jsArrayBuffers = ObjectGroup( name: "ArrayBuffer", From ae3d83a50899cb622412a2ce8c6dee1f54b8892a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 14:41:59 +0100 Subject: [PATCH 138/234] [environment] Add DataView prototype and getBigUint64 method getBigInt64 and getBigUin64 also take an optional second parameter which is a bool to mark if little-endian encoding should be used. Bug: 487347678 Change-Id: I352e74c7e5d74bd72f5c7ae35c8114bceba297d6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9050878 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 45687d0d2..987f6bf30 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -357,6 +357,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsUint8ArrayConstructor) registerObjectGroup(.jsUint8ArrayPrototype) registerObjectGroup(.jsDataViews) + registerObjectGroup(.jsDataViewPrototype) + registerObjectGroup(.jsDataViewConstructor) registerObjectGroup(.jsObjectConstructor) registerObjectGroup(.jsPromiseConstructor) @@ -1084,7 +1086,7 @@ public extension ILType { static let jsSharedArrayBuffer = ILType.object(ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], withMethods: ["grow", "slice"]) /// Type of a JavaScript DataView object. - static let jsDataView = ILType.object(ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], withMethods: ["getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", "getFloat32", "getFloat64", "getBigInt64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", "setFloat64", "setBigInt64"]) + 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"]) /// Type of a JavaScript TypedArray object of the given variant. static func jsTypedArray(_ variant: String) -> ILType { @@ -1155,7 +1157,7 @@ public extension ILType { + .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) + static let jsDataViewConstructor = ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Promise constructor builtin. static let jsPromiseConstructor = ILType.constructor([.function()] => .jsPromise) + .object(ofGroup: "PromiseConstructor", withProperties: ["prototype"], withMethods: ["resolve", "reject", "all", "any", "race", "allSettled", "try"]) @@ -1856,27 +1858,41 @@ public extension ObjectGroup { "byteOffset" : .integer ], methods: [ - "getInt8" : [.integer] => .integer, - "getUint8" : [.integer] => .integer, - "getInt16" : [.integer] => .integer, - "getUint16" : [.integer] => .integer, - "getInt32" : [.integer] => .integer, - "getUint32" : [.integer] => .integer, - "getFloat16" : [.integer] => .float, - "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, - "setFloat16" : [.integer, .float] => .undefined, - "setFloat32" : [.integer, .float] => .undefined, - "setFloat64" : [.integer, .float] => .undefined, - "setBigInt64": [.integer, .bigint] => .undefined, - ] + "getInt8" : [.integer] => .integer, + "getUint8" : [.integer] => .integer, + "getInt16" : [.integer] => .integer, + "getUint16" : [.integer] => .integer, + "getInt32" : [.integer] => .integer, + "getUint32" : [.integer] => .integer, + "getFloat16" : [.integer] => .float, + "getFloat32" : [.integer] => .float, + "getFloat64" : [.integer] => .float, + "getBigInt64" : [.integer, .opt(.boolean)] => .bigint, + "getBigUint64": [.integer, .opt(.boolean)] => .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, + "setFloat16" : [.integer, .float] => .undefined, + "setFloat32" : [.integer, .float] => .undefined, + "setFloat64" : [.integer, .float] => .undefined, + "setBigInt64" : [.integer, .bigint] => .undefined, + ] + ) + + static let jsDataViewPrototype = createPrototypeObjectGroup(jsDataViews, + constructor: .jsDataViewConstructor) + + static let jsDataViewConstructor = ObjectGroup( + name: "DataViewConstructor", + constructorPath: "DataView", + instanceType: .jsDataViewConstructor, + properties: [ + "prototype": jsDataViewPrototype.instanceType, + ], + methods: [:] ) static let jsPromisePrototype = From 29c5cee53c62f7c6827924146daee5452263a77b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 15:01:57 +0100 Subject: [PATCH 139/234] [environment] Add FinalizationRegistry.prototype Bug: 487347678 Change-Id: Ide8f3c5d4439981c729f14ecc96e4e54e4cfbe6f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9050879 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 987f6bf30..a04863e5f 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -343,6 +343,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsWeakSets) registerObjectGroup(.jsWeakRefs) registerObjectGroup(.jsFinalizationRegistrys) + registerObjectGroup(.jsFinalizationRegistryPrototype) + registerObjectGroup(.jsFinalizationRegistryConstructor) registerObjectGroup(.jsDisposableStacks) registerObjectGroup(.jsDisposableStackPrototype) registerObjectGroup(.jsDisposableStackConstructor) @@ -1181,7 +1183,7 @@ public extension ILType { static let jsWeakRefConstructor = ILType.constructor([.object()] => .jsWeakRef) /// Type of the JavaScript FinalizationRegistry constructor builtin. - static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) /// Type of the JavaScript DisposableStack constructor builtin. static let jsDisposableStackConstructor = ILType.constructor([] => .jsDisposableStack) + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) @@ -1688,6 +1690,19 @@ public extension ObjectGroup { ] ) + static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup(jsFinalizationRegistrys, + constructor: .jsFinalizationRegistryConstructor) + + static let jsFinalizationRegistryConstructor = ObjectGroup( + name: "FinalizationRegistryConstructor", + constructorPath: "FinalizationRegistry", + instanceType: .jsFinalizationRegistryConstructor, + properties: [ + "prototype" : jsFinalizationRegistryPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript DisposableStack objects static let jsDisposableStacks = ObjectGroup( name: "DisposableStack", From 159714e4c8a77e1665a7799800e9587d83a3ca81 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 15:21:59 +0100 Subject: [PATCH 140/234] [environment] TypedArray: Add BYTES_PER_ELEMENT This also requires some refactoring: 1) We need to extend createPrototypeObjectGroup() to also allow additional properties as BYTES_PER_ELEMENT appears on the TypedArray builtin (the constructor) and on its prototype (and due to the prototype also on any instance of such typed array). 2) Merge Uint8Array (which is somewhat special due to base64) with the other typed arrays to reduce the amount of duplication. Bug: 487347678 Change-Id: I795b16468ec9b52108dd41fee3ff54d74604df18 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9050880 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index a04863e5f..ca8db76cd 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -355,9 +355,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsSharedArrayBuffers) 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) @@ -591,11 +591,9 @@ public class JavaScriptEnvironment: ComponentBase { 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", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { + for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { registerBuiltin(variant, ofType: .jsTypedArrayConstructor(variant)) } - registerBuiltin("Uint8Array", ofType: .jsUint8ArrayConstructor) registerBuiltin("DataView", ofType: .jsDataViewConstructor) registerBuiltin("Date", ofType: .jsDateConstructor) registerBuiltin("Promise", ofType: .jsPromiseConstructor) @@ -1093,7 +1091,7 @@ public extension ILType { /// 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"] + 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) } @@ -1151,13 +1149,15 @@ public extension ILType { /// Type of a JavaScript TypedArray constructor builtin. 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)) + + .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) + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) @@ -1353,11 +1353,16 @@ public extension ObjectGroup { static func createPrototypeObjectGroup( _ receiver: ObjectGroup, constructor: ILType = .object(), - excludeProperties: [String] = []) -> ObjectGroup { + 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)) }) + properties.merge(additionalProperties) { _, _ in + fatalError("duplicate property") + } + // Each .prototype has a constructor property. // In general, the following should hold true: // .prototype.constructor === ; @@ -1808,6 +1813,7 @@ public extension ObjectGroup { name: variant, instanceType: .jsTypedArray(variant), properties: [ + "BYTES_PER_ELEMENT": .integer, "buffer" : .jsArrayBuffer, "byteLength" : .integer, "byteOffset" : .integer, @@ -1849,19 +1855,33 @@ public extension ObjectGroup { ) } - static let jsUint8ArrayPrototype = createPrototypeObjectGroup(jsTypedArrays("Uint8Array")) + 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, - properties: [ - "prototype": jsUint8ArrayPrototype.instanceType, - ], - methods: [ - "fromBase64": [.plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType)] => .jsUint8Array, - "fromHex": [.plain(.string)] => .jsUint8Array, - ] - ) + 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 static let jsDataViews = ObjectGroup( From 3d901fae1a506972e08bb3a72071aec343f25bc8 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 26 Feb 2026 14:00:55 +0100 Subject: [PATCH 141/234] Support more valid JS method names With this change we support defining methods on classes and objects with non-identifier names, like number and string literals. Internally, all method names remain strings, reusing any type information. At lifting, we approximate simple identifiers and use them unquoted for method definition and for usage in dot notation. For definitions, we also support quoted strings and unquoted index values. At call sites, we ensure bracket notation where needed, supporting index access without quotes. This covers method names for plain objects and classes. This does not cover properties, getters and setters yet. We also add 2 custom method names to the environment that don't follow the previous identifier naming. Instructions that define such methods currently are: ObjectLiteralMethod ClassInstanceMethod ClassStaticMethod Instructions that use such methods are: CallMethod CallMethodWithSpread CallSuperMethod BindMethod We ignore definitions and calls of private methods. They also reuse the same typer logic, but naming rules are more strict here, non-identifiers are not supported and should never be produced. We need to separate now identifiers for private and other method names in the JS environment. This also extends the compiler to enable importing the new method types. Bug: 446634535 Change-Id: I2b8fbb8306e4b6bd901b61952c6da91d4210ae3f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9047716 Reviewed-by: Dominik Klemba Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 7 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 8 +- Sources/Fuzzilli/Compiler/Compiler.swift | 14 +- Sources/Fuzzilli/Compiler/Parser/parser.js | 11 +- .../Environment/JavaScriptEnvironment.swift | 45 +++- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 38 ++- Tests/FuzzilliTests/CompilerTests.swift | 2 +- .../computed_and_indexed_properties.js | 24 +- Tests/FuzzilliTests/LifterTest.swift | 221 ++++++++++++++++++ 9 files changed, 340 insertions(+), 30 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index b0759e21c..cee838ad7 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -487,6 +487,13 @@ 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() diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 9767d2f95..a2d94affa 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1236,8 +1236,8 @@ 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( @@ -1273,8 +1273,8 @@ 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( diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 09999ce35..0f2f4f0bb 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -170,8 +170,12 @@ public class JavaScriptCompiler { } else { head = emit(BeginClassInstanceMethod(methodName: name, parameters: parameters)) } - case .index: - throw CompilerError.invalidNodeError("Not supported") + case .index(let index): + if method.isStatic { + head = emit(BeginClassStaticMethod(methodName: String(index), parameters: parameters)) + } else { + head = emit(BeginClassInstanceMethod(methodName: String(index), parameters: parameters)) + } case .expression: if method.isStatic { head = emit(BeginClassStaticComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) @@ -197,7 +201,11 @@ public class JavaScriptCompiler { emit(EndClassInstanceMethod()) } case .index: - throw CompilerError.invalidNodeError("Not supported") + if method.isStatic { + emit(EndClassStaticMethod()) + } else { + emit(EndClassInstanceMethod()) + } case .expression: if method.isStatic { emit(EndClassStaticComputedMethod()) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 372af3fbc..4c5eaace1 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -492,8 +492,15 @@ function parse(script, proto) { 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; + if (method.key.type === 'Identifier') { + out.name = method.key.name; + } else if (method.key.type === 'NumericLiteral') { + out.name = String(method.key.value); + } else if (method.key.type === 'StringLiteral') { + out.name = method.key.value; + } else { + throw "Unknown method key type: " + method.key.type; + } } field = {}; diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index ca8db76cd..092ea9603 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -290,11 +290,13 @@ public class JavaScriptEnvironment: ComponentBase { /// 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 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() @@ -314,7 +316,35 @@ public class JavaScriptEnvironment: ComponentBase { private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] + private let validMethodDefinitionName: Regex? + private let validDotNotationName: Regex? + private let validPropertyIndex: Regex? + public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { + // A simple approximation of a valid JS identifier (used in dot + // notation and for method definitions). + let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" + + // A non-negative integer (with no leading zero) for index access + // without quotes. + let index = "[1-9]\\d*|0" + + // Initialize regular expressions to determine valid property + // identifiers: + + // At method definition site, we support simple identifiers and + // non-negative numbers. Other names will be quoted. + // We don't support unquoted doubles. + self.validMethodDefinitionName = try! Regex("^(\(index)|\(simpleId))$") + + // For dot notation we only support simple identifiers. We don't + // support all possible names according to JS spec. + // Unsupported names will be accessed with bracket notation. + self.validDotNotationName = try! Regex("^(\(simpleId))$") + + // Valid indexes to use in bracket notation without quotes. + self.validPropertyIndex = try! Regex("^(\(index))$") + super.init(name: "JavaScriptEnvironment") // Build model of the JavaScript environment @@ -655,6 +685,7 @@ public class JavaScriptEnvironment: ComponentBase { logger.info("Have \(builtinMethods.count) builtin method names: \(builtinMethods.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() { @@ -936,6 +967,18 @@ public class JavaScriptEnvironment: ComponentBase { $0 || type.Is($1) } } + + func isValidNameForMethodDefinition(_ name: String) -> Bool { + return (try? validMethodDefinitionName?.wholeMatch(in: name)) != nil + } + + func isValidDotNotationName(_ name: String) -> Bool { + return (try? validDotNotationName?.wholeMatch(in: name)) != nil + } + + func isValidPropertyIndex(_ name: String) -> Bool { + return (try? validPropertyIndex?.wholeMatch(in: name)) != nil + } } /// A struct to encapsulate property and method type information for a group of related objects. diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 86617754c..8b523ed25 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 @@ -78,7 +78,7 @@ public class JavaScriptLifter: Lifter { public init(prefix: String = "", suffix: String = "", ecmaVersion: ECMAScriptVersion, - environment: JavaScriptEnvironment? = nil, + environment: JavaScriptEnvironment, alwaysEmitVariables: Bool = false) { self.prefix = prefix self.suffix = suffix @@ -131,7 +131,7 @@ public class JavaScriptLifter: Lifter { if needToSupportWasm { // If we need to support Wasm we need to type all instructions outside of Wasm such that the WasmLifter can access extra type information during lifting. - typer = JSTyper(for: environment!) + typer = JSTyper(for: environment) } var w = JavaScriptWriter(analyzer: analyzer, version: version, stripComments: !options.contains(.includeComments), includeLineNumbers: options.contains(.includeLineNumbers), alwaysEmitVariables: alwaysEmitVariables) @@ -409,7 +409,7 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = op.methodName + let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) currentObjectLiteral.beginMethod("\(METHOD)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -526,7 +526,7 @@ public class JavaScriptLifter: Lifter { case .beginClassInstanceMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = op.methodName + let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) w.emit("\(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) @@ -596,7 +596,7 @@ public class JavaScriptLifter: Lifter { case .beginClassStaticMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = op.methodName + let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) w.emit("static \(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) @@ -981,14 +981,14 @@ public class JavaScriptLifter: Lifter { 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) + ")" w.assign(expr, to: instr.output) @@ -1152,7 +1152,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): @@ -1511,9 +1512,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) @@ -1875,6 +1876,21 @@ public class JavaScriptLifter: Lifter { } } + func quoteMethodDefinitionIfNeeded(_ name: String) -> String { + if environment.isValidNameForMethodDefinition(name) { + return name + } + return "\"\(name)\"" + } + + private func liftMemberAccess(_ name: String) -> String { + if environment.isValidDotNotationName(name){ + return "." + name + } + let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" + return "[" + safeName + "]" + } + private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { assert(parameters.count == variables.count) var paramList = [String]() diff --git a/Tests/FuzzilliTests/CompilerTests.swift b/Tests/FuzzilliTests/CompilerTests.swift index a45e52bd3..c27269dc6 100644 --- a/Tests/FuzzilliTests/CompilerTests.swift +++ b/Tests/FuzzilliTests/CompilerTests.swift @@ -39,7 +39,7 @@ class CompilerTests: XCTestCase { 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 diff --git a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 369b93090..264ade1c9 100644 --- a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js +++ b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js @@ -15,6 +15,18 @@ 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 class property (field)"); (() => { function classify (name) { @@ -136,7 +148,6 @@ console.log("Indexed static class property (field)"); console.log(C[42]); })(); -/* console.log("Indexed class property (method)"); (() => { class C { @@ -148,9 +159,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,7 +170,6 @@ console.log("Indexed static class property (method)"); } console.log(C[42]()); })(); -*/ /* console.log("Indexed class property (getter/setter)"); @@ -319,24 +327,24 @@ 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?"]()); })(); /* diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index f771b802c..9ab5912db 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -579,6 +579,44 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testObjectLiteralLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildObjectLiteral { obj in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + obj.addMethod(name, with: .parameters(n: 0)) { args in + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v8 = { + "???"() { + }, + 0() { + }, + "01"() { + }, + 1() { + }, + "0.1"() { + }, + "-1"() { + }, + $valid_id_42() { + }, + "42_invalid_id"() { + }, + }; + + """ + XCTAssertEqual(actual, expected) + } + func testObjectLiteralIsDistinguishableFromBlockStatement() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -819,6 +857,63 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testClassDefinitionLiftingWeirdNames() { + 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.addInstanceMethod(name, with: .parameters(n: 0)) { params in + } + cls.addStaticMethod(name, with: .parameters(n: 0)) { params in + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C0 { + "???"() { + } + static "???"() { + } + 0() { + } + static 0() { + } + "01"() { + } + static "01"() { + } + 1() { + } + static 1() { + } + "0.1"() { + } + static "0.1"() { + } + "-1"() { + } + static "-1"() { + } + $valid_id_42() { + } + static $valid_id_42() { + } + "42_invalid_id"() { + } + static "42_invalid_id"() { + } + } + + """ + + XCTAssertEqual(actual, expected) + } + func testClassExpressionLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -1861,6 +1956,132 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testMethodCallLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createNamedVariable(forBuiltin: "Funky") + 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 = """ + Funky["???"](); + Funky[0](); + Funky["01"](); + Funky[1](); + Funky["0.1"](); + Funky["-1"](); + Funky.$valid_id_42(); + Funky["42_invalid_id"](); + + """ + + XCTAssertEqual(actual, expected) + } + + func testMethodCallWithSpreadLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createNamedVariable(forBuiltin: "Funky") + 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 v1 = []; + Funky["???"](...v1); + Funky[0](...v1); + Funky["01"](...v1); + Funky[1](...v1); + Funky["0.1"](...v1); + Funky["-1"](...v1); + Funky.$valid_id_42(...v1); + Funky["42_invalid_id"](...v1); + + """ + + XCTAssertEqual(actual, expected) + } + + func testMethodBindLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createNamedVariable(forBuiltin: "Funky") + 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 = """ + let v1 = Function.prototype.call.bind(Funky["???"]); + v1(Funky); + let v3 = Function.prototype.call.bind(Funky[0]); + v3(Funky); + let v5 = Function.prototype.call.bind(Funky["01"]); + v5(Funky); + let v7 = Function.prototype.call.bind(Funky[1]); + v7(Funky); + let v9 = Function.prototype.call.bind(Funky["0.1"]); + v9(Funky); + let v11 = Function.prototype.call.bind(Funky["-1"]); + v11(Funky); + let v13 = Function.prototype.call.bind(Funky.$valid_id_42); + v13(Funky); + let v15 = Function.prototype.call.bind(Funky["42_invalid_id"]); + v15(Funky); + + """ + + 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) + } + func testComputedMethodCallWithSpreadLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() From d15612a573eceafff983ed6249e46f7282a6eeff Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 16:58:55 +0100 Subject: [PATCH 142/234] [environment] Map: Add prototype object and Map.groupBy Bug: 487347678 Change-Id: I37f8126dbd08e989f229246f68675540cfc8c9f4 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9052178 Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk Auto-Submit: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 092ea9603..9fcb60d58 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -368,6 +368,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsFunctions) registerObjectGroup(.jsSymbols) registerObjectGroup(.jsMaps) + registerObjectGroup(.jsMapPrototype) + registerObjectGroup(.jsMapConstructor) registerObjectGroup(.jsWeakMaps) registerObjectGroup(.jsSets) registerObjectGroup(.jsWeakSets) @@ -1211,7 +1213,7 @@ public extension ILType { static let jsProxyConstructor = ILType.constructor([.object(), .object()] => .jsAnything) /// Type of the JavaScript Map constructor builtin. - static let jsMapConstructor = ILType.constructor([.object()] => .jsMap) + 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) @@ -1671,6 +1673,21 @@ public extension ObjectGroup { ] ) + static let jsMapPrototype = createPrototypeObjectGroup(jsMaps, + constructor: .jsMapConstructor) + + 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( name: "WeakMap", From bae3163100e345e4927829aba115aff152ff34de Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 17:14:07 +0100 Subject: [PATCH 143/234] [environment] Math: Add missing static properties Bug: 487347678 Change-Id: I312d4574513d40fc0ecb43218ee62dcd8eada091 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9052179 Reviewed-by: Danylo Mocherniuk Auto-Submit: Matthias Liedtke Commit-Queue: Danylo Mocherniuk --- .../Fuzzilli/Environment/JavaScriptEnvironment.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9fcb60d58..07e2b6887 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1237,7 +1237,7 @@ public extension ILType { 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", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) + 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 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"]) @@ -2275,8 +2275,14 @@ public extension 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, From 32714e6c4c30dca919b7ec8ad53ca068d998b2aa Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 17:32:46 +0100 Subject: [PATCH 144/234] [environment] RegExp: Properly type prototype and add more properties The added properties are deprecated, but in the end it matters what we ship, not if it's deprecated. Bug: 487347678 Change-Id: I3e027d8a1ece8a6bdf31929fd3952d2589cc0bfa Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9052180 Auto-Submit: Matthias Liedtke Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 07e2b6887..3e6c4d8bc 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -402,6 +402,7 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsStringPrototype) registerObjectGroup(.jsSymbolConstructor) registerObjectGroup(.jsBigIntConstructor) + registerObjectGroup(.jsRegExpPrototype) registerObjectGroup(.jsRegExpConstructor) registerObjectGroup(.jsBooleanConstructor) registerObjectGroup(.jsNumberConstructor) @@ -1173,7 +1174,7 @@ public extension ILType { static let jsBigIntConstructor = ILType.function([.number] => .bigint) + .object(ofGroup: "BigIntConstructor", withProperties: ["prototype"], withMethods: ["asIntN", "asUintN"]) /// Type of the JavaScript RegExp constructor builtin. - static let jsRegExpConstructor = ILType.functionAndConstructor([.string] => .jsRegExp) + .object(ofGroup: "RegExpConstructor", withProperties: ["prototype"], withMethods: ["escape"]) + 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 { @@ -2221,13 +2222,29 @@ public extension ObjectGroup { ] ) + static let jsRegExpPrototype = createPrototypeObjectGroup(jsRegExps, constructor: .jsRegExpConstructor) + /// Object group modelling the JavaScript RegExp constructor builtin static let jsRegExpConstructor = ObjectGroup( name: "RegExpConstructor", constructorPath: "RegExp", instanceType: .jsRegExpConstructor, properties: [ - "prototype" : .object() + "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, From f475e21ea6f6e40ce9fce8496d0e4dac797362d6 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 17:43:29 +0100 Subject: [PATCH 145/234] [environment] Add prototypes to WeakMap, WeakRef and WeakSet Bug: 487347678 Change-Id: I11dd214d888556ded07b3d41afe387ae5c4c79cc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9052181 Reviewed-by: Danylo Mocherniuk Commit-Queue: Danylo Mocherniuk Auto-Submit: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 3e6c4d8bc..b94fb277f 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -371,9 +371,15 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsMapPrototype) registerObjectGroup(.jsMapConstructor) registerObjectGroup(.jsWeakMaps) + registerObjectGroup(.jsWeakMapPrototype) + registerObjectGroup(.jsWeakMapConstructor) registerObjectGroup(.jsSets) registerObjectGroup(.jsWeakSets) + registerObjectGroup(.jsWeakSetPrototype) + registerObjectGroup(.jsWeakSetConstructor) registerObjectGroup(.jsWeakRefs) + registerObjectGroup(.jsWeakRefPrototype) + registerObjectGroup(.jsWeakRefConstructor) registerObjectGroup(.jsFinalizationRegistrys) registerObjectGroup(.jsFinalizationRegistryPrototype) registerObjectGroup(.jsFinalizationRegistryConstructor) @@ -1217,16 +1223,16 @@ public extension ILType { 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) + 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) /// Type of the JavaScript WeakSet constructor builtin. - static let jsWeakSetConstructor = ILType.constructor([.object()] => .jsWeakSet) + 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) + static let jsWeakRefConstructor = ILType.constructor([.object()] => .jsWeakRef) + .object(ofGroup: "WeakRefConstructor", withProperties: ["prototype"]) /// Type of the JavaScript FinalizationRegistry constructor builtin. static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) @@ -1704,6 +1710,19 @@ public extension ObjectGroup { ] ) + static let jsWeakMapPrototype = createPrototypeObjectGroup(jsWeakMaps, + constructor: .jsWeakMapConstructor) + + static let jsWeakMapConstructor = ObjectGroup( + name: "WeakMapConstructor", + constructorPath: "WeakMap", + instanceType: .jsWeakMapConstructor, + properties: [ + "prototype" : jsWeakMapPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript Set objects static let jsSets = ObjectGroup( name: "Set", @@ -1735,6 +1754,19 @@ public extension ObjectGroup { ] ) + static let jsWeakSetPrototype = createPrototypeObjectGroup(jsWeakSets, + constructor: .jsWeakSetConstructor) + + static let jsWeakSetConstructor = ObjectGroup( + name: "WeakSetConstructor", + constructorPath: "WeakSet", + instanceType: .jsWeakSetConstructor, + properties: [ + "prototype" : jsWeakSetPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript WeakRef objects static let jsWeakRefs = ObjectGroup( name: "WeakRef", @@ -1745,6 +1777,19 @@ public extension ObjectGroup { ] ) + static let jsWeakRefPrototype = createPrototypeObjectGroup(jsWeakRefs, + constructor: .jsWeakRefConstructor) + + static let jsWeakRefConstructor = ObjectGroup( + name: "WeakRefConstructor", + constructorPath: "WeakRef", + instanceType: .jsWeakRefConstructor, + properties: [ + "prototype" : jsWeakRefPrototype.instanceType + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript FinalizationRegistry objects static let jsFinalizationRegistrys = ObjectGroup( name: "FinalizationRegistry", From aa767058e284002a39ec5da0f026101fd96a19df Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 18:03:20 +0100 Subject: [PATCH 146/234] [environment] Set: Add prototype and missing instance methods Bug: 487347678 Change-Id: I08a1e7346eb50d85832e4d4df798ba5b52348382 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9052182 Commit-Queue: Danylo Mocherniuk Auto-Submit: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index b94fb277f..fb383c082 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -374,6 +374,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsWeakMapPrototype) registerObjectGroup(.jsWeakMapConstructor) registerObjectGroup(.jsSets) + registerObjectGroup(.jsSetPrototype) + registerObjectGroup(.jsSetConstructor) registerObjectGroup(.jsWeakSets) registerObjectGroup(.jsWeakSetPrototype) registerObjectGroup(.jsWeakSetConstructor) @@ -1114,7 +1116,7 @@ public extension ILType { 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"]) + 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"]) @@ -1226,7 +1228,7 @@ public extension ILType { 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) + static let jsSetConstructor = ILType.constructor([.object()] => .jsSet) + .object(ofGroup: "SetConstructor", withProperties: ["prototype"]) /// Type of the JavaScript WeakSet constructor builtin. static let jsWeakSetConstructor = ILType.constructor([.object()] => .jsWeakSet) + .object(ofGroup: "WeakSetConstructor", withProperties: ["prototype"]) @@ -1731,15 +1733,35 @@ public extension ObjectGroup { "size" : .integer ], methods: [ - "add" : [.jsAnything] => .jsSet, - "clear" : [] => .undefined, - "delete" : [.jsAnything] => .boolean, - "entries" : [] => .jsIterator, - "forEach" : [.function(), .opt(.object())] => .undefined, - "has" : [.jsAnything] => .boolean, - "keys" : [] => .jsIterator, - "values" : [] => .jsIterator, - ] + "add" : [.jsAnything] => .jsSet, + "clear" : [] => .undefined, + "delete" : [.jsAnything] => .boolean, + "difference" : [.plain(.jsSet)] => .jsSet, + "entries" : [] => .jsIterator, + "forEach" : [.function(), .opt(.object())] => .undefined, + "has" : [.jsAnything] => .boolean, + "intersection" : [.plain(.jsSet)] => .jsSet, + "isDisjointFrom" : [.plain(.jsSet)] => .boolean, + "isSubsetOf" : [.plain(.jsSet)] => .boolean, + "isSupersetOf" : [.plain(.jsSet)] => .boolean, + "keys" : [] => .jsIterator, + "symmetricDifference" : [.plain(.jsSet)] => .jsSet, + "union" : [.plain(.jsSet)] => .jsSet, + "values" : [] => .jsIterator, + ] + ) + + static let jsSetPrototype = createPrototypeObjectGroup(jsSets, + constructor: .jsSetConstructor) + + static let jsSetConstructor = ObjectGroup( + name: "SetConstructor", + constructorPath: "Set", + instanceType: .jsSetConstructor, + properties: [ + "prototype" : jsSetPrototype.instanceType + ], + methods: [:] ) /// ObjectGroup modelling JavaScript WeakSet objects From 3c4083db3df39b06aa1fcf089a708541779f5f26 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 11:25:43 +0100 Subject: [PATCH 147/234] [protobuf] Regenerate code with consistent version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I13e3653837dbc4502252cbe2ac25e8b4dbb7c44f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9058297 Commit-Queue: Doga Yüksel Reviewed-by: Doga Yüksel Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Protobuf/operations.pb.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 98d1b86cb..3659ec358 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5946,11 +5946,11 @@ public struct Fuzzilli_Protobuf_WasmRefCast: 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} From 713fb3fbf1213afd4fe80724ad51ef2ecfe7f69b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 11:19:20 +0100 Subject: [PATCH 148/234] [environment] Add Atomics builtin and its methods Bug: 487347678 Change-Id: I5fdc080270ee713b71c46faf867a800180c1ec22 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9058836 Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk Auto-Submit: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index fb383c082..3fcaf974e 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -415,6 +415,7 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsBooleanConstructor) registerObjectGroup(.jsNumberConstructor) registerObjectGroup(.jsMathObject) + registerObjectGroup(.jsAtomicsObject) registerObjectGroup(.jsDate) registerObjectGroup(.jsDateConstructor) registerObjectGroup(.jsDatePrototype) @@ -648,6 +649,7 @@ public class JavaScriptEnvironment: ComponentBase { 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) @@ -1151,6 +1153,10 @@ public extension ILType { 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 { @@ -1248,6 +1254,9 @@ public extension ILType { /// Type of the JavaScript Math constructor builtin. static let jsMathObject = ILType.object(ofGroup: "Math", withProperties: ["E", "PI", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"], withMethods: ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) + /// Type of the JavaScript Atomics builtin. + static let jsAtomicsObject = ILType.object(ofGroup: "Atomics", withProperties: [], withMethods: ["add", "and", "compareExchange", "exchange", "isLockFree", "load", "notify", "or", "pause", "store", "sub", "wait", "waitAsync", "xor"]) + /// 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"]) @@ -2409,6 +2418,34 @@ public extension ObjectGroup { ] ) + /// 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. + 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( name: "JSON", From 31a2df5c36f2935cda13ba8a01c419d29ed7383e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 15:13:08 +0100 Subject: [PATCH 149/234] [environment] Add missing builtins to Error objects Bug: 487347678 Change-Id: I649849a5e3d9511e82e5e47a5ffc61433ca8822e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9058837 Reviewed-by: Danylo Mocherniuk Commit-Queue: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 3fcaf974e..d271bbdad 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -427,6 +427,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsSharedArrayBufferPrototype) 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) @@ -627,10 +629,9 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("Iterator", ofType: .jsIteratorConstructor) registerBuiltin("BigInt", ofType: .jsBigIntConstructor) registerBuiltin("RegExp", ofType: .jsRegExpConstructor) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError"] { + 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) for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { @@ -1197,8 +1198,16 @@ public extension ILType { /// Type of the JavaScript Error constructor builtin static func jsErrorConstructor(_ variant: String) -> ILType { - // TODO: Add `Error.isError()` - return .functionAndConstructor([.opt(.string)] => .jsError(variant)) + 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: ["prototype", "stackTraceLimit"], + withMethods: ["isError", "captureStackTrace"]) } /// Type of the JavaScript ArrayBuffer constructor builtin. @@ -2498,6 +2507,26 @@ public extension ObjectGroup { ) } + static func jsErrorPrototype(_ variant: String) -> ObjectGroup { + return createPrototypeObjectGroup(jsError(variant), constructor: .jsErrorConstructor(variant)) + } + + static func jsErrorConstructor(_ variant: String) -> ObjectGroup { + return ObjectGroup( + name: "\(variant)Constructor", + constructorPath: variant, + instanceType: .jsErrorConstructor(variant), + properties: [ + "prototype": jsErrorPrototype(variant).instanceType, + "stackTraceLimit": .integer, + ], + methods: [ + "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( From 2ec7c0d53c051cfda307dd0c16d5bf4a19916fad Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 17:26:46 +0100 Subject: [PATCH 150/234] [environment] Add some more builtins - Proxy.revocabale - Promise.withResolvers - Number.parseFloat - Number.parseInt - Object.groupBy - Object.hasOwn Bug: 487347678 Change-Id: I67c3c1c0b0d517dc61cc8a26c69031b81cf9eccc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9058838 Reviewed-by: Danylo Mocherniuk Commit-Queue: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index d271bbdad..15fcd5d59 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -405,6 +405,7 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsObjectConstructor) registerObjectGroup(.jsPromiseConstructor) registerObjectGroup(.jsPromisePrototype) + registerObjectGroup(.jsProxyConstructor) registerObjectGroup(.jsArrayConstructor) registerObjectGroup(.jsStringConstructor) registerObjectGroup(.jsStringPrototype) @@ -1165,7 +1166,7 @@ public extension ILType { } /// 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"]) + static let jsObjectConstructor = .functionAndConstructor([.jsAnything...] => .object()) + .object(ofGroup: "ObjectConstructor", withProperties: ["prototype"], withMethods: ["assign", "fromEntries", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "values", "groupBy", "hasOwn"]) /// Type of the JavaScript Array constructor builtin. static let jsArrayConstructor = .functionAndConstructor([.integer] => .jsArray) + .object(ofGroup: "ArrayConstructor", withProperties: ["prototype"], withMethods: ["from", "fromAsync", "of", "isArray"]) @@ -1180,7 +1181,7 @@ public extension ILType { 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"]) + 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"]) @@ -1231,10 +1232,10 @@ public extension ILType { static let jsDataViewConstructor = ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Promise constructor builtin. - static let jsPromiseConstructor = ILType.constructor([.function()] => .jsPromise) + .object(ofGroup: "PromiseConstructor", withProperties: ["prototype"], withMethods: ["resolve", "reject", "all", "any", "race", "allSettled", "try"]) + 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) + static let jsProxyConstructor = ILType.constructor([.object(), .object()] => .jsAnything) + .object(ofGroup: "ProxyConstructor", withProperties: [], withMethods: ["revocable"]) /// Type of the JavaScript Map constructor builtin. static let jsMapConstructor = ILType.constructor([.object()] => .jsMap) + .object(ofGroup: "MapConstructor", withProperties: ["prototype"], withMethods: ["groupBy"]) @@ -1700,6 +1701,16 @@ public extension ObjectGroup { ] ) + static let jsProxyConstructor = ObjectGroup( + name: "ProxyConstructor", + constructorPath: "Proxy", + instanceType: .jsProxyConstructor, + properties: [:], + methods: [ + "revocable": [.object(), .object()] => .object(withProperties: ["proxy", "revoke"]) + ] + ) + static let jsMapPrototype = createPrototypeObjectGroup(jsMaps, constructor: .jsMapConstructor) @@ -2095,6 +2106,7 @@ public extension ObjectGroup { "race" : [.jsPromise...] => .jsPromise, "allSettled" : [.jsPromise...] => .jsPromise, "try" : [.function(), .jsAnything...] => .jsPromise, + "withResolvers": [] => .object(withProperties: ["promise", "resolve", "reject"]), ] ) @@ -2199,6 +2211,8 @@ public extension ObjectGroup { "seal" : [.object()] => .object(), "setPrototypeOf" : [.object(), .object()] => .object(), "values" : [.object()] => .jsArray, + "groupBy" : [.iterable, .function()] => .object(), + "hasOwn" : [.object(), .oneof(.jsString, .jsSymbol)] => .boolean, ] ) @@ -2369,6 +2383,8 @@ public extension ObjectGroup { "isFinite" : [.jsAnything] => .boolean, "isInteger" : [.jsAnything] => .boolean, "isSafeInteger" : [.jsAnything] => .boolean, + "parseFloat" : [.string] => .float, + "parseInt" : [.string] => .integer, ] ) From c64357c5a7066446faa8c2a735ea55b080366f25 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Mon, 2 Mar 2026 10:25:12 +0000 Subject: [PATCH 151/234] Remove unused enum wasmBlockType MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I539c771195a5c9a5242c9650815496f8c255cdba Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064096 Commit-Queue: Doga Yüksel Auto-Submit: Danylo Mocherniuk Reviewed-by: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index cee838ad7..ad39437ca 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3922,11 +3922,6 @@ public class ProgramBuilder { b.emit(WasmReassign(), withInputs: [variable, to]) } - public enum wasmBlockType { - case typeIdx(Int) - case valueType(ILType) - } - // 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]) -> ()) { assert(signature.outputTypes.count == 0) From e12a1711274d41478b8910c02c22333eb7379d31 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 12:40:09 +0100 Subject: [PATCH 152/234] [environment] Register Intl.DisplayNames and its builtins and add a custom generator for Intl.DisplayNames.prototype.of() as it contains a tight coupling between the constructor arguments and the code provided to the "of" function as an argument. Bug: 487347678 Change-Id: Ia0ffd3f51599b501a6855b07931249abcf777984 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9063878 Commit-Queue: Matthias Liedtke Reviewed-by: Manish Goregaokar --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 56 +++++++++++++++---- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 44 ++++++++++++++- .../Environment/JavaScriptEnvironment.swift | 55 +++++++++++++++++- 3 files changed, 142 insertions(+), 13 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index ad39437ca..a8c48147c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -5019,22 +5019,28 @@ 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) + 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 $0.Is(OptionsBag.jsTemporalRelativeTo) { - return findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime, - .jsTemporalPlainDate, .string])) + } else if type.Is(OptionsBag.jsTemporalRelativeTo) { + return (propertyName, findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime, + .jsTemporalPlainDate, .string]))) } else { - return findOrGenerateType($0) + return (propertyName, findOrGenerateType(type)) } - } + }) return createObject(with: dict) } @@ -5403,6 +5409,29 @@ public class ProgramBuilder { 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 { @@ -5429,7 +5458,7 @@ public class ProgramBuilder { static func constructIntlRegionString() -> String { // either two letters or three digits if probability(0.5) { - return String((0..<2).map { _ in allAlpha.randomElement()! }) + return allRegionsTwoDigit.randomElement()! } else { return String(format: "%03d", Int.random(in: 0...999)) } @@ -5495,6 +5524,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) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index a2d94affa..4f23233a7 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + // Generator stubs for disposable and async-disposable object variables. func disposableObjVariableGeneratorStubs( inContext contextRequirement : Context, @@ -351,7 +353,47 @@ public let CodeGenerators: [CodeGenerator] = [ }, CodeGenerator("BuiltinIntlGenerator") { b in - let _ = chooseUniform(from: [b.constructIntlDateTimeFormat, b.constructIntlCollator, b.constructIntlListFormat, b.constructIntlLocale, b.constructIntlNumberFormat, b.constructIntlPluralRules, b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter])() + let _ = chooseUniform(from: [ + b.constructIntlDateTimeFormat, + b.constructIntlCollator, + b.constructIntlListFormat, + b.constructIntlLocale, + b.constructIntlNumberFormat, + b.constructIntlPluralRules, + b.constructIntlRelativeTimeFormat, + b.constructIntlSegmenter, + b.constructIntlDisplayNames, + { // Fuzz Intl.DisplayNames.prototype.of() + let intl = b.createNamedVariable(forBuiltin: "Intl") + let ctor = b.getProperty("DisplayNames", of: intl) + let types = + b.fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues + let type = types.randomElement()! + let locale = b.loadString(ProgramBuilder.constructIntlLocaleString()) + let options = b.createOptionsBag(.jsIntlDisplayNamesSettings, + predefined: ["type": b.loadString(type)]) + b.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": + b.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 b.callMethod("of", on: ctor, withArgs: [b.loadString(code)]) + } + ])() }, CodeGenerator("HexGenerator") { b in diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 15fcd5d59..004fd17da 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -483,6 +483,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsIntlCollator) registerObjectGroup(.jsIntlCollatorConstructor) registerObjectGroup(.jsIntlCollatorPrototype) + registerObjectGroup(.jsIntlDisplayNames) + registerObjectGroup(.jsIntlDisplayNamesConstructor) + registerObjectGroup(.jsIntlDisplayNamesPrototype) registerObjectGroup(.jsIntlDateTimeFormat) registerObjectGroup(.jsIntlDateTimeFormatConstructor) registerObjectGroup(.jsIntlDateTimeFormatPrototype) @@ -538,6 +541,9 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlCollationTypeEnum) registerEnumeration(OptionsBag.jsIntlCaseFirstEnum) registerEnumeration(OptionsBag.jsIntlCollatorSensitivityEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesTypeEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesFallbackEnum) + registerEnumeration(OptionsBag.jsIntlDisplayNamesLanguageDisplayEnum) registerEnumeration(OptionsBag.jsIntlListFormatTypeEnum) registerEnumeration(OptionsBag.jsIntlNumberFormatStyleEnum) registerEnumeration(OptionsBag.jsIntlCurrencySystemEnum) @@ -570,6 +576,7 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsTemporalPlainDateToZDTSettings) registerOptionsBag(.jsIntlDateTimeFormatSettings) registerOptionsBag(.jsIntlCollatorSettings) + registerOptionsBag(.jsIntlDisplayNamesSettings) registerOptionsBag(.jsIntlListFormatSettings) registerOptionsBag(.jsIntlLocaleSettings) registerOptionsBag(.jsIntlNumberFormatSettings) @@ -3433,7 +3440,7 @@ extension OptionsBag { // Intl extension ILType { // Intl types - static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "ListFormat", "Locale", "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter"], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) + static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "DisplayNames", "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: []) @@ -3441,6 +3448,9 @@ extension ILType { 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 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"]) @@ -3480,6 +3490,7 @@ extension ObjectGroup { properties: [ "Collator" : .jsIntlCollatorConstructor, "DateTimeFormat" : .jsIntlDateTimeFormatConstructor, + "DisplayNames" : .jsIntlDisplayNamesConstructor, "ListFormat" : .jsIntlListFormatConstructor, "Locale" : .jsIntlLocaleConstructor, "NumberFormat" : .jsIntlNumberFormatConstructor, @@ -3523,6 +3534,33 @@ extension ObjectGroup { ] ) + 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, + ] + ) + 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. @@ -3799,6 +3837,9 @@ extension OptionsBag { 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 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 }) @@ -3857,6 +3898,18 @@ 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/ListFormat/ListFormat#options static let jsIntlListFormatSettings = OptionsBag( name: "IntlListFormatSettings", From 887dfa74c556c46f7e158be0119c2d06e86b7acb Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 13:09:06 +0100 Subject: [PATCH 153/234] [environment] Register Intl.DurationFormat and its builtins Bug: 487347678 Change-Id: I92fa5d5dccfcd3b5f5590ecea134265bb10d1190 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064297 Reviewed-by: Manish Goregaokar Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 004fd17da..fd43586b7 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -486,6 +486,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsIntlDisplayNames) registerObjectGroup(.jsIntlDisplayNamesConstructor) registerObjectGroup(.jsIntlDisplayNamesPrototype) + registerObjectGroup(.jsIntlDurationFormat) + registerObjectGroup(.jsIntlDurationFormatConstructor) + registerObjectGroup(.jsIntlDurationFormatPrototype) registerObjectGroup(.jsIntlDateTimeFormat) registerObjectGroup(.jsIntlDateTimeFormatConstructor) registerObjectGroup(.jsIntlDateTimeFormatPrototype) @@ -544,6 +547,7 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlDisplayNamesTypeEnum) registerEnumeration(OptionsBag.jsIntlDisplayNamesFallbackEnum) registerEnumeration(OptionsBag.jsIntlDisplayNamesLanguageDisplayEnum) + registerEnumeration(OptionsBag.jsIntlDurationFormatStyleEnum) registerEnumeration(OptionsBag.jsIntlListFormatTypeEnum) registerEnumeration(OptionsBag.jsIntlNumberFormatStyleEnum) registerEnumeration(OptionsBag.jsIntlCurrencySystemEnum) @@ -577,6 +581,7 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsIntlDateTimeFormatSettings) registerOptionsBag(.jsIntlCollatorSettings) registerOptionsBag(.jsIntlDisplayNamesSettings) + registerOptionsBag(.jsIntlDurationFormatSettings) registerOptionsBag(.jsIntlListFormatSettings) registerOptionsBag(.jsIntlLocaleSettings) registerOptionsBag(.jsIntlNumberFormatSettings) @@ -3440,7 +3445,7 @@ extension OptionsBag { // Intl extension ILType { // Intl types - static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "DisplayNames", "ListFormat", "Locale", "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter"], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) + 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: []) @@ -3451,6 +3456,9 @@ extension ILType { 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"]) @@ -3491,6 +3499,7 @@ extension ObjectGroup { "Collator" : .jsIntlCollatorConstructor, "DateTimeFormat" : .jsIntlDateTimeFormatConstructor, "DisplayNames" : .jsIntlDisplayNamesConstructor, + "DurationFormat" : .jsIntlDurationFormatConstructor, "ListFormat" : .jsIntlListFormatConstructor, "Locale" : .jsIntlLocaleConstructor, "NumberFormat" : .jsIntlNumberFormatConstructor, @@ -3561,6 +3570,34 @@ extension ObjectGroup { ] ) + 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, + ] + ) + 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. @@ -3840,6 +3877,7 @@ extension OptionsBag { 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 }) @@ -3910,6 +3948,37 @@ extension OptionsBag { ] ) + // 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", From 72b7bb4f613fe6911fe31db6aab93270d09525f4 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 13:30:30 +0100 Subject: [PATCH 154/234] [environment] Add multiple missing builtins - .name for all builtin error types - .prototype.mesage and .prototype.name for all builtin error types - ArrayBuffer.prototype.sliceToImmutable - Date.prototype.toLocaleDateString - Date.prototype.toLocaleTimeString Bug: 487347678 Change-Id: I766290ca1e2ced9556448bf31dbbd4d8f6656576 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064298 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index fd43586b7..9ae232b36 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1150,7 +1150,7 @@ public extension ILType { 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", "transferToFixedLength", "transferToImmutable"]) + 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"]) @@ -1219,7 +1219,7 @@ public extension ILType { return .functionAndConstructor(signature) + .object( ofGroup: "\(variant)Constructor", - withProperties: ["prototype", "stackTraceLimit"], + withProperties: ["name", "prototype", "stackTraceLimit"], withMethods: ["isError", "captureStackTrace"]) } @@ -1280,7 +1280,7 @@ public extension ILType { 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"]) + 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"]) @@ -1946,10 +1946,11 @@ public extension ObjectGroup { ], methods: [ "resize" : [.integer] => .undefined, - "slice" : [.integer, .opt(.integer)] => .jsArrayBuffer, + "slice" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, + "sliceToImmutable" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, "transfer" : [.opt(.integer)] => .jsArrayBuffer, "transferToFixedLength" : [.opt(.integer)] => .jsArrayBuffer, - "transferToImmutable" : [] => .jsArrayBuffer, + "transferToImmutable" : [.opt(.integer)] => .jsArrayBuffer, ] ) @@ -2131,9 +2132,9 @@ public extension ObjectGroup { "toISOString" : [] => .jsString, "toDateString" : [] => .jsString, "toTimeString" : [] => .jsString, - "toLocaleString" : [] => .jsString, - //"toLocaleDateString" : [.localeObject] => .jsString, - //"toLocaleTimeString" : [.localeObject] => .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, @@ -2536,7 +2537,13 @@ public extension ObjectGroup { } static func jsErrorPrototype(_ variant: String) -> ObjectGroup { - return createPrototypeObjectGroup(jsError(variant), constructor: .jsErrorConstructor(variant)) + return createPrototypeObjectGroup( + jsError(variant), + constructor: .jsErrorConstructor(variant), + additionalProperties: [ + "message": .jsString, + "name": .jsString, + ]) } static func jsErrorConstructor(_ variant: String) -> ObjectGroup { @@ -2545,6 +2552,7 @@ public extension ObjectGroup { constructorPath: variant, instanceType: .jsErrorConstructor(variant), properties: [ + "name": .jsString, "prototype": jsErrorPrototype(variant).instanceType, "stackTraceLimit": .integer, ], From a24794096a4e76f02aff94aaea91af5c3be22d12 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 18:33:42 +0100 Subject: [PATCH 155/234] [environment] Properly type Function.prototype Bug: 487347678 Change-Id: Ib8ecc8268ef60847919abe2dc6f081665930fde3 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064299 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9ae232b36..caafdde2c 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -366,6 +366,8 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsPromises) registerObjectGroup(.jsRegExps) registerObjectGroup(.jsFunctions) + registerObjectGroup(.jsFunctionPrototype) + registerObjectGroup(.jsFunctionConstructor) registerObjectGroup(.jsSymbols) registerObjectGroup(.jsMaps) registerObjectGroup(.jsMapPrototype) @@ -1184,7 +1186,7 @@ public extension ILType { 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)) + 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"]) @@ -1605,6 +1607,19 @@ public extension ObjectGroup { ] ) + static let jsFunctionPrototype = createPrototypeObjectGroup(jsFunctions, + constructor: .jsFunctionConstructor) + + static let jsFunctionConstructor = ObjectGroup( + name: "FunctionConstructor", + constructorPath: "Function", + instanceType: .jsFunctionConstructor, + properties: [ + "prototype" : jsFunctionPrototype.instanceType, + ], + methods: [:] + ) + /// ObjectGroup modelling JavaScript Symbols static let jsSymbols = ObjectGroup( name: "Symbol", From 283cd7f55728cfa847cb3dd322ca60521b953497 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 18:10:12 +0100 Subject: [PATCH 156/234] [v8] Add generator for %AllocateHeapNumberWithValue() V8-side change: https://crrev.com/c/7623762 Bug: 487620644 Change-Id: Iee848582cf8ed19085daea8c7715bf8c3f54f3d9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064480 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- Sources/FuzzilliCli/Profiles/V8CommonProfile.swift | 7 +++++++ Sources/FuzzilliCli/Profiles/V8Profile.swift | 1 + 2 files changed, 8 insertions(+) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index ceafa1351..1e4669182 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -177,6 +177,13 @@ public let UndefinedNanGenerator = CodeGenerator("UndefinedNanGenerator") { b in b.eval("%GetUndefinedNaN()", hasOutput: true); } +public let HeapNumberGenerator = CodeGenerator("HeapNumberGenerator", inputs: .preferred(.integer)) +{ b, value in + // This generator prefers an integer input as these have a high chance of being representable as + // a Smi, meaning that we often end up with a HeapNumber that didn't have to be materialized. + b.eval("%AllocateHeapNumberWithValue(%@)", with: [value], hasOutput: true); +} + public let StringShapeGenerator = CodeGenerator("StringShapeGenerator") { b in withEqualProbability( { diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/FuzzilliCli/Profiles/V8Profile.swift index 8402dbd76..cc3d4a9a8 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/FuzzilliCli/Profiles/V8Profile.swift @@ -75,6 +75,7 @@ let v8Profile = Profile( (HoleNanGenerator, 5), (UndefinedNanGenerator, 5), (StringShapeGenerator, 5), + (HeapNumberGenerator, 5), ], additionalProgramTemplates: WeightedList([ From 2a867e91ae97e9062229863712feb3ecd0e3403a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 19:34:44 +0100 Subject: [PATCH 157/234] [github] Fix protobuf installation for presubmit checks Change-Id: I95e6e68e0ce4d2051f3c267667aedef63207b6c2 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064377 Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach --- .github/workflows/swift.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 951fa3872..2d630a4a3 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -30,11 +30,11 @@ jobs: 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 @@ -42,7 +42,7 @@ jobs: 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 From 35db86dc836d25bacf20ba780332433968c63b43 Mon Sep 17 00:00:00 2001 From: Danylo Mocherniuk Date: Tue, 3 Mar 2026 09:39:35 +0000 Subject: [PATCH 158/234] [custom-descriptors] refactor generating fields into a separate function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will probably be needed later for the descriptor/describes relation. Bug: 448858866 Change-Id: Ie4793668172cc9730e1c97a7ceae2f0c10ff2f3b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9067096 Auto-Submit: Danylo Mocherniuk Reviewed-by: Doga Yüksel Commit-Queue: Doga Yüksel --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 26 +++++++++++++++++++ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 22 ++-------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index a8c48147c..27bf63902 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4605,6 +4605,32 @@ 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. diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 493247c29..1d6548fdf 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -2017,26 +2017,8 @@ fileprivate let wasmStructTypeGenerator = GeneratorStub( "WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)]) { b in - var indexTypes: [Variable] = [] - let fields = (0.. Date: Mon, 2 Mar 2026 15:53:22 +0100 Subject: [PATCH 159/234] [environment] Add a large amount of mostly-deprecated string methods Bug: 487347678 Change-Id: Iea000a7b4e83ad259bd9e41c2863e279352c625c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064303 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .../Environment/JavaScriptEnvironment.swift | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index caafdde2c..74fd7b404 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1100,7 +1100,7 @@ public struct OptionsBag { public 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"]) + 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. @@ -1513,9 +1513,25 @@ public extension ObjectGroup { "toLowerCase" : [] => .jsString, "toUpperCase" : [] => .jsString, "localeCompare" : [.string, .opt(.string), .opt(.object())] => .jsString, - //"toLocaleLowerCase" : [.opt(.string...] => .jsString, - //"toLocaleUpperCase" : [.opt(.string...] => .jsString, - // ... + "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, ] ) From ad3e616df735f3318b0a1c647e7f16cef3e4a2b3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 3 Mar 2026 10:33:22 +0100 Subject: [PATCH 160/234] [cleanup] Move Intl.DisplayNames.of fuzzing into ProgramBuilder Follow-up to commit e12a1711274d41478b8910c02c22333eb7379d31 Change-Id: Ie4cfa33fef72c15caaf88336ca408d94c37e759a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9067018 Commit-Queue: Manish Goregaokar Reviewed-by: Manish Goregaokar Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 35 +++++++++++++++++-- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 31 +--------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 27bf63902..93604ed6a 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -5579,6 +5579,37 @@ public class ProgramBuilder { 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/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 4f23233a7..3783c67c5 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -363,36 +363,7 @@ public let CodeGenerators: [CodeGenerator] = [ b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter, b.constructIntlDisplayNames, - { // Fuzz Intl.DisplayNames.prototype.of() - let intl = b.createNamedVariable(forBuiltin: "Intl") - let ctor = b.getProperty("DisplayNames", of: intl) - let types = - b.fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues - let type = types.randomElement()! - let locale = b.loadString(ProgramBuilder.constructIntlLocaleString()) - let options = b.createOptionsBag(.jsIntlDisplayNamesSettings, - predefined: ["type": b.loadString(type)]) - b.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": - b.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 b.callMethod("of", on: ctor, withArgs: [b.loadString(code)]) - } + b.fuzzIntlDisplayNamesOf, ])() }, From 89691a13e737f342f68dcd19f7ca66a71892d8fc Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 4 Mar 2026 17:17:58 +0100 Subject: [PATCH 161/234] [wasm] JSTyper: Fix newly introduced crash for WasmBeginCatch Maybe I shouldn't just predict crashes but instead fix them before landing my changes. Bug: 448860865 Change-Id: I7df709799f11fcaec590960c4eeecdc17696772c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9073196 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 9007fc91f..8620a70b4 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -880,14 +880,11 @@ public struct JSTyper: Analyzer { // exnref in the standard exception handling spec.) setType(of: instr.innerOutput(1), to: .exceptionLabel) // Type the tag parameters. - guard let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters else { - // TODO(mliedtke): I believe that sooner or later we will run into this fatal - // error. A tag can be defined in JavaScript and then be used in Wasm. Later on - // the varaible defining the tag can be reassigned to with a different type, - // loosening the inferred type information suddenly not being a tag any more. - fatalError("Input into WasmBeginCatch not a tag type, actual " - + "\(type(of: instr.input(1))), defined in \(definingInstruction)") - } + // If the input isn't typed as a Wasm tag any more (this can happen as tags can be + // defined in JS and there a reassign as part of a CodeGenMutator run can loosen the + // inferred type), just act as if there weren't any label parameters. In that case + // the lifter will fail and the test case will be discarded. + let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters ?? [] for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), labelParameters) { setType(of: innerOutput, to: paramType) } From 14f098098ad7b29a3d1f84f19374a751a0e40c50 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 23 Feb 2026 19:22:50 +0100 Subject: [PATCH 162/234] Add tool for detecting missing builtins Bug: 487347678 Change-Id: Id253e99069ceb17b0b6da92876234eb1fec2329c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9044026 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- Package.swift | 2 + Sources/Fuzzilli/Base/Logging.swift | 3 +- .../Profiles/DuktapeProfile.swift | 1 - .../Profiles/JSCProfile.swift | 1 - .../Profiles/JerryscriptProfile.swift | 1 - .../Profiles/NjsProfile.swift | 1 - .../Profiles/Profile.swift | 41 ++-- .../Profiles/QjsProfile.swift | 1 - .../Profiles/QtjsProfile.swift | 1 - .../Profiles/Serenity.swift | 1 - .../Profiles/SpidermonkeyProfile.swift | 1 - .../Profiles/V8CommonProfile.swift | 3 +- .../Profiles/V8DumplingProfile.swift | 1 - .../Profiles/V8HoleFuzzingProfile.swift | 1 - .../Profiles/V8Profile.swift | 3 +- .../Profiles/V8SandboxProfile.swift | 2 - .../Profiles/XSProfile.swift | 1 - .../Fuzzilli/Util/JavaScriptExecutor.swift | 14 +- .../FuzzilliDetectMissingBuiltins/main.swift | 178 ++++++++++++++++++ 19 files changed, 211 insertions(+), 46 deletions(-) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/DuktapeProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/JSCProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/JerryscriptProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/NjsProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/Profile.swift (60%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/QjsProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/QtjsProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/Serenity.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/SpidermonkeyProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/V8CommonProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/V8DumplingProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/V8HoleFuzzingProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/V8Profile.swift (98%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/V8SandboxProfile.swift (99%) rename Sources/{FuzzilliCli => Fuzzilli}/Profiles/XSProfile.swift (99%) create mode 100644 Sources/FuzzilliDetectMissingBuiltins/main.swift diff --git a/Package.swift b/Package.swift index 35a5128d1..c7f6c90f0 100644 --- a/Package.swift +++ b/Package.swift @@ -82,6 +82,8 @@ let package = Package( .executableTarget(name: "RelateTool", dependencies: ["Fuzzilli"]), + .executableTarget(name: "FuzzilliDetectMissingBuiltins", dependencies: ["Fuzzilli"]), + .testTarget(name: "FuzzilliTests", dependencies: ["Fuzzilli"], resources: [.copy("CompilerTests")]), diff --git a/Sources/Fuzzilli/Base/Logging.swift b/Sources/Fuzzilli/Base/Logging.swift index c36eabfb7..abbff0cb4 100644 --- a/Sources/Fuzzilli/Base/Logging.swift +++ b/Sources/Fuzzilli/Base/Logging.swift @@ -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/FuzzilliCli/Profiles/DuktapeProfile.swift b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/DuktapeProfile.swift rename to Sources/Fuzzilli/Profiles/DuktapeProfile.swift index bdc685193..0611eb8ed 100644 --- a/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift +++ b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let duktapeProfile = Profile( processArgs: { randomize in diff --git a/Sources/FuzzilliCli/Profiles/JSCProfile.swift b/Sources/Fuzzilli/Profiles/JSCProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/JSCProfile.swift rename to Sources/Fuzzilli/Profiles/JSCProfile.swift index 23305fc90..214a2f9d2 100644 --- a/Sources/FuzzilliCli/Profiles/JSCProfile.swift +++ b/Sources/Fuzzilli/Profiles/JSCProfile.swift @@ -12,7 +12,6 @@ // 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 assert(b.type(of: f).Is(.function())) diff --git a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift rename to Sources/Fuzzilli/Profiles/JerryscriptProfile.swift index 427a3eea5..912aa5b97 100644 --- a/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift +++ b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let jerryscriptProfile = Profile( processArgs: { randomize in diff --git a/Sources/FuzzilliCli/Profiles/NjsProfile.swift b/Sources/Fuzzilli/Profiles/NjsProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/NjsProfile.swift rename to Sources/Fuzzilli/Profiles/NjsProfile.swift index b286196ef..6dc3408c1 100644 --- a/Sources/FuzzilliCli/Profiles/NjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/NjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let njsProfile = Profile( processArgs: { randomize in diff --git a/Sources/FuzzilliCli/Profiles/Profile.swift b/Sources/Fuzzilli/Profiles/Profile.swift similarity index 60% rename from Sources/FuzzilliCli/Profiles/Profile.swift rename to Sources/Fuzzilli/Profiles/Profile.swift index 8d9d7dcd5..aca59b0e7 100644 --- a/Sources/FuzzilliCli/Profiles/Profile.swift +++ b/Sources/Fuzzilli/Profiles/Profile.swift @@ -12,42 +12,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli -struct Profile { - let processArgs: (_ randomize: Bool) -> [String] +public struct Profile { + public let processArgs: (_ randomize: Bool) -> [String] // if not nil, then this is profile for differential fuzzing - let processArgsReference: [String]? - let processEnv: [String : String] - let maxExecsBeforeRespawn: Int + 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? - var isDifferential: Bool { + public var isDifferential: Bool { return processArgsReference != nil } } -let profiles = [ +public let profiles = [ "qtjs": qtjsProfile, "qjs": qjsProfile, "jsc": jscProfile, diff --git a/Sources/FuzzilliCli/Profiles/QjsProfile.swift b/Sources/Fuzzilli/Profiles/QjsProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/QjsProfile.swift rename to Sources/Fuzzilli/Profiles/QjsProfile.swift index dae0ee932..a5e3e8b62 100644 --- a/Sources/FuzzilliCli/Profiles/QjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let qjsProfile = Profile( processArgs: { randomize in diff --git a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift b/Sources/Fuzzilli/Profiles/QtjsProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/QtjsProfile.swift rename to Sources/Fuzzilli/Profiles/QtjsProfile.swift index 656a5022c..5c743062a 100644 --- a/Sources/FuzzilliCli/Profiles/QtjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QtjsProfile.swift @@ -11,7 +11,6 @@ // 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 diff --git a/Sources/FuzzilliCli/Profiles/Serenity.swift b/Sources/Fuzzilli/Profiles/Serenity.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/Serenity.swift rename to Sources/Fuzzilli/Profiles/Serenity.swift index e98f41fd5..12fbd404f 100644 --- a/Sources/FuzzilliCli/Profiles/Serenity.swift +++ b/Sources/Fuzzilli/Profiles/Serenity.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let serenityProfile = Profile( processArgs: { randomize in return [""] }, diff --git a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift rename to Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift index 46dc022b8..bd857368d 100644 --- a/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift +++ b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift @@ -12,7 +12,6 @@ // 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 assert(b.type(of: f).Is(.function())) diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/V8CommonProfile.swift rename to Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 1e4669182..09cd1d1a0 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli public extension ILType { static let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) @@ -675,7 +674,7 @@ public let WasmFastCallFuzzer = WasmProgramTemplate("WasmFastCallFuzzer") { b in 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) } diff --git a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift rename to Sources/Fuzzilli/Profiles/V8DumplingProfile.swift index 89418e8ce..37cbb3f25 100644 --- a/Sources/FuzzilliCli/Profiles/V8DumplingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli let v8DumplingProfile = Profile( processArgs: { randomize in diff --git a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift rename to Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift index 218ea99fe..98fe3b824 100644 --- a/Sources/FuzzilliCli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift @@ -12,7 +12,6 @@ // 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 diff --git a/Sources/FuzzilliCli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift similarity index 98% rename from Sources/FuzzilliCli/Profiles/V8Profile.swift rename to Sources/Fuzzilli/Profiles/V8Profile.swift index cc3d4a9a8..5b81bf43b 100644 --- a/Sources/FuzzilliCli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import Fuzzilli -let v8Profile = Profile( +public let v8Profile = Profile( processArgs: {randomize in v8ProcessArgs(randomize: randomize, forSandbox: false) }, diff --git a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift rename to Sources/Fuzzilli/Profiles/V8SandboxProfile.swift index 50c7669dd..525acc6fe 100644 --- a/Sources/FuzzilliCli/Profiles/V8SandboxProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -12,8 +12,6 @@ // 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 { diff --git a/Sources/FuzzilliCli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift similarity index 99% rename from Sources/FuzzilliCli/Profiles/XSProfile.swift rename to Sources/Fuzzilli/Profiles/XSProfile.swift index 3de2abb17..02c500c97 100644 --- a/Sources/FuzzilliCli/Profiles/XSProfile.swift +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -12,7 +12,6 @@ // 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) diff --git a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift index 286ac1064..65c5a5706 100644 --- a/Sources/Fuzzilli/Util/JavaScriptExecutor.swift +++ b/Sources/Fuzzilli/Util/JavaScriptExecutor.swift @@ -208,22 +208,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/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift new file mode 100644 index 000000000..14dfbda18 --- /dev/null +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -0,0 +1,178 @@ +import Foundation +import Fuzzilli + +// Disable most logging. The JavaScriptEnvironment prints warning when trying to fetch types for +// builtins it doesn't know about. This is what this script wants to do, so printing warningis for +// it isn't helpful. +Logger.defaultLogLevelWithoutFuzzer = .error + +// Helper function that prints out an error message, then exits the process. +func configError(_ msg: String) -> 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]() + +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!) + } + } + + // Each function has a name and a length property. We don't really care about them, so filter + // them out. + let propertyData = node.properties.filter {($0.key != "name" && $0.key != "length") || node.type != "function"} + 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) + + let isRegistered: Bool + if let type { + isRegistered = jsEnvironment.type(ofProperty: prop, on: type) != .jsAnything + } else { + assert(path.isEmpty) + isRegistered = jsEnvironment.hasBuiltin(prop) + } + + if !isRegistered { + missingBuiltins.append(newPath.joined(separator: ".")) + } + + checkNode(childId, path: newPath) + } +} + +checkNode(0, path: []) +print(missingBuiltins.sorted().joined(separator: "\n")) From bf485ca89dcee71217244dda36bd9a46d7fbc7c0 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Feb 2026 12:22:03 +0100 Subject: [PATCH 163/234] DetectMissingBuiltins: Add exclusion list There are some test-only / d8-only functions that we don't need to or don't want to fuzz. Bug: 487347678 Change-Id: Idea475a3afdf4dcba2787e497fca45580299d265 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9051197 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .../FuzzilliDetectMissingBuiltins/main.swift | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift index 14dfbda18..dedfa1316 100644 --- a/Sources/FuzzilliDetectMissingBuiltins/main.swift +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -1,6 +1,27 @@ import Foundation import Fuzzilli +// Static list of excluded paths. +// If any other engines / profiles are interested in using this executable, this should probably be +// incorporated into the Profile, for now it's just being maintained locally here. +let exclusionList : [String: [String]] = [ + "v8": [ + // The shell arguments are stored in a global `arguments` if not called with --no-arguments. + // Note: This is completely unrelated to JS's Function.prototype.arguments or the arguments + // variable inside a function! + "arguments", + // Helper for tests, not exposed in production and should not be fuzzed. + "d8", + // Things to make d8 a more useful repl, not exposed in production and not fuzzable. + "print", "printErr", "read", "readbuffer", "readline", "version", "write", + // Things that exist in Chrome but have separate implementations in d8 and are therefore + // probably not very interesting for fuzzing. + "console", "performance", + // TODO(mliedtke): https://crbug.com/488072252. + "Realm", + ] +] + // Disable most logging. The JavaScriptEnvironment prints warning when trying to fetch types for // builtins it doesn't know about. This is what this script wants to do, so printing warningis for // it isn't helpful. @@ -157,6 +178,14 @@ func checkNode(_ nodeId: Int, path: [String]) { 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 { @@ -167,7 +196,7 @@ func checkNode(_ nodeId: Int, path: [String]) { } if !isRegistered { - missingBuiltins.append(newPath.joined(separator: ".")) + missingBuiltins.append(pathString) } checkNode(childId, path: newPath) From 0ef67b2896baa9cf45fa968396804f9a568b8445 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 11:51:14 +0100 Subject: [PATCH 164/234] DetectMissingBuiltins: Filter out inaccessible builtins There is a large amount of properties on prototype objects that can only be called on a proper instance, e.g. trying to access > DisposableStack.prototype.disposed will throw an error as DisposableStack.prototype is not the expected receiver type (unlike new DisposableStack().disposed). While the property exists on the prototype, it should not be registered as the fuzzer can't really do anything useful with something that always throws. Bug: 487347678 Change-Id: Ie8b2e5d30caa819f512d6791afb1a22d11761c7f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9058839 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- Sources/FuzzilliDetectMissingBuiltins/main.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Sources/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift index dedfa1316..06472f227 100644 --- a/Sources/FuzzilliDetectMissingBuiltins/main.swift +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -149,6 +149,7 @@ do { var visited = Set() var missingBuiltins = [String]() +var potentiallyBroken = [String]() func checkNode(_ nodeId: Int, path: [String]) { if visited.contains(nodeId) { return } @@ -195,8 +196,15 @@ func checkNode(_ nodeId: Int, path: [String]) { isRegistered = jsEnvironment.hasBuiltin(prop) } - if !isRegistered { + // 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) @@ -205,3 +213,7 @@ func checkNode(_ nodeId: Int, path: [String]) { checkNode(0, path: []) print(missingBuiltins.sorted().joined(separator: "\n")) +if !potentiallyBroken.isEmpty { + print("\nPotentially inaccessible but registered builtins: ") + print(potentiallyBroken.sorted().joined(separator: "\n")) +} From 8aba53cc3626838d08fc077fa63b7e99f79c0a5e Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 2 Mar 2026 15:44:09 +0100 Subject: [PATCH 165/234] [v8] Add functions from --expose-externalize-string to environment and skip their prototypes in FuzzilliDetectMissingBuiltins. Bug: 487347678 Change-Id: Ib74c990924c2b194f486c14c8578148240b9a1f5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064302 Auto-Submit: Matthias Liedtke Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Profiles/V8Profile.swift | 5 +++++ Sources/FuzzilliDetectMissingBuiltins/main.swift | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Sources/Fuzzilli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift index 5b81bf43b..b1e34f5c4 100644 --- a/Sources/Fuzzilli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -98,6 +98,11 @@ public let v8Profile = Profile( "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), "d8" : .jsD8, "Worker": .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + // 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], diff --git a/Sources/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift index 06472f227..d924158ec 100644 --- a/Sources/FuzzilliDetectMissingBuiltins/main.swift +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -20,6 +20,10 @@ let exclusionList : [String: [String]] = [ // TODO(mliedtke): https://crbug.com/488072252. "Realm", ] + // These functions are exposed via --expose-externalize-string for testing purposes. The functions + // should be registered but their prototype objects do not matter. + + ["externalizeString", "isOneByteString", "createExternalizableString", + "createExternalizableTwoByteString"].map {"\($0).prototype"} ] // Disable most logging. The JavaScriptEnvironment prints warning when trying to fetch types for From 2be4eeb215aa7dba35c6a36904ea8e21b2f5fcc7 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 27 Feb 2026 18:26:42 +0100 Subject: [PATCH 166/234] [test] Remove obsolete test case for registered global builtins This test case is obsolete. For detecting missing builtins, there is now a script that can recursively scan the available global context of a JavaScript shell. Bug: 487347678 Change-Id: If785dc73fca43d693e29d1c22e345381568072bd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9064301 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- Tests/FuzzilliTests/EnvironmentTest.swift | 58 ----------------------- 1 file changed, 58 deletions(-) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index e180f869c..1c55adf57 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -73,64 +73,6 @@ 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", - "onerror", - "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)]) From b9dd5cd116bec30a4681e7d5a6a34e2dc47cc50c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 5 Mar 2026 23:10:13 +0100 Subject: [PATCH 167/234] DetectMissingBuiltins: Skip type coercion functions valueOf and toString Bug: 487347678 Change-Id: I2157fdb4904c8cd5886c8cf9c3f230cab85fdd76 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9078877 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- Sources/FuzzilliDetectMissingBuiltins/main.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Sources/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift index d924158ec..53206d6b5 100644 --- a/Sources/FuzzilliDetectMissingBuiltins/main.swift +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -168,9 +168,14 @@ func checkNode(_ nodeId: Int, path: [String]) { } } - // Each function has a name and a length property. We don't really care about them, so filter - // them out. - let propertyData = node.properties.filter {($0.key != "name" && $0.key != "length") || node.type != "function"} + 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) From aa008466508123071a5e91225f10e373c87d38b4 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Mar 2026 11:17:05 +0100 Subject: [PATCH 168/234] [v8] Improve registration of Worker builtins Bug: 487347678 Change-Id: I00083540222506cfb09d7b1dfe5d040b7818a58b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9081256 Commit-Queue: Danylo Mocherniuk Reviewed-by: Danylo Mocherniuk Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../Fuzzilli/Profiles/V8CommonProfile.swift | 31 +++++++++++++++++++ Sources/Fuzzilli/Profiles/V8Profile.swift | 4 +-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 09cd1d1a0..974762b35 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -24,6 +24,10 @@ public extension ILType { static let gcTypeEnum = ILType.enumeration(ofName: "gcType", withValues: ["minor", "major"]) static let gcExecutionEnum = ILType.enumeration(ofName: "gcExecution", withValues: ["async", "sync"]) + + static let jsWorker = object(ofGroup: "Worker", withMethods: ["postMessage","getMessage", "terminate", "terminateAndWait"]) + static let jsWorkerConstructor = constructor([.jsAnything, .object()] => jsWorker) + + object(ofGroup: "WorkerConstructor", withProperties: ["prototype"]) } public let gcOptions = ObjectGroup( @@ -33,6 +37,33 @@ public let gcOptions = ObjectGroup( "execution": .gcExecutionEnum], methods: [:]) +public extension ObjectGroup { + static let jsWorkers = ObjectGroup( + name: "Worker", + instanceType: .jsWorker, + properties: [:], + methods: [ + "postMessage": [.jsAnything] => .undefined, + "getMessage": [] => .jsAnything, + "terminate": [] => .undefined, + "terminateAndWait": [] => .undefined + ] + ) + + static let jsWorkerPrototype = + ObjectGroup.createPrototypeObjectGroup(jsWorkers, constructor: .jsWorkerConstructor) + + 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"), diff --git a/Sources/Fuzzilli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift index b1e34f5c4..fe384fd48 100644 --- a/Sources/Fuzzilli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -97,7 +97,7 @@ public let v8Profile = Profile( additionalBuiltins: [ "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), "d8" : .jsD8, - "Worker": .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "Worker": .jsWorkerConstructor, // via --expose-externalize-string: "externalizeString": .function([.plain(.jsString)] => .jsString), "isOneByteString": .function([.plain(.jsString)] => .boolean), @@ -105,7 +105,7 @@ public let v8Profile = Profile( "createExternalizableTwoByteString": .function([.plain(.jsString)] => .jsString), ], - additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], + additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions, .jsWorkers, .jsWorkerPrototype, .jsWorkerConstructors], additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], From e6744c89086e88f8eaf60ffd1529922c529152d5 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 5 Mar 2026 22:59:55 +0100 Subject: [PATCH 169/234] [wasm] Allow abstract heap types in more places Bug: 445356784 Change-Id: I488149208dcda6e632ff1fc36d7c959978c3d470 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9078876 Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke Reviewed-by: Manos Koukoutos --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 18 ++++++++---------- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 4 ++-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 93604ed6a..0f2b56ad3 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4610,19 +4610,16 @@ public class ProgramBuilder { let fields = (0.. Date: Fri, 6 Mar 2026 11:39:12 +0100 Subject: [PATCH 170/234] DetectMissingBuiltins: Cleanup V8 exclusion list These are fixed in d8 via https://crrev.com/c/7642309. Bug: 487347678 Change-Id: I772ae90c0cee6a4c126f11d84934c132bc69c463 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9081257 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- Sources/FuzzilliDetectMissingBuiltins/main.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/FuzzilliDetectMissingBuiltins/main.swift b/Sources/FuzzilliDetectMissingBuiltins/main.swift index 53206d6b5..8f694c1f4 100644 --- a/Sources/FuzzilliDetectMissingBuiltins/main.swift +++ b/Sources/FuzzilliDetectMissingBuiltins/main.swift @@ -20,10 +20,6 @@ let exclusionList : [String: [String]] = [ // TODO(mliedtke): https://crbug.com/488072252. "Realm", ] - // These functions are exposed via --expose-externalize-string for testing purposes. The functions - // should be registered but their prototype objects do not matter. - + ["externalizeString", "isOneByteString", "createExternalizableString", - "createExternalizableTwoByteString"].map {"\($0).prototype"} ] // Disable most logging. The JavaScriptEnvironment prints warning when trying to fetch types for From aa0a70a64ad15afe237fafa53193ddb69fe5eb78 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Mar 2026 13:49:33 +0100 Subject: [PATCH 171/234] [environment] Register WebAssembly..prototype. Bug: 445356784 Change-Id: I583e24a56e0e97b589a9bd796ee7e4e23cd63d0d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9081258 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 74fd7b404..bab7b0228 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -449,6 +449,9 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsWebAssemblyException) registerObjectGroup(.jsWebAssemblyExceptionPrototype) registerObjectGroup(.jsWebAssemblyExceptionConstructor) + registerObjectGroup(.jsWebAssemblyError) + registerObjectGroup(.jsWebAssemblyErrorPrototype) + registerObjectGroup(.jsWebAssemblyErrorConstructor) registerObjectGroup(.jsWebAssembly) registerObjectGroup(.jsWasmGlobal) registerObjectGroup(.jsWasmMemory) @@ -2732,9 +2735,38 @@ public extension ObjectGroup { // 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"]) + 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( From c7266504afb8ad23e742574e9b564eb65e36c3c0 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Mar 2026 18:03:03 +0100 Subject: [PATCH 172/234] [test] Remove invalid --experimental-wasm-exnref flag This flag is enabled by default and has been removed from v8 in: https://crrev.com/c/7642813 Change-Id: I442cd7dfcb0b7d457a06fb73d808285b336738fc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9081797 Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke --- Tests/FuzzilliTests/LiveTests.swift | 4 ++-- Tests/FuzzilliTests/WasmTests.swift | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 8a6dce290..9913279e2 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -58,7 +58,7 @@ 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. @@ -96,7 +96,7 @@ 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. diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 7556b873b..a68c507b8 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -441,7 +441,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()) @@ -3689,7 +3689,7 @@ 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() @@ -3718,7 +3718,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() @@ -3757,7 +3757,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() @@ -3797,7 +3797,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() @@ -3865,7 +3865,7 @@ 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() @@ -3882,7 +3882,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() @@ -4033,7 +4033,7 @@ 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() @@ -4803,7 +4803,7 @@ class WasmGCTests: XCTestCase { } func refNullAbstractTypes(sharedRef: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-exnref", "--experimental-wasm-shared"]) + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() From 1cb9578418ee41e90c064e6a97767d943a0b853d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Mar 2026 17:09:54 +0100 Subject: [PATCH 173/234] [environment] Uncomment a few more global builtins Also add DataView.prototype.setBigUint64 and its optional littleEndian parameter. Bug: 445356784 Change-Id: If49c62df8beb2c7202ad12bad58d220ca3f1a3ad Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9081796 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- .../Environment/JavaScriptEnvironment.swift | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index bab7b0228..3527a08e7 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -673,12 +673,12 @@ public class JavaScriptEnvironment: ComponentBase { 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) @@ -1161,7 +1161,7 @@ public extension ILType { static let jsSharedArrayBuffer = ILType.object(ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], withMethods: ["grow", "slice"]) /// Type of a JavaScript DataView object. - static let jsDataView = ILType.object(ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], withMethods: ["getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", "getFloat32", "getFloat64", "getBigInt64", "getBigUint64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", "setFloat64", "setBigInt64"]) + 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 { @@ -2117,7 +2117,8 @@ public extension ObjectGroup { "setFloat16" : [.integer, .float] => .undefined, "setFloat32" : [.integer, .float] => .undefined, "setFloat64" : [.integer, .float] => .undefined, - "setBigInt64" : [.integer, .bigint] => .undefined, + "setBigInt64" : [.integer, .bigint, .opt(.boolean)] => .undefined, + "setBigUint64" : [.integer, .bigint, .opt(.boolean)] => .undefined, ] ) From f0f491a10bfe89973b98ef465881a0e1e1dfd354 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 6 Mar 2026 18:24:14 +0100 Subject: [PATCH 174/234] Fix some wrongly registered builtins - Promise.all, Promise.race, Promise.allSettled expect a single (iterable) argument. - Date.now, Date.parse, Date.UTC don't return a Date, they return a number (the timestamp). The same applies to all the mutator / setter methods on Date.prototype. - String.prototype.localeCompare returns an integer, not a string. - String.prototype.match returns an array of matches, not a single string. - FinalizationRegistry.prototype.register doesn't return anything. - FinalizationRegistry.prototype.unregister returns a boolean (whether at least one cell was unregistered). - Reflect.getPrototypeOf, Reflect.isExtensible, and Reflect.ownKeys throw a TypeError if passed a primitive value, so type them as requiring an object. - DataView: The multi-byte getter and setter methods were missing the optional littleEndian boolean parameter. - Math.max and Math.min return a number (which might be NaN). - Object.assign, .defineProperty, .defineProperties and .freeze all return the object. - Array.fill, .reverse and .sort return the passed (modified) array. - The same is true for the typed arrays (Int8Array and friends). Change-Id: I1c96b03f3303aad8868a13102b6675126bcc3997 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9087136 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach --- .../Environment/JavaScriptEnvironment.swift | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 3527a08e7..0714ab1d5 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1495,7 +1495,7 @@ public extension ObjectGroup { "endsWith" : [.string, .opt(.integer)] => .boolean, "indexOf" : [.jsAnything, .opt(.integer)] => .integer, "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "match" : [.regexp] => .jsString, + "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, @@ -1515,7 +1515,7 @@ public extension ObjectGroup { "trimRight" : [] => .jsString, "toLowerCase" : [] => .jsString, "toUpperCase" : [] => .jsString, - "localeCompare" : [.string, .opt(.string), .opt(.object())] => .jsString, + "localeCompare" : [.string, .opt(.string), .opt(.object())] => .integer, "anchor" : [.string] => .jsString, "at" : [.integer] => .jsString, "big" : [] => .jsString, @@ -1571,7 +1571,7 @@ public extension ObjectGroup { "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsArray, "entries" : [] => .jsIterator, "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined, + "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsArray, "find" : [.function(), .opt(.object())] => .jsAnything, "findIndex" : [.function(), .opt(.object())] => .integer, "findLast" : [.function(), .opt(.object())] => .jsAnything, @@ -1584,9 +1584,9 @@ public extension ObjectGroup { "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .undefined, + "reverse" : [] => .jsArray, "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .undefined, + "sort" : [.function()] => .jsArray, "values" : [] => .jsIterator, "pop" : [] => .jsAnything, "push" : [.jsAnything...] => .integer, @@ -1893,8 +1893,8 @@ public extension ObjectGroup { instanceType: .jsFinalizationRegistry, properties: [:], methods: [ - "register" : [.object(), .jsAnything, .opt(.object())] => .object(), - "unregister" : [.jsAnything] => .undefined, + "register" : [.object(), .jsAnything, .opt(.object())] => .undefined, + "unregister" : [.jsAnything] => .boolean, ] ) @@ -2025,10 +2025,10 @@ public extension ObjectGroup { ], methods: [ "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .undefined, + "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsTypedArray(variant), "entries" : [] => .jsIterator, "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .undefined, + "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsTypedArray(variant), "find" : [.function(), .opt(.object())] => .jsAnything, "findIndex" : [.function(), .opt(.object())] => .integer, "findLast" : [.function(), .opt(.object())] => .jsAnything, @@ -2041,10 +2041,10 @@ public extension ObjectGroup { "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .undefined, + "reverse" : [] => .jsTypedArray(variant), "set" : [.object(), .opt(.integer)] => .undefined, "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .undefined, + "sort" : [.function()] => .jsTypedArray(variant), "values" : [] => .jsIterator, "filter" : [.function(), .opt(.object())] => .jsTypedArray(variant), "map" : [.function(), .opt(.object())] => .jsTypedArray(variant), @@ -2099,24 +2099,24 @@ public extension ObjectGroup { methods: [ "getInt8" : [.integer] => .integer, "getUint8" : [.integer] => .integer, - "getInt16" : [.integer] => .integer, - "getUint16" : [.integer] => .integer, - "getInt32" : [.integer] => .integer, - "getUint32" : [.integer] => .integer, - "getFloat16" : [.integer] => .float, - "getFloat32" : [.integer] => .float, - "getFloat64" : [.integer] => .float, + "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] => .undefined, - "setUint16" : [.integer, .integer] => .undefined, - "setInt32" : [.integer, .integer] => .undefined, - "setUint32" : [.integer, .integer] => .undefined, - "setFloat16" : [.integer, .float] => .undefined, - "setFloat32" : [.integer, .float] => .undefined, - "setFloat64" : [.integer, .float] => .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, ] @@ -2149,10 +2149,10 @@ public extension ObjectGroup { methods: [ "resolve" : [.jsAnything] => .jsPromise, "reject" : [.jsAnything] => .jsPromise, - "all" : [.jsPromise...] => .jsPromise, - "any" : [.jsPromise...] => .jsPromise, - "race" : [.jsPromise...] => .jsPromise, - "allSettled" : [.jsPromise...] => .jsPromise, + "all" : [.iterable] => .jsPromise, + "any" : [.iterable] => .jsPromise, + "race" : [.iterable] => .jsPromise, + "allSettled" : [.iterable] => .jsPromise, "try" : [.function(), .jsAnything...] => .jsPromise, "withResolvers": [] => .object(withProperties: ["promise", "resolve", "reject"]), ] @@ -2189,22 +2189,22 @@ public extension ObjectGroup { "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, + "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, @@ -2223,9 +2223,9 @@ public extension ObjectGroup { "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, ] ) @@ -2238,12 +2238,12 @@ public extension ObjectGroup { "prototype" : .object(), // TODO ], methods: [ - "assign" : [.object(), .object()] => .undefined, + "assign" : [.object(), .object()] => .object(), "create" : [.object(), .object()] => .object(), - "defineProperty" : [.object(), .string, .oneof(.object(withProperties: ["configurable", "writable", "enumerable", "value"]), .object(withMethods: ["get", "set"]))] => .undefined, - "defineProperties" : [.object(), .object()] => .undefined, + "defineProperty" : [.object(), .string, .oneof(.object(withProperties: ["configurable", "writable", "enumerable", "value"]), .object(withMethods: ["get", "set"]))] => .object(), + "defineProperties" : [.object(), .object()] => .object(), "entries" : [.object()] => .object(), - "freeze" : [.object()] => .undefined, + "freeze" : [.object()] => .object(), "fromEntries" : [.object()] => .object(), "getOwnPropertyDescriptor" : [.object(), .string] => .object(withProperties: ["configurable", "writable", "enumerable", "value"]), "getOwnPropertyDescriptors" : [.object()] => .object(), @@ -2475,8 +2475,8 @@ public extension ObjectGroup { "log1p" : [.jsAnything] => .number, "log10" : [.jsAnything] => .number, "log2" : [.jsAnything] => .number, - "max" : [.jsAnything...] => .jsAnything, - "min" : [.jsAnything...] => .jsAnything, + "max" : [.jsAnything...] => .number, + "min" : [.jsAnything...] => .number, "pow" : [.jsAnything, .jsAnything] => .number, "random" : [] => .number, "round" : [.jsAnything] => .number, @@ -2544,10 +2544,10 @@ public extension ObjectGroup { "deleteProperty" : [.object(), .string] => .boolean, "get" : [.object(), .string, .opt(.object())] => .jsAnything, "getOwnPropertyDescriptor" : [.object(), .string] => .jsAnything, - "getPrototypeOf" : [.jsAnything] => .jsAnything, + "getPrototypeOf" : [.object()] => .jsAnything, "has" : [.object(), .string] => .boolean, - "isExtensible" : [.jsAnything] => .boolean, - "ownKeys" : [.jsAnything] => .jsArray, + "isExtensible" : [.object()] => .boolean, + "ownKeys" : [.object()] => .jsArray, "preventExtensions" : [.object()] => .boolean, "set" : [.object(), .string, .jsAnything, .opt(.object())] => .boolean, "setPrototypeOf" : [.object(), .object()] => .boolean, From 10c761db60094ae7c0b2052608a7c453504ca6b8 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Mon, 9 Mar 2026 13:14:23 +0100 Subject: [PATCH 175/234] Add a code generator to force OSR Test cases that use OSR currently only do this through --jit-fuzzing triggering OSR in loops, often leading to brittle repros like the referenced bug. This creates a typical pattern in a code generator making use of the %OptimizeOsr() runtime function. Bug: 490353576 Change-Id: Id09459d8f7ba26a1b0eaec7e438de555b22fc7b5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9087056 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- .../Fuzzilli/Profiles/V8CommonProfile.swift | 28 +++++++++++++++++++ .../Fuzzilli/Profiles/V8DumplingProfile.swift | 1 + .../Profiles/V8HoleFuzzingProfile.swift | 1 + Sources/Fuzzilli/Profiles/V8Profile.swift | 1 + .../Fuzzilli/Profiles/V8SandboxProfile.swift | 1 + 5 files changed, 32 insertions(+) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 974762b35..f7f25ff74 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -148,6 +148,34 @@ public let ForceTurboFanCompilationGenerator = forceCompilationGenerator( 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.. Date: Sat, 7 Mar 2026 08:44:45 +0000 Subject: [PATCH 176/234] Refactor V8 Sandbox fuzzing profile Moves the randomness of the sandbox corruption engine from the JavaScript runtime to the Swift program generator. Functional changes: - Splits the monolithic `corrupt(obj, seed)` JS payload into modular entry points: `corruptDataWithBitflip`, `corruptDataWithIncrement`, `corruptDataWithReplace`, `corruptWithWorker`, and `corruptFunction`. - Replaces JS recursion with deterministic `pathArray` tuples generated by Fuzzilli, explicitly passing required entropy seeds (e.g., `[[Step.POINTER, offsetSeed], [Step.NEIGHBOR, hashQuery]]`). - `corruptFunction` evaluates the entire traversal path first and only hijacks the function if the final target is a JSFunction. - `corruptWithWorker` only sets up a background flipping race condition. - Operations, sizes, bit positions, sub-field offsets, and BigInt increment values are now calculated natively by Fuzzilli and passed to JS as explicit arguments. - Deletes the JS `Mutator` and `RNG` classes entirely, rendering the JS payload completely state-free. - Adds startup tests to explicitly verify the parser and read-only safety logic for all new corruption entry points. Bug: 490512258, 490522975 Change-Id: Ia4459efa2526ecd46aa6db441657905c057e1e37 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9053496 Reviewed-by: Michael Achenbach Auto-Submit: Dominik Klemba Commit-Queue: Dominik Klemba --- .../Fuzzilli/Profiles/V8SandboxProfile.swift | 442 +++++++++--------- 1 file changed, 233 insertions(+), 209 deletions(-) diff --git a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift index 0820497d7..65bb35f37 100644 --- a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -13,7 +13,7 @@ // limitations under the License. -// A post-processor that inserts calls to the `corrupt` function (defined in the prefix below) into the generated samples. +// A post-processor that inserts calls to the sandbox corruption functions (defined in the codeSuffix 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 @@ -23,15 +23,70 @@ fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { 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.. 0); + + const Step = { + NEIGHBOR: 0, + POINTER: 1, + }; + // Helper class for accessing in-sandbox memory. class Memory { constructor() { @@ -149,28 +213,20 @@ let v8SandboxProfile = Profile( 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)); + 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)); + } } - write8(addr, value) { - this.dataView.setUint8(addr, Number(value)); + 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) { @@ -227,102 +283,12 @@ let v8SandboxProfile = Profile( setTimeout(doWork); } } - if (typeof this.memory_corruption_worker === 'undefined') { + if (typeof globalThis.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}); + Object.defineProperty(globalThis, '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. // @@ -331,10 +297,10 @@ let v8SandboxProfile = Profile( // 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) { + // 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; @@ -350,7 +316,7 @@ let v8SandboxProfile = Profile( return x; } - let query = rng.randomInt() & 0xffff; + hashQuery = hashQuery & 0xffff; let currentWinner = addr; let currentBest = kUint16Max; @@ -358,11 +324,10 @@ let v8SandboxProfile = Profile( 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); + let score = Math.abs(hash - hashQuery); if (score < currentBest) { currentBest = score; currentWinner = addr; @@ -376,108 +341,161 @@ let v8SandboxProfile = Profile( // 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); + 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(size).fill("a").join(""); + let placeholder = Array(objectSize).fill("a").join(""); let destination = Sandbox.getAddressOf(placeholder); - memory.copyTagged(source, destination, size); + memory.copyTagged(source, destination, objectSize); 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; - } + function getRandomAlignedOffset(addr, offsetSeed) { + let objectSize = Sandbox.getSizeOfObjectAt(addr); + return (offsetSeed % objectSize) & kOffsetAlignmentMask; + } - // 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; + function getBaseAddress(obj) { + try { + if (!Sandbox.isWritable(obj)) return null; + return Sandbox.getAddressOf(obj); + } catch (e) { + // Presumably, |obj| is a Smi, not a HeapObject. + return null; } + } - let 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); - } + function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return null; - // 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); - } - } + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return null; - // 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; - } + 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))); - print(indent + "Corrupted " + numBitsToCorrupt + "-bit field at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + memory.write(addr + offset, newValue, numBitsToCorrupt); + print(" Corrupted " + numBitsToCorrupt + "-bit field (" + typeString + ") at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + } + + // The path argument is an array of [Step, Value] tuples. + // If Step === Step.NEIGHBOR, Value is the exact 16-bit hash query. + // If Step === Step.POINTER, Value is a random UInt32 seed used to calculate an aligned offset. + function evaluateTraversalPath(addr, path) { + let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); + print("Corrupting memory starting from object at 0x" + addr.toString(16) + " of type " + instanceType); + + for (let [stepType, seedValue] of path) { + if (!Sandbox.isWritableObjectAt(addr)) { + print(" Not corrupting read-only object. Bailing out."); + return null; + } - // 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}); + 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; } - let addr; - try { - addr = Sandbox.getAddressOf(obj); - } catch (e) { - // Presumably, |obj| is a Smi, not a HeapObject. - return; - } + 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"); + } - print("Corrupting memory starting from object at 0x" + addr.toString(16) + " with RNG seed " + seed); - corruptObjectAt(addr, new RNG(seed), 0); + 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) {} + } } """, @@ -488,8 +506,14 @@ let v8SandboxProfile = Profile( ("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 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. From 62fcae99343543d3190127dd4044eb5f9dd0c6d2 Mon Sep 17 00:00:00 2001 From: Dominik Klemba Date: Mon, 9 Mar 2026 15:12:06 +0000 Subject: [PATCH 177/234] [tests] Increase failure threshold for Wasm execution test Changes the failure rate for LiveTests.testWasmCodeGenerationAndCompilationAndExecution from 25% to 35%. This threshold should be reduced again once ref.cast is properly handled. Change-Id: I92938e5c58ce6171627cc003a13d5344c9cafe70 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9087656 Commit-Queue: Matthias Liedtke Auto-Submit: Dominik Klemba Commit-Queue: Dominik Klemba Reviewed-by: Matthias Liedtke --- Tests/FuzzilliTests/LiveTests.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 9913279e2..535e6401f 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -158,8 +158,9 @@ 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 From 44c33a4bde1c4b4179bfd8b540f3062f28706e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Tue, 10 Mar 2026 13:45:11 +0100 Subject: [PATCH 178/234] [turbolev] Increase the probability of --turbolev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I28783d963f1ac4678f2e2cdd170f9a8c5182e299 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9091116 Commit-Queue: Marja Hölttä Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index f7f25ff74..20cc66c7b 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -967,7 +967,7 @@ 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") From 4aee239f02a93cc47105071e7414e2c29fe73f49 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 10 Mar 2026 12:04:20 +0100 Subject: [PATCH 179/234] [environment] Register Iterator.zip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and support iterables in OptionsBags. Iterator.zip was added to V8 with https://crrev.com/c/7605659. Bug: 465357675 Change-Id: Ia5e5c49831f8ad10c166bb32a264ee90a1aadead Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9090936 Auto-Submit: Matthias Liedtke Reviewed-by: Olivier Flückiger Commit-Queue: Nikos Papaspyrou Reviewed-by: Nikos Papaspyrou --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 1 + .../Environment/JavaScriptEnvironment.swift | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 0f2b56ad3..978c9b7e4 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -737,6 +737,7 @@ public class ProgramBuilder { let (pattern, flags) = self.randomRegExpPatternAndFlags() return self.loadRegExp(pattern, flags) }), + (.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. diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 0714ab1d5..6d99073c8 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -566,6 +566,7 @@ public class JavaScriptEnvironment: ComponentBase { registerEnumeration(OptionsBag.jsIntlSignDisplayEnum) registerEnumeration(OptionsBag.jsIntlPluralRulesTypeEnum) registerEnumeration(OptionsBag.jsIntlSegmenterGranularityEnum) + registerEnumeration(OptionsBag.jsIteratorZipModeEnum) registerEnumeration(OptionsBag.base64Alphabet) registerEnumeration(OptionsBag.base64LastChunkHandling) @@ -594,6 +595,7 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsIntlRelativeTimeFormatSettings) registerOptionsBag(.jsIntlSegmenterSettings) registerOptionsBag(.jsIntlLocaleMatcherSettings) + registerOptionsBag(.jsIteratorZipSettings) registerTemporalFieldsObject(.jsTemporalPlainTimeLikeObject, forWith: false, dateFields: false, timeFields: true, zonedFields: false) registerTemporalFieldsObject(.jsTemporalPlainDateLikeObject, forWith: false, dateFields: true, timeFields: false, zonedFields: false) @@ -1072,7 +1074,7 @@ 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) || // Has explicit support in createOptionsBag @@ -1122,7 +1124,7 @@ public extension ILType { static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"]) /// Type of the JavaScript Iterator constructor builtin. - static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from", "concat"]) + 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"]) @@ -1699,6 +1701,7 @@ public extension ObjectGroup { methods: [ "from" : [.jsAnything] => .jsIterator, "concat" : [.jsAnything...] => .jsIterator, + "zip" : [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] => .jsIterator, ] ) @@ -4158,6 +4161,19 @@ extension OptionsBag { ) } +// 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, + ] + ) +} + // Base64 extension OptionsBag { fileprivate static let base64Alphabet = From 4caa266c0c884f9d855993cfab9e919c0726fe10 Mon Sep 17 00:00:00 2001 From: Raphael Herouart Date: Wed, 11 Mar 2026 14:52:45 +0100 Subject: [PATCH 180/234] [v8] Add `--proto_assign_seq_lazy_func_opt` and `--private_field_bytecodes` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include `--private_field_bytecodes` with a 0.5 probability. Include `--proto_assign_seq_lazy_func_opt` with a 0.5 probability in fuzzili. This flag does imply the flag it replaces. Seq count is fixed to 1 to stress the pattern. Bug: 449885256 Bug: 474269456 Change-Id: I4e9928c2c3b23ebc129bfae67d06dc286a8dfba7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9095116 Reviewed-by: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Raphaël Hérouart --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 20cc66c7b..95927c91c 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -1027,12 +1027,16 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } 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") + } + // // Sometimes enable additional verification/stressing logic (which may be fairly expensive). // From 0e5757e7dfc80952d2d0cbcbe2bef88920e59ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 12 Mar 2026 12:29:54 +0100 Subject: [PATCH 181/234] [v8] Add --maglev-untagged-phis with 0.5 probability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9f2aedf60a7d3d8eec7011243e6ddac5af94aa74 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9099036 Commit-Queue: Marja Hölttä Reviewed-by: Matthias Liedtke Reviewed-by: Darius Mercadier --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 95927c91c..d8cf7db26 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -946,6 +946,9 @@ 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.25) { args.append("--maglev-future") } @@ -1152,7 +1155,6 @@ 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") From b3dcb4941900da35e00a11d74140ed0f7d6ffcd2 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 16 Mar 2026 11:51:03 +0100 Subject: [PATCH 182/234] [wasm] Remove parameter and return types from wasmReturnCallDirect Same as commit 226938a27cb4ac261fdae1bd7ae68cc6f7ac1d6f but now for the tail call variant (in preparation for using wasm-gc signatures for wasm functions.) Bug: 445356784 Change-Id: I5b2501b45a4a3f7e15c8814008d2d6d5bc9a9974 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9108116 Reviewed-by: Manos Koukoutos Commit-Queue: Manos Koukoutos Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 7 ++----- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 8 ++++---- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 ++-- Sources/Fuzzilli/Protobuf/operations.pb.swift | 19 ++++++------------- Sources/Fuzzilli/Protobuf/operations.proto | 3 +-- 6 files changed, 16 insertions(+), 27 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 978c9b7e4..3786efee6 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3787,7 +3787,7 @@ public class ProgramBuilder { 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) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ee607f6ff..e533380f7 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1318,8 +1318,7 @@ extension Instruction: ProtobufConvertible { } 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 { @@ -2418,9 +2417,7 @@ extension Instruction: ProtobufConvertible { case .wasmCallDirect(let p): 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) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index d72ca4822..426f057a6 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -972,12 +972,12 @@ final class WasmCallDirect: WasmOperation { 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 { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index c9ac5520b..20275e2b9 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1073,9 +1073,9 @@ public class FuzzILLifter: Lifter { w.emit("\(outputs) <- WasmCallDirect \(inputs)") } - case .wasmReturnCallDirect(let op): + case .wasmReturnCallDirect(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmReturnCallDirect(\(op.signature)) \(inputs)") + w.emit("WasmReturnCallDirect \(inputs)") case .wasmReturnCallIndirect(let op): let inputs = instr.inputs.map(lift).joined(separator: ", ") diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 3659ec358..f9a4fbaca 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -5059,9 +5059,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() @@ -13488,7 +13486,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() { @@ -13496,26 +13494,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 9575ffb0b..09838fb00 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1178,8 +1178,7 @@ message WasmCallDirect { } message WasmReturnCallDirect { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message WasmReturnCallIndirect { From cab3f42b09c4fac2ed423e96f346b92a1d567168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giovanni=20Ortu=C3=B1o=20Urquidi?= Date: Mon, 16 Mar 2026 14:43:19 -0400 Subject: [PATCH 183/234] chromium: Log target stdout and stderr on REPRL execution failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when Fuzzilli fails to execute a script via the REPRL protocol (e.g., if the target fails to launch and send the HELO message, or crashes unexpectedly), the resulting error message is opaque (e.g., "Did not receive HELO message from child: Bad file descriptor"). Fuzzilli already captures the target's stdout and stderr in memory-mapped files by default, this change extracts those buffers and appends them to the Fuzzilli warning and error logs whenever `reprl_execute` fails. This surfaces the actual crash dump, missing dependencies, or startup errors directly in the logs, making debugging broken targets locally or on bots significantly easier. Bug: 492209808 Change-Id: If94fc9eadc97645ab240f648b7e6cf42378d091e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9095283 Auto-Submit: Giovanni Ortuño Urquidi Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Execution/REPRL.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Execution/REPRL.swift b/Sources/Fuzzilli/Execution/REPRL.swift index 005310ec8..40555fbd2 100644 --- a/Sources/Fuzzilli/Execution/REPRL.swift +++ b/Sources/Fuzzilli/Execution/REPRL.swift @@ -113,7 +113,8 @@ public class REPRL: ComponentBase, ScriptRunner { // 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)!)) } @@ -123,7 +124,16 @@ public class REPRL: ComponentBase, ScriptRunner { } 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 { From 52e4ba5fc85867f71a72edd2b4944806ae48ab31 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 17 Mar 2026 11:54:26 +0100 Subject: [PATCH 184/234] [js] Add magic numbers around Smi range V8 has lots of optimizations around smi ranges (e.g. untagging smis). Change-Id: I1393d1c30a61ef43d45f3ede4a74e6fe0b6c0e2d Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9111056 Reviewed-by: Darius Mercadier Commit-Queue: Darius Mercadier Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 6d99073c8..87c572104 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -27,26 +27,28 @@ public class JavaScriptEnvironment: ComponentBase { // Integer values that are more likely to trigger edge-cases. public static let InterestingIntegers: [Int64] = [ - -9223372036854775808, -9223372036854775807, // Int64 min, mostly for BigInts - -9007199254740992, -9007199254740991, -9007199254740990, // Smallest integer value that is still precisely representable by a double - -4294967297, -4294967296, -4294967295, // Negative Uint32 max - -2147483649, -2147483648, -2147483647, // Int32 min - -1073741824, -536870912, -268435456, // -2**32 / {4, 8, 16} - -65537, -65536, -65535, // -2**16 - -4096, -1024, -256, -128, // Other powers of two - -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 - 127, 128, 129, // 2**7 - 255, 256, 257, // 2**8 - 512, 1000, 1024, 4096, 10000, // Misc numbers - 65535, 65536, 65537, // 2**16 - 268435439, 268435440, 268435441, // V8 String kMaxLength (32-bit) - 536870887, 536870888, 536870889, // V8 String kMaxLength (64-bit) - 268435456, 536870912, 1073741824, // 2**32 / {4, 8, 16} - 1073741823, 1073741824, 1073741825, // 2**30 - 2147483647, 2147483648, 2147483649, // Int32 max - 4294967295, 4294967296, 4294967297, // Uint32 max - 9007199254740990, 9007199254740991, 9007199254740992, // Biggest integer value that is still precisely representable by a double - 9223372036854775807, // Int64 max, mostly for BigInts + -9223372036854775808, -9223372036854775807, // Int64 min, mostly for BigInts + -9007199254740992, -9007199254740991, -9007199254740990, // Smallest integer value that is still precisely representable by a double + -4294967297, -4294967296, -4294967295, // Negative Uint32 max + -2147483649, -2147483648, -2147483647, // Int32 min + -1073741824, -536870912, -268435456, // -2**32 / {4, 8, 16} + -65537, -65536, -65535, // -2**16 + -4096, -1024, -256, -128, // Other powers of two + -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 + 127, 128, 129, // 2**7 + 255, 256, 257, // 2**8 + 512, 1000, 1024, 4096, 10000, // Misc numbers + 65535, 65536, 65537, // 2**16 + 268435439, 268435440, 268435441, // V8 String kMaxLength (32-bit) + 536870887, 536870888, 536870889, // V8 String kMaxLength (64-bit) + 268435456, 536870912, 1073741824, // 2**32 / {4, 8, 16} + 1073741823, 1073741824, 1073741825, // 2**30 + 2147483647, 2147483648, 2147483649, // Int32 max + 4294967295, 4294967296, 4294967297, // Uint32 max + 9007199254740990, 9007199254740991, 9007199254740992, // Biggest integer value that is still precisely representable by a double + 9223372036854775807, // Int64 max, mostly for BigInts + 0x3ffffffc, 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000002, // Numbers around smi max (2^30 - 1) + 0xbffffffd, 0xbfffffff, 0xc0000000, 0xc0000001, 0xc0000003 // Numbers around Smi min (-2^30) ] static let wellKnownSymbols = ["iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", "hasInstance", "isConcatSpreadable", "unscopables", "species", "toPrimitive", "toStringTag", "dispose", "asyncDispose"] From e335bb5bdbb9de64a8c1ec456f546d5f5de7da31 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 16 Mar 2026 12:42:44 +0100 Subject: [PATCH 185/234] [wasm] Remove parameter and return types from WasmJsCall Bug: 445356784 Change-Id: I0eb33e4e3f800919b5c92bf6ce48ded45d372ac5 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9108176 Auto-Submit: Matthias Liedtke Reviewed-by: Manos Koukoutos Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 +++-- Sources/Fuzzilli/FuzzIL/Instruction.swift | 8 +++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 7 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 10 ++++----- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 10 ++++----- Sources/Fuzzilli/Lifting/WasmLifter.swift | 11 +++++----- Sources/Fuzzilli/Protobuf/operations.pb.swift | 22 +++++++++---------- Sources/Fuzzilli/Protobuf/operations.proto | 4 ++-- Tests/FuzzilliTests/WasmTests.swift | 6 +++-- 9 files changed, 43 insertions(+), 40 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 3786efee6..1448845f3 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3802,8 +3802,9 @@ public class ProgramBuilder { @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) + 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 diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index e533380f7..bc48ed434 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1131,8 +1131,8 @@ extension Instruction: ProtobufConvertible { $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) } @@ -2287,9 +2287,7 @@ extension Instruction: ProtobufConvertible { 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): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 8620a70b4..da7acc4a1 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -803,14 +803,15 @@ public struct JSTyper: Analyzer { registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: isMemory64 ? .wasmi64 : .wasmi32) case .wasmJsCall(let op): - let sigOutputTypes = op.functionSignature.outputTypes + 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)) + dynamicObjectGroupManager.addWasmFunction(withSignature: type(of: instr.input(1)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(1)) case .beginWasmFunction(let op): wasmTypeBeginBlock(instr, op.signature) case .endWasmFunction(let op): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 426f057a6..15c9c6533 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1225,12 +1225,12 @@ 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 { diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 20275e2b9..09c706802 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -1046,13 +1046,13 @@ public class FuzzILLifter: Lifter { case .wasmJsCall(let op): var arguments: [Variable] = [] - for i in 0..(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11767,26 +11767,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 } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 09838fb00..11eec98eb 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -939,8 +939,8 @@ message EndWasmFunction { } message WasmJsCall { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; + int32 outputCount = 2; } message Wasmi32CompareOp { diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index a68c507b8..8fe71c418 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -6539,7 +6539,8 @@ class WasmSpliceTests: XCTestCase { 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() + // +1 for the wasm-gc signature type that is created implicitly. + splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) return [] } @@ -6583,7 +6584,8 @@ class WasmSpliceTests: XCTestCase { 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() + // +1 for the wasm-gc signature type that is created implicitly. + splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) return [] } From 36fe897c8559e10155089f4238a13fbbb4fbf823 Mon Sep 17 00:00:00 2001 From: Darius Mercadier Date: Tue, 17 Mar 2026 12:30:03 +0100 Subject: [PATCH 186/234] [v8] Add --no-maglev-loop-peeling with 10% probability Bug: 491410818 Change-Id: I400fbd530f32c3a8ee2c16cd71c73d24adf43357 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9110957 Commit-Queue: Darius Mercadier Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index d8cf7db26..43a004e68 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -949,6 +949,9 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { 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") } @@ -1146,7 +1149,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { // 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") From 2b9cdba18ef865d0a331fb5c29cb8a41d8675551 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 17 Mar 2026 13:53:15 +0100 Subject: [PATCH 187/234] Work around the f.arguments problem in dumpling mode This works around false positives in connection with code referring to `f.arguments` in differential fuzzing. We now suppress any access to the `arguments` property and instead reject such samples. This has only an effect in differential fuzzing and is a no-op otherwise. We don't really care if the receiver actually is a function, and instead over-approximate this slightly. This might cover weird other ways of transferring the arguments to another object with `o.__proto__ = f`. Bug: 490382714 Change-Id: Ia7e78a6708f4d0db4c1ba671cfd279db8f57b70e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9102176 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Engines/FuzzEngine.swift | 13 ++++- .../Engines/FuzzingPostProcessor.swift | 2 +- .../Fuzzilli/Profiles/V8DumplingProfile.swift | 31 +++++++++- .../Fuzzilli/Profiles/V8SandboxProfile.swift | 2 +- Sources/Fuzzilli/Util/Error.swift | 5 ++ Tests/FuzzilliTests/EngineTests.swift | 58 +++++++++++++++++++ 6 files changed, 106 insertions(+), 5 deletions(-) diff --git a/Sources/Fuzzilli/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift index 1a8602312..ce13aab1e 100644 --- a/Sources/Fuzzilli/Engines/FuzzEngine.swift +++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift @@ -32,8 +32,17 @@ 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) 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/Profiles/V8DumplingProfile.swift b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift index 40964b197..2f8aa988b 100644 --- a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift @@ -154,5 +154,34 @@ let v8DumplingProfile = Profile( additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], - optionalPostProcessor: nil + 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/Fuzzilli/Profiles/V8SandboxProfile.swift b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift index 65bb35f37..38744e23b 100644 --- a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -15,7 +15,7 @@ // A post-processor that inserts calls to the sandbox corruption functions (defined in the codeSuffix below) into the generated samples. fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { - func process(_ program: Fuzzilli.Program, for fuzzer: Fuzzer) -> Fuzzilli.Program { + 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. diff --git a/Sources/Fuzzilli/Util/Error.swift b/Sources/Fuzzilli/Util/Error.swift index 379c316c5..61dbd80bd 100644 --- a/Sources/Fuzzilli/Util/Error.swift +++ b/Sources/Fuzzilli/Util/Error.swift @@ -23,3 +23,8 @@ public enum FuzzilliError: Error { case evaluatorStateImportError(String) case codeVerificationError(String) } + +// Simple error enum for internally handled errors, not displayed to the user. +public enum InternalError: Error { + case postProcessRejection(String) +} diff --git a/Tests/FuzzilliTests/EngineTests.swift b/Tests/FuzzilliTests/EngineTests.swift index 420698c5c..6d0960a48 100644 --- a/Tests/FuzzilliTests/EngineTests.swift +++ b/Tests/FuzzilliTests/EngineTests.swift @@ -48,4 +48,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) -> ()] = [ + { 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) -> () 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) + } + } } From 4dee437028bef30079d134cee6810ca0868db992 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 17 Mar 2026 13:50:14 +0100 Subject: [PATCH 188/234] [wasm] Use wasm-gc signatures for wasm functions While this changes the IL to emit wasm-gc signatures for the functions, it doesn't yet actually allow using wasm-gc types in them. A few places (WasmDefineTable and WasmCallIndirect / WasmReturnCallIndirect) still need to be adapted to allow wasm-gc types before we can actually allow indexed wasm-gc types in function signatures. Bug: 445356784 Change-Id: I5715f584cfa5ee664f957a28e28bf80b6f3cdd9e Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9115296 Commit-Queue: Matthias Liedtke Reviewed-by: Manos Koukoutos --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 22 ++++++++--- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 16 ++++---- Sources/Fuzzilli/FuzzIL/Instruction.swift | 14 ++----- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 12 +++--- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 16 ++++---- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 4 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 5 ++- Sources/Fuzzilli/Protobuf/operations.pb.swift | 38 ++++++------------- Sources/Fuzzilli/Protobuf/operations.proto | 6 +-- Tests/FuzzilliTests/MinimizerTest.swift | 12 +++--- 10 files changed, 69 insertions(+), 76 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 1448845f3..48d2a9cc2 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3495,11 +3495,14 @@ public class ProgramBuilder { private let b: ProgramBuilder let signature: WasmSignature let jsSignature: Signature + let signatureDef: Variable - public init(forBuilder b: ProgramBuilder, withSignature signature: WasmSignature) { + public init(forBuilder b: ProgramBuilder, signatureDef: Variable) { + assert(b.type(of: signatureDef).Is(.wasmTypeDef())) self.b = b - self.signature = signature + self.signature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature self.jsSignature = convertWasmSignatureToJsSignature(signature) + self.signatureDef = signatureDef } // Wasm Instructions @@ -4500,9 +4503,16 @@ public class ProgramBuilder { // TODO: distinguish between exported and non-exported functions @discardableResult public func addWasmFunction(with signature: WasmSignature, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { - let instr = b.emit(BeginWasmFunction(signature: signature)) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + return addWasmFunction(signature: signatureDef, body) + } + + @discardableResult + public func addWasmFunction(signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + let signatureType = b.type(of: signature).wasmFunctionSignatureDefSignature + let instr = b.emit(BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), withInputs: [signature]) let results = body(currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return b.emit(EndWasmFunction(signature: signature), withInputs: results).output + return b.emit(EndWasmFunction(outputCount: signatureType.outputTypes.count), withInputs: [signature] + results, types: [.wasmTypeDef()] + signatureType.outputTypes).output } @discardableResult @@ -5022,8 +5032,8 @@ public class ProgramBuilder { break case .wasmDefineTag(_): break - case .beginWasmFunction(let op): - activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature)) + case .beginWasmFunction(_): + activeWasmModule!.functions.append(WasmFunction(forBuilder: self, signatureDef: instr.input(0))) case .wasmBeginTry(_), .wasmEndTryDelegate(_), .wasmBeginTryDelegate(_), diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index ebe454e1d..5077ac26a 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1276,8 +1276,13 @@ public let WasmCodeGenerators: [CodeGenerator] = [ provides: [.wasmFunction] ) { b in let module = b.currentWasmModule + // TODO(mliedtke): Support index wasm-gc types in the signature. This requires the + // WasmDefineTable operation to track their types in a way that is compatible with + // wasm-gc types. Similarly, WasmCallIndirect and WasmReturnCallIndirect need to be + // adapted to use wasm-gc signatures. let functionSignature = b.randomWasmSignature() - b.emit(BeginWasmFunction(signature: functionSignature)) + let signatureDef = b.wasmDefineAdHocSignatureType(signature: functionSignature) + b.emit(BeginWasmFunction(parameterCount: functionSignature.parameterTypes.count), withInputs: [signatureDef]) }, GeneratorStub( "WasmFunctionEndGenerator", @@ -1285,14 +1290,11 @@ public let WasmCodeGenerators: [CodeGenerator] = [ produces: [.wasmFunctionDef()] ) { b in let function = b.currentWasmFunction - let results = function.signature.outputTypes.map { - b.randomVariable(ofType: $0) ?? b.currentWasmFunction - .generateRandomWasmVar(ofType: $0)! - } + let results = function.signature.outputTypes.map(function.findOrGenerateWasmVar) b.emit( - EndWasmFunction(signature: function.signature), - withInputs: results) + EndWasmFunction(outputCount: results.count), + withInputs: [function.signatureDef] + results) }, ]), diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index bc48ed434..e558bb6fb 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1373,13 +1373,11 @@ extension Instruction: ProtobufConvertible { $0.wasmDropDataSegment = Fuzzilli_Protobuf_WasmDropDataSegment() case .beginWasmFunction(let op): $0.beginWasmFunction = Fuzzilli_Protobuf_BeginWasmFunction.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.parameterCount = Int32(op.parameterCount) } case .endWasmFunction(let op): $0.endWasmFunction = Fuzzilli_Protobuf_EndWasmFunction.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + $0.outputCount = Int32(op.outputCount) } case .wasmBeginBlock(let op): $0.wasmBeginBlock = Fuzzilli_Protobuf_WasmBeginBlock.with { @@ -2441,13 +2439,9 @@ extension Instruction: ProtobufConvertible { case .wasmDropDataSegment(_): op = WasmDropDataSegment() case .beginWasmFunction(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = BeginWasmFunction(signature: parameters => outputs) + op = BeginWasmFunction(parameterCount: Int(p.parameterCount)) case .endWasmFunction(let p): - let parameters = p.parameterTypes.map(WasmTypeEnumToILType) - let outputs = p.outputTypes.map(WasmTypeEnumToILType) - op = EndWasmFunction(signature: parameters => outputs) + op = EndWasmFunction(outputCount: Int(p.outputCount)) case .wasmBeginBlock(let p): op = WasmBeginBlock(parameterCount: Int(p.parameterCount)) case .wasmEndBlock(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index da7acc4a1..51ddac359 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -812,11 +812,13 @@ public struct JSTyper: Analyzer { let definingInstruction = defUseAnalyzer.definition(of: instr.input(1)) // Here we query the typer for the signature of the instruction as that is the correct "JS" Signature instead of taking the call-site specific converted wasm signature. dynamicObjectGroupManager.addWasmFunction(withSignature: type(of: instr.input(1)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(1)) - case .beginWasmFunction(let op): - wasmTypeBeginBlock(instr, op.signature) - case .endWasmFunction(let op): - setType(of: instr.output, to: .wasmFunctionDef(op.signature)) - dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(op.signature), forDefinition: instr, forVariable: instr.output) + case .beginWasmFunction(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + wasmTypeBeginBlock(instr, signature) + case .endWasmFunction(_): + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + setType(of: instr.output, to: .wasmFunctionDef(signature)) + dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), forDefinition: instr, forVariable: instr.output) case .wasmSelect(_): setType(of: instr.output, to: type(of: instr.input(0))) case .wasmBeginBlock(_): diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 15c9c6533..55d3b16c0 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1552,22 +1552,22 @@ final class WasmReassign: WasmOperation { final class BeginWasmFunction: WasmOperation { override var opcode: Opcode { .beginWasmFunction(self) } - public let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInnerOutputs: 1 + signature.parameterTypes.count, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) + init(parameterCount: Int) { + super.init(numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) } + + var parameterCount: Int { numInnerOutputs - 1 } } final class EndWasmFunction: WasmOperation { override var opcode: Opcode { .endWasmFunction(self) } - let signature: WasmSignature - init(signature: WasmSignature) { - self.signature = signature - super.init(numInputs: signature.outputTypes.count, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + init(outputCount: Int) { + super.init(numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) } + + var outputCount: Int { numInputs - 1 } } /// This class is used to indicate nops in the wasm world, this makes handling of minimization much easier. diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 09c706802..fd6ce0df9 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -830,9 +830,9 @@ public class FuzzILLifter: Lifter { // Wasm Instructions - case .beginWasmFunction(let op): + case .beginWasmFunction(_): // TODO(cffsmith): do this properly? - w.emit("BeginWasmFunction (\(op.signature)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit("BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") w.increaseIndentionLevel() case .endWasmFunction: diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index d27d6d24a..5a3f391dc 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1287,8 +1287,9 @@ public class WasmLifter { // Just analyze the instruction but do nothing else here. // This lets the typer know that we can skip this instruction without breaking any analysis. break - case .beginWasmFunction(let op): - let functionInfo = FunctionInfo(op.signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) + case .beginWasmFunction(_): + let signature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let functionInfo = FunctionInfo(signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) self.exports.append(.function(functionInfo)) // Set the current active function as we are *actively* in it. currentFunction = functionInfo diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 8c92cbfd5..f3ff5d557 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4180,9 +4180,7 @@ public struct Fuzzilli_Protobuf_BeginWasmFunction: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var parameterCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -4194,9 +4192,7 @@ public struct Fuzzilli_Protobuf_EndWasmFunction: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var parameterTypes: [Fuzzilli_Protobuf_WasmILType] = [] - - public var outputTypes: [Fuzzilli_Protobuf_WasmILType] = [] + public var outputCount: Int32 = 0 public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -11689,7 +11685,7 @@ extension Fuzzilli_Protobuf_WasmILType: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginWasmFunction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11697,26 +11693,21 @@ extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProto // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.parameterCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 2) + if self.parameterCount != 0 { + try visitor.visitSingularInt32Field(value: self.parameterCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_BeginWasmFunction, rhs: Fuzzilli_Protobuf_BeginWasmFunction) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.parameterCount != rhs.parameterCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -11724,7 +11715,7 @@ extension Fuzzilli_Protobuf_BeginWasmFunction: SwiftProtobuf.Message, SwiftProto extension Fuzzilli_Protobuf_EndWasmFunction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EndWasmFunction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameterTypes\0\u{1}outputTypes\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}outputCount\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -11732,26 +11723,21 @@ extension Fuzzilli_Protobuf_EndWasmFunction: SwiftProtobuf.Message, SwiftProtobu // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.parameterTypes) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.outputTypes) }() + case 1: try { try decoder.decodeSingularInt32Field(value: &self.outputCount) }() default: break } } } public func traverse(visitor: inout V) throws { - if !self.parameterTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.parameterTypes, fieldNumber: 1) - } - if !self.outputTypes.isEmpty { - try visitor.visitRepeatedMessageField(value: self.outputTypes, fieldNumber: 2) + if self.outputCount != 0 { + try visitor.visitSingularInt32Field(value: self.outputCount, fieldNumber: 1) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_EndWasmFunction, rhs: Fuzzilli_Protobuf_EndWasmFunction) -> Bool { - if lhs.parameterTypes != rhs.parameterTypes {return false} - if lhs.outputTypes != rhs.outputTypes {return false} + if lhs.outputCount != rhs.outputCount {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 11eec98eb..a67da4b89 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -929,13 +929,11 @@ message WasmILType { } message BeginWasmFunction { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 parameterCount = 1; } message EndWasmFunction { - repeated WasmILType parameterTypes = 1; - repeated WasmILType outputTypes = 2; + int32 outputCount = 1; } message WasmJsCall { diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 74b14a786..b874ca9c6 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -1592,7 +1592,7 @@ class MinimizerTests: XCTestCase { } catchAllBody: { label in function.wasmReturn(function.consti64(-1)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1602,7 +1602,7 @@ class MinimizerTests: XCTestCase { function.wasmBuildLegacyTryVoid { label in function.wasmReturn(function.consti64(42)) } - return [function.consti32(-1)] + return [function.consti64(-1)] } } } @@ -1628,7 +1628,7 @@ class MinimizerTests: XCTestCase { function.wasmReturn(val) }), (tag: irrelevantTag, body: { _, _, _ in })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1642,7 +1642,7 @@ class MinimizerTests: XCTestCase { }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmReturn(function.consti64(42)) })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } } @@ -1659,7 +1659,7 @@ class MinimizerTests: XCTestCase { evaluator.nextInstructionIsImportant(in: b) function.wasmReturn(val) }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) - return [function.consti32(-1)] + return [function.consti64(-1)] } } @@ -1667,7 +1667,7 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmReturn(function.consti64(42)) - return [function.consti32(-1)] + return [function.consti64(-1)] } } } From 376c31fe638bde932737651480d56a7f0e724602 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Fri, 20 Mar 2026 09:01:12 +0100 Subject: [PATCH 189/234] Fix an unused-variable warning Change-Id: I4e2111aca7b7619584bffe9d008c60f55da18999 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9122916 Auto-Submit: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 51ddac359..e9a469a67 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -802,7 +802,7 @@ public struct JSTyper: Analyzer { let isMemory64 = type(of: instr.input(0)).wasmMemoryType?.isMemory64 ?? false registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: isMemory64 ? .wasmi64 : .wasmi32) - case .wasmJsCall(let op): + case .wasmJsCall(_): let wasmSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature let sigOutputTypes = wasmSignature.outputTypes assert(sigOutputTypes.count < 2, "multi-return js calls are not supported") From 794dda87980fe673391bec0c7ce170c14a5a1aa9 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 19 Mar 2026 12:41:18 +0100 Subject: [PATCH 190/234] Refactoring: Merge static and instance class member instructions This simplifies and reduces a lot of code and prepares adding support for more kinds of class members without exploding the number of instructions due to the additional factor 2 for static and instance members. Concretely this merges instructions for all members (properties, elements and methods) that have a static and non-static (instance) variant. The static bit is represented by a variable in the instruction. This was also tested locally with and without this change, both with large number for class-related code generators. Both versions resulted in similar correctness stats without any crashes. Bug: 446634535 Change-Id: I57b3261e202dffeb57704d0040b2a8d02b50a9e6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9094176 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 135 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 65 +- Sources/Fuzzilli/Compiler/Compiler.swift | 80 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 200 +- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 173 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 227 +- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 42 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 30 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 147 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 152 +- .../Fuzzilli/Minimization/BlockReducer.swift | 15 +- .../Minimization/InliningReducer.swift | 30 +- .../Fuzzilli/Mutators/OperationMutator.swift | 57 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 844 ++------ Sources/Fuzzilli/Protobuf/operations.proto | 93 +- Sources/Fuzzilli/Protobuf/program.pb.swift | 1926 +++++++---------- Sources/Fuzzilli/Protobuf/program.proto | 600 +++-- 17 files changed, 1720 insertions(+), 3096 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 48d2a9cc2..aea8a1c5f 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2649,60 +2649,61 @@ public class ProgramBuilder { b.emit(EndClassConstructor()) } + public func addInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddInstanceProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddInstanceElement(index: index, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddInstanceComputedProperty(hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassInstanceMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) } public func addInstanceComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassInstanceComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), withInputs: [name]) body(Array(instr.innerOutputs)) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) } public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceGetter(propertyName: name)) + let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: false)) body(instr.innerOutput) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassGetter()) } public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassInstanceSetter(propertyName: name)) + let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) - b.emit(EndClassInstanceSetter()) + b.emit(EndClassSetter()) } public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddStaticProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddStaticElement(index: index, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddStaticComputedProperty(hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addStaticInitializer(_ body: (Variable) -> ()) { @@ -2713,52 +2714,52 @@ public class ProgramBuilder { public func addStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassStaticMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) } public func addStaticComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassStaticComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), withInputs: [name]) body(Array(instr.innerOutputs)) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) } public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> ()) { - let instr = b.emit(BeginClassStaticGetter(propertyName: name)) + let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: true)) body(instr.innerOutput) - b.emit(EndClassStaticGetter()) + b.emit(EndClassGetter()) } public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { - let instr = b.emit(BeginClassStaticSetter(propertyName: name)) + let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) - b.emit(EndClassStaticSetter()) + b.emit(EndClassSetter()) } public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateInstanceProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) } public func addPrivateInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateInstanceMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) - b.emit(EndClassPrivateInstanceMethod()) + b.emit(EndClassPrivateMethod()) } public func addPrivateStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateStaticProperty(propertyName: name, hasValue: value != nil), withInputs: inputs) + b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) } public func addPrivateStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateStaticMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) - b.emit(EndClassPrivateStaticMethod()) + b.emit(EndClassPrivateMethod()) } } @@ -4963,41 +4964,51 @@ public class ProgramBuilder { activeClassDefinitions.push(ClassDefinition(in: self, isDerived: op.hasSuperclass)) case .beginClassConstructor: activeClassDefinitions.top.hasConstructor = true - case .classAddInstanceProperty(let op): - activeClassDefinitions.top.instanceProperties.append(op.propertyName) - case .classAddInstanceElement(let op): - activeClassDefinitions.top.instanceElements.append(op.index) - case .classAddInstanceComputedProperty: - activeClassDefinitions.top.instanceComputedProperties.append(instr.input(0)) - case .beginClassInstanceMethod(let op): - activeClassDefinitions.top.instanceMethods.append(op.methodName) - case .beginClassInstanceComputedMethod: - activeClassDefinitions.top.instanceComputedMethods.append(instr.input(0)) - case .beginClassInstanceGetter(let op): - activeClassDefinitions.top.instanceGetters.append(op.propertyName) - case .beginClassInstanceSetter(let op): - activeClassDefinitions.top.instanceSetters.append(op.propertyName) - case .classAddStaticProperty(let op): - activeClassDefinitions.top.staticProperties.append(op.propertyName) - case .classAddStaticElement(let op): - activeClassDefinitions.top.staticElements.append(op.index) - case .classAddStaticComputedProperty: - activeClassDefinitions.top.staticComputedProperties.append(instr.input(0)) - case .beginClassStaticMethod(let op): - activeClassDefinitions.top.staticMethods.append(op.methodName) - case .beginClassStaticComputedMethod: - activeClassDefinitions.top.staticComputedMethods.append(instr.input(0)) - case .beginClassStaticGetter(let op): - activeClassDefinitions.top.staticGetters.append(op.propertyName) - case .beginClassStaticSetter(let op): - activeClassDefinitions.top.staticSetters.append(op.propertyName) - case .classAddPrivateInstanceProperty(let op): - activeClassDefinitions.top.privateProperties.append(op.propertyName) - case .beginClassPrivateInstanceMethod(let op): - activeClassDefinitions.top.privateMethods.append(op.methodName) - case .classAddPrivateStaticProperty(let op): + case .classAddProperty(let op): + if op.isStatic { + activeClassDefinitions.top.staticProperties.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceProperties.append(op.propertyName) + } + case .classAddElement(let op): + if op.isStatic { + activeClassDefinitions.top.staticElements.append(op.index) + } else { + activeClassDefinitions.top.instanceElements.append(op.index) + } + case .classAddComputedProperty(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedProperties.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedProperties.append(instr.input(0)) + } + case .beginClassMethod(let op): + if op.isStatic { + activeClassDefinitions.top.staticMethods.append(op.methodName) + } else { + activeClassDefinitions.top.instanceMethods.append(op.methodName) + } + case .beginClassComputedMethod(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedMethods.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedMethods.append(instr.input(0)) + } + case .beginClassGetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticGetters.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceGetters.append(op.propertyName) + } + case .beginClassSetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticSetters.append(op.propertyName) + } else { + activeClassDefinitions.top.instanceSetters.append(op.propertyName) + } + case .classAddPrivateProperty(let op): activeClassDefinitions.top.privateProperties.append(op.propertyName) - case .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): activeClassDefinitions.top.privateMethods.append(op.methodName) case .beginClassStaticInitializer: break diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 3783c67c5..5a3bed0eb 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -100,8 +100,9 @@ func disposableClassVariableGeneratorStubs( let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), withInputs: [symbol]) }, GeneratorStub( @@ -110,7 +111,7 @@ func disposableClassVariableGeneratorStubs( provides: [.classDefinition] ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) }, GeneratorStub( "DisposableClassDefinitionEndGenerator", @@ -967,16 +968,17 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: false)) }, GeneratorStub( "ClassInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceMethod()) + b.emit(EndClassMethod()) }, ]), @@ -1001,8 +1003,9 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassInstanceComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: false), withInputs: [methodName]) }, GeneratorStub( @@ -1010,7 +1013,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassInstanceComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -1026,13 +1029,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties + b.currentClassDefinition.instanceGetters) - b.emit(BeginClassInstanceGetter(propertyName: propertyName)) + b.emit(BeginClassGetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( "ClassInstanceGetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.doReturn(b.randomJsVariable()) - b.emit(EndClassInstanceGetter()) + b.emit(EndClassGetter()) }, ]), @@ -1048,13 +1051,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.instanceProperties + b.currentClassDefinition.instanceSetters) - b.emit(BeginClassInstanceSetter(propertyName: propertyName)) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: false)) }, GeneratorStub( "ClassInstanceSetterEndGenerator", inContext: .single([.javascript, .method, .subroutine, .classMethod]) ) { b in - b.emit(EndClassInstanceSetter()) + b.emit(EndClassSetter()) }, ]), @@ -1136,9 +1139,10 @@ public let CodeGenerators: [CodeGenerator] = [ b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassStaticMethod( + BeginClassMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: true)) }, GeneratorStub( @@ -1146,7 +1150,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .classMethod, .subroutine, .method]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticMethod()) + b.emit(EndClassMethod()) }, ]), @@ -1171,8 +1175,9 @@ public let CodeGenerators: [CodeGenerator] = [ let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( - BeginClassStaticComputedMethod( - parameters: parameters.parameters), + BeginClassComputedMethod( + parameters: parameters.parameters, + isStatic: true), withInputs: [methodName]) }, GeneratorStub( @@ -1180,7 +1185,7 @@ public let CodeGenerators: [CodeGenerator] = [ inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassStaticComputedMethod()) + b.emit(EndClassComputedMethod()) }, ]), @@ -1196,14 +1201,14 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties + b.currentClassDefinition.staticGetters) - b.emit(BeginClassStaticGetter(propertyName: propertyName)) + b.emit(BeginClassGetter(propertyName: propertyName, isStatic: true)) }, GeneratorStub( "ClassStaticGetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.doReturn(b.randomJsVariable()) - b.emit(EndClassStaticGetter()) + b.emit(EndClassGetter()) }, ]), @@ -1219,13 +1224,13 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentClassDefinition.staticProperties + b.currentClassDefinition.staticSetters) - b.emit(BeginClassStaticSetter(propertyName: propertyName)) + b.emit(BeginClassSetter(propertyName: propertyName, isStatic: true)) }, GeneratorStub( "ClassStaticSetterEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.emit(EndClassStaticSetter()) + b.emit(EndClassSetter()) }, ]), @@ -1254,16 +1259,17 @@ public let CodeGenerators: [CodeGenerator] = [ notIn: b.currentClassDefinition.privateFields) let parameters = b.randomParameters() b.emit( - BeginClassPrivateInstanceMethod( + BeginClassPrivateMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: false)) }, GeneratorStub( "ClassPrivateInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassPrivateInstanceMethod()) + b.emit(EndClassPrivateMethod()) }, ]), @@ -1291,16 +1297,17 @@ public let CodeGenerators: [CodeGenerator] = [ notIn: b.currentClassDefinition.privateFields) let parameters = b.randomParameters() b.emit( - BeginClassPrivateStaticMethod( + BeginClassPrivateMethod( methodName: methodName, - parameters: parameters.parameters)) + parameters: parameters.parameters, + isStatic: true)) }, GeneratorStub( "ClassPrivateStaticMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in b.maybeReturnRandomJsVariable(0.9) - b.emit(EndClassPrivateStaticMethod()) + b.emit(EndClassPrivateMethod()) }, ]), diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 0f2f4f0bb..d8a4def6e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -117,24 +117,12 @@ public class JavaScriptCompiler { var inputs = [Variable]() switch key { case .name(let name): - if property.isStatic { - op = ClassAddStaticProperty(propertyName: name, hasValue: property.hasValue) - } else { - op = ClassAddInstanceProperty(propertyName: name, hasValue: property.hasValue) - } + op = ClassAddProperty(propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic) case .index(let index): - if property.isStatic { - op = ClassAddStaticElement(index: index, hasValue: property.hasValue) - } else { - op = ClassAddInstanceElement(index: index, hasValue: property.hasValue) - } + op = ClassAddElement(index: index, hasValue: property.hasValue, isStatic: property.isStatic) case .expression: inputs.append(computedKeys.removeLast()) - if property.isStatic { - op = ClassAddStaticComputedProperty(hasValue: property.hasValue) - } else { - op = ClassAddInstanceComputedProperty(hasValue: property.hasValue) - } + op = ClassAddComputedProperty(hasValue: property.hasValue, isStatic: property.isStatic) } if property.hasValue { inputs.append(propertyValues.removeLast()) @@ -165,23 +153,11 @@ public class JavaScriptCompiler { } switch key { case .name(let name): - if method.isStatic { - head = emit(BeginClassStaticMethod(methodName: name, parameters: parameters)) - } else { - head = emit(BeginClassInstanceMethod(methodName: name, parameters: parameters)) - } + head = emit(BeginClassMethod(methodName: name, parameters: parameters, isStatic: method.isStatic)) case .index(let index): - if method.isStatic { - head = emit(BeginClassStaticMethod(methodName: String(index), parameters: parameters)) - } else { - head = emit(BeginClassInstanceMethod(methodName: String(index), parameters: parameters)) - } + head = emit(BeginClassMethod(methodName: String(index), parameters: parameters, isStatic: method.isStatic)) case .expression: - if method.isStatic { - head = emit(BeginClassStaticComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) - } else { - head = emit(BeginClassInstanceComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) - } + head = emit(BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -195,32 +171,15 @@ public class JavaScriptCompiler { switch key { case .name: - if method.isStatic { - emit(EndClassStaticMethod()) - } else { - emit(EndClassInstanceMethod()) - } + emit(EndClassMethod()) case .index: - if method.isStatic { - emit(EndClassStaticMethod()) - } else { - emit(EndClassInstanceMethod()) - } + emit(EndClassMethod()) case .expression: - if method.isStatic { - emit(EndClassStaticComputedMethod()) - } else { - emit(EndClassInstanceComputedMethod()) - } + emit(EndClassComputedMethod()) } case .getter(let getter): - let head: Instruction - if getter.isStatic { - head = emit(BeginClassStaticGetter(propertyName: getter.name)) - } else { - head = emit(BeginClassInstanceGetter(propertyName: getter.name)) - } + let head = emit(BeginClassGetter(propertyName: getter.name, isStatic: getter.isStatic)) try enterNewScope { map("this", to: head.innerOutput) @@ -229,19 +188,10 @@ public class JavaScriptCompiler { } } - if getter.isStatic { - emit(EndClassStaticGetter()) - } else { - emit(EndClassInstanceGetter()) - } + emit(EndClassGetter()) case .setter(let setter): - let head: Instruction - if setter.isStatic { - head = emit(BeginClassStaticSetter(propertyName: setter.name)) - } else { - head = emit(BeginClassInstanceSetter(propertyName: setter.name)) - } + let head = emit(BeginClassSetter(propertyName: setter.name, isStatic: setter.isStatic)) try enterNewScope { var parameters = head.innerOutputs @@ -253,11 +203,7 @@ public class JavaScriptCompiler { } } - if setter.isStatic { - emit(EndClassStaticSetter()) - } else { - emit(EndClassInstanceSetter()) - } + emit(EndClassSetter()) case .staticInitializer(let staticInitializer): let head = emit(BeginClassStaticInitializer()) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index e558bb6fb..2ea23a453 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -613,100 +613,70 @@ extension Instruction: ProtobufConvertible { $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { $0.parameters = convertParameters(op.parameters) } case .endClassConstructor: $0.endClassConstructor = Fuzzilli_Protobuf_EndClassConstructor() - case .classAddInstanceProperty(let op): - $0.classAddInstanceProperty = Fuzzilli_Protobuf_ClassAddInstanceProperty.with { + case .classAddProperty(let op): + $0.classAddProperty = Fuzzilli_Protobuf_ClassAddProperty.with { $0.propertyName = op.propertyName $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddInstanceElement(let op): - $0.classAddInstanceElement = Fuzzilli_Protobuf_ClassAddInstanceElement.with { + case .classAddElement(let op): + $0.classAddElement = Fuzzilli_Protobuf_ClassAddElement.with { $0.index = op.index $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddInstanceComputedProperty(let op): - $0.classAddInstanceComputedProperty = Fuzzilli_Protobuf_ClassAddInstanceComputedProperty.with { $0.hasValue_p = op.hasValue } - case .beginClassInstanceMethod(let op): - $0.beginClassInstanceMethod = Fuzzilli_Protobuf_BeginClassInstanceMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) + case .classAddComputedProperty(let op): + $0.classAddComputedProperty = Fuzzilli_Protobuf_ClassAddComputedProperty.with { + $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .endClassInstanceMethod: - $0.endClassInstanceMethod = Fuzzilli_Protobuf_EndClassInstanceMethod() - case .beginClassInstanceComputedMethod(let op): - $0.beginClassInstanceComputedMethod = Fuzzilli_Protobuf_BeginClassInstanceComputedMethod.with { + case .endClassMethod: + $0.endClassMethod = Fuzzilli_Protobuf_EndClassMethod() + case .beginClassComputedMethod(let op): + $0.beginClassComputedMethod = Fuzzilli_Protobuf_BeginClassComputedMethod.with { $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassInstanceComputedMethod: - $0.endClassInstanceComputedMethod = Fuzzilli_Protobuf_EndClassInstanceComputedMethod() - case .beginClassInstanceGetter(let op): - $0.beginClassInstanceGetter = Fuzzilli_Protobuf_BeginClassInstanceGetter.with { $0.propertyName = op.propertyName } - case .endClassInstanceGetter: - $0.endClassInstanceGetter = Fuzzilli_Protobuf_EndClassInstanceGetter() - case .beginClassInstanceSetter(let op): - $0.beginClassInstanceSetter = Fuzzilli_Protobuf_BeginClassInstanceSetter.with { $0.propertyName = op.propertyName } - case .endClassInstanceSetter: - $0.endClassInstanceSetter = Fuzzilli_Protobuf_EndClassInstanceSetter() - case .classAddStaticProperty(let op): - $0.classAddStaticProperty = Fuzzilli_Protobuf_ClassAddStaticProperty.with { + case .endClassComputedMethod: + $0.endClassComputedMethod = Fuzzilli_Protobuf_EndClassComputedMethod() + case .beginClassGetter(let op): + $0.beginClassGetter = Fuzzilli_Protobuf_BeginClassGetter.with { $0.propertyName = op.propertyName - $0.hasValue_p = op.hasValue - } - case .classAddStaticElement(let op): - $0.classAddStaticElement = Fuzzilli_Protobuf_ClassAddStaticElement.with { - $0.index = op.index - $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .classAddStaticComputedProperty(let op): - $0.classAddStaticComputedProperty = Fuzzilli_Protobuf_ClassAddStaticComputedProperty.with { $0.hasValue_p = op.hasValue } - case .beginClassStaticInitializer: - $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() - case .endClassStaticInitializer: - $0.endClassStaticInitializer = Fuzzilli_Protobuf_EndClassStaticInitializer() - case .beginClassStaticMethod(let op): - $0.beginClassStaticMethod = Fuzzilli_Protobuf_BeginClassStaticMethod.with { + case .beginClassPrivateMethod(let op): + $0.beginClassPrivateMethod = Fuzzilli_Protobuf_BeginClassPrivateMethod.with { $0.methodName = op.methodName $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassStaticMethod: - $0.endClassStaticMethod = Fuzzilli_Protobuf_EndClassStaticMethod() - case .beginClassStaticComputedMethod(let op): - $0.beginClassStaticComputedMethod = Fuzzilli_Protobuf_BeginClassStaticComputedMethod.with { + case .endClassPrivateMethod: + $0.endClassPrivateMethod = Fuzzilli_Protobuf_EndClassPrivateMethod() + case .beginClassMethod(let op): + $0.beginClassMethod = Fuzzilli_Protobuf_BeginClassMethod.with { + $0.methodName = op.methodName $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassStaticComputedMethod: - $0.endClassStaticComputedMethod = Fuzzilli_Protobuf_EndClassStaticComputedMethod() - case .beginClassStaticGetter(let op): - $0.beginClassStaticGetter = Fuzzilli_Protobuf_BeginClassStaticGetter.with { $0.propertyName = op.propertyName } - case .endClassStaticGetter: - $0.endClassStaticGetter = Fuzzilli_Protobuf_EndClassStaticGetter() - case .beginClassStaticSetter(let op): - $0.beginClassStaticSetter = Fuzzilli_Protobuf_BeginClassStaticSetter.with { $0.propertyName = op.propertyName } - case .endClassStaticSetter: - $0.endClassStaticSetter = Fuzzilli_Protobuf_EndClassStaticSetter() - case .classAddPrivateInstanceProperty(let op): - $0.classAddPrivateInstanceProperty = Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty.with { + case .endClassGetter: + $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() + case .beginClassSetter(let op): + $0.beginClassSetter = Fuzzilli_Protobuf_BeginClassSetter.with { $0.propertyName = op.propertyName - $0.hasValue_p = op.hasValue - } - case .beginClassPrivateInstanceMethod(let op): - $0.beginClassPrivateInstanceMethod = Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) + $0.isStatic = op.isStatic } - case .endClassPrivateInstanceMethod: - $0.endClassPrivateInstanceMethod = Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - case .classAddPrivateStaticProperty(let op): - $0.classAddPrivateStaticProperty = Fuzzilli_Protobuf_ClassAddPrivateStaticProperty.with { + case .endClassSetter: + $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() + case .beginClassStaticInitializer: + $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() + case .endClassStaticInitializer: + $0.endClassStaticInitializer = Fuzzilli_Protobuf_EndClassStaticInitializer() + case .classAddPrivateProperty(let op): + $0.classAddPrivateProperty = Fuzzilli_Protobuf_ClassAddPrivateProperty.with { $0.propertyName = op.propertyName $0.hasValue_p = op.hasValue + $0.isStatic = op.isStatic } - case .beginClassPrivateStaticMethod(let op): - $0.beginClassPrivateStaticMethod = Fuzzilli_Protobuf_BeginClassPrivateStaticMethod.with { - $0.methodName = op.methodName - $0.parameters = convertParameters(op.parameters) - } - case .endClassPrivateStaticMethod: - $0.endClassPrivateStaticMethod = Fuzzilli_Protobuf_EndClassPrivateStaticMethod() case .endClassDefinition: $0.endClassDefinition = Fuzzilli_Protobuf_EndClassDefinition() case .createArray: @@ -1907,66 +1877,38 @@ extension Instruction: ProtobufConvertible { op = BeginClassConstructor(parameters: convertParameters(p.parameters)) case .endClassConstructor: op = EndClassConstructor() - case .classAddInstanceProperty(let p): - op = ClassAddInstanceProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .classAddInstanceElement(let p): - op = ClassAddInstanceElement(index: p.index, hasValue: p.hasValue_p) - case .classAddInstanceComputedProperty(let p): - op = ClassAddInstanceComputedProperty(hasValue: p.hasValue_p) - case .beginClassInstanceMethod(let p): - op = BeginClassInstanceMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassInstanceMethod: - op = EndClassInstanceMethod() - case .beginClassInstanceComputedMethod(let p): - op = BeginClassInstanceComputedMethod(parameters: convertParameters(p.parameters)) - case .endClassInstanceComputedMethod: - op = EndClassInstanceComputedMethod() - case .beginClassInstanceGetter(let p): - op = BeginClassInstanceGetter(propertyName: p.propertyName) - case .endClassInstanceGetter: - op = EndClassInstanceGetter() - case .beginClassInstanceSetter(let p): - op = BeginClassInstanceSetter(propertyName: p.propertyName) - case .endClassInstanceSetter: - op = EndClassInstanceSetter() - case .classAddStaticProperty(let p): - op = ClassAddStaticProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .classAddStaticElement(let p): - op = ClassAddStaticElement(index: p.index, hasValue: p.hasValue_p) - case .classAddStaticComputedProperty(let p): - op = ClassAddStaticComputedProperty(hasValue: p.hasValue_p) + case .classAddProperty(let p): + op = ClassAddProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .classAddElement(let p): + op = ClassAddElement(index: p.index, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .classAddComputedProperty(let p): + op = ClassAddComputedProperty(hasValue: p.hasValue_p, isStatic: p.isStatic) + case .beginClassMethod(let p): + op = BeginClassMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassMethod: + op = EndClassMethod() + case .beginClassComputedMethod(let p): + op = BeginClassComputedMethod(parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassComputedMethod: + op = EndClassComputedMethod() + case .beginClassGetter(let p): + op = BeginClassGetter(propertyName: p.propertyName, isStatic: p.isStatic) + case .endClassGetter: + op = EndClassGetter() + case .beginClassSetter(let p): + op = BeginClassSetter(propertyName: p.propertyName, isStatic: p.isStatic) + case .endClassSetter: + op = EndClassSetter() case .beginClassStaticInitializer: op = BeginClassStaticInitializer() case .endClassStaticInitializer: op = EndClassStaticInitializer() - case .beginClassStaticMethod(let p): - op = BeginClassStaticMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassStaticMethod: - op = EndClassStaticMethod() - case .beginClassStaticComputedMethod(let p): - op = BeginClassStaticComputedMethod(parameters: convertParameters(p.parameters)) - case .endClassStaticComputedMethod: - op = EndClassStaticComputedMethod() - case .beginClassStaticGetter(let p): - op = BeginClassStaticGetter(propertyName: p.propertyName) - case .endClassStaticGetter: - op = EndClassStaticGetter() - case .beginClassStaticSetter(let p): - op = BeginClassStaticSetter(propertyName: p.propertyName) - case .endClassStaticSetter: - op = EndClassStaticSetter() - case .classAddPrivateInstanceProperty(let p): - op = ClassAddPrivateInstanceProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .beginClassPrivateInstanceMethod(let p): - op = BeginClassPrivateInstanceMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassPrivateInstanceMethod: - op = EndClassPrivateInstanceMethod() - case .classAddPrivateStaticProperty(let p): - op = ClassAddPrivateStaticProperty(propertyName: p.propertyName, hasValue: p.hasValue_p) - case .beginClassPrivateStaticMethod(let p): - op = BeginClassPrivateStaticMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) - case .endClassPrivateStaticMethod: - op = EndClassPrivateStaticMethod() + case .classAddPrivateProperty(let p): + op = ClassAddPrivateProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + case .beginClassPrivateMethod(let p): + op = BeginClassPrivateMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + case .endClassPrivateMethod: + op = EndClassPrivateMethod() case .endClassDefinition: op = EndClassDefinition() case .createArray: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index e9a469a67..584572320 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1295,16 +1295,11 @@ public struct JSTyper: Analyzer { .beginAsyncGeneratorFunction, .beginConstructor, .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, + .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, @@ -1319,16 +1314,11 @@ public struct JSTyper: Analyzer { .endAsyncGeneratorFunction, .endConstructor, .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter, + .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). // @@ -1363,30 +1353,30 @@ public struct JSTyper: Analyzer { // TODO(cffsmith): this is probably the wrong place to do this. // Update the dynamic object group to correctly reflect the signature of objects of this type. switch instr.op.opcode { - case .endClassInstanceMethod(_): - assert(begin.op is BeginClassInstanceMethod) - let beginOp = begin.op as! BeginClassInstanceMethod - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) - case .endClassInstanceGetter(_): - assert(begin.op is BeginClassInstanceGetter) - let beginOp = begin.op as! BeginClassInstanceGetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassInstanceSetter(_): - assert(begin.op is BeginClassInstanceSetter) - let beginOp = begin.op as! BeginClassInstanceSetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassStaticGetter(_): - assert(begin.op is BeginClassStaticGetter) - let beginOp = begin.op as! BeginClassStaticGetter - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) - case .endClassStaticMethod(_): - assert(begin.op is BeginClassStaticMethod) - let beginOp = begin.op as! BeginClassStaticMethod - dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) - case .endClassStaticSetter(_): - assert(begin.op is BeginClassStaticSetter) - let beginOp = begin.op as! BeginClassStaticSetter - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + case .endClassMethod(_): + assert(begin.op is BeginClassMethod) + let beginOp = begin.op as! BeginClassMethod + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + } else { + dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + } + case .endClassGetter(_): + assert(begin.op is BeginClassGetter) + let beginOp = begin.op as! BeginClassGetter + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } else { + dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } + case .endClassSetter(_): + assert(begin.op is BeginClassSetter) + let beginOp = begin.op as! BeginClassSetter + if beginOp.isStatic { + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } else { + dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + } case .endObjectLiteralMethod(_): assert(begin.op is BeginObjectLiteralMethod) let beginOp = begin.op as! BeginObjectLiteralMethod @@ -1600,74 +1590,71 @@ public struct JSTyper: Analyzer { processParameterDeclarations(instr.innerOutputs(1...), parameters: parameters) dynamicObjectGroupManager.setConstructorParameters(parameters: parameters) - case .classAddInstanceProperty(let op): - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) - - case .beginClassInstanceMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) - - case .beginClassInstanceComputedMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - - case .beginClassInstanceGetter(let op): - // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - assert(instr.numInnerOutputs == 1) - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - - case .beginClassInstanceSetter(let op): - // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - - case .classAddStaticProperty(let op): - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + case .classAddProperty(let op): + if op.isStatic { + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + } else { + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + } case .beginClassStaticInitializer: // The first inner output is the explicit |this| set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) - case .beginClassStaticMethod(let op): + case .beginClassMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) - case .beginClassStaticComputedMethod(let op): + case .beginClassComputedMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - case .beginClassStaticGetter(let op): + case .beginClassGetter(let op): // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) - assert(instr.numInnerOutputs == 1) - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + assert(instr.numInnerOutputs == 1) + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + assert(instr.numInnerOutputs == 1) + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + } - case .beginClassStaticSetter(let op): + case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + } assert(instr.numInnerOutputs == 2) processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) - case .beginClassPrivateInstanceMethod(let op): + case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) - - case .beginClassPrivateStaticMethod(let op): - // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .createArray, diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index bc87ecb2a..f47db65d8 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -696,145 +696,119 @@ final class EndClassConstructor: EndAnySubroutine { override var opcode: Opcode { .endClassConstructor(self) } } -final class ClassAddInstanceProperty: JsOperation { - override var opcode: Opcode { .classAddInstanceProperty(self) } +final class ClassAddProperty: JsOperation { + override var opcode: Opcode { .classAddProperty(self) } let propertyName: String var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(propertyName: String, hasValue: Bool) { + init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } -final class ClassAddInstanceElement: JsOperation { - override var opcode: Opcode { .classAddInstanceElement(self) } +final class ClassAddElement: JsOperation { + override var opcode: Opcode { .classAddElement(self) } let index: Int64 var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(index: Int64, hasValue: Bool) { + init(index: Int64, hasValue: Bool, isStatic: Bool) { self.index = index + self.isStatic = isStatic super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } -final class ClassAddInstanceComputedProperty: JsOperation { - override var opcode: Opcode { .classAddInstanceComputedProperty(self) } +final class ClassAddComputedProperty: JsOperation { + override var opcode: Opcode { .classAddComputedProperty(self) } var hasValue: Bool { return numInputs == 2 } + let isStatic: Bool - init(hasValue: Bool) { + init(hasValue: Bool, isStatic: Bool) { + self.isStatic = isStatic super.init(numInputs: hasValue ? 2 : 1, requiredContext: .classDefinition) } } -final class BeginClassInstanceMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceMethod(self) } +final class BeginClassMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassMethod(self) } let methodName: String + let isStatic: Bool - init(methodName: String, parameters: Parameters) { + init(methodName: String, parameters: Parameters, isStatic: Bool) { self.methodName = methodName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceMethod(self) } +final class EndClassMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassMethod(self) } } -final class BeginClassInstanceComputedMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceComputedMethod(self) } +final class BeginClassComputedMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedMethod(self) } + let isStatic: Bool - init(parameters: Parameters) { + init(parameters: Parameters, isStatic: Bool) { + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceComputedMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceComputedMethod(self) } +final class EndClassComputedMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedMethod(self) } } -final class BeginClassInstanceGetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceGetter(self) } +final class BeginClassGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassGetter(self) } let propertyName: String + let isStatic: Bool - init(propertyName: String) { + init(propertyName: String, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceGetter: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceGetter(self) } +final class EndClassGetter: EndAnySubroutine { + override var opcode: Opcode { .endClassGetter(self) } } -final class BeginClassInstanceSetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassInstanceSetter(self) } +final class BeginClassSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassSetter(self) } let propertyName: String + let isStatic: Bool - init(propertyName: String) { + init(propertyName: String, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassInstanceSetter: EndAnySubroutine { - override var opcode: Opcode { .endClassInstanceSetter(self) } -} - -final class ClassAddStaticProperty: JsOperation { - override var opcode: Opcode { .classAddStaticProperty(self) } - - let propertyName: String - var hasValue: Bool { - return numInputs == 1 - } - - init(propertyName: String, hasValue: Bool) { - self.propertyName = propertyName - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) - } -} - -final class ClassAddStaticElement: JsOperation { - override var opcode: Opcode { .classAddStaticElement(self) } - - let index: Int64 - var hasValue: Bool { - return numInputs == 1 - } - - init(index: Int64, hasValue: Bool) { - self.index = index - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) - } -} - -final class ClassAddStaticComputedProperty: JsOperation { - override var opcode: Opcode { .classAddStaticComputedProperty(self) } - - var hasValue: Bool { - return numInputs == 2 - } - - init(hasValue: Bool) { - super.init(numInputs: hasValue ? 2 : 1, requiredContext: .classDefinition) - } +final class EndClassSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassSetter(self) } } final class BeginClassStaticInitializer: JsOperation { @@ -855,130 +829,41 @@ final class EndClassStaticInitializer: JsOperation { } } -final class BeginClassStaticMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticMethod(self) } - - let methodName: String - - init(methodName: String, parameters: Parameters) { - self.methodName = methodName - // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticMethod(self) } -} - -final class BeginClassStaticComputedMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticComputedMethod(self) } - - init(parameters: Parameters) { - // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticComputedMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticComputedMethod(self) } -} - -final class BeginClassStaticGetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticGetter(self) } - - let propertyName: String - - init(propertyName: String) { - self.propertyName = propertyName - // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticGetter: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticGetter(self) } -} - -final class BeginClassStaticSetter: BeginAnySubroutine { - override var opcode: Opcode { .beginClassStaticSetter(self) } - - let propertyName: String - - init(propertyName: String) { - self.propertyName = propertyName - // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassStaticSetter: EndAnySubroutine { - override var opcode: Opcode { .endClassStaticSetter(self) } -} - -final class ClassAddPrivateInstanceProperty: JsOperation { - override var opcode: Opcode { .classAddPrivateInstanceProperty(self) } +final class ClassAddPrivateProperty: JsOperation { + override var opcode: Opcode { .classAddPrivateProperty(self) } let propertyName: String var hasValue: Bool { return numInputs == 1 } + let isStatic: Bool - init(propertyName: String, hasValue: Bool) { + init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName + self.isStatic = isStatic // We currently don't want to change the names of private properties since that has a good chance of making // following code _syntactically_ incorrect (if it uses them) because an undeclared private field is accessed. super.init(numInputs: hasValue ? 1 : 0, requiredContext: .classDefinition) } } -final class BeginClassPrivateInstanceMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassPrivateInstanceMethod(self) } - - let methodName: String - - init(methodName: String, parameters: Parameters) { - self.methodName = methodName - // First inner output is the explicit |this| parameter. - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) - } -} - -final class EndClassPrivateInstanceMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassPrivateInstanceMethod(self) } -} - -final class ClassAddPrivateStaticProperty: JsOperation { - override var opcode: Opcode { .classAddPrivateStaticProperty(self) } - - let propertyName: String - var hasValue: Bool { - return numInputs == 1 - } - - init(propertyName: String, hasValue: Bool) { - self.propertyName = propertyName - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. - super.init(numInputs: hasValue ? 1 : 0, requiredContext: .classDefinition) - } -} - -final class BeginClassPrivateStaticMethod: BeginAnySubroutine { - override var opcode: Opcode { .beginClassPrivateStaticMethod(self) } +final class BeginClassPrivateMethod: BeginAnySubroutine { + override var opcode: Opcode { .beginClassPrivateMethod(self) } let methodName: String + let isStatic: Bool - init(methodName: String, parameters: Parameters) { + init(methodName: String, parameters: Parameters, isStatic: Bool) { self.methodName = methodName + self.isStatic = isStatic // First inner output is the explicit |this| parameter. - // See comment in ClassAddPrivateInstanceProperty for why this operation isn't mutable. + // See comment in ClassAddPrivateProperty for why this operation isn't mutable. super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } -final class EndClassPrivateStaticMethod: EndAnySubroutine { - override var opcode: Opcode { .endClassPrivateStaticMethod(self) } +final class EndClassPrivateMethod: EndAnySubroutine { + override var opcode: Opcode { .endClassPrivateMethod(self) } } final class EndClassDefinition: JsOperation { diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index b50931649..4918d7d14 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -62,36 +62,22 @@ enum Opcode { case beginClassDefinition(BeginClassDefinition) case beginClassConstructor(BeginClassConstructor) case endClassConstructor(EndClassConstructor) - case classAddInstanceProperty(ClassAddInstanceProperty) - case classAddInstanceElement(ClassAddInstanceElement) - case classAddInstanceComputedProperty(ClassAddInstanceComputedProperty) - case beginClassInstanceMethod(BeginClassInstanceMethod) - case endClassInstanceMethod(EndClassInstanceMethod) - case beginClassInstanceComputedMethod(BeginClassInstanceComputedMethod) - case endClassInstanceComputedMethod(EndClassInstanceComputedMethod) - case beginClassInstanceGetter(BeginClassInstanceGetter) - case endClassInstanceGetter(EndClassInstanceGetter) - case beginClassInstanceSetter(BeginClassInstanceSetter) - case endClassInstanceSetter(EndClassInstanceSetter) - case classAddStaticProperty(ClassAddStaticProperty) - case classAddStaticElement(ClassAddStaticElement) - case classAddStaticComputedProperty(ClassAddStaticComputedProperty) + case classAddProperty(ClassAddProperty) + case classAddElement(ClassAddElement) + case classAddComputedProperty(ClassAddComputedProperty) + case beginClassMethod(BeginClassMethod) + case endClassMethod(EndClassMethod) + case beginClassComputedMethod(BeginClassComputedMethod) + case endClassComputedMethod(EndClassComputedMethod) + case beginClassGetter(BeginClassGetter) + case endClassGetter(EndClassGetter) + case beginClassSetter(BeginClassSetter) + case endClassSetter(EndClassSetter) case beginClassStaticInitializer(BeginClassStaticInitializer) case endClassStaticInitializer(EndClassStaticInitializer) - case beginClassStaticMethod(BeginClassStaticMethod) - case endClassStaticMethod(EndClassStaticMethod) - case beginClassStaticComputedMethod(BeginClassStaticComputedMethod) - case endClassStaticComputedMethod(EndClassStaticComputedMethod) - case beginClassStaticGetter(BeginClassStaticGetter) - case endClassStaticGetter(EndClassStaticGetter) - case beginClassStaticSetter(BeginClassStaticSetter) - case endClassStaticSetter(EndClassStaticSetter) - case classAddPrivateInstanceProperty(ClassAddPrivateInstanceProperty) - case beginClassPrivateInstanceMethod(BeginClassPrivateInstanceMethod) - case endClassPrivateInstanceMethod(EndClassPrivateInstanceMethod) - case classAddPrivateStaticProperty(ClassAddPrivateStaticProperty) - case beginClassPrivateStaticMethod(BeginClassPrivateStaticMethod) - case endClassPrivateStaticMethod(EndClassPrivateStaticMethod) + case classAddPrivateProperty(ClassAddPrivateProperty) + case beginClassPrivateMethod(BeginClassPrivateMethod) + case endClassPrivateMethod(EndClassPrivateMethod) case endClassDefinition(EndClassDefinition) case createArray(CreateArray) case createIntArray(CreateIntArray) diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index 968003082..ab4af0339 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -144,28 +144,18 @@ extension Operation { return endOp is EndClassDefinition case .beginClassConstructor: return endOp is EndClassConstructor - case .beginClassInstanceMethod: - return endOp is EndClassInstanceMethod - case .beginClassInstanceComputedMethod: - return endOp is EndClassInstanceComputedMethod - case .beginClassInstanceGetter: - return endOp is EndClassInstanceGetter - case .beginClassInstanceSetter: - return endOp is EndClassInstanceSetter + case .beginClassMethod: + return endOp is EndClassMethod + case .beginClassComputedMethod: + return endOp is EndClassComputedMethod + case .beginClassGetter: + return endOp is EndClassGetter + case .beginClassSetter: + return endOp is EndClassSetter case .beginClassStaticInitializer: return endOp is EndClassStaticInitializer - case .beginClassStaticMethod: - return endOp is EndClassStaticMethod - case .beginClassStaticComputedMethod: - return endOp is EndClassStaticComputedMethod - case .beginClassStaticGetter: - return endOp is EndClassStaticGetter - case .beginClassStaticSetter: - return endOp is EndClassStaticSetter - case .beginClassPrivateInstanceMethod: - return endOp is EndClassPrivateInstanceMethod - case .beginClassPrivateStaticMethod: - return endOp is EndClassPrivateStaticMethod + case .beginClassPrivateMethod: + return endOp is EndClassPrivateMethod case .beginPlainFunction: return endOp is EndPlainFunction case .beginArrowFunction: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index fd6ce0df9..7b94c258e 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -167,83 +167,69 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassConstructor") - case .classAddInstanceProperty(let op): + case .classAddProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceProperty '\(op.propertyName)' \(input(0))") + w.emit("ClassAddProperty '\(maybeStatic)\(op.propertyName)' \(input(0))") } else { - w.emit("ClassAddInstanceProperty '\(op.propertyName)'") + w.emit("ClassAddProperty '\(maybeStatic)\(op.propertyName)'") } - case .classAddInstanceElement(let op): + case .classAddElement(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceElement '\(op.index)' \(input(0))") + w.emit("ClassAddElement '\(maybeStatic)\(op.index)' \(input(0))") } else { - w.emit("ClassAddInstanceElement '\(op.index)'") + w.emit("ClassAddElement '\(maybeStatic)\(op.index)'") } - case .classAddInstanceComputedProperty(let op): + case .classAddComputedProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddInstanceComputedProperty \(input(0)) \(input(1))") + w.emit("ClassAddComputedProperty \(maybeStatic)\(input(0)) \(input(1))") } else { - w.emit("ClassAddInstanceComputedProperty \(input(0))") + w.emit("ClassAddComputedProperty \(maybeStatic)\(input(0))") } - case .beginClassInstanceMethod(let op): + case .beginClassMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceMethod '\(op.methodName)' -> \(params)") + w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceMethod: + case .endClassMethod: w.decreaseIndentionLevel() - w.emit("EndClassInstanceMethod") + w.emit("EndClassMethod") - case .beginClassInstanceComputedMethod: + case .beginClassComputedMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceComputedMethod \(input(0)) -> \(params)") + w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0)) -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceComputedMethod: + case .endClassComputedMethod: w.decreaseIndentionLevel() - w.emit("EndClassInstanceComputedMethod") + w.emit("EndClassComputedMethod") - case .beginClassInstanceGetter(let op): + case .beginClassGetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceGetter `\(op.propertyName)` -> \(params)") + w.emit("BeginClassGetter '\(maybeStatic)\(op.propertyName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceGetter: + case .endClassGetter: w.decreaseIndentionLevel() - w.emit("EndClassInstanceGetter") + w.emit("EndClassGetter") - case .beginClassInstanceSetter(let op): + case .beginClassSetter(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassInstanceSetter `\(op.propertyName)` -> \(params)") + w.emit("BeginClassSetter '\(maybeStatic)\(op.propertyName)' -> \(params)") w.increaseIndentionLevel() - case .endClassInstanceSetter: + case .endClassSetter: w.decreaseIndentionLevel() - w.emit("EndClassInstanceSetter") - - case .classAddStaticProperty(let op): - if op.hasValue { - w.emit("ClassAddStaticProperty '\(op.propertyName)' \(input(0))") - } else { - w.emit("ClassAddStaticProperty '\(op.propertyName)'") - } - - case .classAddStaticElement(let op): - if op.hasValue { - w.emit("ClassAddStaticElement '\(op.index)' \(input(0))") - } else { - w.emit("ClassAddStaticElement '\(op.index)'") - } - - case .classAddStaticComputedProperty(let op): - if op.hasValue { - w.emit("ClassAddStaticComputedProperty \(input(0)) \(input(1))") - } else { - w.emit("ClassAddStaticComputedProperty \(input(0))") - } + w.emit("EndClassSetter") case .beginClassStaticInitializer: w.emit("BeginClassStaticInitializer -> \(lift(instr.innerOutput))") @@ -253,74 +239,23 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassStaticInitializer") - case .beginClassStaticMethod(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticMethod '\(op.methodName)' -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticMethod: - w.decreaseIndentionLevel() - w.emit("EndClassStaticMethod") - - case .beginClassStaticComputedMethod: - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticComputedMethod \(input(0)) -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticComputedMethod: - w.decreaseIndentionLevel() - w.emit("EndClassStaticComputedMethod") - - case .beginClassStaticGetter(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticGetter `\(op.propertyName)` -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticGetter: - w.decreaseIndentionLevel() - w.emit("EndClassStaticGetter") - - case .beginClassStaticSetter(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassStaticSetter `\(op.propertyName)` -> \(params)") - w.increaseIndentionLevel() - - case .endClassStaticSetter: - w.decreaseIndentionLevel() - w.emit("EndClassStaticSetter") - - case .classAddPrivateInstanceProperty(let op): + case .classAddPrivateProperty(let op): + let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { - w.emit("ClassAddPrivateInstanceProperty '\(op.propertyName)' \(input(0))") + w.emit("ClassAddPrivateProperty '\(maybeStatic)\(op.propertyName)' \(input(0))") } else { - w.emit("ClassAddPrivateInstanceProperty '\(op.propertyName)'") + w.emit("ClassAddPrivateProperty '\(maybeStatic)\(op.propertyName)'") } - case .beginClassPrivateInstanceMethod(let op): + case .beginClassPrivateMethod(let op): + let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateInstanceMethod '\(op.methodName)' -> \(params)") + w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)' -> \(params)") w.increaseIndentionLevel() - case .endClassPrivateInstanceMethod: + case .endClassPrivateMethod: w.decreaseIndentionLevel() - w.emit("EndClassPrivateInstanceMethod") - - case .classAddPrivateStaticProperty(let op): - if op.hasValue { - w.emit("ClassAddPrivateStaticProperty '\(op.propertyName)' \(input(0))") - } else { - w.emit("ClassAddPrivateStaticProperty '\(op.propertyName)'") - } - - case .beginClassPrivateStaticMethod(let op): - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateStaticMethod '\(op.methodName)' -> \(params)") - w.increaseIndentionLevel() - - case .endClassPrivateStaticMethod: - w.decreaseIndentionLevel() - w.emit("EndClassPrivateStaticMethod") - + w.emit("EndClassPrivateMethod") case .endClassDefinition: w.decreaseIndentionLevel() w.emit("EndClassDefinition") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 8b523ed25..680e77f47 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -496,179 +496,107 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") - case .classAddInstanceProperty(let op): + case .classAddProperty(let op): let PROPERTY = op.propertyName + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("\(PROPERTY) = \(VALUE);") + w.emit("\(staticStr)\(PROPERTY) = \(VALUE);") } else { - w.emit("\(PROPERTY);") + w.emit("\(staticStr)\(PROPERTY);") } - case .classAddInstanceElement(let op): + case .classAddElement(let op): let INDEX = op.index < 0 ? "[\(op.index)]" : String(op.index) + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("\(INDEX) = \(VALUE);") + w.emit("\(staticStr)\(INDEX) = \(VALUE);") } else { - w.emit("\(INDEX);") + w.emit("\(staticStr)\(INDEX);") } - case .classAddInstanceComputedProperty(let op): + case .classAddComputedProperty(let op): let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(1) - w.emit("[\(PROPERTY)] = \(VALUE);") + w.emit("\(staticStr)[\(PROPERTY)] = \(VALUE);") } else { - w.emit("[\(PROPERTY)];") + w.emit("\(staticStr)[\(PROPERTY)];") } - case .beginClassInstanceMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) - w.emit("\(METHOD)(\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceComputedMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = input(0) - w.emit("[\(METHOD)](\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceGetter(let op): - let PROPERTY = op.propertyName - w.emit("get \(PROPERTY)() {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassInstanceSetter(let op): - assert(instr.numInnerOutputs == 2) - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName - w.emit("set \(PROPERTY)(\(PARAMS)) {") + case .beginClassStaticInitializer: + w.emit("static {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter: + case .endClassStaticInitializer: w.leaveCurrentBlock() w.emit("}") - case .classAddStaticProperty(let op): - let PROPERTY = op.propertyName - if op.hasValue { - let VALUE = input(0) - w.emit("static \(PROPERTY) = \(VALUE);") - } else { - w.emit("static \(PROPERTY);") - } - - case .classAddStaticElement(let op): - let INDEX = op.index < 0 ? "[\(op.index)]" : String(op.index) - if op.hasValue { - let VALUE = input(0) - w.emit("static \(INDEX) = \(VALUE);") - } else { - w.emit("static \(INDEX);") - } - - case .classAddStaticComputedProperty(let op): - let PROPERTY = input(0) - if op.hasValue { - let VALUE = input(1) - w.emit("static [\(PROPERTY)] = \(VALUE);") - } else { - w.emit("static [\(PROPERTY)];") - } - - case .beginClassStaticInitializer: - w.emit("static {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .beginClassStaticMethod(let op): + case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) - w.emit("static \(METHOD)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticComputedMethod(let op): + case .beginClassComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = input(0) - w.emit("static [\(METHOD)](\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)[\(METHOD)](\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticGetter(let op): - assert(instr.numInnerOutputs == 1) + case .beginClassGetter(let op): let PROPERTY = op.propertyName - w.emit("static get \(PROPERTY)() {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)get \(PROPERTY)() {") w.enterNewBlock() - bindVariableToThis(instr.innerOutput) + bindVariableToThis(instr.innerOutput(0)) - case .beginClassStaticSetter(let op): + case .beginClassSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let PROPERTY = op.propertyName - w.emit("static set \(PROPERTY)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)set \(PROPERTY)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassStaticInitializer, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter: + case .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter: w.leaveCurrentBlock() w.emit("}") - case .classAddPrivateInstanceProperty(let op): - let PROPERTY = op.propertyName - if op.hasValue { - let VALUE = input(0) - w.emit("#\(PROPERTY) = \(VALUE);") - } else { - w.emit("#\(PROPERTY);") - } - - case .beginClassPrivateInstanceMethod(let op): - let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = op.methodName - w.emit("#\(METHOD)(\(PARAMS)) {") - w.enterNewBlock() - bindVariableToThis(instr.innerOutput(0)) - - case .classAddPrivateStaticProperty(let op): + case .classAddPrivateProperty(let op): let PROPERTY = op.propertyName + let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) - w.emit("static #\(PROPERTY) = \(VALUE);") + w.emit("\(staticStr)#\(PROPERTY) = \(VALUE);") } else { - w.emit("static #\(PROPERTY);") + w.emit("\(staticStr)#\(PROPERTY);") } - case .beginClassPrivateStaticMethod(let op): + case .beginClassPrivateMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) let METHOD = op.methodName - w.emit("static #\(METHOD)(\(PARAMS)) {") + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)#\(METHOD)(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) - case .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + case .endClassPrivateMethod: w.leaveCurrentBlock() w.emit("}") diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index aec2abf3c..af5ca9fbc 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -37,17 +37,12 @@ struct BlockReducer: Reducer { reduceClassDefinition(group.block(0), with: helper) case .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 9704f81d9..7f6cf85d5 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -61,17 +61,12 @@ struct InliningReducer: Reducer { .beginObjectLiteralGetter, .beginObjectLiteralSetter, .beginClassConstructor, - .beginClassInstanceMethod, - .beginClassInstanceComputedMethod, - .beginClassInstanceGetter, - .beginClassInstanceSetter, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassSetter, .beginClassStaticInitializer, - .beginClassStaticMethod, - .beginClassStaticComputedMethod, - .beginClassStaticGetter, - .beginClassStaticSetter, - .beginClassPrivateInstanceMethod, - .beginClassPrivateStaticMethod: + .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, .endArrowFunction, @@ -85,17 +80,12 @@ struct InliningReducer: Reducer { .endObjectLiteralGetter, .endObjectLiteralSetter, .endClassConstructor, - .endClassInstanceMethod, - .endClassInstanceComputedMethod, - .endClassInstanceGetter, - .endClassInstanceSetter, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassSetter, .endClassStaticInitializer, - .endClassStaticMethod, - .endClassStaticComputedMethod, - .endClassStaticGetter, - .endClassStaticSetter, - .endClassPrivateInstanceMethod, - .endClassPrivateStaticMethod: + .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 2e73465e0..d87ef0d23 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -124,26 +124,16 @@ public class OperationMutator: BaseInstructionMutator { newOp = BeginObjectLiteralGetter(propertyName: b.randomPropertyName()) case .beginObjectLiteralSetter: newOp = BeginObjectLiteralSetter(propertyName: b.randomPropertyName()) - case .classAddInstanceProperty(let op): - newOp = ClassAddInstanceProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue) - case .classAddInstanceElement(let op): - newOp = ClassAddInstanceElement(index: b.randomIndex(), hasValue: op.hasValue) - case .beginClassInstanceMethod(let op): - newOp = BeginClassInstanceMethod(methodName: b.randomMethodName(), parameters: op.parameters) - case .beginClassInstanceGetter: - newOp = BeginClassInstanceGetter(propertyName: b.randomPropertyName()) - case .beginClassInstanceSetter: - newOp = BeginClassInstanceSetter(propertyName: b.randomPropertyName()) - case .classAddStaticProperty(let op): - newOp = ClassAddStaticProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue) - case .classAddStaticElement(let op): - newOp = ClassAddStaticElement(index: b.randomIndex(), hasValue: op.hasValue) - case .beginClassStaticMethod(let op): - newOp = BeginClassStaticMethod(methodName: b.randomMethodName(), parameters: op.parameters) - case .beginClassStaticGetter: - newOp = BeginClassStaticGetter(propertyName: b.randomPropertyName()) - case .beginClassStaticSetter: - newOp = BeginClassStaticSetter(propertyName: b.randomPropertyName()) + case .classAddProperty(let op): + newOp = ClassAddProperty(propertyName: b.randomPropertyName(), hasValue: op.hasValue, isStatic: op.isStatic) + case .classAddElement(let op): + newOp = ClassAddElement(index: b.randomIndex(), hasValue: op.hasValue, isStatic: op.isStatic) + case .beginClassMethod(let op): + newOp = BeginClassMethod(methodName: b.randomMethodName(), parameters: op.parameters, isStatic: op.isStatic) + case .beginClassGetter(let op): + newOp = BeginClassGetter(propertyName: b.randomPropertyName(), isStatic: op.isStatic) + case .beginClassSetter(let op): + newOp = BeginClassSetter(propertyName: b.randomPropertyName(), isStatic: op.isStatic) case .createIntArray: var values = [Int64]() for _ in 0..(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7050,6 +6873,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, Swi switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7062,20 +6886,24 @@ extension Fuzzilli_Protobuf_ClassAddInstanceProperty: SwiftProtobuf.Message, Swi if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceProperty, rhs: Fuzzilli_Protobuf_ClassAddInstanceProperty) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddProperty, rhs: Fuzzilli_Protobuf_ClassAddProperty) -> Bool { if lhs.propertyName != rhs.propertyName {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddInstanceElement" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddElement" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7085,6 +6913,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, Swif switch fieldNumber { case 1: try { try decoder.decodeSingularInt64Field(value: &self.index) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7097,20 +6926,24 @@ extension Fuzzilli_Protobuf_ClassAddInstanceElement: SwiftProtobuf.Message, Swif if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceElement, rhs: Fuzzilli_Protobuf_ClassAddInstanceElement) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddElement, rhs: Fuzzilli_Protobuf_ClassAddElement) -> Bool { if lhs.index != rhs.index {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddInstanceComputedProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddComputedProperty" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7119,6 +6952,7 @@ extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Mess // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7128,19 +6962,23 @@ extension Fuzzilli_Protobuf_ClassAddInstanceComputedProperty: SwiftProtobuf.Mess if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddComputedProperty) -> Bool { if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") +extension Fuzzilli_Protobuf_BeginClassMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7150,6 +6988,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, Swi switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7166,19 +7005,23 @@ extension Fuzzilli_Protobuf_BeginClassInstanceMethod: SwiftProtobuf.Message, Swi try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceMethod, rhs: Fuzzilli_Protobuf_BeginClassInstanceMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassMethod, rhs: Fuzzilli_Protobuf_BeginClassMethod) -> Bool { if lhs.methodName != rhs.methodName {return false} if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceMethod" +extension Fuzzilli_Protobuf_EndClassMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7190,15 +7033,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceMethod: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceMethod, rhs: Fuzzilli_Protobuf_EndClassInstanceMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassMethod, rhs: Fuzzilli_Protobuf_EndClassMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0") +extension Fuzzilli_Protobuf_BeginClassComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7207,6 +7050,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Mess // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7220,18 +7064,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceComputedMethod: SwiftProtobuf.Mess try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) } }() + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassComputedMethod) -> Bool { if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceComputedMethod" +extension Fuzzilli_Protobuf_EndClassComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7243,15 +7091,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceComputedMethod: SwiftProtobuf.Messag try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceComputedMethod, rhs: Fuzzilli_Protobuf_EndClassInstanceComputedMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedMethod, rhs: Fuzzilli_Protobuf_EndClassComputedMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") +extension Fuzzilli_Protobuf_BeginClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7260,6 +7108,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, Swi // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7269,18 +7118,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceGetter: SwiftProtobuf.Message, Swi if !self.propertyName.isEmpty { try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceGetter, rhs: Fuzzilli_Protobuf_BeginClassInstanceGetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassGetter, rhs: Fuzzilli_Protobuf_BeginClassGetter) -> Bool { if lhs.propertyName != rhs.propertyName {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceGetter" +extension Fuzzilli_Protobuf_EndClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassGetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7292,15 +7145,15 @@ extension Fuzzilli_Protobuf_EndClassInstanceGetter: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceGetter, rhs: Fuzzilli_Protobuf_EndClassInstanceGetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassGetter, rhs: Fuzzilli_Protobuf_EndClassGetter) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassInstanceSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") +extension Fuzzilli_Protobuf_BeginClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7309,6 +7162,7 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() + case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7318,18 +7172,22 @@ extension Fuzzilli_Protobuf_BeginClassInstanceSetter: SwiftProtobuf.Message, Swi if !self.propertyName.isEmpty { try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassInstanceSetter, rhs: Fuzzilli_Protobuf_BeginClassInstanceSetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassSetter, rhs: Fuzzilli_Protobuf_BeginClassSetter) -> Bool { if lhs.propertyName != rhs.propertyName {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassInstanceSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassInstanceSetter" +extension Fuzzilli_Protobuf_EndClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7341,50 +7199,53 @@ extension Fuzzilli_Protobuf_EndClassInstanceSetter: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassInstanceSetter, rhs: Fuzzilli_Protobuf_EndClassInstanceSetter) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassSetter, rhs: Fuzzilli_Protobuf_EndClassSetter) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddStaticProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticInitializer, rhs: Fuzzilli_Protobuf_BeginClassStaticInitializer) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassStaticInitializer" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticInitializer, rhs: Fuzzilli_Protobuf_EndClassStaticInitializer) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticElement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticElement" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}index\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_ClassAddPrivateProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateProperty" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7392,34 +7253,39 @@ extension Fuzzilli_Protobuf_ClassAddStaticElement: SwiftProtobuf.Message, SwiftP // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularInt64Field(value: &self.index) }() + case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } } public func traverse(visitor: inout V) throws { - if self.index != 0 { - try visitor.visitSingularInt64Field(value: self.index, fieldNumber: 1) + if !self.propertyName.isEmpty { + try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) } if self.hasValue_p != false { try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticElement, rhs: Fuzzilli_Protobuf_ClassAddStaticElement) -> Bool { - if lhs.index != rhs.index {return false} + public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateProperty) -> Bool { + if lhs.propertyName != rhs.propertyName {return false} if lhs.hasValue_p != rhs.hasValue_p {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddStaticComputedProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}hasValue\0") +extension Fuzzilli_Protobuf_BeginClassPrivateMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateMethod" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0\u{3}is_static\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7427,320 +7293,9 @@ extension Fuzzilli_Protobuf_ClassAddStaticComputedProperty: SwiftProtobuf.Messag // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddStaticComputedProperty, rhs: Fuzzilli_Protobuf_ClassAddStaticComputedProperty) -> Bool { - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticInitializer, rhs: Fuzzilli_Protobuf_BeginClassStaticInitializer) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticInitializer" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticInitializer, rhs: Fuzzilli_Protobuf_EndClassStaticInitializer) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.methodName.isEmpty { - try visitor.visitSingularStringField(value: self.methodName, fieldNumber: 1) - } - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticMethod, rhs: Fuzzilli_Protobuf_BeginClassStaticMethod) -> Bool { - if lhs.methodName != rhs.methodName {return false} - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticMethod, rhs: Fuzzilli_Protobuf_EndClassStaticMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticComputedMethod, rhs: Fuzzilli_Protobuf_BeginClassStaticComputedMethod) -> Bool { - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticComputedMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticComputedMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticComputedMethod, rhs: Fuzzilli_Protobuf_EndClassStaticComputedMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticGetter, rhs: Fuzzilli_Protobuf_BeginClassStaticGetter) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticGetter, rhs: Fuzzilli_Protobuf_EndClassStaticGetter) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassStaticSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassStaticSetter, rhs: Fuzzilli_Protobuf_BeginClassStaticSetter) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassStaticSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassStaticSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassStaticSetter, rhs: Fuzzilli_Protobuf_EndClassStaticSetter) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateInstanceProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() default: break } } @@ -7757,112 +7312,23 @@ extension Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod: SwiftProtobuf.Messa try { if let v = self._parameters { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod) -> Bool { - if lhs.methodName != rhs.methodName {return false} - if lhs._parameters != rhs._parameters {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_EndClassPrivateInstanceMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateInstanceMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() - - public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} - } - - public func traverse(visitor: inout V) throws { - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod) -> Bool { - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_ClassAddPrivateStaticProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".ClassAddPrivateStaticProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{1}hasValue\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.propertyName) }() - case 2: try { try decoder.decodeSingularBoolField(value: &self.hasValue_p) }() - default: break - } + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 3) } - } - - public func traverse(visitor: inout V) throws { - if !self.propertyName.isEmpty { - try visitor.visitSingularStringField(value: self.propertyName, fieldNumber: 1) - } - if self.hasValue_p != false { - try visitor.visitSingularBoolField(value: self.hasValue_p, fieldNumber: 2) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty, rhs: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty) -> Bool { - if lhs.propertyName != rhs.propertyName {return false} - if lhs.hasValue_p != rhs.hasValue_p {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Fuzzilli_Protobuf_BeginClassPrivateStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginClassPrivateStaticMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}methodName\0\u{1}parameters\0") - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.methodName) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.methodName.isEmpty { - try visitor.visitSingularStringField(value: self.methodName, fieldNumber: 1) - } - try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassPrivateMethod, rhs: Fuzzilli_Protobuf_BeginClassPrivateMethod) -> Bool { if lhs.methodName != rhs.methodName {return false} if lhs._parameters != rhs._parameters {return false} + if lhs.isStatic != rhs.isStatic {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Fuzzilli_Protobuf_EndClassPrivateStaticMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateStaticMethod" +extension Fuzzilli_Protobuf_EndClassPrivateMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassPrivateMethod" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { @@ -7874,7 +7340,7 @@ extension Fuzzilli_Protobuf_EndClassPrivateStaticMethod: SwiftProtobuf.Message, try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateStaticMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateStaticMethod) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_EndClassPrivateMethod, rhs: Fuzzilli_Protobuf_EndClassPrivateMethod) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index a67da4b89..1be3ee744 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -129,61 +129,54 @@ message BeginClassConstructor { message EndClassConstructor { } -message ClassAddInstanceProperty { +message ClassAddProperty { string propertyName = 1; bool hasValue = 2; + bool is_static = 3; } -message ClassAddInstanceElement { +message ClassAddElement { int64 index = 1; bool hasValue = 2; + bool is_static = 3; } -message ClassAddInstanceComputedProperty { +message ClassAddComputedProperty { bool hasValue = 1; + bool is_static = 2; } -message BeginClassInstanceMethod { +message BeginClassMethod { string methodName = 1; Parameters parameters = 2; + bool is_static = 3; } -message EndClassInstanceMethod { +message EndClassMethod { } -message BeginClassInstanceComputedMethod { +message BeginClassComputedMethod { Parameters parameters = 1; + bool is_static = 2; } -message EndClassInstanceComputedMethod { +message EndClassComputedMethod { } -message BeginClassInstanceGetter { +message BeginClassGetter { string propertyName = 1; + bool is_static = 2; } -message EndClassInstanceGetter { +message EndClassGetter { } -message BeginClassInstanceSetter { +message BeginClassSetter { string propertyName = 1; + bool is_static = 2; } -message EndClassInstanceSetter { -} - -message ClassAddStaticProperty { - string propertyName = 1; - bool hasValue = 2; -} - -message ClassAddStaticElement { - int64 index = 1; - bool hasValue = 2; -} - -message ClassAddStaticComputedProperty { - bool hasValue = 1; +message EndClassSetter { } message BeginClassStaticInitializer { @@ -192,59 +185,19 @@ message BeginClassStaticInitializer { message EndClassStaticInitializer { } -message BeginClassStaticMethod { - string methodName = 1; - Parameters parameters = 2; -} - -message EndClassStaticMethod { -} - -message BeginClassStaticComputedMethod { - Parameters parameters = 1; -} - -message EndClassStaticComputedMethod { -} - -message BeginClassStaticGetter { - string propertyName = 1; -} - -message EndClassStaticGetter { -} - -message BeginClassStaticSetter { - string propertyName = 1; -} - -message EndClassStaticSetter { -} - -message ClassAddPrivateInstanceProperty { - string propertyName = 1; - bool hasValue = 2; -} - -message BeginClassPrivateInstanceMethod { - string methodName = 1; - Parameters parameters = 2; -} - -message EndClassPrivateInstanceMethod { -} - -message ClassAddPrivateStaticProperty { +message ClassAddPrivateProperty { string propertyName = 1; bool hasValue = 2; + bool is_static = 3; } -message BeginClassPrivateStaticMethod { +message BeginClassPrivateMethod { string methodName = 1; Parameters parameters = 2; + bool is_static = 3; } -message EndClassPrivateStaticMethod { +message EndClassPrivateMethod { } message EndClassDefinition { diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 2b13319ad..9684e4e6c 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -313,116 +313,92 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassConstructor(newValue)} } - public var classAddInstanceProperty: Fuzzilli_Protobuf_ClassAddInstanceProperty { + public var classAddProperty: Fuzzilli_Protobuf_ClassAddProperty { get { - if case .classAddInstanceProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceProperty() + if case .classAddProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddProperty() } - set {operation = .classAddInstanceProperty(newValue)} + set {operation = .classAddProperty(newValue)} } - public var classAddInstanceElement: Fuzzilli_Protobuf_ClassAddInstanceElement { + public var classAddElement: Fuzzilli_Protobuf_ClassAddElement { get { - if case .classAddInstanceElement(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceElement() + if case .classAddElement(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddElement() } - set {operation = .classAddInstanceElement(newValue)} + set {operation = .classAddElement(newValue)} } - public var classAddInstanceComputedProperty: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty { + public var classAddComputedProperty: Fuzzilli_Protobuf_ClassAddComputedProperty { get { - if case .classAddInstanceComputedProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddInstanceComputedProperty() + if case .classAddComputedProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddComputedProperty() } - set {operation = .classAddInstanceComputedProperty(newValue)} + set {operation = .classAddComputedProperty(newValue)} } - public var beginClassInstanceMethod: Fuzzilli_Protobuf_BeginClassInstanceMethod { + public var beginClassMethod: Fuzzilli_Protobuf_BeginClassMethod { get { - if case .beginClassInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceMethod() + if case .beginClassMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassMethod() } - set {operation = .beginClassInstanceMethod(newValue)} + set {operation = .beginClassMethod(newValue)} } - public var endClassInstanceMethod: Fuzzilli_Protobuf_EndClassInstanceMethod { + public var endClassMethod: Fuzzilli_Protobuf_EndClassMethod { get { - if case .endClassInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceMethod() + if case .endClassMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassMethod() } - set {operation = .endClassInstanceMethod(newValue)} + set {operation = .endClassMethod(newValue)} } - public var beginClassInstanceComputedMethod: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod { + public var beginClassComputedMethod: Fuzzilli_Protobuf_BeginClassComputedMethod { get { - if case .beginClassInstanceComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceComputedMethod() + if case .beginClassComputedMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedMethod() } - set {operation = .beginClassInstanceComputedMethod(newValue)} + set {operation = .beginClassComputedMethod(newValue)} } - public var endClassInstanceComputedMethod: Fuzzilli_Protobuf_EndClassInstanceComputedMethod { + public var endClassComputedMethod: Fuzzilli_Protobuf_EndClassComputedMethod { get { - if case .endClassInstanceComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceComputedMethod() + if case .endClassComputedMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedMethod() } - set {operation = .endClassInstanceComputedMethod(newValue)} + set {operation = .endClassComputedMethod(newValue)} } - public var beginClassInstanceGetter: Fuzzilli_Protobuf_BeginClassInstanceGetter { + public var beginClassGetter: Fuzzilli_Protobuf_BeginClassGetter { get { - if case .beginClassInstanceGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceGetter() + if case .beginClassGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassGetter() } - set {operation = .beginClassInstanceGetter(newValue)} + set {operation = .beginClassGetter(newValue)} } - public var endClassInstanceGetter: Fuzzilli_Protobuf_EndClassInstanceGetter { + public var endClassGetter: Fuzzilli_Protobuf_EndClassGetter { get { - if case .endClassInstanceGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceGetter() + if case .endClassGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassGetter() } - set {operation = .endClassInstanceGetter(newValue)} + set {operation = .endClassGetter(newValue)} } - public var beginClassInstanceSetter: Fuzzilli_Protobuf_BeginClassInstanceSetter { + public var beginClassSetter: Fuzzilli_Protobuf_BeginClassSetter { get { - if case .beginClassInstanceSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassInstanceSetter() + if case .beginClassSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassSetter() } - set {operation = .beginClassInstanceSetter(newValue)} + set {operation = .beginClassSetter(newValue)} } - public var endClassInstanceSetter: Fuzzilli_Protobuf_EndClassInstanceSetter { + public var endClassSetter: Fuzzilli_Protobuf_EndClassSetter { get { - if case .endClassInstanceSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassInstanceSetter() + if case .endClassSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassSetter() } - set {operation = .endClassInstanceSetter(newValue)} - } - - public var classAddStaticProperty: Fuzzilli_Protobuf_ClassAddStaticProperty { - get { - if case .classAddStaticProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticProperty() - } - set {operation = .classAddStaticProperty(newValue)} - } - - public var classAddStaticElement: Fuzzilli_Protobuf_ClassAddStaticElement { - get { - if case .classAddStaticElement(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticElement() - } - set {operation = .classAddStaticElement(newValue)} - } - - public var classAddStaticComputedProperty: Fuzzilli_Protobuf_ClassAddStaticComputedProperty { - get { - if case .classAddStaticComputedProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddStaticComputedProperty() - } - set {operation = .classAddStaticComputedProperty(newValue)} + set {operation = .endClassSetter(newValue)} } public var beginClassStaticInitializer: Fuzzilli_Protobuf_BeginClassStaticInitializer { @@ -441,116 +417,28 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassStaticInitializer(newValue)} } - public var beginClassStaticMethod: Fuzzilli_Protobuf_BeginClassStaticMethod { - get { - if case .beginClassStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticMethod() - } - set {operation = .beginClassStaticMethod(newValue)} - } - - public var endClassStaticMethod: Fuzzilli_Protobuf_EndClassStaticMethod { - get { - if case .endClassStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticMethod() - } - set {operation = .endClassStaticMethod(newValue)} - } - - public var beginClassStaticComputedMethod: Fuzzilli_Protobuf_BeginClassStaticComputedMethod { - get { - if case .beginClassStaticComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticComputedMethod() - } - set {operation = .beginClassStaticComputedMethod(newValue)} - } - - public var endClassStaticComputedMethod: Fuzzilli_Protobuf_EndClassStaticComputedMethod { - get { - if case .endClassStaticComputedMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticComputedMethod() - } - set {operation = .endClassStaticComputedMethod(newValue)} - } - - public var beginClassStaticGetter: Fuzzilli_Protobuf_BeginClassStaticGetter { - get { - if case .beginClassStaticGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticGetter() - } - set {operation = .beginClassStaticGetter(newValue)} - } - - public var endClassStaticGetter: Fuzzilli_Protobuf_EndClassStaticGetter { + public var classAddPrivateProperty: Fuzzilli_Protobuf_ClassAddPrivateProperty { get { - if case .endClassStaticGetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticGetter() + if case .classAddPrivateProperty(let v)? = operation {return v} + return Fuzzilli_Protobuf_ClassAddPrivateProperty() } - set {operation = .endClassStaticGetter(newValue)} + set {operation = .classAddPrivateProperty(newValue)} } - public var beginClassStaticSetter: Fuzzilli_Protobuf_BeginClassStaticSetter { + public var beginClassPrivateMethod: Fuzzilli_Protobuf_BeginClassPrivateMethod { get { - if case .beginClassStaticSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassStaticSetter() + if case .beginClassPrivateMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassPrivateMethod() } - set {operation = .beginClassStaticSetter(newValue)} + set {operation = .beginClassPrivateMethod(newValue)} } - public var endClassStaticSetter: Fuzzilli_Protobuf_EndClassStaticSetter { + public var endClassPrivateMethod: Fuzzilli_Protobuf_EndClassPrivateMethod { get { - if case .endClassStaticSetter(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassStaticSetter() + if case .endClassPrivateMethod(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassPrivateMethod() } - set {operation = .endClassStaticSetter(newValue)} - } - - public var classAddPrivateInstanceProperty: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty { - get { - if case .classAddPrivateInstanceProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty() - } - set {operation = .classAddPrivateInstanceProperty(newValue)} - } - - public var beginClassPrivateInstanceMethod: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod { - get { - if case .beginClassPrivateInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod() - } - set {operation = .beginClassPrivateInstanceMethod(newValue)} - } - - public var endClassPrivateInstanceMethod: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod { - get { - if case .endClassPrivateInstanceMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateInstanceMethod() - } - set {operation = .endClassPrivateInstanceMethod(newValue)} - } - - public var classAddPrivateStaticProperty: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty { - get { - if case .classAddPrivateStaticProperty(let v)? = operation {return v} - return Fuzzilli_Protobuf_ClassAddPrivateStaticProperty() - } - set {operation = .classAddPrivateStaticProperty(newValue)} - } - - public var beginClassPrivateStaticMethod: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod { - get { - if case .beginClassPrivateStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginClassPrivateStaticMethod() - } - set {operation = .beginClassPrivateStaticMethod(newValue)} - } - - public var endClassPrivateStaticMethod: Fuzzilli_Protobuf_EndClassPrivateStaticMethod { - get { - if case .endClassPrivateStaticMethod(let v)? = operation {return v} - return Fuzzilli_Protobuf_EndClassPrivateStaticMethod() - } - set {operation = .endClassPrivateStaticMethod(newValue)} + set {operation = .endClassPrivateMethod(newValue)} } public var endClassDefinition: Fuzzilli_Protobuf_EndClassDefinition { @@ -2805,36 +2693,22 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case beginClassDefinition(Fuzzilli_Protobuf_BeginClassDefinition) case beginClassConstructor(Fuzzilli_Protobuf_BeginClassConstructor) case endClassConstructor(Fuzzilli_Protobuf_EndClassConstructor) - case classAddInstanceProperty(Fuzzilli_Protobuf_ClassAddInstanceProperty) - case classAddInstanceElement(Fuzzilli_Protobuf_ClassAddInstanceElement) - case classAddInstanceComputedProperty(Fuzzilli_Protobuf_ClassAddInstanceComputedProperty) - case beginClassInstanceMethod(Fuzzilli_Protobuf_BeginClassInstanceMethod) - case endClassInstanceMethod(Fuzzilli_Protobuf_EndClassInstanceMethod) - case beginClassInstanceComputedMethod(Fuzzilli_Protobuf_BeginClassInstanceComputedMethod) - case endClassInstanceComputedMethod(Fuzzilli_Protobuf_EndClassInstanceComputedMethod) - case beginClassInstanceGetter(Fuzzilli_Protobuf_BeginClassInstanceGetter) - case endClassInstanceGetter(Fuzzilli_Protobuf_EndClassInstanceGetter) - case beginClassInstanceSetter(Fuzzilli_Protobuf_BeginClassInstanceSetter) - case endClassInstanceSetter(Fuzzilli_Protobuf_EndClassInstanceSetter) - case classAddStaticProperty(Fuzzilli_Protobuf_ClassAddStaticProperty) - case classAddStaticElement(Fuzzilli_Protobuf_ClassAddStaticElement) - case classAddStaticComputedProperty(Fuzzilli_Protobuf_ClassAddStaticComputedProperty) + case classAddProperty(Fuzzilli_Protobuf_ClassAddProperty) + case classAddElement(Fuzzilli_Protobuf_ClassAddElement) + case classAddComputedProperty(Fuzzilli_Protobuf_ClassAddComputedProperty) + case beginClassMethod(Fuzzilli_Protobuf_BeginClassMethod) + case endClassMethod(Fuzzilli_Protobuf_EndClassMethod) + case beginClassComputedMethod(Fuzzilli_Protobuf_BeginClassComputedMethod) + case endClassComputedMethod(Fuzzilli_Protobuf_EndClassComputedMethod) + case beginClassGetter(Fuzzilli_Protobuf_BeginClassGetter) + case endClassGetter(Fuzzilli_Protobuf_EndClassGetter) + case beginClassSetter(Fuzzilli_Protobuf_BeginClassSetter) + case endClassSetter(Fuzzilli_Protobuf_EndClassSetter) case beginClassStaticInitializer(Fuzzilli_Protobuf_BeginClassStaticInitializer) case endClassStaticInitializer(Fuzzilli_Protobuf_EndClassStaticInitializer) - case beginClassStaticMethod(Fuzzilli_Protobuf_BeginClassStaticMethod) - case endClassStaticMethod(Fuzzilli_Protobuf_EndClassStaticMethod) - case beginClassStaticComputedMethod(Fuzzilli_Protobuf_BeginClassStaticComputedMethod) - case endClassStaticComputedMethod(Fuzzilli_Protobuf_EndClassStaticComputedMethod) - case beginClassStaticGetter(Fuzzilli_Protobuf_BeginClassStaticGetter) - case endClassStaticGetter(Fuzzilli_Protobuf_EndClassStaticGetter) - case beginClassStaticSetter(Fuzzilli_Protobuf_BeginClassStaticSetter) - case endClassStaticSetter(Fuzzilli_Protobuf_EndClassStaticSetter) - case classAddPrivateInstanceProperty(Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty) - case beginClassPrivateInstanceMethod(Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod) - case endClassPrivateInstanceMethod(Fuzzilli_Protobuf_EndClassPrivateInstanceMethod) - case classAddPrivateStaticProperty(Fuzzilli_Protobuf_ClassAddPrivateStaticProperty) - case beginClassPrivateStaticMethod(Fuzzilli_Protobuf_BeginClassPrivateStaticMethod) - case endClassPrivateStaticMethod(Fuzzilli_Protobuf_EndClassPrivateStaticMethod) + case classAddPrivateProperty(Fuzzilli_Protobuf_ClassAddPrivateProperty) + case beginClassPrivateMethod(Fuzzilli_Protobuf_BeginClassPrivateMethod) + case endClassPrivateMethod(Fuzzilli_Protobuf_EndClassPrivateMethod) case endClassDefinition(Fuzzilli_Protobuf_EndClassDefinition) case createArray(Fuzzilli_Protobuf_CreateArray) case createIntArray(Fuzzilli_Protobuf_CreateIntArray) @@ -3160,7 +3034,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddInstanceProperty\0\u{1}classAddInstanceElement\0\u{1}classAddInstanceComputedProperty\0\u{1}beginClassInstanceMethod\0\u{1}endClassInstanceMethod\0\u{1}beginClassInstanceComputedMethod\0\u{1}endClassInstanceComputedMethod\0\u{1}beginClassInstanceGetter\0\u{1}endClassInstanceGetter\0\u{1}beginClassInstanceSetter\0\u{1}endClassInstanceSetter\0\u{1}classAddStaticProperty\0\u{1}classAddStaticElement\0\u{1}classAddStaticComputedProperty\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}beginClassStaticMethod\0\u{1}endClassStaticMethod\0\u{1}beginClassStaticComputedMethod\0\u{1}endClassStaticComputedMethod\0\u{1}beginClassStaticGetter\0\u{1}endClassStaticGetter\0\u{1}beginClassStaticSetter\0\u{1}endClassStaticSetter\0\u{1}classAddPrivateInstanceProperty\0\u{1}beginClassPrivateInstanceMethod\0\u{1}endClassPrivateInstanceMethod\0\u{1}classAddPrivateStaticProperty\0\u{1}beginClassPrivateStaticMethod\0\u{1}endClassPrivateStaticMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3594,891 +3468,709 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M } }() case 35: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceProperty? + var v: Fuzzilli_Protobuf_ClassAddProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceProperty(let m) = current {v = m} + if case .classAddProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceProperty(v) + self.operation = .classAddProperty(v) } }() case 36: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceElement? + var v: Fuzzilli_Protobuf_ClassAddElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceElement(let m) = current {v = m} + if case .classAddElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceElement(v) + self.operation = .classAddElement(v) } }() case 37: try { - var v: Fuzzilli_Protobuf_ClassAddInstanceComputedProperty? + var v: Fuzzilli_Protobuf_ClassAddComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddInstanceComputedProperty(let m) = current {v = m} + if case .classAddComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddInstanceComputedProperty(v) + self.operation = .classAddComputedProperty(v) } }() case 38: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceMethod? + var v: Fuzzilli_Protobuf_BeginClassMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceMethod(let m) = current {v = m} + if case .beginClassMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceMethod(v) + self.operation = .beginClassMethod(v) } }() case 39: try { - var v: Fuzzilli_Protobuf_EndClassInstanceMethod? + var v: Fuzzilli_Protobuf_EndClassMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceMethod(let m) = current {v = m} + if case .endClassMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceMethod(v) + self.operation = .endClassMethod(v) } }() case 40: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceComputedMethod? + var v: Fuzzilli_Protobuf_BeginClassComputedMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceComputedMethod(let m) = current {v = m} + if case .beginClassComputedMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceComputedMethod(v) + self.operation = .beginClassComputedMethod(v) } }() case 41: try { - var v: Fuzzilli_Protobuf_EndClassInstanceComputedMethod? + var v: Fuzzilli_Protobuf_EndClassComputedMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceComputedMethod(let m) = current {v = m} + if case .endClassComputedMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceComputedMethod(v) + self.operation = .endClassComputedMethod(v) } }() case 42: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceGetter? + var v: Fuzzilli_Protobuf_BeginClassGetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceGetter(let m) = current {v = m} + if case .beginClassGetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceGetter(v) + self.operation = .beginClassGetter(v) } }() case 43: try { - var v: Fuzzilli_Protobuf_EndClassInstanceGetter? + var v: Fuzzilli_Protobuf_EndClassGetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceGetter(let m) = current {v = m} + if case .endClassGetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceGetter(v) + self.operation = .endClassGetter(v) } }() case 44: try { - var v: Fuzzilli_Protobuf_BeginClassInstanceSetter? + var v: Fuzzilli_Protobuf_BeginClassSetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassInstanceSetter(let m) = current {v = m} + if case .beginClassSetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassInstanceSetter(v) + self.operation = .beginClassSetter(v) } }() case 45: try { - var v: Fuzzilli_Protobuf_EndClassInstanceSetter? + var v: Fuzzilli_Protobuf_EndClassSetter? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassInstanceSetter(let m) = current {v = m} + if case .endClassSetter(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassInstanceSetter(v) + self.operation = .endClassSetter(v) } }() case 46: try { - var v: Fuzzilli_Protobuf_ClassAddStaticProperty? + var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticProperty(let m) = current {v = m} + if case .beginClassStaticInitializer(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticProperty(v) + self.operation = .beginClassStaticInitializer(v) } }() case 47: try { - var v: Fuzzilli_Protobuf_ClassAddStaticElement? + var v: Fuzzilli_Protobuf_EndClassStaticInitializer? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticElement(let m) = current {v = m} + if case .endClassStaticInitializer(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticElement(v) + self.operation = .endClassStaticInitializer(v) } }() case 48: try { - var v: Fuzzilli_Protobuf_ClassAddStaticComputedProperty? + var v: Fuzzilli_Protobuf_ClassAddPrivateProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddStaticComputedProperty(let m) = current {v = m} + if case .classAddPrivateProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddStaticComputedProperty(v) + self.operation = .classAddPrivateProperty(v) } }() case 49: try { - var v: Fuzzilli_Protobuf_BeginClassStaticInitializer? + var v: Fuzzilli_Protobuf_BeginClassPrivateMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticInitializer(let m) = current {v = m} + if case .beginClassPrivateMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticInitializer(v) + self.operation = .beginClassPrivateMethod(v) } }() case 50: try { - var v: Fuzzilli_Protobuf_EndClassStaticInitializer? + var v: Fuzzilli_Protobuf_EndClassPrivateMethod? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticInitializer(let m) = current {v = m} + if case .endClassPrivateMethod(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticInitializer(v) + self.operation = .endClassPrivateMethod(v) } }() case 51: try { - var v: Fuzzilli_Protobuf_BeginClassStaticMethod? + var v: Fuzzilli_Protobuf_EndClassDefinition? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticMethod(let m) = current {v = m} + if case .endClassDefinition(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticMethod(v) + self.operation = .endClassDefinition(v) } }() case 52: try { - var v: Fuzzilli_Protobuf_EndClassStaticMethod? + var v: Fuzzilli_Protobuf_CreateArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticMethod(let m) = current {v = m} + if case .createArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticMethod(v) + self.operation = .createArray(v) } }() case 53: try { - var v: Fuzzilli_Protobuf_BeginClassStaticComputedMethod? + var v: Fuzzilli_Protobuf_CreateIntArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticComputedMethod(let m) = current {v = m} + if case .createIntArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticComputedMethod(v) + self.operation = .createIntArray(v) } }() case 54: try { - var v: Fuzzilli_Protobuf_EndClassStaticComputedMethod? + var v: Fuzzilli_Protobuf_CreateFloatArray? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticComputedMethod(let m) = current {v = m} + if case .createFloatArray(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticComputedMethod(v) + self.operation = .createFloatArray(v) } }() case 55: try { - var v: Fuzzilli_Protobuf_BeginClassStaticGetter? + var v: Fuzzilli_Protobuf_CreateArrayWithSpread? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticGetter(let m) = current {v = m} + if case .createArrayWithSpread(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticGetter(v) + self.operation = .createArrayWithSpread(v) } }() case 56: try { - var v: Fuzzilli_Protobuf_EndClassStaticGetter? + var v: Fuzzilli_Protobuf_CreateTemplateString? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticGetter(let m) = current {v = m} + if case .createTemplateString(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticGetter(v) + self.operation = .createTemplateString(v) } }() case 57: try { - var v: Fuzzilli_Protobuf_BeginClassStaticSetter? + var v: Fuzzilli_Protobuf_GetProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassStaticSetter(let m) = current {v = m} + if case .getProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassStaticSetter(v) + self.operation = .getProperty(v) } }() case 58: try { - var v: Fuzzilli_Protobuf_EndClassStaticSetter? + var v: Fuzzilli_Protobuf_SetProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassStaticSetter(let m) = current {v = m} + if case .setProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassStaticSetter(v) + self.operation = .setProperty(v) } }() case 59: try { - var v: Fuzzilli_Protobuf_ClassAddPrivateInstanceProperty? + var v: Fuzzilli_Protobuf_UpdateProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddPrivateInstanceProperty(let m) = current {v = m} + if case .updateProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddPrivateInstanceProperty(v) + self.operation = .updateProperty(v) } }() case 60: try { - var v: Fuzzilli_Protobuf_BeginClassPrivateInstanceMethod? + var v: Fuzzilli_Protobuf_DeleteProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassPrivateInstanceMethod(let m) = current {v = m} + if case .deleteProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassPrivateInstanceMethod(v) + self.operation = .deleteProperty(v) } }() case 61: try { - var v: Fuzzilli_Protobuf_EndClassPrivateInstanceMethod? + var v: Fuzzilli_Protobuf_ConfigureProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassPrivateInstanceMethod(let m) = current {v = m} + if case .configureProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassPrivateInstanceMethod(v) + self.operation = .configureProperty(v) } }() case 62: try { - var v: Fuzzilli_Protobuf_ClassAddPrivateStaticProperty? + var v: Fuzzilli_Protobuf_GetElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .classAddPrivateStaticProperty(let m) = current {v = m} + if case .getElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .classAddPrivateStaticProperty(v) + self.operation = .getElement(v) } }() case 63: try { - var v: Fuzzilli_Protobuf_BeginClassPrivateStaticMethod? + var v: Fuzzilli_Protobuf_SetElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginClassPrivateStaticMethod(let m) = current {v = m} + if case .setElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginClassPrivateStaticMethod(v) + self.operation = .setElement(v) } }() case 64: try { - var v: Fuzzilli_Protobuf_EndClassPrivateStaticMethod? + var v: Fuzzilli_Protobuf_UpdateElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassPrivateStaticMethod(let m) = current {v = m} + if case .updateElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassPrivateStaticMethod(v) + self.operation = .updateElement(v) } }() case 65: try { - var v: Fuzzilli_Protobuf_EndClassDefinition? + var v: Fuzzilli_Protobuf_DeleteElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .endClassDefinition(let m) = current {v = m} + if case .deleteElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endClassDefinition(v) + self.operation = .deleteElement(v) } }() case 66: try { - var v: Fuzzilli_Protobuf_CreateArray? + var v: Fuzzilli_Protobuf_ConfigureElement? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createArray(let m) = current {v = m} + if case .configureElement(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createArray(v) + self.operation = .configureElement(v) } }() case 67: try { - var v: Fuzzilli_Protobuf_CreateIntArray? + var v: Fuzzilli_Protobuf_GetComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createIntArray(let m) = current {v = m} + if case .getComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createIntArray(v) + self.operation = .getComputedProperty(v) } }() case 68: try { - var v: Fuzzilli_Protobuf_CreateFloatArray? + var v: Fuzzilli_Protobuf_SetComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createFloatArray(let m) = current {v = m} + if case .setComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createFloatArray(v) + self.operation = .setComputedProperty(v) } }() case 69: try { - var v: Fuzzilli_Protobuf_CreateArrayWithSpread? + var v: Fuzzilli_Protobuf_UpdateComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createArrayWithSpread(let m) = current {v = m} + if case .updateComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createArrayWithSpread(v) + self.operation = .updateComputedProperty(v) } }() case 70: try { - var v: Fuzzilli_Protobuf_CreateTemplateString? + var v: Fuzzilli_Protobuf_DeleteComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .createTemplateString(let m) = current {v = m} + if case .deleteComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .createTemplateString(v) + self.operation = .deleteComputedProperty(v) } }() case 71: try { - var v: Fuzzilli_Protobuf_GetProperty? + var v: Fuzzilli_Protobuf_ConfigureComputedProperty? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getProperty(let m) = current {v = m} + if case .configureComputedProperty(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getProperty(v) + self.operation = .configureComputedProperty(v) } }() case 72: try { - var v: Fuzzilli_Protobuf_SetProperty? + var v: Fuzzilli_Protobuf_TypeOf? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setProperty(let m) = current {v = m} + if case .typeOf(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setProperty(v) + self.operation = .typeOf(v) } }() case 73: try { - var v: Fuzzilli_Protobuf_UpdateProperty? + var v: Fuzzilli_Protobuf_Void? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateProperty(let m) = current {v = m} + if case .void(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateProperty(v) + self.operation = .void(v) } }() case 74: try { - var v: Fuzzilli_Protobuf_DeleteProperty? + var v: Fuzzilli_Protobuf_TestInstanceOf? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteProperty(let m) = current {v = m} + if case .testInstanceOf(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteProperty(v) + self.operation = .testInstanceOf(v) } }() case 75: try { - var v: Fuzzilli_Protobuf_ConfigureProperty? + var v: Fuzzilli_Protobuf_TestIn? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureProperty(let m) = current {v = m} + if case .testIn(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureProperty(v) + self.operation = .testIn(v) } }() case 76: try { - var v: Fuzzilli_Protobuf_GetElement? + var v: Fuzzilli_Protobuf_BeginPlainFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getElement(let m) = current {v = m} + if case .beginPlainFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getElement(v) + self.operation = .beginPlainFunction(v) } }() case 77: try { - var v: Fuzzilli_Protobuf_SetElement? + var v: Fuzzilli_Protobuf_EndPlainFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setElement(let m) = current {v = m} + if case .endPlainFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setElement(v) + self.operation = .endPlainFunction(v) } }() case 78: try { - var v: Fuzzilli_Protobuf_UpdateElement? + var v: Fuzzilli_Protobuf_BeginArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateElement(let m) = current {v = m} + if case .beginArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateElement(v) + self.operation = .beginArrowFunction(v) } }() case 79: try { - var v: Fuzzilli_Protobuf_DeleteElement? + var v: Fuzzilli_Protobuf_EndArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteElement(let m) = current {v = m} + if case .endArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteElement(v) + self.operation = .endArrowFunction(v) } }() case 80: try { - var v: Fuzzilli_Protobuf_ConfigureElement? + var v: Fuzzilli_Protobuf_BeginGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureElement(let m) = current {v = m} + if case .beginGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureElement(v) + self.operation = .beginGeneratorFunction(v) } }() case 81: try { - var v: Fuzzilli_Protobuf_GetComputedProperty? + var v: Fuzzilli_Protobuf_EndGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .getComputedProperty(let m) = current {v = m} + if case .endGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .getComputedProperty(v) + self.operation = .endGeneratorFunction(v) } }() case 82: try { - var v: Fuzzilli_Protobuf_SetComputedProperty? + var v: Fuzzilli_Protobuf_BeginAsyncFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .setComputedProperty(let m) = current {v = m} + if case .beginAsyncFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .setComputedProperty(v) + self.operation = .beginAsyncFunction(v) } }() case 83: try { - var v: Fuzzilli_Protobuf_UpdateComputedProperty? + var v: Fuzzilli_Protobuf_EndAsyncFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .updateComputedProperty(let m) = current {v = m} + if case .endAsyncFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .updateComputedProperty(v) + self.operation = .endAsyncFunction(v) } }() case 84: try { - var v: Fuzzilli_Protobuf_DeleteComputedProperty? + var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .deleteComputedProperty(let m) = current {v = m} + if case .beginAsyncArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .deleteComputedProperty(v) + self.operation = .beginAsyncArrowFunction(v) } }() case 85: try { - var v: Fuzzilli_Protobuf_ConfigureComputedProperty? + var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .configureComputedProperty(let m) = current {v = m} + if case .endAsyncArrowFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .configureComputedProperty(v) + self.operation = .endAsyncArrowFunction(v) } }() case 86: try { - var v: Fuzzilli_Protobuf_TypeOf? + var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .typeOf(let m) = current {v = m} + if case .beginAsyncGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .typeOf(v) + self.operation = .beginAsyncGeneratorFunction(v) } }() case 87: try { - var v: Fuzzilli_Protobuf_Void? + var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .void(let m) = current {v = m} + if case .endAsyncGeneratorFunction(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .void(v) + self.operation = .endAsyncGeneratorFunction(v) } }() case 88: try { - var v: Fuzzilli_Protobuf_TestInstanceOf? + var v: Fuzzilli_Protobuf_BeginConstructor? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .testInstanceOf(let m) = current {v = m} + if case .beginConstructor(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .testInstanceOf(v) + self.operation = .beginConstructor(v) } }() case 89: try { - var v: Fuzzilli_Protobuf_TestIn? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .testIn(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .testIn(v) - } - }() - case 90: try { - var v: Fuzzilli_Protobuf_BeginPlainFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginPlainFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginPlainFunction(v) - } - }() - case 91: try { - var v: Fuzzilli_Protobuf_EndPlainFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endPlainFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endPlainFunction(v) - } - }() - case 92: try { - var v: Fuzzilli_Protobuf_BeginArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginArrowFunction(v) - } - }() - case 93: try { - var v: Fuzzilli_Protobuf_EndArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endArrowFunction(v) - } - }() - case 94: try { - var v: Fuzzilli_Protobuf_BeginGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginGeneratorFunction(v) - } - }() - case 95: try { - var v: Fuzzilli_Protobuf_EndGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endGeneratorFunction(v) - } - }() - case 96: try { - var v: Fuzzilli_Protobuf_BeginAsyncFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncFunction(v) - } - }() - case 97: try { - var v: Fuzzilli_Protobuf_EndAsyncFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncFunction(v) - } - }() - case 98: try { - var v: Fuzzilli_Protobuf_BeginAsyncArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncArrowFunction(v) - } - }() - case 99: try { - var v: Fuzzilli_Protobuf_EndAsyncArrowFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncArrowFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncArrowFunction(v) - } - }() - case 100: try { - var v: Fuzzilli_Protobuf_BeginAsyncGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginAsyncGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginAsyncGeneratorFunction(v) - } - }() - case 101: try { - var v: Fuzzilli_Protobuf_EndAsyncGeneratorFunction? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .endAsyncGeneratorFunction(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .endAsyncGeneratorFunction(v) - } - }() - case 102: try { - var v: Fuzzilli_Protobuf_BeginConstructor? - var hadOneofValue = false - if let current = self.operation { - hadOneofValue = true - if case .beginConstructor(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginConstructor(v) - } - }() - case 103: try { - var v: Fuzzilli_Protobuf_EndConstructor? + var v: Fuzzilli_Protobuf_EndConstructor? var hadOneofValue = false if let current = self.operation { hadOneofValue = true @@ -4490,7 +4182,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endConstructor(v) } }() - case 104: try { + case 90: try { var v: Fuzzilli_Protobuf_Directive? var hadOneofValue = false if let current = self.operation { @@ -4503,7 +4195,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .directive(v) } }() - case 105: try { + case 91: try { var v: Fuzzilli_Protobuf_Return? var hadOneofValue = false if let current = self.operation { @@ -4516,7 +4208,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .return(v) } }() - case 106: try { + case 92: try { var v: Fuzzilli_Protobuf_Yield? var hadOneofValue = false if let current = self.operation { @@ -4529,7 +4221,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .yield(v) } }() - case 107: try { + case 93: try { var v: Fuzzilli_Protobuf_YieldEach? var hadOneofValue = false if let current = self.operation { @@ -4542,7 +4234,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .yieldEach(v) } }() - case 108: try { + case 94: try { var v: Fuzzilli_Protobuf_Await? var hadOneofValue = false if let current = self.operation { @@ -4555,7 +4247,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .await(v) } }() - case 109: try { + case 95: try { var v: Fuzzilli_Protobuf_CallFunction? var hadOneofValue = false if let current = self.operation { @@ -4568,7 +4260,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callFunction(v) } }() - case 110: try { + case 96: try { var v: Fuzzilli_Protobuf_CallFunctionWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4581,7 +4273,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callFunctionWithSpread(v) } }() - case 111: try { + case 97: try { var v: Fuzzilli_Protobuf_Construct? var hadOneofValue = false if let current = self.operation { @@ -4594,7 +4286,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .construct(v) } }() - case 112: try { + case 98: try { var v: Fuzzilli_Protobuf_ConstructWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4607,7 +4299,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constructWithSpread(v) } }() - case 113: try { + case 99: try { var v: Fuzzilli_Protobuf_CallMethod? var hadOneofValue = false if let current = self.operation { @@ -4620,7 +4312,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callMethod(v) } }() - case 114: try { + case 100: try { var v: Fuzzilli_Protobuf_CallMethodWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4633,7 +4325,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callMethodWithSpread(v) } }() - case 115: try { + case 101: try { var v: Fuzzilli_Protobuf_CallComputedMethod? var hadOneofValue = false if let current = self.operation { @@ -4646,7 +4338,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callComputedMethod(v) } }() - case 116: try { + case 102: try { var v: Fuzzilli_Protobuf_CallComputedMethodWithSpread? var hadOneofValue = false if let current = self.operation { @@ -4659,7 +4351,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callComputedMethodWithSpread(v) } }() - case 117: try { + case 103: try { var v: Fuzzilli_Protobuf_UnaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4672,7 +4364,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .unaryOperation(v) } }() - case 118: try { + case 104: try { var v: Fuzzilli_Protobuf_BinaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4685,7 +4377,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .binaryOperation(v) } }() - case 119: try { + case 105: try { var v: Fuzzilli_Protobuf_TernaryOperation? var hadOneofValue = false if let current = self.operation { @@ -4698,7 +4390,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .ternaryOperation(v) } }() - case 120: try { + case 106: try { var v: Fuzzilli_Protobuf_Update? var hadOneofValue = false if let current = self.operation { @@ -4711,7 +4403,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .update(v) } }() - case 121: try { + case 107: try { var v: Fuzzilli_Protobuf_Dup? var hadOneofValue = false if let current = self.operation { @@ -4724,7 +4416,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .dup(v) } }() - case 122: try { + case 108: try { var v: Fuzzilli_Protobuf_Reassign? var hadOneofValue = false if let current = self.operation { @@ -4737,7 +4429,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .reassign(v) } }() - case 123: try { + case 109: try { var v: Fuzzilli_Protobuf_DestructArray? var hadOneofValue = false if let current = self.operation { @@ -4750,7 +4442,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructArray(v) } }() - case 124: try { + case 110: try { var v: Fuzzilli_Protobuf_DestructArrayAndReassign? var hadOneofValue = false if let current = self.operation { @@ -4763,7 +4455,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructArrayAndReassign(v) } }() - case 125: try { + case 111: try { var v: Fuzzilli_Protobuf_DestructObject? var hadOneofValue = false if let current = self.operation { @@ -4776,7 +4468,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructObject(v) } }() - case 126: try { + case 112: try { var v: Fuzzilli_Protobuf_DestructObjectAndReassign? var hadOneofValue = false if let current = self.operation { @@ -4789,7 +4481,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .destructObjectAndReassign(v) } }() - case 127: try { + case 113: try { var v: Fuzzilli_Protobuf_Compare? var hadOneofValue = false if let current = self.operation { @@ -4802,7 +4494,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .compare(v) } }() - case 128: try { + case 114: try { var v: Fuzzilli_Protobuf_Eval? var hadOneofValue = false if let current = self.operation { @@ -4815,7 +4507,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .eval(v) } }() - case 129: try { + case 115: try { var v: Fuzzilli_Protobuf_BeginWith? var hadOneofValue = false if let current = self.operation { @@ -4828,7 +4520,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWith(v) } }() - case 130: try { + case 116: try { var v: Fuzzilli_Protobuf_EndWith? var hadOneofValue = false if let current = self.operation { @@ -4841,7 +4533,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWith(v) } }() - case 131: try { + case 117: try { var v: Fuzzilli_Protobuf_CallSuperConstructor? var hadOneofValue = false if let current = self.operation { @@ -4854,7 +4546,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callSuperConstructor(v) } }() - case 132: try { + case 118: try { var v: Fuzzilli_Protobuf_CallSuperMethod? var hadOneofValue = false if let current = self.operation { @@ -4867,7 +4559,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callSuperMethod(v) } }() - case 133: try { + case 119: try { var v: Fuzzilli_Protobuf_GetPrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4880,7 +4572,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getPrivateProperty(v) } }() - case 134: try { + case 120: try { var v: Fuzzilli_Protobuf_SetPrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4893,7 +4585,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setPrivateProperty(v) } }() - case 135: try { + case 121: try { var v: Fuzzilli_Protobuf_UpdatePrivateProperty? var hadOneofValue = false if let current = self.operation { @@ -4906,7 +4598,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .updatePrivateProperty(v) } }() - case 136: try { + case 122: try { var v: Fuzzilli_Protobuf_CallPrivateMethod? var hadOneofValue = false if let current = self.operation { @@ -4919,7 +4611,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .callPrivateMethod(v) } }() - case 137: try { + case 123: try { var v: Fuzzilli_Protobuf_GetSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4932,7 +4624,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getSuperProperty(v) } }() - case 138: try { + case 124: try { var v: Fuzzilli_Protobuf_SetSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4945,7 +4637,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setSuperProperty(v) } }() - case 139: try { + case 125: try { var v: Fuzzilli_Protobuf_GetComputedSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4958,7 +4650,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .getComputedSuperProperty(v) } }() - case 140: try { + case 126: try { var v: Fuzzilli_Protobuf_SetComputedSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4971,7 +4663,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .setComputedSuperProperty(v) } }() - case 141: try { + case 127: try { var v: Fuzzilli_Protobuf_UpdateSuperProperty? var hadOneofValue = false if let current = self.operation { @@ -4984,7 +4676,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .updateSuperProperty(v) } }() - case 142: try { + case 128: try { var v: Fuzzilli_Protobuf_BeginIf? var hadOneofValue = false if let current = self.operation { @@ -4997,7 +4689,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginIf(v) } }() - case 143: try { + case 129: try { var v: Fuzzilli_Protobuf_BeginElse? var hadOneofValue = false if let current = self.operation { @@ -5010,7 +4702,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginElse(v) } }() - case 144: try { + case 130: try { var v: Fuzzilli_Protobuf_EndIf? var hadOneofValue = false if let current = self.operation { @@ -5023,7 +4715,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endIf(v) } }() - case 145: try { + case 131: try { var v: Fuzzilli_Protobuf_BeginWhileLoopHeader? var hadOneofValue = false if let current = self.operation { @@ -5036,7 +4728,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWhileLoopHeader(v) } }() - case 146: try { + case 132: try { var v: Fuzzilli_Protobuf_BeginWhileLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5049,7 +4741,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWhileLoopBody(v) } }() - case 147: try { + case 133: try { var v: Fuzzilli_Protobuf_EndWhileLoop? var hadOneofValue = false if let current = self.operation { @@ -5062,7 +4754,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWhileLoop(v) } }() - case 148: try { + case 134: try { var v: Fuzzilli_Protobuf_BeginDoWhileLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5075,7 +4767,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginDoWhileLoopBody(v) } }() - case 149: try { + case 135: try { var v: Fuzzilli_Protobuf_BeginDoWhileLoopHeader? var hadOneofValue = false if let current = self.operation { @@ -5088,7 +4780,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginDoWhileLoopHeader(v) } }() - case 150: try { + case 136: try { var v: Fuzzilli_Protobuf_EndDoWhileLoop? var hadOneofValue = false if let current = self.operation { @@ -5101,7 +4793,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endDoWhileLoop(v) } }() - case 151: try { + case 137: try { var v: Fuzzilli_Protobuf_BeginForLoopInitializer? var hadOneofValue = false if let current = self.operation { @@ -5114,7 +4806,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopInitializer(v) } }() - case 152: try { + case 138: try { var v: Fuzzilli_Protobuf_BeginForLoopCondition? var hadOneofValue = false if let current = self.operation { @@ -5127,7 +4819,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopCondition(v) } }() - case 153: try { + case 139: try { var v: Fuzzilli_Protobuf_BeginForLoopAfterthought? var hadOneofValue = false if let current = self.operation { @@ -5140,7 +4832,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopAfterthought(v) } }() - case 154: try { + case 140: try { var v: Fuzzilli_Protobuf_BeginForLoopBody? var hadOneofValue = false if let current = self.operation { @@ -5153,7 +4845,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForLoopBody(v) } }() - case 155: try { + case 141: try { var v: Fuzzilli_Protobuf_EndForLoop? var hadOneofValue = false if let current = self.operation { @@ -5166,7 +4858,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForLoop(v) } }() - case 156: try { + case 142: try { var v: Fuzzilli_Protobuf_BeginForInLoop? var hadOneofValue = false if let current = self.operation { @@ -5179,7 +4871,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForInLoop(v) } }() - case 157: try { + case 143: try { var v: Fuzzilli_Protobuf_EndForInLoop? var hadOneofValue = false if let current = self.operation { @@ -5192,7 +4884,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForInLoop(v) } }() - case 158: try { + case 144: try { var v: Fuzzilli_Protobuf_BeginForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -5205,7 +4897,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoop(v) } }() - case 159: try { + case 145: try { var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? var hadOneofValue = false if let current = self.operation { @@ -5218,7 +4910,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoopWithDestruct(v) } }() - case 160: try { + case 146: try { var v: Fuzzilli_Protobuf_EndForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -5231,7 +4923,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForOfLoop(v) } }() - case 161: try { + case 147: try { var v: Fuzzilli_Protobuf_BeginRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -5244,7 +4936,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginRepeatLoop(v) } }() - case 162: try { + case 148: try { var v: Fuzzilli_Protobuf_EndRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -5257,7 +4949,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endRepeatLoop(v) } }() - case 163: try { + case 149: try { var v: Fuzzilli_Protobuf_LoopBreak? var hadOneofValue = false if let current = self.operation { @@ -5270,7 +4962,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopBreak(v) } }() - case 164: try { + case 150: try { var v: Fuzzilli_Protobuf_LoopContinue? var hadOneofValue = false if let current = self.operation { @@ -5283,7 +4975,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopContinue(v) } }() - case 165: try { + case 151: try { var v: Fuzzilli_Protobuf_BeginTry? var hadOneofValue = false if let current = self.operation { @@ -5296,7 +4988,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginTry(v) } }() - case 166: try { + case 152: try { var v: Fuzzilli_Protobuf_BeginCatch? var hadOneofValue = false if let current = self.operation { @@ -5309,7 +5001,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCatch(v) } }() - case 167: try { + case 153: try { var v: Fuzzilli_Protobuf_BeginFinally? var hadOneofValue = false if let current = self.operation { @@ -5322,7 +5014,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginFinally(v) } }() - case 168: try { + case 154: try { var v: Fuzzilli_Protobuf_EndTryCatchFinally? var hadOneofValue = false if let current = self.operation { @@ -5335,7 +5027,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endTryCatchFinally(v) } }() - case 169: try { + case 155: try { var v: Fuzzilli_Protobuf_ThrowException? var hadOneofValue = false if let current = self.operation { @@ -5348,7 +5040,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .throwException(v) } }() - case 170: try { + case 156: try { var v: Fuzzilli_Protobuf_BeginCodeString? var hadOneofValue = false if let current = self.operation { @@ -5361,7 +5053,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCodeString(v) } }() - case 171: try { + case 157: try { var v: Fuzzilli_Protobuf_EndCodeString? var hadOneofValue = false if let current = self.operation { @@ -5374,7 +5066,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endCodeString(v) } }() - case 172: try { + case 158: try { var v: Fuzzilli_Protobuf_BeginBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -5387,7 +5079,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginBlockStatement(v) } }() - case 173: try { + case 159: try { var v: Fuzzilli_Protobuf_EndBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -5400,7 +5092,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endBlockStatement(v) } }() - case 174: try { + case 160: try { var v: Fuzzilli_Protobuf_BeginSwitch? var hadOneofValue = false if let current = self.operation { @@ -5413,7 +5105,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitch(v) } }() - case 175: try { + case 161: try { var v: Fuzzilli_Protobuf_BeginSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -5426,7 +5118,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchCase(v) } }() - case 176: try { + case 162: try { var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? var hadOneofValue = false if let current = self.operation { @@ -5439,7 +5131,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchDefaultCase(v) } }() - case 177: try { + case 163: try { var v: Fuzzilli_Protobuf_EndSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -5452,7 +5144,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitchCase(v) } }() - case 178: try { + case 164: try { var v: Fuzzilli_Protobuf_EndSwitch? var hadOneofValue = false if let current = self.operation { @@ -5465,7 +5157,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitch(v) } }() - case 179: try { + case 165: try { var v: Fuzzilli_Protobuf_SwitchBreak? var hadOneofValue = false if let current = self.operation { @@ -5478,7 +5170,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .switchBreak(v) } }() - case 180: try { + case 166: try { var v: Fuzzilli_Protobuf_LoadNewTarget? var hadOneofValue = false if let current = self.operation { @@ -5491,7 +5183,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loadNewTarget(v) } }() - case 181: try { + case 167: try { var v: Fuzzilli_Protobuf_Print? var hadOneofValue = false if let current = self.operation { @@ -5504,7 +5196,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .print(v) } }() - case 182: try { + case 168: try { var v: Fuzzilli_Protobuf_Explore? var hadOneofValue = false if let current = self.operation { @@ -5517,7 +5209,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .explore(v) } }() - case 183: try { + case 169: try { var v: Fuzzilli_Protobuf_Probe? var hadOneofValue = false if let current = self.operation { @@ -5530,7 +5222,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .probe(v) } }() - case 184: try { + case 170: try { var v: Fuzzilli_Protobuf_Fixup? var hadOneofValue = false if let current = self.operation { @@ -5543,7 +5235,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .fixup(v) } }() - case 185: try { + case 171: try { var v: Fuzzilli_Protobuf_BeginWasmModule? var hadOneofValue = false if let current = self.operation { @@ -5556,7 +5248,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWasmModule(v) } }() - case 186: try { + case 172: try { var v: Fuzzilli_Protobuf_EndWasmModule? var hadOneofValue = false if let current = self.operation { @@ -5569,7 +5261,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWasmModule(v) } }() - case 187: try { + case 173: try { var v: Fuzzilli_Protobuf_CreateWasmGlobal? var hadOneofValue = false if let current = self.operation { @@ -5582,7 +5274,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmGlobal(v) } }() - case 188: try { + case 174: try { var v: Fuzzilli_Protobuf_CreateWasmMemory? var hadOneofValue = false if let current = self.operation { @@ -5595,7 +5287,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmMemory(v) } }() - case 189: try { + case 175: try { var v: Fuzzilli_Protobuf_CreateWasmTable? var hadOneofValue = false if let current = self.operation { @@ -5608,7 +5300,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmTable(v) } }() - case 190: try { + case 176: try { var v: Fuzzilli_Protobuf_CreateWasmJSTag? var hadOneofValue = false if let current = self.operation { @@ -5621,7 +5313,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmJstag(v) } }() - case 191: try { + case 177: try { var v: Fuzzilli_Protobuf_CreateWasmTag? var hadOneofValue = false if let current = self.operation { @@ -5634,7 +5326,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createWasmTag(v) } }() - case 192: try { + case 178: try { var v: Fuzzilli_Protobuf_WrapPromising? var hadOneofValue = false if let current = self.operation { @@ -5647,7 +5339,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wrapPromising(v) } }() - case 193: try { + case 179: try { var v: Fuzzilli_Protobuf_WrapSuspending? var hadOneofValue = false if let current = self.operation { @@ -5660,7 +5352,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wrapSuspending(v) } }() - case 194: try { + case 180: try { var v: Fuzzilli_Protobuf_BindMethod? var hadOneofValue = false if let current = self.operation { @@ -5673,7 +5365,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .bindMethod(v) } }() - case 195: try { + case 181: try { var v: Fuzzilli_Protobuf_BindFunction? var hadOneofValue = false if let current = self.operation { @@ -5686,7 +5378,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .bindFunction(v) } }() - case 196: try { + case 182: try { var v: Fuzzilli_Protobuf_Consti64? var hadOneofValue = false if let current = self.operation { @@ -5699,7 +5391,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .consti64(v) } }() - case 197: try { + case 183: try { var v: Fuzzilli_Protobuf_Consti32? var hadOneofValue = false if let current = self.operation { @@ -5712,7 +5404,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .consti32(v) } }() - case 198: try { + case 184: try { var v: Fuzzilli_Protobuf_Constf32? var hadOneofValue = false if let current = self.operation { @@ -5725,7 +5417,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constf32(v) } }() - case 199: try { + case 185: try { var v: Fuzzilli_Protobuf_Constf64? var hadOneofValue = false if let current = self.operation { @@ -5738,7 +5430,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constf64(v) } }() - case 200: try { + case 186: try { var v: Fuzzilli_Protobuf_WasmReturn? var hadOneofValue = false if let current = self.operation { @@ -5751,7 +5443,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturn(v) } }() - case 201: try { + case 187: try { var v: Fuzzilli_Protobuf_WasmJsCall? var hadOneofValue = false if let current = self.operation { @@ -5764,7 +5456,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmJsCall(v) } }() - case 202: try { + case 188: try { var v: Fuzzilli_Protobuf_Wasmi32CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5777,7 +5469,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32CompareOp(v) } }() - case 203: try { + case 189: try { var v: Fuzzilli_Protobuf_Wasmi64CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5790,7 +5482,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64CompareOp(v) } }() - case 204: try { + case 190: try { var v: Fuzzilli_Protobuf_Wasmf32CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5803,7 +5495,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32CompareOp(v) } }() - case 205: try { + case 191: try { var v: Fuzzilli_Protobuf_Wasmf64CompareOp? var hadOneofValue = false if let current = self.operation { @@ -5816,7 +5508,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64CompareOp(v) } }() - case 206: try { + case 192: try { var v: Fuzzilli_Protobuf_Wasmi32EqualZero? var hadOneofValue = false if let current = self.operation { @@ -5829,7 +5521,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32EqualZero(v) } }() - case 207: try { + case 193: try { var v: Fuzzilli_Protobuf_Wasmi64EqualZero? var hadOneofValue = false if let current = self.operation { @@ -5842,7 +5534,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64EqualZero(v) } }() - case 208: try { + case 194: try { var v: Fuzzilli_Protobuf_Wasmi32BinOp? var hadOneofValue = false if let current = self.operation { @@ -5855,7 +5547,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32BinOp(v) } }() - case 209: try { + case 195: try { var v: Fuzzilli_Protobuf_Wasmi64BinOp? var hadOneofValue = false if let current = self.operation { @@ -5868,7 +5560,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64BinOp(v) } }() - case 210: try { + case 196: try { var v: Fuzzilli_Protobuf_Wasmi32UnOp? var hadOneofValue = false if let current = self.operation { @@ -5881,7 +5573,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi32UnOp(v) } }() - case 211: try { + case 197: try { var v: Fuzzilli_Protobuf_Wasmi64UnOp? var hadOneofValue = false if let current = self.operation { @@ -5894,7 +5586,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmi64UnOp(v) } }() - case 212: try { + case 198: try { var v: Fuzzilli_Protobuf_Wasmf32BinOp? var hadOneofValue = false if let current = self.operation { @@ -5907,7 +5599,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32BinOp(v) } }() - case 213: try { + case 199: try { var v: Fuzzilli_Protobuf_Wasmf64BinOp? var hadOneofValue = false if let current = self.operation { @@ -5920,7 +5612,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64BinOp(v) } }() - case 214: try { + case 200: try { var v: Fuzzilli_Protobuf_Wasmf32UnOp? var hadOneofValue = false if let current = self.operation { @@ -5933,7 +5625,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf32UnOp(v) } }() - case 215: try { + case 201: try { var v: Fuzzilli_Protobuf_Wasmf64UnOp? var hadOneofValue = false if let current = self.operation { @@ -5946,7 +5638,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmf64UnOp(v) } }() - case 216: try { + case 202: try { var v: Fuzzilli_Protobuf_WasmWrapi64Toi32? var hadOneofValue = false if let current = self.operation { @@ -5959,7 +5651,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmWrapi64Toi32(v) } }() - case 217: try { + case 203: try { var v: Fuzzilli_Protobuf_WasmTruncatef32Toi32? var hadOneofValue = false if let current = self.operation { @@ -5972,7 +5664,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef32Toi32(v) } }() - case 218: try { + case 204: try { var v: Fuzzilli_Protobuf_WasmTruncatef64Toi32? var hadOneofValue = false if let current = self.operation { @@ -5985,7 +5677,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef64Toi32(v) } }() - case 219: try { + case 205: try { var v: Fuzzilli_Protobuf_WasmExtendi32Toi64? var hadOneofValue = false if let current = self.operation { @@ -5998,7 +5690,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmExtendi32Toi64(v) } }() - case 220: try { + case 206: try { var v: Fuzzilli_Protobuf_WasmTruncatef32Toi64? var hadOneofValue = false if let current = self.operation { @@ -6011,7 +5703,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef32Toi64(v) } }() - case 221: try { + case 207: try { var v: Fuzzilli_Protobuf_WasmTruncatef64Toi64? var hadOneofValue = false if let current = self.operation { @@ -6024,7 +5716,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncatef64Toi64(v) } }() - case 222: try { + case 208: try { var v: Fuzzilli_Protobuf_WasmConverti32Tof32? var hadOneofValue = false if let current = self.operation { @@ -6037,7 +5729,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti32Tof32(v) } }() - case 223: try { + case 209: try { var v: Fuzzilli_Protobuf_WasmConverti64Tof32? var hadOneofValue = false if let current = self.operation { @@ -6050,7 +5742,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti64Tof32(v) } }() - case 224: try { + case 210: try { var v: Fuzzilli_Protobuf_WasmDemotef64Tof32? var hadOneofValue = false if let current = self.operation { @@ -6063,7 +5755,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDemotef64Tof32(v) } }() - case 225: try { + case 211: try { var v: Fuzzilli_Protobuf_WasmConverti32Tof64? var hadOneofValue = false if let current = self.operation { @@ -6076,7 +5768,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti32Tof64(v) } }() - case 226: try { + case 212: try { var v: Fuzzilli_Protobuf_WasmConverti64Tof64? var hadOneofValue = false if let current = self.operation { @@ -6089,7 +5781,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmConverti64Tof64(v) } }() - case 227: try { + case 213: try { var v: Fuzzilli_Protobuf_WasmPromotef32Tof64? var hadOneofValue = false if let current = self.operation { @@ -6102,7 +5794,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmPromotef32Tof64(v) } }() - case 228: try { + case 214: try { var v: Fuzzilli_Protobuf_WasmReinterpretf32Asi32? var hadOneofValue = false if let current = self.operation { @@ -6115,7 +5807,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpretf32Asi32(v) } }() - case 229: try { + case 215: try { var v: Fuzzilli_Protobuf_WasmReinterpretf64Asi64? var hadOneofValue = false if let current = self.operation { @@ -6128,7 +5820,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpretf64Asi64(v) } }() - case 230: try { + case 216: try { var v: Fuzzilli_Protobuf_WasmReinterpreti32Asf32? var hadOneofValue = false if let current = self.operation { @@ -6141,7 +5833,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpreti32Asf32(v) } }() - case 231: try { + case 217: try { var v: Fuzzilli_Protobuf_WasmReinterpreti64Asf64? var hadOneofValue = false if let current = self.operation { @@ -6154,7 +5846,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReinterpreti64Asf64(v) } }() - case 232: try { + case 218: try { var v: Fuzzilli_Protobuf_WasmSignExtend8Intoi32? var hadOneofValue = false if let current = self.operation { @@ -6167,7 +5859,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend8Intoi32(v) } }() - case 233: try { + case 219: try { var v: Fuzzilli_Protobuf_WasmSignExtend16Intoi32? var hadOneofValue = false if let current = self.operation { @@ -6180,7 +5872,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend16Intoi32(v) } }() - case 234: try { + case 220: try { var v: Fuzzilli_Protobuf_WasmSignExtend8Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6193,7 +5885,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend8Intoi64(v) } }() - case 235: try { + case 221: try { var v: Fuzzilli_Protobuf_WasmSignExtend16Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6206,7 +5898,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend16Intoi64(v) } }() - case 236: try { + case 222: try { var v: Fuzzilli_Protobuf_WasmSignExtend32Intoi64? var hadOneofValue = false if let current = self.operation { @@ -6219,7 +5911,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSignExtend32Intoi64(v) } }() - case 237: try { + case 223: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf32Toi32? var hadOneofValue = false if let current = self.operation { @@ -6232,7 +5924,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf32Toi32(v) } }() - case 238: try { + case 224: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf64Toi32? var hadOneofValue = false if let current = self.operation { @@ -6245,7 +5937,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf64Toi32(v) } }() - case 239: try { + case 225: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf32Toi64? var hadOneofValue = false if let current = self.operation { @@ -6258,7 +5950,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf32Toi64(v) } }() - case 240: try { + case 226: try { var v: Fuzzilli_Protobuf_WasmTruncateSatf64Toi64? var hadOneofValue = false if let current = self.operation { @@ -6271,7 +5963,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTruncateSatf64Toi64(v) } }() - case 241: try { + case 227: try { var v: Fuzzilli_Protobuf_WasmReassign? var hadOneofValue = false if let current = self.operation { @@ -6284,7 +5976,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReassign(v) } }() - case 242: try { + case 228: try { var v: Fuzzilli_Protobuf_WasmDefineGlobal? var hadOneofValue = false if let current = self.operation { @@ -6297,7 +5989,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineGlobal(v) } }() - case 243: try { + case 229: try { var v: Fuzzilli_Protobuf_WasmDefineTable? var hadOneofValue = false if let current = self.operation { @@ -6310,7 +6002,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineTable(v) } }() - case 244: try { + case 230: try { var v: Fuzzilli_Protobuf_WasmDefineMemory? var hadOneofValue = false if let current = self.operation { @@ -6323,7 +6015,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineMemory(v) } }() - case 245: try { + case 231: try { var v: Fuzzilli_Protobuf_WasmDefineDataSegment? var hadOneofValue = false if let current = self.operation { @@ -6336,7 +6028,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineDataSegment(v) } }() - case 246: try { + case 232: try { var v: Fuzzilli_Protobuf_WasmLoadGlobal? var hadOneofValue = false if let current = self.operation { @@ -6349,7 +6041,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmLoadGlobal(v) } }() - case 247: try { + case 233: try { var v: Fuzzilli_Protobuf_WasmStoreGlobal? var hadOneofValue = false if let current = self.operation { @@ -6362,7 +6054,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStoreGlobal(v) } }() - case 248: try { + case 234: try { var v: Fuzzilli_Protobuf_WasmTableGet? var hadOneofValue = false if let current = self.operation { @@ -6375,7 +6067,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableGet(v) } }() - case 249: try { + case 235: try { var v: Fuzzilli_Protobuf_WasmTableSet? var hadOneofValue = false if let current = self.operation { @@ -6388,7 +6080,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableSet(v) } }() - case 250: try { + case 236: try { var v: Fuzzilli_Protobuf_WasmTableSize? var hadOneofValue = false if let current = self.operation { @@ -6401,7 +6093,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableSize(v) } }() - case 251: try { + case 237: try { var v: Fuzzilli_Protobuf_WasmTableGrow? var hadOneofValue = false if let current = self.operation { @@ -6414,7 +6106,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableGrow(v) } }() - case 252: try { + case 238: try { var v: Fuzzilli_Protobuf_WasmCallIndirect? var hadOneofValue = false if let current = self.operation { @@ -6427,7 +6119,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmCallIndirect(v) } }() - case 253: try { + case 239: try { var v: Fuzzilli_Protobuf_WasmCallDirect? var hadOneofValue = false if let current = self.operation { @@ -6440,7 +6132,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmCallDirect(v) } }() - case 254: try { + case 240: try { var v: Fuzzilli_Protobuf_WasmReturnCallDirect? var hadOneofValue = false if let current = self.operation { @@ -6453,7 +6145,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturnCallDirect(v) } }() - case 255: try { + case 241: try { var v: Fuzzilli_Protobuf_WasmReturnCallIndirect? var hadOneofValue = false if let current = self.operation { @@ -6466,7 +6158,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmReturnCallIndirect(v) } }() - case 256: try { + case 242: try { var v: Fuzzilli_Protobuf_WasmMemoryLoad? var hadOneofValue = false if let current = self.operation { @@ -6479,7 +6171,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryLoad(v) } }() - case 257: try { + case 243: try { var v: Fuzzilli_Protobuf_WasmMemoryStore? var hadOneofValue = false if let current = self.operation { @@ -6492,7 +6184,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryStore(v) } }() - case 258: try { + case 244: try { var v: Fuzzilli_Protobuf_WasmAtomicLoad? var hadOneofValue = false if let current = self.operation { @@ -6505,7 +6197,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicLoad(v) } }() - case 259: try { + case 245: try { var v: Fuzzilli_Protobuf_WasmAtomicStore? var hadOneofValue = false if let current = self.operation { @@ -6518,7 +6210,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicStore(v) } }() - case 260: try { + case 246: try { var v: Fuzzilli_Protobuf_WasmAtomicRMW? var hadOneofValue = false if let current = self.operation { @@ -6531,7 +6223,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicRmw(v) } }() - case 261: try { + case 247: try { var v: Fuzzilli_Protobuf_WasmAtomicCmpxchg? var hadOneofValue = false if let current = self.operation { @@ -6544,7 +6236,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAtomicCmpxchg(v) } }() - case 262: try { + case 248: try { var v: Fuzzilli_Protobuf_WasmMemorySize? var hadOneofValue = false if let current = self.operation { @@ -6557,7 +6249,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemorySize(v) } }() - case 263: try { + case 249: try { var v: Fuzzilli_Protobuf_WasmMemoryGrow? var hadOneofValue = false if let current = self.operation { @@ -6570,7 +6262,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryGrow(v) } }() - case 264: try { + case 250: try { var v: Fuzzilli_Protobuf_WasmMemoryFill? var hadOneofValue = false if let current = self.operation { @@ -6583,7 +6275,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryFill(v) } }() - case 265: try { + case 251: try { var v: Fuzzilli_Protobuf_WasmMemoryInit? var hadOneofValue = false if let current = self.operation { @@ -6596,7 +6288,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryInit(v) } }() - case 266: try { + case 252: try { var v: Fuzzilli_Protobuf_WasmDropDataSegment? var hadOneofValue = false if let current = self.operation { @@ -6609,7 +6301,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDropDataSegment(v) } }() - case 267: try { + case 253: try { var v: Fuzzilli_Protobuf_BeginWasmFunction? var hadOneofValue = false if let current = self.operation { @@ -6622,7 +6314,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginWasmFunction(v) } }() - case 268: try { + case 254: try { var v: Fuzzilli_Protobuf_EndWasmFunction? var hadOneofValue = false if let current = self.operation { @@ -6635,7 +6327,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endWasmFunction(v) } }() - case 269: try { + case 255: try { var v: Fuzzilli_Protobuf_WasmBeginBlock? var hadOneofValue = false if let current = self.operation { @@ -6648,7 +6340,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginBlock(v) } }() - case 270: try { + case 256: try { var v: Fuzzilli_Protobuf_WasmEndBlock? var hadOneofValue = false if let current = self.operation { @@ -6661,7 +6353,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndBlock(v) } }() - case 271: try { + case 257: try { var v: Fuzzilli_Protobuf_WasmBeginLoop? var hadOneofValue = false if let current = self.operation { @@ -6674,7 +6366,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginLoop(v) } }() - case 272: try { + case 258: try { var v: Fuzzilli_Protobuf_WasmEndLoop? var hadOneofValue = false if let current = self.operation { @@ -6687,7 +6379,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndLoop(v) } }() - case 273: try { + case 259: try { var v: Fuzzilli_Protobuf_WasmBranch? var hadOneofValue = false if let current = self.operation { @@ -6700,7 +6392,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranch(v) } }() - case 274: try { + case 260: try { var v: Fuzzilli_Protobuf_WasmBranchIf? var hadOneofValue = false if let current = self.operation { @@ -6713,7 +6405,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranchIf(v) } }() - case 275: try { + case 261: try { var v: Fuzzilli_Protobuf_WasmBranchTable? var hadOneofValue = false if let current = self.operation { @@ -6726,7 +6418,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBranchTable(v) } }() - case 276: try { + case 262: try { var v: Fuzzilli_Protobuf_WasmNop? var hadOneofValue = false if let current = self.operation { @@ -6739,7 +6431,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmNop(v) } }() - case 277: try { + case 263: try { var v: Fuzzilli_Protobuf_WasmBeginIf? var hadOneofValue = false if let current = self.operation { @@ -6752,7 +6444,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginIf(v) } }() - case 278: try { + case 264: try { var v: Fuzzilli_Protobuf_WasmBeginElse? var hadOneofValue = false if let current = self.operation { @@ -6765,7 +6457,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginElse(v) } }() - case 279: try { + case 265: try { var v: Fuzzilli_Protobuf_WasmEndIf? var hadOneofValue = false if let current = self.operation { @@ -6778,7 +6470,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndIf(v) } }() - case 280: try { + case 266: try { var v: Fuzzilli_Protobuf_WasmBeginTryTable? var hadOneofValue = false if let current = self.operation { @@ -6791,7 +6483,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTryTable(v) } }() - case 281: try { + case 267: try { var v: Fuzzilli_Protobuf_WasmEndTryTable? var hadOneofValue = false if let current = self.operation { @@ -6804,7 +6496,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTryTable(v) } }() - case 282: try { + case 268: try { var v: Fuzzilli_Protobuf_WasmBeginTry? var hadOneofValue = false if let current = self.operation { @@ -6817,7 +6509,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTry(v) } }() - case 283: try { + case 269: try { var v: Fuzzilli_Protobuf_WasmBeginCatchAll? var hadOneofValue = false if let current = self.operation { @@ -6830,7 +6522,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginCatchAll(v) } }() - case 284: try { + case 270: try { var v: Fuzzilli_Protobuf_WasmBeginCatch? var hadOneofValue = false if let current = self.operation { @@ -6843,7 +6535,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginCatch(v) } }() - case 285: try { + case 271: try { var v: Fuzzilli_Protobuf_WasmEndTry? var hadOneofValue = false if let current = self.operation { @@ -6856,7 +6548,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTry(v) } }() - case 286: try { + case 272: try { var v: Fuzzilli_Protobuf_WasmBeginTryDelegate? var hadOneofValue = false if let current = self.operation { @@ -6869,7 +6561,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTryDelegate(v) } }() - case 287: try { + case 273: try { var v: Fuzzilli_Protobuf_WasmEndTryDelegate? var hadOneofValue = false if let current = self.operation { @@ -6882,7 +6574,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTryDelegate(v) } }() - case 288: try { + case 274: try { var v: Fuzzilli_Protobuf_WasmThrow? var hadOneofValue = false if let current = self.operation { @@ -6895,7 +6587,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmThrow(v) } }() - case 289: try { + case 275: try { var v: Fuzzilli_Protobuf_WasmRethrow? var hadOneofValue = false if let current = self.operation { @@ -6908,7 +6600,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRethrow(v) } }() - case 290: try { + case 276: try { var v: Fuzzilli_Protobuf_WasmThrowRef? var hadOneofValue = false if let current = self.operation { @@ -6921,7 +6613,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmThrowRef(v) } }() - case 291: try { + case 277: try { var v: Fuzzilli_Protobuf_WasmDefineTag? var hadOneofValue = false if let current = self.operation { @@ -6934,7 +6626,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineTag(v) } }() - case 292: try { + case 278: try { var v: Fuzzilli_Protobuf_ConstSimd128? var hadOneofValue = false if let current = self.operation { @@ -6947,7 +6639,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .constSimd128(v) } }() - case 293: try { + case 279: try { var v: Fuzzilli_Protobuf_WasmSimd128Compare? var hadOneofValue = false if let current = self.operation { @@ -6960,7 +6652,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128Compare(v) } }() - case 294: try { + case 280: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerUnOp? var hadOneofValue = false if let current = self.operation { @@ -6973,7 +6665,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerUnOp(v) } }() - case 295: try { + case 281: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerBinOp? var hadOneofValue = false if let current = self.operation { @@ -6986,7 +6678,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerBinOp(v) } }() - case 296: try { + case 282: try { var v: Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp? var hadOneofValue = false if let current = self.operation { @@ -6999,7 +6691,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128IntegerTernaryOp(v) } }() - case 297: try { + case 283: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatUnOp? var hadOneofValue = false if let current = self.operation { @@ -7012,7 +6704,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatUnOp(v) } }() - case 298: try { + case 284: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatBinOp? var hadOneofValue = false if let current = self.operation { @@ -7025,7 +6717,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatBinOp(v) } }() - case 299: try { + case 285: try { var v: Fuzzilli_Protobuf_WasmSimd128FloatTernaryOp? var hadOneofValue = false if let current = self.operation { @@ -7038,7 +6730,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimd128FloatTernaryOp(v) } }() - case 300: try { + case 286: try { var v: Fuzzilli_Protobuf_WasmSimdSplat? var hadOneofValue = false if let current = self.operation { @@ -7051,7 +6743,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdSplat(v) } }() - case 301: try { + case 287: try { var v: Fuzzilli_Protobuf_WasmSimdExtractLane? var hadOneofValue = false if let current = self.operation { @@ -7064,7 +6756,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdExtractLane(v) } }() - case 302: try { + case 288: try { var v: Fuzzilli_Protobuf_WasmSimdReplaceLane? var hadOneofValue = false if let current = self.operation { @@ -7077,7 +6769,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdReplaceLane(v) } }() - case 303: try { + case 289: try { var v: Fuzzilli_Protobuf_WasmSimdStoreLane? var hadOneofValue = false if let current = self.operation { @@ -7090,7 +6782,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdStoreLane(v) } }() - case 304: try { + case 290: try { var v: Fuzzilli_Protobuf_WasmSimdLoadLane? var hadOneofValue = false if let current = self.operation { @@ -7103,7 +6795,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdLoadLane(v) } }() - case 305: try { + case 291: try { var v: Fuzzilli_Protobuf_WasmSimdLoad? var hadOneofValue = false if let current = self.operation { @@ -7116,7 +6808,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSimdLoad(v) } }() - case 306: try { + case 292: try { var v: Fuzzilli_Protobuf_WasmUnreachable? var hadOneofValue = false if let current = self.operation { @@ -7129,7 +6821,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmUnreachable(v) } }() - case 307: try { + case 293: try { var v: Fuzzilli_Protobuf_WasmSelect? var hadOneofValue = false if let current = self.operation { @@ -7142,7 +6834,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSelect(v) } }() - case 308: try { + case 294: try { var v: Fuzzilli_Protobuf_WasmBeginTypeGroup? var hadOneofValue = false if let current = self.operation { @@ -7155,7 +6847,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmBeginTypeGroup(v) } }() - case 309: try { + case 295: try { var v: Fuzzilli_Protobuf_WasmEndTypeGroup? var hadOneofValue = false if let current = self.operation { @@ -7168,7 +6860,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmEndTypeGroup(v) } }() - case 310: try { + case 296: try { var v: Fuzzilli_Protobuf_WasmDefineArrayType? var hadOneofValue = false if let current = self.operation { @@ -7181,7 +6873,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineArrayType(v) } }() - case 311: try { + case 297: try { var v: Fuzzilli_Protobuf_WasmDefineStructType? var hadOneofValue = false if let current = self.operation { @@ -7194,7 +6886,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineStructType(v) } }() - case 312: try { + case 298: try { var v: Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference? var hadOneofValue = false if let current = self.operation { @@ -7207,7 +6899,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineForwardOrSelfReference(v) } }() - case 313: try { + case 299: try { var v: Fuzzilli_Protobuf_WasmResolveForwardReference? var hadOneofValue = false if let current = self.operation { @@ -7220,7 +6912,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmResolveForwardReference(v) } }() - case 314: try { + case 300: try { var v: Fuzzilli_Protobuf_WasmArrayNewFixed? var hadOneofValue = false if let current = self.operation { @@ -7233,7 +6925,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayNewFixed(v) } }() - case 315: try { + case 301: try { var v: Fuzzilli_Protobuf_WasmArrayNewDefault? var hadOneofValue = false if let current = self.operation { @@ -7246,7 +6938,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayNewDefault(v) } }() - case 316: try { + case 302: try { var v: Fuzzilli_Protobuf_WasmArrayLen? var hadOneofValue = false if let current = self.operation { @@ -7259,7 +6951,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayLen(v) } }() - case 317: try { + case 303: try { var v: Fuzzilli_Protobuf_WasmArrayGet? var hadOneofValue = false if let current = self.operation { @@ -7272,7 +6964,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArrayGet(v) } }() - case 318: try { + case 304: try { var v: Fuzzilli_Protobuf_WasmArraySet? var hadOneofValue = false if let current = self.operation { @@ -7285,7 +6977,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmArraySet(v) } }() - case 319: try { + case 305: try { var v: Fuzzilli_Protobuf_WasmStructNewDefault? var hadOneofValue = false if let current = self.operation { @@ -7298,7 +6990,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructNewDefault(v) } }() - case 320: try { + case 306: try { var v: Fuzzilli_Protobuf_WasmStructGet? var hadOneofValue = false if let current = self.operation { @@ -7311,7 +7003,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructGet(v) } }() - case 321: try { + case 307: try { var v: Fuzzilli_Protobuf_WasmStructSet? var hadOneofValue = false if let current = self.operation { @@ -7324,7 +7016,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructSet(v) } }() - case 322: try { + case 308: try { var v: Fuzzilli_Protobuf_WasmRefNull? var hadOneofValue = false if let current = self.operation { @@ -7337,7 +7029,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefNull(v) } }() - case 323: try { + case 309: try { var v: Fuzzilli_Protobuf_WasmRefIsNull? var hadOneofValue = false if let current = self.operation { @@ -7350,7 +7042,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefIsNull(v) } }() - case 324: try { + case 310: try { var v: Fuzzilli_Protobuf_WasmRefI31? var hadOneofValue = false if let current = self.operation { @@ -7363,7 +7055,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefI31(v) } }() - case 325: try { + case 311: try { var v: Fuzzilli_Protobuf_WasmI31Get? var hadOneofValue = false if let current = self.operation { @@ -7376,7 +7068,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmI31Get(v) } }() - case 326: try { + case 312: try { var v: Fuzzilli_Protobuf_WasmAnyConvertExtern? var hadOneofValue = false if let current = self.operation { @@ -7389,7 +7081,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmAnyConvertExtern(v) } }() - case 327: try { + case 313: try { var v: Fuzzilli_Protobuf_WasmExternConvertAny? var hadOneofValue = false if let current = self.operation { @@ -7402,7 +7094,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmExternConvertAny(v) } }() - case 328: try { + case 314: try { var v: Fuzzilli_Protobuf_WasmMemoryCopy? var hadOneofValue = false if let current = self.operation { @@ -7415,7 +7107,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmMemoryCopy(v) } }() - case 329: try { + case 315: try { var v: Fuzzilli_Protobuf_WasmDefineElementSegment? var hadOneofValue = false if let current = self.operation { @@ -7428,7 +7120,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineElementSegment(v) } }() - case 330: try { + case 316: try { var v: Fuzzilli_Protobuf_WasmTableInit? var hadOneofValue = false if let current = self.operation { @@ -7441,7 +7133,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableInit(v) } }() - case 331: try { + case 317: try { var v: Fuzzilli_Protobuf_WasmDropElementSegment? var hadOneofValue = false if let current = self.operation { @@ -7454,7 +7146,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDropElementSegment(v) } }() - case 332: try { + case 318: try { var v: Fuzzilli_Protobuf_WasmTableCopy? var hadOneofValue = false if let current = self.operation { @@ -7467,7 +7159,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmTableCopy(v) } }() - case 333: try { + case 319: try { var v: Fuzzilli_Protobuf_WasmDefineSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7480,7 +7172,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineSignatureType(v) } }() - case 334: try { + case 320: try { var v: Fuzzilli_Protobuf_CreateNamedDisposableVariable? var hadOneofValue = false if let current = self.operation { @@ -7493,7 +7185,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedDisposableVariable(v) } }() - case 335: try { + case 321: try { var v: Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable? var hadOneofValue = false if let current = self.operation { @@ -7506,7 +7198,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .createNamedAsyncDisposableVariable(v) } }() - case 336: try { + case 322: try { var v: Fuzzilli_Protobuf_WasmDefineAdHocSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7519,7 +7211,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocSignatureType(v) } }() - case 337: try { + case 323: try { var v: Fuzzilli_Protobuf_WasmStructNew? var hadOneofValue = false if let current = self.operation { @@ -7532,7 +7224,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmStructNew(v) } }() - case 338: try { + case 324: try { var v: Fuzzilli_Protobuf_WasmRefEq? var hadOneofValue = false if let current = self.operation { @@ -7545,7 +7237,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefEq(v) } }() - case 339: try { + case 325: try { var v: Fuzzilli_Protobuf_WasmRefTest? var hadOneofValue = false if let current = self.operation { @@ -7558,7 +7250,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefTest(v) } }() - case 340: try { + case 326: try { var v: Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType? var hadOneofValue = false if let current = self.operation { @@ -7571,7 +7263,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmDefineAdHocModuleSignatureType(v) } }() - case 341: try { + case 327: try { var v: Fuzzilli_Protobuf_WasmRefCast? var hadOneofValue = false if let current = self.operation { @@ -7730,1233 +7422,1177 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endClassConstructor(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 34) }() - case .classAddInstanceProperty?: try { - guard case .classAddInstanceProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddProperty?: try { + guard case .classAddProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 35) }() - case .classAddInstanceElement?: try { - guard case .classAddInstanceElement(let v)? = self.operation else { preconditionFailure() } + case .classAddElement?: try { + guard case .classAddElement(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 36) }() - case .classAddInstanceComputedProperty?: try { - guard case .classAddInstanceComputedProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddComputedProperty?: try { + guard case .classAddComputedProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 37) }() - case .beginClassInstanceMethod?: try { - guard case .beginClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } + case .beginClassMethod?: try { + guard case .beginClassMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 38) }() - case .endClassInstanceMethod?: try { - guard case .endClassInstanceMethod(let v)? = self.operation else { preconditionFailure() } + case .endClassMethod?: try { + guard case .endClassMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 39) }() - case .beginClassInstanceComputedMethod?: try { - guard case .beginClassInstanceComputedMethod(let v)? = self.operation else { preconditionFailure() } + case .beginClassComputedMethod?: try { + guard case .beginClassComputedMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 40) }() - case .endClassInstanceComputedMethod?: try { - guard case .endClassInstanceComputedMethod(let v)? = self.operation else { preconditionFailure() } + case .endClassComputedMethod?: try { + guard case .endClassComputedMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 41) }() - case .beginClassInstanceGetter?: try { - guard case .beginClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } + case .beginClassGetter?: try { + guard case .beginClassGetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 42) }() - case .endClassInstanceGetter?: try { - guard case .endClassInstanceGetter(let v)? = self.operation else { preconditionFailure() } + case .endClassGetter?: try { + guard case .endClassGetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 43) }() - case .beginClassInstanceSetter?: try { - guard case .beginClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } + case .beginClassSetter?: try { + guard case .beginClassSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 44) }() - case .endClassInstanceSetter?: try { - guard case .endClassInstanceSetter(let v)? = self.operation else { preconditionFailure() } + case .endClassSetter?: try { + guard case .endClassSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 45) }() - case .classAddStaticProperty?: try { - guard case .classAddStaticProperty(let v)? = self.operation else { preconditionFailure() } + case .beginClassStaticInitializer?: try { + guard case .beginClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 46) }() - case .classAddStaticElement?: try { - guard case .classAddStaticElement(let v)? = self.operation else { preconditionFailure() } + case .endClassStaticInitializer?: try { + guard case .endClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 47) }() - case .classAddStaticComputedProperty?: try { - guard case .classAddStaticComputedProperty(let v)? = self.operation else { preconditionFailure() } + case .classAddPrivateProperty?: try { + guard case .classAddPrivateProperty(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 48) }() - case .beginClassStaticInitializer?: try { - guard case .beginClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } + case .beginClassPrivateMethod?: try { + guard case .beginClassPrivateMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 49) }() - case .endClassStaticInitializer?: try { - guard case .endClassStaticInitializer(let v)? = self.operation else { preconditionFailure() } + case .endClassPrivateMethod?: try { + guard case .endClassPrivateMethod(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 50) }() - case .beginClassStaticMethod?: try { - guard case .beginClassStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 51) - }() - case .endClassStaticMethod?: try { - guard case .endClassStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 52) - }() - case .beginClassStaticComputedMethod?: try { - guard case .beginClassStaticComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 53) - }() - case .endClassStaticComputedMethod?: try { - guard case .endClassStaticComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 54) - }() - case .beginClassStaticGetter?: try { - guard case .beginClassStaticGetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 55) - }() - case .endClassStaticGetter?: try { - guard case .endClassStaticGetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 56) - }() - case .beginClassStaticSetter?: try { - guard case .beginClassStaticSetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 57) - }() - case .endClassStaticSetter?: try { - guard case .endClassStaticSetter(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 58) - }() - case .classAddPrivateInstanceProperty?: try { - guard case .classAddPrivateInstanceProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 59) - }() - case .beginClassPrivateInstanceMethod?: try { - guard case .beginClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 60) - }() - case .endClassPrivateInstanceMethod?: try { - guard case .endClassPrivateInstanceMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 61) - }() - case .classAddPrivateStaticProperty?: try { - guard case .classAddPrivateStaticProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 62) - }() - case .beginClassPrivateStaticMethod?: try { - guard case .beginClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 63) - }() - case .endClassPrivateStaticMethod?: try { - guard case .endClassPrivateStaticMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 64) - }() case .endClassDefinition?: try { guard case .endClassDefinition(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 65) + try visitor.visitSingularMessageField(value: v, fieldNumber: 51) }() case .createArray?: try { guard case .createArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 66) + try visitor.visitSingularMessageField(value: v, fieldNumber: 52) }() case .createIntArray?: try { guard case .createIntArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 67) + try visitor.visitSingularMessageField(value: v, fieldNumber: 53) }() case .createFloatArray?: try { guard case .createFloatArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 68) + try visitor.visitSingularMessageField(value: v, fieldNumber: 54) }() case .createArrayWithSpread?: try { guard case .createArrayWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 69) + try visitor.visitSingularMessageField(value: v, fieldNumber: 55) }() case .createTemplateString?: try { guard case .createTemplateString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 70) + try visitor.visitSingularMessageField(value: v, fieldNumber: 56) }() case .getProperty?: try { guard case .getProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 71) + try visitor.visitSingularMessageField(value: v, fieldNumber: 57) }() case .setProperty?: try { guard case .setProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 72) + try visitor.visitSingularMessageField(value: v, fieldNumber: 58) }() case .updateProperty?: try { guard case .updateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 73) + try visitor.visitSingularMessageField(value: v, fieldNumber: 59) }() case .deleteProperty?: try { guard case .deleteProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 74) + try visitor.visitSingularMessageField(value: v, fieldNumber: 60) }() case .configureProperty?: try { guard case .configureProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 75) + try visitor.visitSingularMessageField(value: v, fieldNumber: 61) }() case .getElement?: try { guard case .getElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 76) + try visitor.visitSingularMessageField(value: v, fieldNumber: 62) }() case .setElement?: try { guard case .setElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 77) + try visitor.visitSingularMessageField(value: v, fieldNumber: 63) }() case .updateElement?: try { guard case .updateElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 78) + try visitor.visitSingularMessageField(value: v, fieldNumber: 64) }() case .deleteElement?: try { guard case .deleteElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 79) + try visitor.visitSingularMessageField(value: v, fieldNumber: 65) }() case .configureElement?: try { guard case .configureElement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 80) + try visitor.visitSingularMessageField(value: v, fieldNumber: 66) }() case .getComputedProperty?: try { guard case .getComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 81) + try visitor.visitSingularMessageField(value: v, fieldNumber: 67) }() case .setComputedProperty?: try { guard case .setComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 82) + try visitor.visitSingularMessageField(value: v, fieldNumber: 68) }() case .updateComputedProperty?: try { guard case .updateComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 83) + try visitor.visitSingularMessageField(value: v, fieldNumber: 69) }() case .deleteComputedProperty?: try { guard case .deleteComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 84) + try visitor.visitSingularMessageField(value: v, fieldNumber: 70) }() case .configureComputedProperty?: try { guard case .configureComputedProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 85) + try visitor.visitSingularMessageField(value: v, fieldNumber: 71) }() case .typeOf?: try { guard case .typeOf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 86) + try visitor.visitSingularMessageField(value: v, fieldNumber: 72) }() case .void?: try { guard case .void(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 87) + try visitor.visitSingularMessageField(value: v, fieldNumber: 73) }() case .testInstanceOf?: try { guard case .testInstanceOf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 88) + try visitor.visitSingularMessageField(value: v, fieldNumber: 74) }() case .testIn?: try { guard case .testIn(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 89) + try visitor.visitSingularMessageField(value: v, fieldNumber: 75) }() case .beginPlainFunction?: try { guard case .beginPlainFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 90) + try visitor.visitSingularMessageField(value: v, fieldNumber: 76) }() case .endPlainFunction?: try { guard case .endPlainFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 91) + try visitor.visitSingularMessageField(value: v, fieldNumber: 77) }() case .beginArrowFunction?: try { guard case .beginArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 92) + try visitor.visitSingularMessageField(value: v, fieldNumber: 78) }() case .endArrowFunction?: try { guard case .endArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 93) + try visitor.visitSingularMessageField(value: v, fieldNumber: 79) }() case .beginGeneratorFunction?: try { guard case .beginGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 94) + try visitor.visitSingularMessageField(value: v, fieldNumber: 80) }() case .endGeneratorFunction?: try { guard case .endGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 95) + try visitor.visitSingularMessageField(value: v, fieldNumber: 81) }() case .beginAsyncFunction?: try { guard case .beginAsyncFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 96) + try visitor.visitSingularMessageField(value: v, fieldNumber: 82) }() case .endAsyncFunction?: try { guard case .endAsyncFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 97) + try visitor.visitSingularMessageField(value: v, fieldNumber: 83) }() case .beginAsyncArrowFunction?: try { guard case .beginAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 98) + try visitor.visitSingularMessageField(value: v, fieldNumber: 84) }() case .endAsyncArrowFunction?: try { guard case .endAsyncArrowFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 99) + try visitor.visitSingularMessageField(value: v, fieldNumber: 85) }() case .beginAsyncGeneratorFunction?: try { guard case .beginAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 100) + try visitor.visitSingularMessageField(value: v, fieldNumber: 86) }() case .endAsyncGeneratorFunction?: try { guard case .endAsyncGeneratorFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 101) + try visitor.visitSingularMessageField(value: v, fieldNumber: 87) }() case .beginConstructor?: try { guard case .beginConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 102) + try visitor.visitSingularMessageField(value: v, fieldNumber: 88) }() case .endConstructor?: try { guard case .endConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 103) + try visitor.visitSingularMessageField(value: v, fieldNumber: 89) }() case .directive?: try { guard case .directive(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 104) + try visitor.visitSingularMessageField(value: v, fieldNumber: 90) }() case .return?: try { guard case .return(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 105) + try visitor.visitSingularMessageField(value: v, fieldNumber: 91) }() case .yield?: try { guard case .yield(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 106) + try visitor.visitSingularMessageField(value: v, fieldNumber: 92) }() case .yieldEach?: try { guard case .yieldEach(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 107) + try visitor.visitSingularMessageField(value: v, fieldNumber: 93) }() case .await?: try { guard case .await(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 108) + try visitor.visitSingularMessageField(value: v, fieldNumber: 94) }() case .callFunction?: try { guard case .callFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 109) + try visitor.visitSingularMessageField(value: v, fieldNumber: 95) }() case .callFunctionWithSpread?: try { guard case .callFunctionWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 110) + try visitor.visitSingularMessageField(value: v, fieldNumber: 96) }() case .construct?: try { guard case .construct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 111) + try visitor.visitSingularMessageField(value: v, fieldNumber: 97) }() case .constructWithSpread?: try { guard case .constructWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 112) + try visitor.visitSingularMessageField(value: v, fieldNumber: 98) }() case .callMethod?: try { guard case .callMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 113) + try visitor.visitSingularMessageField(value: v, fieldNumber: 99) }() case .callMethodWithSpread?: try { guard case .callMethodWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 114) + try visitor.visitSingularMessageField(value: v, fieldNumber: 100) }() case .callComputedMethod?: try { guard case .callComputedMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 115) + try visitor.visitSingularMessageField(value: v, fieldNumber: 101) }() case .callComputedMethodWithSpread?: try { guard case .callComputedMethodWithSpread(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 116) + try visitor.visitSingularMessageField(value: v, fieldNumber: 102) }() case .unaryOperation?: try { guard case .unaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 117) + try visitor.visitSingularMessageField(value: v, fieldNumber: 103) }() case .binaryOperation?: try { guard case .binaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 118) + try visitor.visitSingularMessageField(value: v, fieldNumber: 104) }() case .ternaryOperation?: try { guard case .ternaryOperation(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 119) + try visitor.visitSingularMessageField(value: v, fieldNumber: 105) }() case .update?: try { guard case .update(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 120) + try visitor.visitSingularMessageField(value: v, fieldNumber: 106) }() case .dup?: try { guard case .dup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 121) + try visitor.visitSingularMessageField(value: v, fieldNumber: 107) }() case .reassign?: try { guard case .reassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 122) + try visitor.visitSingularMessageField(value: v, fieldNumber: 108) }() case .destructArray?: try { guard case .destructArray(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 123) + try visitor.visitSingularMessageField(value: v, fieldNumber: 109) }() case .destructArrayAndReassign?: try { guard case .destructArrayAndReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 124) + try visitor.visitSingularMessageField(value: v, fieldNumber: 110) }() case .destructObject?: try { guard case .destructObject(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 125) + try visitor.visitSingularMessageField(value: v, fieldNumber: 111) }() case .destructObjectAndReassign?: try { guard case .destructObjectAndReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 126) + try visitor.visitSingularMessageField(value: v, fieldNumber: 112) }() case .compare?: try { guard case .compare(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 127) + try visitor.visitSingularMessageField(value: v, fieldNumber: 113) }() case .eval?: try { guard case .eval(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 128) + try visitor.visitSingularMessageField(value: v, fieldNumber: 114) }() case .beginWith?: try { guard case .beginWith(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 129) + try visitor.visitSingularMessageField(value: v, fieldNumber: 115) }() case .endWith?: try { guard case .endWith(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 130) + try visitor.visitSingularMessageField(value: v, fieldNumber: 116) }() case .callSuperConstructor?: try { guard case .callSuperConstructor(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 131) + try visitor.visitSingularMessageField(value: v, fieldNumber: 117) }() case .callSuperMethod?: try { guard case .callSuperMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 132) + try visitor.visitSingularMessageField(value: v, fieldNumber: 118) }() case .getPrivateProperty?: try { guard case .getPrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 133) + try visitor.visitSingularMessageField(value: v, fieldNumber: 119) }() case .setPrivateProperty?: try { guard case .setPrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 134) + try visitor.visitSingularMessageField(value: v, fieldNumber: 120) }() case .updatePrivateProperty?: try { guard case .updatePrivateProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 135) + try visitor.visitSingularMessageField(value: v, fieldNumber: 121) }() case .callPrivateMethod?: try { guard case .callPrivateMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 136) + try visitor.visitSingularMessageField(value: v, fieldNumber: 122) }() case .getSuperProperty?: try { guard case .getSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 137) + try visitor.visitSingularMessageField(value: v, fieldNumber: 123) }() case .setSuperProperty?: try { guard case .setSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 138) + try visitor.visitSingularMessageField(value: v, fieldNumber: 124) }() case .getComputedSuperProperty?: try { guard case .getComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 139) + try visitor.visitSingularMessageField(value: v, fieldNumber: 125) }() case .setComputedSuperProperty?: try { guard case .setComputedSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 140) + try visitor.visitSingularMessageField(value: v, fieldNumber: 126) }() case .updateSuperProperty?: try { guard case .updateSuperProperty(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 141) + try visitor.visitSingularMessageField(value: v, fieldNumber: 127) }() case .beginIf?: try { guard case .beginIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 142) + try visitor.visitSingularMessageField(value: v, fieldNumber: 128) }() case .beginElse?: try { guard case .beginElse(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 143) + try visitor.visitSingularMessageField(value: v, fieldNumber: 129) }() case .endIf?: try { guard case .endIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 144) + try visitor.visitSingularMessageField(value: v, fieldNumber: 130) }() case .beginWhileLoopHeader?: try { guard case .beginWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 145) + try visitor.visitSingularMessageField(value: v, fieldNumber: 131) }() case .beginWhileLoopBody?: try { guard case .beginWhileLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 146) + try visitor.visitSingularMessageField(value: v, fieldNumber: 132) }() case .endWhileLoop?: try { guard case .endWhileLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 147) + try visitor.visitSingularMessageField(value: v, fieldNumber: 133) }() case .beginDoWhileLoopBody?: try { guard case .beginDoWhileLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 148) + try visitor.visitSingularMessageField(value: v, fieldNumber: 134) }() case .beginDoWhileLoopHeader?: try { guard case .beginDoWhileLoopHeader(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 149) + try visitor.visitSingularMessageField(value: v, fieldNumber: 135) }() case .endDoWhileLoop?: try { guard case .endDoWhileLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 150) + try visitor.visitSingularMessageField(value: v, fieldNumber: 136) }() case .beginForLoopInitializer?: try { guard case .beginForLoopInitializer(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 151) + try visitor.visitSingularMessageField(value: v, fieldNumber: 137) }() case .beginForLoopCondition?: try { guard case .beginForLoopCondition(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 152) + try visitor.visitSingularMessageField(value: v, fieldNumber: 138) }() case .beginForLoopAfterthought?: try { guard case .beginForLoopAfterthought(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 153) + try visitor.visitSingularMessageField(value: v, fieldNumber: 139) }() case .beginForLoopBody?: try { guard case .beginForLoopBody(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 154) + try visitor.visitSingularMessageField(value: v, fieldNumber: 140) }() case .endForLoop?: try { guard case .endForLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + try visitor.visitSingularMessageField(value: v, fieldNumber: 141) }() case .beginForInLoop?: try { guard case .beginForInLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 156) + try visitor.visitSingularMessageField(value: v, fieldNumber: 142) }() case .endForInLoop?: try { guard case .endForInLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 157) + try visitor.visitSingularMessageField(value: v, fieldNumber: 143) }() case .beginForOfLoop?: try { guard case .beginForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 158) + try visitor.visitSingularMessageField(value: v, fieldNumber: 144) }() case .beginForOfLoopWithDestruct?: try { guard case .beginForOfLoopWithDestruct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 159) + try visitor.visitSingularMessageField(value: v, fieldNumber: 145) }() case .endForOfLoop?: try { guard case .endForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 160) + try visitor.visitSingularMessageField(value: v, fieldNumber: 146) }() case .beginRepeatLoop?: try { guard case .beginRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 161) + try visitor.visitSingularMessageField(value: v, fieldNumber: 147) }() case .endRepeatLoop?: try { guard case .endRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 162) + try visitor.visitSingularMessageField(value: v, fieldNumber: 148) }() case .loopBreak?: try { guard case .loopBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 163) + try visitor.visitSingularMessageField(value: v, fieldNumber: 149) }() case .loopContinue?: try { guard case .loopContinue(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 164) + try visitor.visitSingularMessageField(value: v, fieldNumber: 150) }() case .beginTry?: try { guard case .beginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 165) + try visitor.visitSingularMessageField(value: v, fieldNumber: 151) }() case .beginCatch?: try { guard case .beginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 166) + try visitor.visitSingularMessageField(value: v, fieldNumber: 152) }() case .beginFinally?: try { guard case .beginFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 167) + try visitor.visitSingularMessageField(value: v, fieldNumber: 153) }() case .endTryCatchFinally?: try { guard case .endTryCatchFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 168) + try visitor.visitSingularMessageField(value: v, fieldNumber: 154) }() case .throwException?: try { guard case .throwException(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 169) + try visitor.visitSingularMessageField(value: v, fieldNumber: 155) }() case .beginCodeString?: try { guard case .beginCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 170) + try visitor.visitSingularMessageField(value: v, fieldNumber: 156) }() case .endCodeString?: try { guard case .endCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 171) + try visitor.visitSingularMessageField(value: v, fieldNumber: 157) }() case .beginBlockStatement?: try { guard case .beginBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 172) + try visitor.visitSingularMessageField(value: v, fieldNumber: 158) }() case .endBlockStatement?: try { guard case .endBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 173) + try visitor.visitSingularMessageField(value: v, fieldNumber: 159) }() case .beginSwitch?: try { guard case .beginSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 174) + try visitor.visitSingularMessageField(value: v, fieldNumber: 160) }() case .beginSwitchCase?: try { guard case .beginSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 175) + try visitor.visitSingularMessageField(value: v, fieldNumber: 161) }() case .beginSwitchDefaultCase?: try { guard case .beginSwitchDefaultCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 176) + try visitor.visitSingularMessageField(value: v, fieldNumber: 162) }() case .endSwitchCase?: try { guard case .endSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 177) + try visitor.visitSingularMessageField(value: v, fieldNumber: 163) }() case .endSwitch?: try { guard case .endSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 178) + try visitor.visitSingularMessageField(value: v, fieldNumber: 164) }() case .switchBreak?: try { guard case .switchBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 179) + try visitor.visitSingularMessageField(value: v, fieldNumber: 165) }() case .loadNewTarget?: try { guard case .loadNewTarget(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 180) + try visitor.visitSingularMessageField(value: v, fieldNumber: 166) }() case .print?: try { guard case .print(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 181) + try visitor.visitSingularMessageField(value: v, fieldNumber: 167) }() case .explore?: try { guard case .explore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 182) + try visitor.visitSingularMessageField(value: v, fieldNumber: 168) }() case .probe?: try { guard case .probe(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 183) + try visitor.visitSingularMessageField(value: v, fieldNumber: 169) }() case .fixup?: try { guard case .fixup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 184) + try visitor.visitSingularMessageField(value: v, fieldNumber: 170) }() case .beginWasmModule?: try { guard case .beginWasmModule(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 185) + try visitor.visitSingularMessageField(value: v, fieldNumber: 171) }() case .endWasmModule?: try { guard case .endWasmModule(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 186) + try visitor.visitSingularMessageField(value: v, fieldNumber: 172) }() case .createWasmGlobal?: try { guard case .createWasmGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 187) + try visitor.visitSingularMessageField(value: v, fieldNumber: 173) }() case .createWasmMemory?: try { guard case .createWasmMemory(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 188) + try visitor.visitSingularMessageField(value: v, fieldNumber: 174) }() case .createWasmTable?: try { guard case .createWasmTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 189) + try visitor.visitSingularMessageField(value: v, fieldNumber: 175) }() case .createWasmJstag?: try { guard case .createWasmJstag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 190) + try visitor.visitSingularMessageField(value: v, fieldNumber: 176) }() case .createWasmTag?: try { guard case .createWasmTag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 191) + try visitor.visitSingularMessageField(value: v, fieldNumber: 177) }() case .wrapPromising?: try { guard case .wrapPromising(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 192) + try visitor.visitSingularMessageField(value: v, fieldNumber: 178) }() case .wrapSuspending?: try { guard case .wrapSuspending(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 193) + try visitor.visitSingularMessageField(value: v, fieldNumber: 179) }() case .bindMethod?: try { guard case .bindMethod(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 194) + try visitor.visitSingularMessageField(value: v, fieldNumber: 180) }() case .bindFunction?: try { guard case .bindFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 195) + try visitor.visitSingularMessageField(value: v, fieldNumber: 181) }() case .consti64?: try { guard case .consti64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 196) + try visitor.visitSingularMessageField(value: v, fieldNumber: 182) }() case .consti32?: try { guard case .consti32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 197) + try visitor.visitSingularMessageField(value: v, fieldNumber: 183) }() case .constf32?: try { guard case .constf32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 198) + try visitor.visitSingularMessageField(value: v, fieldNumber: 184) }() case .constf64?: try { guard case .constf64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 199) + try visitor.visitSingularMessageField(value: v, fieldNumber: 185) }() case .wasmReturn?: try { guard case .wasmReturn(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 200) + try visitor.visitSingularMessageField(value: v, fieldNumber: 186) }() case .wasmJsCall?: try { guard case .wasmJsCall(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 201) + try visitor.visitSingularMessageField(value: v, fieldNumber: 187) }() case .wasmi32CompareOp?: try { guard case .wasmi32CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 202) + try visitor.visitSingularMessageField(value: v, fieldNumber: 188) }() case .wasmi64CompareOp?: try { guard case .wasmi64CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 203) + try visitor.visitSingularMessageField(value: v, fieldNumber: 189) }() case .wasmf32CompareOp?: try { guard case .wasmf32CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 204) + try visitor.visitSingularMessageField(value: v, fieldNumber: 190) }() case .wasmf64CompareOp?: try { guard case .wasmf64CompareOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 205) + try visitor.visitSingularMessageField(value: v, fieldNumber: 191) }() case .wasmi32EqualZero?: try { guard case .wasmi32EqualZero(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 206) + try visitor.visitSingularMessageField(value: v, fieldNumber: 192) }() case .wasmi64EqualZero?: try { guard case .wasmi64EqualZero(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 207) + try visitor.visitSingularMessageField(value: v, fieldNumber: 193) }() case .wasmi32BinOp?: try { guard case .wasmi32BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 208) + try visitor.visitSingularMessageField(value: v, fieldNumber: 194) }() case .wasmi64BinOp?: try { guard case .wasmi64BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 209) + try visitor.visitSingularMessageField(value: v, fieldNumber: 195) }() case .wasmi32UnOp?: try { guard case .wasmi32UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 210) + try visitor.visitSingularMessageField(value: v, fieldNumber: 196) }() case .wasmi64UnOp?: try { guard case .wasmi64UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 211) + try visitor.visitSingularMessageField(value: v, fieldNumber: 197) }() case .wasmf32BinOp?: try { guard case .wasmf32BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 212) + try visitor.visitSingularMessageField(value: v, fieldNumber: 198) }() case .wasmf64BinOp?: try { guard case .wasmf64BinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 213) + try visitor.visitSingularMessageField(value: v, fieldNumber: 199) }() case .wasmf32UnOp?: try { guard case .wasmf32UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 214) + try visitor.visitSingularMessageField(value: v, fieldNumber: 200) }() case .wasmf64UnOp?: try { guard case .wasmf64UnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 215) + try visitor.visitSingularMessageField(value: v, fieldNumber: 201) }() case .wasmWrapi64Toi32?: try { guard case .wasmWrapi64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 216) + try visitor.visitSingularMessageField(value: v, fieldNumber: 202) }() case .wasmTruncatef32Toi32?: try { guard case .wasmTruncatef32Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 217) + try visitor.visitSingularMessageField(value: v, fieldNumber: 203) }() case .wasmTruncatef64Toi32?: try { guard case .wasmTruncatef64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 218) + try visitor.visitSingularMessageField(value: v, fieldNumber: 204) }() case .wasmExtendi32Toi64?: try { guard case .wasmExtendi32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 219) + try visitor.visitSingularMessageField(value: v, fieldNumber: 205) }() case .wasmTruncatef32Toi64?: try { guard case .wasmTruncatef32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 220) + try visitor.visitSingularMessageField(value: v, fieldNumber: 206) }() case .wasmTruncatef64Toi64?: try { guard case .wasmTruncatef64Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 221) + try visitor.visitSingularMessageField(value: v, fieldNumber: 207) }() case .wasmConverti32Tof32?: try { guard case .wasmConverti32Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 222) + try visitor.visitSingularMessageField(value: v, fieldNumber: 208) }() case .wasmConverti64Tof32?: try { guard case .wasmConverti64Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 223) + try visitor.visitSingularMessageField(value: v, fieldNumber: 209) }() case .wasmDemotef64Tof32?: try { guard case .wasmDemotef64Tof32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 224) + try visitor.visitSingularMessageField(value: v, fieldNumber: 210) }() case .wasmConverti32Tof64?: try { guard case .wasmConverti32Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 225) + try visitor.visitSingularMessageField(value: v, fieldNumber: 211) }() case .wasmConverti64Tof64?: try { guard case .wasmConverti64Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 226) + try visitor.visitSingularMessageField(value: v, fieldNumber: 212) }() case .wasmPromotef32Tof64?: try { guard case .wasmPromotef32Tof64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 227) + try visitor.visitSingularMessageField(value: v, fieldNumber: 213) }() case .wasmReinterpretf32Asi32?: try { guard case .wasmReinterpretf32Asi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 228) + try visitor.visitSingularMessageField(value: v, fieldNumber: 214) }() case .wasmReinterpretf64Asi64?: try { guard case .wasmReinterpretf64Asi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 229) + try visitor.visitSingularMessageField(value: v, fieldNumber: 215) }() case .wasmReinterpreti32Asf32?: try { guard case .wasmReinterpreti32Asf32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 230) + try visitor.visitSingularMessageField(value: v, fieldNumber: 216) }() case .wasmReinterpreti64Asf64?: try { guard case .wasmReinterpreti64Asf64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 231) + try visitor.visitSingularMessageField(value: v, fieldNumber: 217) }() case .wasmSignExtend8Intoi32?: try { guard case .wasmSignExtend8Intoi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 232) + try visitor.visitSingularMessageField(value: v, fieldNumber: 218) }() case .wasmSignExtend16Intoi32?: try { guard case .wasmSignExtend16Intoi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 233) + try visitor.visitSingularMessageField(value: v, fieldNumber: 219) }() case .wasmSignExtend8Intoi64?: try { guard case .wasmSignExtend8Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 234) + try visitor.visitSingularMessageField(value: v, fieldNumber: 220) }() case .wasmSignExtend16Intoi64?: try { guard case .wasmSignExtend16Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 235) + try visitor.visitSingularMessageField(value: v, fieldNumber: 221) }() case .wasmSignExtend32Intoi64?: try { guard case .wasmSignExtend32Intoi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 236) + try visitor.visitSingularMessageField(value: v, fieldNumber: 222) }() case .wasmTruncateSatf32Toi32?: try { guard case .wasmTruncateSatf32Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 237) + try visitor.visitSingularMessageField(value: v, fieldNumber: 223) }() case .wasmTruncateSatf64Toi32?: try { guard case .wasmTruncateSatf64Toi32(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 238) + try visitor.visitSingularMessageField(value: v, fieldNumber: 224) }() case .wasmTruncateSatf32Toi64?: try { guard case .wasmTruncateSatf32Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 239) + try visitor.visitSingularMessageField(value: v, fieldNumber: 225) }() case .wasmTruncateSatf64Toi64?: try { guard case .wasmTruncateSatf64Toi64(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 240) + try visitor.visitSingularMessageField(value: v, fieldNumber: 226) }() case .wasmReassign?: try { guard case .wasmReassign(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 241) + try visitor.visitSingularMessageField(value: v, fieldNumber: 227) }() case .wasmDefineGlobal?: try { guard case .wasmDefineGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 242) + try visitor.visitSingularMessageField(value: v, fieldNumber: 228) }() case .wasmDefineTable?: try { guard case .wasmDefineTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 243) + try visitor.visitSingularMessageField(value: v, fieldNumber: 229) }() case .wasmDefineMemory?: try { guard case .wasmDefineMemory(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 244) + try visitor.visitSingularMessageField(value: v, fieldNumber: 230) }() case .wasmDefineDataSegment?: try { guard case .wasmDefineDataSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 245) + try visitor.visitSingularMessageField(value: v, fieldNumber: 231) }() case .wasmLoadGlobal?: try { guard case .wasmLoadGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 246) + try visitor.visitSingularMessageField(value: v, fieldNumber: 232) }() case .wasmStoreGlobal?: try { guard case .wasmStoreGlobal(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 247) + try visitor.visitSingularMessageField(value: v, fieldNumber: 233) }() case .wasmTableGet?: try { guard case .wasmTableGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 248) + try visitor.visitSingularMessageField(value: v, fieldNumber: 234) }() case .wasmTableSet?: try { guard case .wasmTableSet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 249) + try visitor.visitSingularMessageField(value: v, fieldNumber: 235) }() case .wasmTableSize?: try { guard case .wasmTableSize(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 250) + try visitor.visitSingularMessageField(value: v, fieldNumber: 236) }() case .wasmTableGrow?: try { guard case .wasmTableGrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 251) + try visitor.visitSingularMessageField(value: v, fieldNumber: 237) }() case .wasmCallIndirect?: try { guard case .wasmCallIndirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 252) + try visitor.visitSingularMessageField(value: v, fieldNumber: 238) }() case .wasmCallDirect?: try { guard case .wasmCallDirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 253) + try visitor.visitSingularMessageField(value: v, fieldNumber: 239) }() case .wasmReturnCallDirect?: try { guard case .wasmReturnCallDirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 254) + try visitor.visitSingularMessageField(value: v, fieldNumber: 240) }() case .wasmReturnCallIndirect?: try { guard case .wasmReturnCallIndirect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 255) + try visitor.visitSingularMessageField(value: v, fieldNumber: 241) }() case .wasmMemoryLoad?: try { guard case .wasmMemoryLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 256) + try visitor.visitSingularMessageField(value: v, fieldNumber: 242) }() case .wasmMemoryStore?: try { guard case .wasmMemoryStore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 257) + try visitor.visitSingularMessageField(value: v, fieldNumber: 243) }() case .wasmAtomicLoad?: try { guard case .wasmAtomicLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 258) + try visitor.visitSingularMessageField(value: v, fieldNumber: 244) }() case .wasmAtomicStore?: try { guard case .wasmAtomicStore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 259) + try visitor.visitSingularMessageField(value: v, fieldNumber: 245) }() case .wasmAtomicRmw?: try { guard case .wasmAtomicRmw(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 260) + try visitor.visitSingularMessageField(value: v, fieldNumber: 246) }() case .wasmAtomicCmpxchg?: try { guard case .wasmAtomicCmpxchg(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 261) + try visitor.visitSingularMessageField(value: v, fieldNumber: 247) }() case .wasmMemorySize?: try { guard case .wasmMemorySize(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 262) + try visitor.visitSingularMessageField(value: v, fieldNumber: 248) }() case .wasmMemoryGrow?: try { guard case .wasmMemoryGrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 263) + try visitor.visitSingularMessageField(value: v, fieldNumber: 249) }() case .wasmMemoryFill?: try { guard case .wasmMemoryFill(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 264) + try visitor.visitSingularMessageField(value: v, fieldNumber: 250) }() case .wasmMemoryInit?: try { guard case .wasmMemoryInit(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 265) + try visitor.visitSingularMessageField(value: v, fieldNumber: 251) }() case .wasmDropDataSegment?: try { guard case .wasmDropDataSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 266) + try visitor.visitSingularMessageField(value: v, fieldNumber: 252) }() case .beginWasmFunction?: try { guard case .beginWasmFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 267) + try visitor.visitSingularMessageField(value: v, fieldNumber: 253) }() case .endWasmFunction?: try { guard case .endWasmFunction(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 268) + try visitor.visitSingularMessageField(value: v, fieldNumber: 254) }() case .wasmBeginBlock?: try { guard case .wasmBeginBlock(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 269) + try visitor.visitSingularMessageField(value: v, fieldNumber: 255) }() case .wasmEndBlock?: try { guard case .wasmEndBlock(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 270) + try visitor.visitSingularMessageField(value: v, fieldNumber: 256) }() case .wasmBeginLoop?: try { guard case .wasmBeginLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 271) + try visitor.visitSingularMessageField(value: v, fieldNumber: 257) }() case .wasmEndLoop?: try { guard case .wasmEndLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 272) + try visitor.visitSingularMessageField(value: v, fieldNumber: 258) }() case .wasmBranch?: try { guard case .wasmBranch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 273) + try visitor.visitSingularMessageField(value: v, fieldNumber: 259) }() case .wasmBranchIf?: try { guard case .wasmBranchIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 274) + try visitor.visitSingularMessageField(value: v, fieldNumber: 260) }() case .wasmBranchTable?: try { guard case .wasmBranchTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 275) + try visitor.visitSingularMessageField(value: v, fieldNumber: 261) }() case .wasmNop?: try { guard case .wasmNop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 276) + try visitor.visitSingularMessageField(value: v, fieldNumber: 262) }() case .wasmBeginIf?: try { guard case .wasmBeginIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 277) + try visitor.visitSingularMessageField(value: v, fieldNumber: 263) }() case .wasmBeginElse?: try { guard case .wasmBeginElse(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 278) + try visitor.visitSingularMessageField(value: v, fieldNumber: 264) }() case .wasmEndIf?: try { guard case .wasmEndIf(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 279) + try visitor.visitSingularMessageField(value: v, fieldNumber: 265) }() case .wasmBeginTryTable?: try { guard case .wasmBeginTryTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 280) + try visitor.visitSingularMessageField(value: v, fieldNumber: 266) }() case .wasmEndTryTable?: try { guard case .wasmEndTryTable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 281) + try visitor.visitSingularMessageField(value: v, fieldNumber: 267) }() case .wasmBeginTry?: try { guard case .wasmBeginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 282) + try visitor.visitSingularMessageField(value: v, fieldNumber: 268) }() case .wasmBeginCatchAll?: try { guard case .wasmBeginCatchAll(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 283) + try visitor.visitSingularMessageField(value: v, fieldNumber: 269) }() case .wasmBeginCatch?: try { guard case .wasmBeginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 284) + try visitor.visitSingularMessageField(value: v, fieldNumber: 270) }() case .wasmEndTry?: try { guard case .wasmEndTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 285) + try visitor.visitSingularMessageField(value: v, fieldNumber: 271) }() case .wasmBeginTryDelegate?: try { guard case .wasmBeginTryDelegate(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 286) + try visitor.visitSingularMessageField(value: v, fieldNumber: 272) }() case .wasmEndTryDelegate?: try { guard case .wasmEndTryDelegate(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 287) + try visitor.visitSingularMessageField(value: v, fieldNumber: 273) }() case .wasmThrow?: try { guard case .wasmThrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 288) + try visitor.visitSingularMessageField(value: v, fieldNumber: 274) }() case .wasmRethrow?: try { guard case .wasmRethrow(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 289) + try visitor.visitSingularMessageField(value: v, fieldNumber: 275) }() case .wasmThrowRef?: try { guard case .wasmThrowRef(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 290) + try visitor.visitSingularMessageField(value: v, fieldNumber: 276) }() case .wasmDefineTag?: try { guard case .wasmDefineTag(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 291) + try visitor.visitSingularMessageField(value: v, fieldNumber: 277) }() case .constSimd128?: try { guard case .constSimd128(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 292) + try visitor.visitSingularMessageField(value: v, fieldNumber: 278) }() case .wasmSimd128Compare?: try { guard case .wasmSimd128Compare(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 293) + try visitor.visitSingularMessageField(value: v, fieldNumber: 279) }() case .wasmSimd128IntegerUnOp?: try { guard case .wasmSimd128IntegerUnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 294) + try visitor.visitSingularMessageField(value: v, fieldNumber: 280) }() case .wasmSimd128IntegerBinOp?: try { guard case .wasmSimd128IntegerBinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 295) + try visitor.visitSingularMessageField(value: v, fieldNumber: 281) }() case .wasmSimd128IntegerTernaryOp?: try { guard case .wasmSimd128IntegerTernaryOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 296) + try visitor.visitSingularMessageField(value: v, fieldNumber: 282) }() case .wasmSimd128FloatUnOp?: try { guard case .wasmSimd128FloatUnOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 297) + try visitor.visitSingularMessageField(value: v, fieldNumber: 283) }() case .wasmSimd128FloatBinOp?: try { guard case .wasmSimd128FloatBinOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 298) + try visitor.visitSingularMessageField(value: v, fieldNumber: 284) }() case .wasmSimd128FloatTernaryOp?: try { guard case .wasmSimd128FloatTernaryOp(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 299) + try visitor.visitSingularMessageField(value: v, fieldNumber: 285) }() case .wasmSimdSplat?: try { guard case .wasmSimdSplat(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 300) + try visitor.visitSingularMessageField(value: v, fieldNumber: 286) }() case .wasmSimdExtractLane?: try { guard case .wasmSimdExtractLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 301) + try visitor.visitSingularMessageField(value: v, fieldNumber: 287) }() case .wasmSimdReplaceLane?: try { guard case .wasmSimdReplaceLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 302) + try visitor.visitSingularMessageField(value: v, fieldNumber: 288) }() case .wasmSimdStoreLane?: try { guard case .wasmSimdStoreLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 303) + try visitor.visitSingularMessageField(value: v, fieldNumber: 289) }() case .wasmSimdLoadLane?: try { guard case .wasmSimdLoadLane(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 304) + try visitor.visitSingularMessageField(value: v, fieldNumber: 290) }() case .wasmSimdLoad?: try { guard case .wasmSimdLoad(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 305) + try visitor.visitSingularMessageField(value: v, fieldNumber: 291) }() case .wasmUnreachable?: try { guard case .wasmUnreachable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 306) + try visitor.visitSingularMessageField(value: v, fieldNumber: 292) }() case .wasmSelect?: try { guard case .wasmSelect(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 307) + try visitor.visitSingularMessageField(value: v, fieldNumber: 293) }() case .wasmBeginTypeGroup?: try { guard case .wasmBeginTypeGroup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 308) + try visitor.visitSingularMessageField(value: v, fieldNumber: 294) }() case .wasmEndTypeGroup?: try { guard case .wasmEndTypeGroup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 309) + try visitor.visitSingularMessageField(value: v, fieldNumber: 295) }() case .wasmDefineArrayType?: try { guard case .wasmDefineArrayType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 310) + try visitor.visitSingularMessageField(value: v, fieldNumber: 296) }() case .wasmDefineStructType?: try { guard case .wasmDefineStructType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 311) + try visitor.visitSingularMessageField(value: v, fieldNumber: 297) }() case .wasmDefineForwardOrSelfReference?: try { guard case .wasmDefineForwardOrSelfReference(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 312) + try visitor.visitSingularMessageField(value: v, fieldNumber: 298) }() case .wasmResolveForwardReference?: try { guard case .wasmResolveForwardReference(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 313) + try visitor.visitSingularMessageField(value: v, fieldNumber: 299) }() case .wasmArrayNewFixed?: try { guard case .wasmArrayNewFixed(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 314) + try visitor.visitSingularMessageField(value: v, fieldNumber: 300) }() case .wasmArrayNewDefault?: try { guard case .wasmArrayNewDefault(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 315) + try visitor.visitSingularMessageField(value: v, fieldNumber: 301) }() case .wasmArrayLen?: try { guard case .wasmArrayLen(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 316) + try visitor.visitSingularMessageField(value: v, fieldNumber: 302) }() case .wasmArrayGet?: try { guard case .wasmArrayGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 317) + try visitor.visitSingularMessageField(value: v, fieldNumber: 303) }() case .wasmArraySet?: try { guard case .wasmArraySet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 318) + try visitor.visitSingularMessageField(value: v, fieldNumber: 304) }() case .wasmStructNewDefault?: try { guard case .wasmStructNewDefault(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 319) + try visitor.visitSingularMessageField(value: v, fieldNumber: 305) }() case .wasmStructGet?: try { guard case .wasmStructGet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 320) + try visitor.visitSingularMessageField(value: v, fieldNumber: 306) }() case .wasmStructSet?: try { guard case .wasmStructSet(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 321) + try visitor.visitSingularMessageField(value: v, fieldNumber: 307) }() case .wasmRefNull?: try { guard case .wasmRefNull(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 322) + try visitor.visitSingularMessageField(value: v, fieldNumber: 308) }() case .wasmRefIsNull?: try { guard case .wasmRefIsNull(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 323) + try visitor.visitSingularMessageField(value: v, fieldNumber: 309) }() case .wasmRefI31?: try { guard case .wasmRefI31(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 324) + try visitor.visitSingularMessageField(value: v, fieldNumber: 310) }() case .wasmI31Get?: try { guard case .wasmI31Get(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 325) + try visitor.visitSingularMessageField(value: v, fieldNumber: 311) }() case .wasmAnyConvertExtern?: try { guard case .wasmAnyConvertExtern(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 326) + try visitor.visitSingularMessageField(value: v, fieldNumber: 312) }() case .wasmExternConvertAny?: try { guard case .wasmExternConvertAny(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 327) + try visitor.visitSingularMessageField(value: v, fieldNumber: 313) }() case .wasmMemoryCopy?: try { guard case .wasmMemoryCopy(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 328) + try visitor.visitSingularMessageField(value: v, fieldNumber: 314) }() case .wasmDefineElementSegment?: try { guard case .wasmDefineElementSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 329) + try visitor.visitSingularMessageField(value: v, fieldNumber: 315) }() case .wasmTableInit?: try { guard case .wasmTableInit(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 330) + try visitor.visitSingularMessageField(value: v, fieldNumber: 316) }() case .wasmDropElementSegment?: try { guard case .wasmDropElementSegment(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 331) + try visitor.visitSingularMessageField(value: v, fieldNumber: 317) }() case .wasmTableCopy?: try { guard case .wasmTableCopy(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 332) + try visitor.visitSingularMessageField(value: v, fieldNumber: 318) }() case .wasmDefineSignatureType?: try { guard case .wasmDefineSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 333) + try visitor.visitSingularMessageField(value: v, fieldNumber: 319) }() case .createNamedDisposableVariable?: try { guard case .createNamedDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 334) + try visitor.visitSingularMessageField(value: v, fieldNumber: 320) }() case .createNamedAsyncDisposableVariable?: try { guard case .createNamedAsyncDisposableVariable(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 335) + try visitor.visitSingularMessageField(value: v, fieldNumber: 321) }() case .wasmDefineAdHocSignatureType?: try { guard case .wasmDefineAdHocSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 336) + try visitor.visitSingularMessageField(value: v, fieldNumber: 322) }() case .wasmStructNew?: try { guard case .wasmStructNew(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 337) + try visitor.visitSingularMessageField(value: v, fieldNumber: 323) }() case .wasmRefEq?: try { guard case .wasmRefEq(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 338) + try visitor.visitSingularMessageField(value: v, fieldNumber: 324) }() case .wasmRefTest?: try { guard case .wasmRefTest(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 339) + try visitor.visitSingularMessageField(value: v, fieldNumber: 325) }() case .wasmDefineAdHocModuleSignatureType?: try { guard case .wasmDefineAdHocModuleSignatureType(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 340) + try visitor.visitSingularMessageField(value: v, fieldNumber: 326) }() case .wasmRefCast?: try { guard case .wasmRefCast(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 341) + try visitor.visitSingularMessageField(value: v, fieldNumber: 327) }() case nil: break } diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 1ae505cf7..abf2a678c 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -58,313 +58,299 @@ message Instruction { BeginClassDefinition beginClassDefinition = 32; BeginClassConstructor beginClassConstructor = 33; EndClassConstructor endClassConstructor = 34; - ClassAddInstanceProperty classAddInstanceProperty = 35; - ClassAddInstanceElement classAddInstanceElement = 36; - ClassAddInstanceComputedProperty classAddInstanceComputedProperty = 37; - BeginClassInstanceMethod beginClassInstanceMethod = 38; - EndClassInstanceMethod endClassInstanceMethod = 39; - BeginClassInstanceComputedMethod beginClassInstanceComputedMethod = 40; - EndClassInstanceComputedMethod endClassInstanceComputedMethod = 41; - BeginClassInstanceGetter beginClassInstanceGetter = 42; - EndClassInstanceGetter endClassInstanceGetter = 43; - BeginClassInstanceSetter beginClassInstanceSetter = 44; - EndClassInstanceSetter endClassInstanceSetter = 45; - ClassAddStaticProperty classAddStaticProperty = 46; - ClassAddStaticElement classAddStaticElement = 47; - ClassAddStaticComputedProperty classAddStaticComputedProperty = 48; - BeginClassStaticInitializer beginClassStaticInitializer = 49; - EndClassStaticInitializer endClassStaticInitializer = 50; - BeginClassStaticMethod beginClassStaticMethod = 51; - EndClassStaticMethod endClassStaticMethod = 52; - BeginClassStaticComputedMethod beginClassStaticComputedMethod = 53; - EndClassStaticComputedMethod endClassStaticComputedMethod = 54; - BeginClassStaticGetter beginClassStaticGetter = 55; - EndClassStaticGetter endClassStaticGetter = 56; - BeginClassStaticSetter beginClassStaticSetter = 57; - EndClassStaticSetter endClassStaticSetter = 58; - ClassAddPrivateInstanceProperty classAddPrivateInstanceProperty = 59; - BeginClassPrivateInstanceMethod beginClassPrivateInstanceMethod = 60; - EndClassPrivateInstanceMethod endClassPrivateInstanceMethod = 61; - ClassAddPrivateStaticProperty classAddPrivateStaticProperty = 62; - BeginClassPrivateStaticMethod beginClassPrivateStaticMethod = 63; - EndClassPrivateStaticMethod endClassPrivateStaticMethod = 64; - EndClassDefinition endClassDefinition = 65; - CreateArray createArray = 66; - CreateIntArray createIntArray = 67; - CreateFloatArray createFloatArray = 68; - CreateArrayWithSpread createArrayWithSpread = 69; - CreateTemplateString createTemplateString = 70; - GetProperty getProperty = 71; - SetProperty setProperty = 72; - UpdateProperty updateProperty = 73; - DeleteProperty deleteProperty = 74; - ConfigureProperty configureProperty = 75; - GetElement getElement = 76; - SetElement setElement = 77; - UpdateElement updateElement = 78; - DeleteElement deleteElement = 79; - ConfigureElement configureElement = 80; - GetComputedProperty getComputedProperty = 81; - SetComputedProperty setComputedProperty = 82; - UpdateComputedProperty updateComputedProperty = 83; - DeleteComputedProperty deleteComputedProperty = 84; - ConfigureComputedProperty configureComputedProperty = 85; - TypeOf typeOf = 86; - Void void = 87; - TestInstanceOf testInstanceOf = 88; - TestIn testIn = 89; - BeginPlainFunction beginPlainFunction = 90; - EndPlainFunction endPlainFunction = 91; - BeginArrowFunction beginArrowFunction = 92; - EndArrowFunction endArrowFunction = 93; - BeginGeneratorFunction beginGeneratorFunction = 94; - EndGeneratorFunction endGeneratorFunction = 95; - BeginAsyncFunction beginAsyncFunction = 96; - EndAsyncFunction endAsyncFunction = 97; - BeginAsyncArrowFunction beginAsyncArrowFunction = 98; - EndAsyncArrowFunction endAsyncArrowFunction = 99; - BeginAsyncGeneratorFunction beginAsyncGeneratorFunction = 100; - EndAsyncGeneratorFunction endAsyncGeneratorFunction = 101; - BeginConstructor beginConstructor = 102; - EndConstructor endConstructor = 103; - Directive directive = 104; - Return return = 105; - Yield yield = 106; - YieldEach yieldEach = 107; - Await await = 108; - CallFunction callFunction = 109; - CallFunctionWithSpread callFunctionWithSpread = 110; - Construct construct = 111; - ConstructWithSpread constructWithSpread = 112; - CallMethod callMethod = 113; - CallMethodWithSpread callMethodWithSpread = 114; - CallComputedMethod callComputedMethod = 115; - CallComputedMethodWithSpread callComputedMethodWithSpread = 116; - UnaryOperation unaryOperation = 117; - BinaryOperation binaryOperation = 118; - TernaryOperation ternaryOperation = 119; - Update update = 120; - Dup dup = 121; - Reassign reassign = 122; - DestructArray destructArray = 123; - DestructArrayAndReassign destructArrayAndReassign = 124; - DestructObject destructObject = 125; - DestructObjectAndReassign destructObjectAndReassign = 126; - Compare compare = 127; - Eval eval = 128; - BeginWith beginWith = 129; - EndWith endWith = 130; - CallSuperConstructor callSuperConstructor = 131; - CallSuperMethod callSuperMethod = 132; - GetPrivateProperty getPrivateProperty = 133; - SetPrivateProperty setPrivateProperty = 134; - UpdatePrivateProperty updatePrivateProperty = 135; - CallPrivateMethod callPrivateMethod = 136; - GetSuperProperty getSuperProperty = 137; - SetSuperProperty setSuperProperty = 138; - GetComputedSuperProperty getComputedSuperProperty = 139; - SetComputedSuperProperty setComputedSuperProperty = 140; - UpdateSuperProperty updateSuperProperty = 141; - BeginIf beginIf = 142; - BeginElse beginElse = 143; - EndIf endIf = 144; - BeginWhileLoopHeader beginWhileLoopHeader = 145; - BeginWhileLoopBody beginWhileLoopBody = 146; - EndWhileLoop endWhileLoop = 147; - BeginDoWhileLoopBody beginDoWhileLoopBody = 148; - BeginDoWhileLoopHeader beginDoWhileLoopHeader = 149; - EndDoWhileLoop endDoWhileLoop = 150; - BeginForLoopInitializer beginForLoopInitializer = 151; - BeginForLoopCondition beginForLoopCondition = 152; - BeginForLoopAfterthought beginForLoopAfterthought = 153; - BeginForLoopBody beginForLoopBody = 154; - EndForLoop endForLoop = 155; - BeginForInLoop beginForInLoop = 156; - EndForInLoop endForInLoop = 157; - BeginForOfLoop beginForOfLoop = 158; - BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 159; - EndForOfLoop endForOfLoop = 160; - BeginRepeatLoop beginRepeatLoop = 161; - EndRepeatLoop endRepeatLoop = 162; - LoopBreak loopBreak = 163; - LoopContinue loopContinue = 164; - BeginTry beginTry = 165; - BeginCatch beginCatch = 166; - BeginFinally beginFinally = 167; - EndTryCatchFinally endTryCatchFinally = 168; - ThrowException throwException = 169; - BeginCodeString beginCodeString = 170; - EndCodeString endCodeString = 171; - BeginBlockStatement beginBlockStatement = 172; - EndBlockStatement endBlockStatement = 173; - BeginSwitch beginSwitch = 174; - BeginSwitchCase beginSwitchCase = 175; - BeginSwitchDefaultCase beginSwitchDefaultCase = 176; - EndSwitchCase endSwitchCase = 177; - EndSwitch endSwitch = 178; - SwitchBreak switchBreak = 179; - LoadNewTarget loadNewTarget = 180; - Print print = 181; - Explore explore = 182; - Probe probe = 183; - Fixup fixup = 184; - BeginWasmModule beginWasmModule = 185; - EndWasmModule endWasmModule = 186; - CreateWasmGlobal createWasmGlobal = 187; - CreateWasmMemory createWasmMemory = 188; - CreateWasmTable createWasmTable = 189; - CreateWasmJSTag createWasmJSTag = 190; - CreateWasmTag createWasmTag = 191; - WrapPromising wrapPromising = 192; - WrapSuspending wrapSuspending = 193; - BindMethod bindMethod = 194; - BindFunction bindFunction = 195; - Consti64 consti64 = 196; - Consti32 consti32 = 197; - Constf32 constf32 = 198; - Constf64 constf64 = 199; - WasmReturn wasmReturn = 200; - WasmJsCall wasmJsCall = 201; - Wasmi32CompareOp wasmi32CompareOp = 202; - Wasmi64CompareOp wasmi64CompareOp = 203; - Wasmf32CompareOp wasmf32CompareOp = 204; - Wasmf64CompareOp wasmf64CompareOp = 205; - Wasmi32EqualZero wasmi32EqualZero = 206; - Wasmi64EqualZero wasmi64EqualZero = 207; - Wasmi32BinOp wasmi32BinOp = 208; - Wasmi64BinOp wasmi64BinOp = 209; - Wasmi32UnOp wasmi32UnOp = 210; - Wasmi64UnOp wasmi64UnOp = 211; - Wasmf32BinOp wasmf32BinOp = 212; - Wasmf64BinOp wasmf64BinOp = 213; - Wasmf32UnOp wasmf32UnOp = 214; - Wasmf64UnOp wasmf64UnOp = 215; - WasmWrapi64Toi32 wasmWrapi64Toi32 = 216; - WasmTruncatef32Toi32 wasmTruncatef32Toi32 = 217; - WasmTruncatef64Toi32 wasmTruncatef64Toi32 = 218; - WasmExtendi32Toi64 wasmExtendi32Toi64 = 219; - WasmTruncatef32Toi64 wasmTruncatef32Toi64 = 220; - WasmTruncatef64Toi64 wasmTruncatef64Toi64 = 221; - WasmConverti32Tof32 wasmConverti32Tof32 = 222; - WasmConverti64Tof32 wasmConverti64Tof32 = 223; - WasmDemotef64Tof32 wasmDemotef64Tof32 = 224; - WasmConverti32Tof64 wasmConverti32Tof64 = 225; - WasmConverti64Tof64 wasmConverti64Tof64 = 226; - WasmPromotef32Tof64 wasmPromotef32Tof64 = 227; - WasmReinterpretf32Asi32 wasmReinterpretf32Asi32 = 228; - WasmReinterpretf64Asi64 wasmReinterpretf64Asi64 = 229; - WasmReinterpreti32Asf32 wasmReinterpreti32Asf32 = 230; - WasmReinterpreti64Asf64 wasmReinterpreti64Asf64 = 231; - WasmSignExtend8Intoi32 wasmSignExtend8Intoi32 = 232; - WasmSignExtend16Intoi32 wasmSignExtend16Intoi32 = 233; - WasmSignExtend8Intoi64 wasmSignExtend8Intoi64 = 234; - WasmSignExtend16Intoi64 wasmSignExtend16Intoi64 = 235; - WasmSignExtend32Intoi64 wasmSignExtend32Intoi64 = 236; - WasmTruncateSatf32Toi32 wasmTruncateSatf32Toi32 = 237; - WasmTruncateSatf64Toi32 wasmTruncateSatf64Toi32 = 238; - WasmTruncateSatf32Toi64 wasmTruncateSatf32Toi64 = 239; - WasmTruncateSatf64Toi64 wasmTruncateSatf64Toi64 = 240; - WasmReassign wasmReassign = 241; - WasmDefineGlobal wasmDefineGlobal = 242; - WasmDefineTable wasmDefineTable = 243; - WasmDefineMemory wasmDefineMemory = 244; - WasmDefineDataSegment wasmDefineDataSegment = 245; - WasmLoadGlobal wasmLoadGlobal = 246; - WasmStoreGlobal wasmStoreGlobal = 247; - WasmTableGet wasmTableGet = 248; - WasmTableSet wasmTableSet = 249; - WasmTableSize wasmTableSize = 250; - WasmTableGrow wasmTableGrow = 251; - WasmCallIndirect wasmCallIndirect = 252; - WasmCallDirect wasmCallDirect = 253; - WasmReturnCallDirect wasmReturnCallDirect = 254; - WasmReturnCallIndirect wasmReturnCallIndirect = 255; - WasmMemoryLoad wasmMemoryLoad = 256; - WasmMemoryStore wasmMemoryStore = 257; - WasmAtomicLoad wasmAtomicLoad = 258; - WasmAtomicStore wasmAtomicStore = 259; - WasmAtomicRMW wasmAtomicRMW = 260; - WasmAtomicCmpxchg wasmAtomicCmpxchg = 261; - WasmMemorySize wasmMemorySize = 262; - WasmMemoryGrow wasmMemoryGrow = 263; - WasmMemoryFill wasmMemoryFill = 264; - WasmMemoryInit wasmMemoryInit = 265; - WasmDropDataSegment wasmDropDataSegment = 266; - BeginWasmFunction beginWasmFunction = 267; - EndWasmFunction endWasmFunction = 268; - WasmBeginBlock wasmBeginBlock = 269; - WasmEndBlock wasmEndBlock = 270; - WasmBeginLoop wasmBeginLoop = 271; - WasmEndLoop wasmEndLoop = 272; - WasmBranch wasmBranch = 273; - WasmBranchIf wasmBranchIf = 274; - WasmBranchTable wasmBranchTable = 275; - WasmNop wasmNop = 276; - WasmBeginIf wasmBeginIf = 277; - WasmBeginElse wasmBeginElse = 278; - WasmEndIf wasmEndIf = 279; - WasmBeginTryTable wasmBeginTryTable = 280; - WasmEndTryTable wasmEndTryTable = 281; - WasmBeginTry wasmBeginTry = 282; - WasmBeginCatchAll wasmBeginCatchAll = 283; - WasmBeginCatch wasmBeginCatch = 284; - WasmEndTry wasmEndTry = 285; - WasmBeginTryDelegate wasmBeginTryDelegate = 286; - WasmEndTryDelegate wasmEndTryDelegate = 287; - WasmThrow wasmThrow = 288; - WasmRethrow wasmRethrow = 289; - WasmThrowRef wasmThrowRef = 290; - WasmDefineTag wasmDefineTag = 291; - ConstSimd128 constSimd128 = 292; - WasmSimd128Compare wasmSimd128Compare = 293; - WasmSimd128IntegerUnOp wasmSimd128IntegerUnOp = 294; - WasmSimd128IntegerBinOp wasmSimd128IntegerBinOp = 295; - WasmSimd128IntegerTernaryOp wasmSimd128IntegerTernaryOp = 296; - WasmSimd128FloatUnOp wasmSimd128FloatUnOp = 297; - WasmSimd128FloatBinOp wasmSimd128FloatBinOp = 298; - WasmSimd128FloatTernaryOp wasmSimd128FloatTernaryOp = 299; - WasmSimdSplat wasmSimdSplat = 300; - WasmSimdExtractLane wasmSimdExtractLane = 301; - WasmSimdReplaceLane wasmSimdReplaceLane = 302; - WasmSimdStoreLane wasmSimdStoreLane = 303; - WasmSimdLoadLane wasmSimdLoadLane = 304; - WasmSimdLoad wasmSimdLoad = 305; - WasmUnreachable wasmUnreachable = 306; - WasmSelect wasmSelect = 307; - WasmBeginTypeGroup wasmBeginTypeGroup = 308; - WasmEndTypeGroup wasmEndTypeGroup = 309; - WasmDefineArrayType wasmDefineArrayType = 310; - WasmDefineStructType wasmDefineStructType = 311; - WasmDefineForwardOrSelfReference wasmDefineForwardOrSelfReference = 312; - WasmResolveForwardReference wasmResolveForwardReference = 313; - WasmArrayNewFixed wasmArrayNewFixed = 314; - WasmArrayNewDefault wasmArrayNewDefault = 315; - WasmArrayLen wasmArrayLen = 316; - WasmArrayGet wasmArrayGet = 317; - WasmArraySet wasmArraySet = 318; - WasmStructNewDefault wasmStructNewDefault = 319; - WasmStructGet wasmStructGet = 320; - WasmStructSet wasmStructSet = 321; - WasmRefNull wasmRefNull = 322; - WasmRefIsNull wasmRefIsNull = 323; - WasmRefI31 wasmRefI31 = 324; - WasmI31Get wasmI31Get = 325; - WasmAnyConvertExtern wasmAnyConvertExtern = 326; - WasmExternConvertAny wasmExternConvertAny = 327; - WasmMemoryCopy wasmMemoryCopy = 328; - WasmDefineElementSegment wasmDefineElementSegment = 329; - WasmTableInit wasmTableInit = 330; - WasmDropElementSegment wasmDropElementSegment = 331; - WasmTableCopy wasmTableCopy = 332; - WasmDefineSignatureType wasmDefineSignatureType = 333; - CreateNamedDisposableVariable createNamedDisposableVariable = 334; - CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 335; - WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 336; - WasmStructNew wasmStructNew = 337; - WasmRefEq wasmRefEq = 338; - WasmRefTest wasmRefTest = 339; - WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 340; - WasmRefCast wasmRefCast = 341; + ClassAddProperty classAddProperty = 35; + ClassAddElement classAddElement = 36; + ClassAddComputedProperty classAddComputedProperty = 37; + BeginClassMethod beginClassMethod = 38; + EndClassMethod endClassMethod = 39; + BeginClassComputedMethod beginClassComputedMethod = 40; + EndClassComputedMethod endClassComputedMethod = 41; + BeginClassGetter beginClassGetter = 42; + EndClassGetter endClassGetter = 43; + BeginClassSetter beginClassSetter = 44; + EndClassSetter endClassSetter = 45; + BeginClassStaticInitializer beginClassStaticInitializer = 46; + EndClassStaticInitializer endClassStaticInitializer = 47; + ClassAddPrivateProperty classAddPrivateProperty = 48; + BeginClassPrivateMethod beginClassPrivateMethod = 49; + EndClassPrivateMethod endClassPrivateMethod = 50; + EndClassDefinition endClassDefinition = 51; + CreateArray createArray = 52; + CreateIntArray createIntArray = 53; + CreateFloatArray createFloatArray = 54; + CreateArrayWithSpread createArrayWithSpread = 55; + CreateTemplateString createTemplateString = 56; + GetProperty getProperty = 57; + SetProperty setProperty = 58; + UpdateProperty updateProperty = 59; + DeleteProperty deleteProperty = 60; + ConfigureProperty configureProperty = 61; + GetElement getElement = 62; + SetElement setElement = 63; + UpdateElement updateElement = 64; + DeleteElement deleteElement = 65; + ConfigureElement configureElement = 66; + GetComputedProperty getComputedProperty = 67; + SetComputedProperty setComputedProperty = 68; + UpdateComputedProperty updateComputedProperty = 69; + DeleteComputedProperty deleteComputedProperty = 70; + ConfigureComputedProperty configureComputedProperty = 71; + TypeOf typeOf = 72; + Void void = 73; + TestInstanceOf testInstanceOf = 74; + TestIn testIn = 75; + BeginPlainFunction beginPlainFunction = 76; + EndPlainFunction endPlainFunction = 77; + BeginArrowFunction beginArrowFunction = 78; + EndArrowFunction endArrowFunction = 79; + BeginGeneratorFunction beginGeneratorFunction = 80; + EndGeneratorFunction endGeneratorFunction = 81; + BeginAsyncFunction beginAsyncFunction = 82; + EndAsyncFunction endAsyncFunction = 83; + BeginAsyncArrowFunction beginAsyncArrowFunction = 84; + EndAsyncArrowFunction endAsyncArrowFunction = 85; + BeginAsyncGeneratorFunction beginAsyncGeneratorFunction = 86; + EndAsyncGeneratorFunction endAsyncGeneratorFunction = 87; + BeginConstructor beginConstructor = 88; + EndConstructor endConstructor = 89; + Directive directive = 90; + Return return = 91; + Yield yield = 92; + YieldEach yieldEach = 93; + Await await = 94; + CallFunction callFunction = 95; + CallFunctionWithSpread callFunctionWithSpread = 96; + Construct construct = 97; + ConstructWithSpread constructWithSpread = 98; + CallMethod callMethod = 99; + CallMethodWithSpread callMethodWithSpread = 100; + CallComputedMethod callComputedMethod = 101; + CallComputedMethodWithSpread callComputedMethodWithSpread = 102; + UnaryOperation unaryOperation = 103; + BinaryOperation binaryOperation = 104; + TernaryOperation ternaryOperation = 105; + Update update = 106; + Dup dup = 107; + Reassign reassign = 108; + DestructArray destructArray = 109; + DestructArrayAndReassign destructArrayAndReassign = 110; + DestructObject destructObject = 111; + DestructObjectAndReassign destructObjectAndReassign = 112; + Compare compare = 113; + Eval eval = 114; + BeginWith beginWith = 115; + EndWith endWith = 116; + CallSuperConstructor callSuperConstructor = 117; + CallSuperMethod callSuperMethod = 118; + GetPrivateProperty getPrivateProperty = 119; + SetPrivateProperty setPrivateProperty = 120; + UpdatePrivateProperty updatePrivateProperty = 121; + CallPrivateMethod callPrivateMethod = 122; + GetSuperProperty getSuperProperty = 123; + SetSuperProperty setSuperProperty = 124; + GetComputedSuperProperty getComputedSuperProperty = 125; + SetComputedSuperProperty setComputedSuperProperty = 126; + UpdateSuperProperty updateSuperProperty = 127; + BeginIf beginIf = 128; + BeginElse beginElse = 129; + EndIf endIf = 130; + BeginWhileLoopHeader beginWhileLoopHeader = 131; + BeginWhileLoopBody beginWhileLoopBody = 132; + EndWhileLoop endWhileLoop = 133; + BeginDoWhileLoopBody beginDoWhileLoopBody = 134; + BeginDoWhileLoopHeader beginDoWhileLoopHeader = 135; + EndDoWhileLoop endDoWhileLoop = 136; + BeginForLoopInitializer beginForLoopInitializer = 137; + BeginForLoopCondition beginForLoopCondition = 138; + BeginForLoopAfterthought beginForLoopAfterthought = 139; + BeginForLoopBody beginForLoopBody = 140; + EndForLoop endForLoop = 141; + BeginForInLoop beginForInLoop = 142; + EndForInLoop endForInLoop = 143; + BeginForOfLoop beginForOfLoop = 144; + BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 145; + EndForOfLoop endForOfLoop = 146; + BeginRepeatLoop beginRepeatLoop = 147; + EndRepeatLoop endRepeatLoop = 148; + LoopBreak loopBreak = 149; + LoopContinue loopContinue = 150; + BeginTry beginTry = 151; + BeginCatch beginCatch = 152; + BeginFinally beginFinally = 153; + EndTryCatchFinally endTryCatchFinally = 154; + ThrowException throwException = 155; + BeginCodeString beginCodeString = 156; + EndCodeString endCodeString = 157; + BeginBlockStatement beginBlockStatement = 158; + EndBlockStatement endBlockStatement = 159; + BeginSwitch beginSwitch = 160; + BeginSwitchCase beginSwitchCase = 161; + BeginSwitchDefaultCase beginSwitchDefaultCase = 162; + EndSwitchCase endSwitchCase = 163; + EndSwitch endSwitch = 164; + SwitchBreak switchBreak = 165; + LoadNewTarget loadNewTarget = 166; + Print print = 167; + Explore explore = 168; + Probe probe = 169; + Fixup fixup = 170; + BeginWasmModule beginWasmModule = 171; + EndWasmModule endWasmModule = 172; + CreateWasmGlobal createWasmGlobal = 173; + CreateWasmMemory createWasmMemory = 174; + CreateWasmTable createWasmTable = 175; + CreateWasmJSTag createWasmJSTag = 176; + CreateWasmTag createWasmTag = 177; + WrapPromising wrapPromising = 178; + WrapSuspending wrapSuspending = 179; + BindMethod bindMethod = 180; + BindFunction bindFunction = 181; + Consti64 consti64 = 182; + Consti32 consti32 = 183; + Constf32 constf32 = 184; + Constf64 constf64 = 185; + WasmReturn wasmReturn = 186; + WasmJsCall wasmJsCall = 187; + Wasmi32CompareOp wasmi32CompareOp = 188; + Wasmi64CompareOp wasmi64CompareOp = 189; + Wasmf32CompareOp wasmf32CompareOp = 190; + Wasmf64CompareOp wasmf64CompareOp = 191; + Wasmi32EqualZero wasmi32EqualZero = 192; + Wasmi64EqualZero wasmi64EqualZero = 193; + Wasmi32BinOp wasmi32BinOp = 194; + Wasmi64BinOp wasmi64BinOp = 195; + Wasmi32UnOp wasmi32UnOp = 196; + Wasmi64UnOp wasmi64UnOp = 197; + Wasmf32BinOp wasmf32BinOp = 198; + Wasmf64BinOp wasmf64BinOp = 199; + Wasmf32UnOp wasmf32UnOp = 200; + Wasmf64UnOp wasmf64UnOp = 201; + WasmWrapi64Toi32 wasmWrapi64Toi32 = 202; + WasmTruncatef32Toi32 wasmTruncatef32Toi32 = 203; + WasmTruncatef64Toi32 wasmTruncatef64Toi32 = 204; + WasmExtendi32Toi64 wasmExtendi32Toi64 = 205; + WasmTruncatef32Toi64 wasmTruncatef32Toi64 = 206; + WasmTruncatef64Toi64 wasmTruncatef64Toi64 = 207; + WasmConverti32Tof32 wasmConverti32Tof32 = 208; + WasmConverti64Tof32 wasmConverti64Tof32 = 209; + WasmDemotef64Tof32 wasmDemotef64Tof32 = 210; + WasmConverti32Tof64 wasmConverti32Tof64 = 211; + WasmConverti64Tof64 wasmConverti64Tof64 = 212; + WasmPromotef32Tof64 wasmPromotef32Tof64 = 213; + WasmReinterpretf32Asi32 wasmReinterpretf32Asi32 = 214; + WasmReinterpretf64Asi64 wasmReinterpretf64Asi64 = 215; + WasmReinterpreti32Asf32 wasmReinterpreti32Asf32 = 216; + WasmReinterpreti64Asf64 wasmReinterpreti64Asf64 = 217; + WasmSignExtend8Intoi32 wasmSignExtend8Intoi32 = 218; + WasmSignExtend16Intoi32 wasmSignExtend16Intoi32 = 219; + WasmSignExtend8Intoi64 wasmSignExtend8Intoi64 = 220; + WasmSignExtend16Intoi64 wasmSignExtend16Intoi64 = 221; + WasmSignExtend32Intoi64 wasmSignExtend32Intoi64 = 222; + WasmTruncateSatf32Toi32 wasmTruncateSatf32Toi32 = 223; + WasmTruncateSatf64Toi32 wasmTruncateSatf64Toi32 = 224; + WasmTruncateSatf32Toi64 wasmTruncateSatf32Toi64 = 225; + WasmTruncateSatf64Toi64 wasmTruncateSatf64Toi64 = 226; + WasmReassign wasmReassign = 227; + WasmDefineGlobal wasmDefineGlobal = 228; + WasmDefineTable wasmDefineTable = 229; + WasmDefineMemory wasmDefineMemory = 230; + WasmDefineDataSegment wasmDefineDataSegment = 231; + WasmLoadGlobal wasmLoadGlobal = 232; + WasmStoreGlobal wasmStoreGlobal = 233; + WasmTableGet wasmTableGet = 234; + WasmTableSet wasmTableSet = 235; + WasmTableSize wasmTableSize = 236; + WasmTableGrow wasmTableGrow = 237; + WasmCallIndirect wasmCallIndirect = 238; + WasmCallDirect wasmCallDirect = 239; + WasmReturnCallDirect wasmReturnCallDirect = 240; + WasmReturnCallIndirect wasmReturnCallIndirect = 241; + WasmMemoryLoad wasmMemoryLoad = 242; + WasmMemoryStore wasmMemoryStore = 243; + WasmAtomicLoad wasmAtomicLoad = 244; + WasmAtomicStore wasmAtomicStore = 245; + WasmAtomicRMW wasmAtomicRMW = 246; + WasmAtomicCmpxchg wasmAtomicCmpxchg = 247; + WasmMemorySize wasmMemorySize = 248; + WasmMemoryGrow wasmMemoryGrow = 249; + WasmMemoryFill wasmMemoryFill = 250; + WasmMemoryInit wasmMemoryInit = 251; + WasmDropDataSegment wasmDropDataSegment = 252; + BeginWasmFunction beginWasmFunction = 253; + EndWasmFunction endWasmFunction = 254; + WasmBeginBlock wasmBeginBlock = 255; + WasmEndBlock wasmEndBlock = 256; + WasmBeginLoop wasmBeginLoop = 257; + WasmEndLoop wasmEndLoop = 258; + WasmBranch wasmBranch = 259; + WasmBranchIf wasmBranchIf = 260; + WasmBranchTable wasmBranchTable = 261; + WasmNop wasmNop = 262; + WasmBeginIf wasmBeginIf = 263; + WasmBeginElse wasmBeginElse = 264; + WasmEndIf wasmEndIf = 265; + WasmBeginTryTable wasmBeginTryTable = 266; + WasmEndTryTable wasmEndTryTable = 267; + WasmBeginTry wasmBeginTry = 268; + WasmBeginCatchAll wasmBeginCatchAll = 269; + WasmBeginCatch wasmBeginCatch = 270; + WasmEndTry wasmEndTry = 271; + WasmBeginTryDelegate wasmBeginTryDelegate = 272; + WasmEndTryDelegate wasmEndTryDelegate = 273; + WasmThrow wasmThrow = 274; + WasmRethrow wasmRethrow = 275; + WasmThrowRef wasmThrowRef = 276; + WasmDefineTag wasmDefineTag = 277; + ConstSimd128 constSimd128 = 278; + WasmSimd128Compare wasmSimd128Compare = 279; + WasmSimd128IntegerUnOp wasmSimd128IntegerUnOp = 280; + WasmSimd128IntegerBinOp wasmSimd128IntegerBinOp = 281; + WasmSimd128IntegerTernaryOp wasmSimd128IntegerTernaryOp = 282; + WasmSimd128FloatUnOp wasmSimd128FloatUnOp = 283; + WasmSimd128FloatBinOp wasmSimd128FloatBinOp = 284; + WasmSimd128FloatTernaryOp wasmSimd128FloatTernaryOp = 285; + WasmSimdSplat wasmSimdSplat = 286; + WasmSimdExtractLane wasmSimdExtractLane = 287; + WasmSimdReplaceLane wasmSimdReplaceLane = 288; + WasmSimdStoreLane wasmSimdStoreLane = 289; + WasmSimdLoadLane wasmSimdLoadLane = 290; + WasmSimdLoad wasmSimdLoad = 291; + WasmUnreachable wasmUnreachable = 292; + WasmSelect wasmSelect = 293; + WasmBeginTypeGroup wasmBeginTypeGroup = 294; + WasmEndTypeGroup wasmEndTypeGroup = 295; + WasmDefineArrayType wasmDefineArrayType = 296; + WasmDefineStructType wasmDefineStructType = 297; + WasmDefineForwardOrSelfReference wasmDefineForwardOrSelfReference = 298; + WasmResolveForwardReference wasmResolveForwardReference = 299; + WasmArrayNewFixed wasmArrayNewFixed = 300; + WasmArrayNewDefault wasmArrayNewDefault = 301; + WasmArrayLen wasmArrayLen = 302; + WasmArrayGet wasmArrayGet = 303; + WasmArraySet wasmArraySet = 304; + WasmStructNewDefault wasmStructNewDefault = 305; + WasmStructGet wasmStructGet = 306; + WasmStructSet wasmStructSet = 307; + WasmRefNull wasmRefNull = 308; + WasmRefIsNull wasmRefIsNull = 309; + WasmRefI31 wasmRefI31 = 310; + WasmI31Get wasmI31Get = 311; + WasmAnyConvertExtern wasmAnyConvertExtern = 312; + WasmExternConvertAny wasmExternConvertAny = 313; + WasmMemoryCopy wasmMemoryCopy = 314; + WasmDefineElementSegment wasmDefineElementSegment = 315; + WasmTableInit wasmTableInit = 316; + WasmDropElementSegment wasmDropElementSegment = 317; + WasmTableCopy wasmTableCopy = 318; + WasmDefineSignatureType wasmDefineSignatureType = 319; + CreateNamedDisposableVariable createNamedDisposableVariable = 320; + CreateNamedAsyncDisposableVariable createNamedAsyncDisposableVariable = 321; + WasmDefineAdHocSignatureType wasmDefineAdHocSignatureType = 322; + WasmStructNew wasmStructNew = 323; + WasmRefEq wasmRefEq = 324; + WasmRefTest wasmRefTest = 325; + WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 326; + WasmRefCast wasmRefCast = 327; } } From 7e5724ccc4551bf54773cb14450dc6f65c01f6ae Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 16:25:55 +0100 Subject: [PATCH 191/234] [wasm] Simplify Table.get/set The TableType will need to be adapted for tracking wasm-gc signatures. I just couldn't find a good reason why we'd need to store the TableType on Table.get and Table.set? Bug: 445356784 Change-Id: Ia115d287b27cc18f52a48ddce25b897f1a19b293 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123736 Reviewed-by: Manos Koukoutos Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 34 ++--- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 7 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 13 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 123 +----------------- Sources/Fuzzilli/Protobuf/operations.proto | 9 -- 6 files changed, 22 insertions(+), 168 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index aea8a1c5f..73b2d8258 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3747,14 +3747,14 @@ public class ProgramBuilder { public func wasmTableGet(tableRef: Variable, idx: Variable) -> Variable { let tableType = b.type(of: tableRef) let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGet(tableType: tableType), withInputs: [tableRef, idx], types: [tableType, offsetType]).output + return b.emit(WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType]).output } public func wasmTableSet(tableRef: Variable, idx: Variable, to value: Variable) { let tableType = b.type(of: tableRef) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableSet(tableType: tableType), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) + b.emit(WasmTableSet(), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) } @discardableResult diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 2ea23a453..ccf98f9f6 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1258,24 +1258,10 @@ extension Instruction: ProtobufConvertible { $0.wasmStoreGlobal = Fuzzilli_Protobuf_WasmStoreGlobal.with { $0.globalType = ILTypeToWasmTypeEnum(op.globalType) } - case .wasmTableGet(let op): - $0.wasmTableGet = Fuzzilli_Protobuf_WasmTableGet.with { - $0.elementType = ILTypeToWasmTypeEnum(op.tableType.elementType) - $0.minSize = Int64(op.tableType.limits.min) - if let max = op.tableType.limits.max { - $0.maxSize = Int64(max) - } - $0.isTable64 = op.tableType.isTable64 - } - case .wasmTableSet(let op): - $0.wasmTableSet = Fuzzilli_Protobuf_WasmTableSet.with { - $0.elementType = ILTypeToWasmTypeEnum(op.tableType.elementType) - $0.minSize = Int64(op.tableType.limits.min) - if let max = op.tableType.limits.max { - $0.maxSize = Int64(max) - } - $0.isTable64 = op.tableType.isTable64 - } + case .wasmTableGet(_): + $0.wasmTableGet = Fuzzilli_Protobuf_WasmTableGet() + case .wasmTableSet(_): + $0.wasmTableSet = Fuzzilli_Protobuf_WasmTableSet() case .wasmCallIndirect(let op): $0.wasmCallIndirect = Fuzzilli_Protobuf_WasmCallIndirect.with { $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) @@ -2340,14 +2326,10 @@ extension Instruction: ProtobufConvertible { op = WasmLoadGlobal(globalType: WasmTypeEnumToILType(p.globalType)) case .wasmStoreGlobal(let p): op = WasmStoreGlobal(globalType: WasmTypeEnumToILType(p.globalType)) - case .wasmTableGet(let p): - op = WasmTableGet(tableType: .wasmTable(wasmTableType: - WasmTableType(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), isTable64: p.isTable64, knownEntries: []))) - case .wasmTableSet(let p): - op = WasmTableSet(tableType: .wasmTable(wasmTableType: - WasmTableType(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), isTable64: p.isTable64, knownEntries: []))) + case .wasmTableGet(_): + op = WasmTableGet() + case .wasmTableSet(_): + op = WasmTableSet() case .wasmCallIndirect(let p): let parameters = p.parameterTypes.map(WasmTypeEnumToILType) let outputs = p.outputTypes.map(WasmTypeEnumToILType) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 584572320..331599b2d 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -768,10 +768,11 @@ public struct JSTyper: Analyzer { case .wasmStoreGlobal(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - case .wasmTableGet(let op): + case .wasmTableGet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - setType(of: instr.output, to: op.tableType.elementType) + let tableType = type(of: instr.input(0)) + dynamicObjectGroupManager.addWasmTable(withType: tableType, forDefinition: definingInstruction, forVariable: instr.input(0)) + setType(of: instr.output, to: tableType.wasmTableType!.elementType) case .wasmTableSet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 55d3b16c0..f707d1ce9 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -912,12 +912,7 @@ final class WasmStoreGlobal: WasmOperation { final class WasmTableGet: WasmOperation { override var opcode: Opcode { .wasmTableGet(self) } - let tableType: WasmTableType - - init(tableType: ILType) { - assert(tableType.isWasmTableType) - self.tableType = tableType.wasmTableType! - + init() { super.init(numInputs: 2, numOutputs: 1, requiredContext: [.wasmFunction]) } } @@ -925,11 +920,7 @@ final class WasmTableGet: WasmOperation { final class WasmTableSet: WasmOperation { override var opcode: Opcode { .wasmTableSet(self) } - let tableType: WasmTableType - - init(tableType: ILType) { - assert(tableType.isWasmTableType) - self.tableType = tableType.wasmTableType! + init() { super.init(numInputs: 3, requiredContext: [.wasmFunction]) } } diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 1ae44b73e..90e194e63 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -4754,40 +4754,14 @@ public struct Fuzzilli_Protobuf_WasmStoreGlobal: Sendable { fileprivate var _globalType: Fuzzilli_Protobuf_WasmILType? = nil } -/// WasmTableGet and WasmTableSet need a WasmTableType as input. public struct Fuzzilli_Protobuf_WasmTableGet: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var elementType: Fuzzilli_Protobuf_WasmILType { - get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {self._elementType != nil} - /// Clears the value of `elementType`. Subsequent reads from it will return its default value. - public mutating func clearElementType() {self._elementType = nil} - - public var minSize: Int64 = 0 - - public var maxSize: Int64 { - get {_maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {self._maxSize != nil} - /// Clears the value of `maxSize`. Subsequent reads from it will return its default value. - public mutating func clearMaxSize() {self._maxSize = nil} - - public var isTable64: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _elementType: Fuzzilli_Protobuf_WasmILType? = nil - fileprivate var _maxSize: Int64? = nil } public struct Fuzzilli_Protobuf_WasmTableSet: Sendable { @@ -4795,34 +4769,9 @@ public struct Fuzzilli_Protobuf_WasmTableSet: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var elementType: Fuzzilli_Protobuf_WasmILType { - get {_elementType ?? Fuzzilli_Protobuf_WasmILType()} - set {_elementType = newValue} - } - /// Returns true if `elementType` has been explicitly set. - public var hasElementType: Bool {self._elementType != nil} - /// Clears the value of `elementType`. Subsequent reads from it will return its default value. - public mutating func clearElementType() {self._elementType = nil} - - public var minSize: Int64 = 0 - - public var maxSize: Int64 { - get {_maxSize ?? 0} - set {_maxSize = newValue} - } - /// Returns true if `maxSize` has been explicitly set. - public var hasMaxSize: Bool {self._maxSize != nil} - /// Clears the value of `maxSize`. Subsequent reads from it will return its default value. - public mutating func clearMaxSize() {self._maxSize = nil} - - public var isTable64: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - - fileprivate var _elementType: Fuzzilli_Protobuf_WasmILType? = nil - fileprivate var _maxSize: Int64? = nil } public struct Fuzzilli_Protobuf_WasmTableSize: Sendable { @@ -12732,48 +12681,18 @@ extension Fuzzilli_Protobuf_WasmStoreGlobal: SwiftProtobuf.Message, SwiftProtobu extension Fuzzilli_Protobuf_WasmTableGet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmTableGet" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}elementType\0\u{1}minSize\0\u{1}maxSize\0\u{1}isTable64\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._elementType) }() - case 2: try { try decoder.decodeSingularInt64Field(value: &self.minSize) }() - case 3: try { try decoder.decodeSingularInt64Field(value: &self._maxSize) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.isTable64) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._elementType { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if self.minSize != 0 { - try visitor.visitSingularInt64Field(value: self.minSize, fieldNumber: 2) - } - try { if let v = self._maxSize { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 3) - } }() - if self.isTable64 != false { - try visitor.visitSingularBoolField(value: self.isTable64, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmTableGet, rhs: Fuzzilli_Protobuf_WasmTableGet) -> Bool { - if lhs._elementType != rhs._elementType {return false} - if lhs.minSize != rhs.minSize {return false} - if lhs._maxSize != rhs._maxSize {return false} - if lhs.isTable64 != rhs.isTable64 {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -12781,48 +12700,18 @@ extension Fuzzilli_Protobuf_WasmTableGet: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_WasmTableSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".WasmTableSet" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}elementType\0\u{1}minSize\0\u{1}maxSize\0\u{1}isTable64\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._elementType) }() - case 2: try { try decoder.decodeSingularInt64Field(value: &self.minSize) }() - case 3: try { try decoder.decodeSingularInt64Field(value: &self._maxSize) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.isTable64) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._elementType { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if self.minSize != 0 { - try visitor.visitSingularInt64Field(value: self.minSize, fieldNumber: 2) - } - try { if let v = self._maxSize { - try visitor.visitSingularInt64Field(value: v, fieldNumber: 3) - } }() - if self.isTable64 != false { - try visitor.visitSingularBoolField(value: self.isTable64, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_WasmTableSet, rhs: Fuzzilli_Protobuf_WasmTableSet) -> Bool { - if lhs._elementType != rhs._elementType {return false} - if lhs.minSize != rhs.minSize {return false} - if lhs._maxSize != rhs._maxSize {return false} - if lhs.isTable64 != rhs.isTable64 {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 1be3ee744..4699a27f0 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1097,19 +1097,10 @@ message WasmStoreGlobal { WasmILType globalType = 2; } -// WasmTableGet and WasmTableSet need a WasmTableType as input. message WasmTableGet { - WasmILType elementType = 1; - int64 minSize = 2; - optional int64 maxSize = 3; - bool isTable64 = 4; } message WasmTableSet { - WasmILType elementType = 1; - int64 minSize = 2; - optional int64 maxSize = 3; - bool isTable64 = 4; } message WasmTableSize { From 2ae06c9a1917ddacaf09cef5bbc6b7ccbfe4e8c1 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 19:12:24 +0100 Subject: [PATCH 192/234] [wasm] Don't emit empty module sections Change-Id: I99bc88a3cefdd5d4cbaf645b10e1cdcd66138a52 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123977 Commit-Queue: Manos Koukoutos Reviewed-by: Manos Koukoutos Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Lifting/WasmLifter.swift | 72 +++++++++++++++-------- Tests/FuzzilliTests/LifterTest.swift | 18 ++++++ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 5a3f391dc..c3e880992 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -622,10 +622,6 @@ public class WasmLifter { } private func buildTypeSection() throws { - self.bytecode += [WasmSection.type.rawValue] - - var temp = Data() - // Collect all signatures of imported functions, suspendable objects or tags. // See importAnalysis for more details. for signature in self.exports.compactMap({ $0.getImport()?.signature }) { @@ -638,7 +634,12 @@ public class WasmLifter { } let typeCount = self.signatures.count + typeGroups.count - temp += Leb128.unsignedEncode(typeCount) + if typeCount == 0 { + return + } + + self.bytecode += [WasmSection.type.rawValue] + var temp = Leb128.unsignedEncode(typeCount) // TODO(mliedtke): Integrate this with the whole signature mechanism as // these signatures could contain wasm-gc types. @@ -791,11 +792,16 @@ public class WasmLifter { } private func buildFunctionSection() throws { + let functionCount = self.exports.count { $0.isFunction } + if functionCount == 0 { + return + } + self.bytecode += [WasmSection.function.rawValue] // The number of functions we have, as this is a vector of type idxs. // TODO(cffsmith): functions can share type indices. This could be an optimization later on. - var temp = Leb128.unsignedEncode(self.exports.count { $0.isFunction }) + var temp = Leb128.unsignedEncode(functionCount) for case let .function(functionInfo) in self.exports { temp.append(Leb128.unsignedEncode(try getSignatureIndex(functionInfo!.signature))) @@ -814,9 +820,14 @@ public class WasmLifter { } private func buildTableSection() throws { + let tableCount = self.exports.count { $0.isTable } + if tableCount == 0 { + return + } + self.bytecode += [WasmSection.table.rawValue] - var temp = Leb128.unsignedEncode(self.exports.count { $0.isTable }) + var temp = Leb128.unsignedEncode(tableCount) for case let .table(instruction) in self.exports { let op = instruction!.op as! WasmDefineTable @@ -922,9 +933,13 @@ public class WasmLifter { } private func buildCodeSection(_ instructions: Code) throws { + let functionCount = self.exports.count { $0.isFunction } + if functionCount == 0 { + return + } + // Build the contents of the section - var temp = Data() - temp += Leb128.unsignedEncode(self.exports.count { $0.isFunction }) + var temp = Leb128.unsignedEncode(functionCount) var functionBranchHints = [Data]() @@ -1006,6 +1021,10 @@ public class WasmLifter { } private func buildDataSection() throws { + if self.dataSegments.isEmpty { + return + } + self.bytecode += [WasmSection.data.rawValue] var temp = Data() @@ -1030,11 +1049,12 @@ public class WasmLifter { } private func buildDataCountSection() throws { - self.bytecode += [WasmSection.datacount.rawValue] - - var temp = Data() - temp += Leb128.unsignedEncode(self.dataSegments.count) + if self.dataSegments.isEmpty { + return + } + self.bytecode += [WasmSection.datacount.rawValue] + let temp = Leb128.unsignedEncode(self.dataSegments.count) self.bytecode.append(Leb128.unsignedEncode(temp.count)) self.bytecode.append(temp) @@ -1047,11 +1067,13 @@ public class WasmLifter { } private func buildGlobalSection() throws { - self.bytecode += [WasmSection.global.rawValue] - - var temp = Data() + let globalCount = self.exports.count { $0.isGlobal } + if globalCount == 0 { + return + } - temp += Leb128.unsignedEncode(self.exports.count { $0.isGlobal }) + self.bytecode += [WasmSection.global.rawValue] + var temp = Leb128.unsignedEncode(globalCount) // TODO: in the future this should maybe be a context that allows instructions? Such that we can fuzz this expression as well? for case let .global(instruction) in self.exports { @@ -1102,13 +1124,13 @@ public class WasmLifter { } private func buildMemorySection() { - self.bytecode += [WasmSection.memory.rawValue] - - var temp = Data() + let memoryCount = self.exports.count { $0.isMemory } + if memoryCount == 0 { + return + } - // The amount of memories we have, per standard this can currently only be one, either defined or imported - // https://webassembly.github.io/spec/core/syntax/modules.html#memories - temp += Leb128.unsignedEncode(self.exports.count { $0.isMemory }) + self.bytecode += [WasmSection.memory.rawValue] + var temp = Leb128.unsignedEncode(memoryCount) for case let .memory(instruction) in self.exports { let type = typer.type(of: instruction!.output) @@ -1164,6 +1186,10 @@ public class WasmLifter { // Export all imports and defined things by default. private func buildExportedSection() throws { + if self.exports.isEmpty { + return + } + self.bytecode += [WasmSection.export.rawValue] var temp = Data() diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 9ab5912db..8f3b5e6fc 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3897,4 +3897,22 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testEmptyWasmModule() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + b.buildWasmModule {_ in} + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + // An empty Wasm module should only contain the needed prefix but no empty sections. + let expected = """ + const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ]))); + + """ + + XCTAssertEqual(actual, expected) + } } From 6bac790345a42dc2b6ae295b13798d8641ab9410 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 20 Mar 2026 18:30:44 +0100 Subject: [PATCH 193/234] [wasm] Add code generator producing an exnref The WasmThrowRefGenerator requires an exnref as an input. Without having a generator that produces it, it isn't very likely that there is an exnref available in the current program, so the generator cannot be run in most cases. Registering a generator producing that exnref (if a tag is available) helps significantly. Change-Id: Idbd9337f5a7339d58fe1f76e264569907f7081ce Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9123976 Auto-Submit: Matthias Liedtke Reviewed-by: Manos Koukoutos Commit-Queue: Manos Koukoutos --- .../CodeGen/CodeGeneratorWeights.swift | 3 +++ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 24 +++++++++++++++++++ Tests/FuzzilliTests/ProgramBuilderTest.swift | 1 + 3 files changed, 28 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 32540cfc0..aa026f062 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -324,6 +324,9 @@ public let codeGeneratorWeights = [ "WasmLegacyTryDelegateGenerator": 8, "WasmThrowGenerator": 2, "WasmLegacyRethrowGenerator": 10, + // This generator is mostly just there, so that the WasmThrowRefGenerator + // can create an exnref on demand (if a wasm tag is present). + "WasmCreateExnRefGenerator": 1, "WasmThrowRefGenerator": 6, "WasmBranchGenerator": 6, "WasmBranchIfGenerator": 6, diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 5077ac26a..b6050f5ea 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1620,6 +1620,30 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLegacyRethrow(exception) }, + CodeGenerator( + "WasmCreateExnRefGenerator", inContext: .single(.wasmFunction), + inputs: .required(.object(ofGroup: "WasmTag")), + produces: [.wasmExnRef()] + ) { b, tag in + let function = b.currentWasmModule.currentWasmFunction + let tagType = b.type(of: tag).wasmTagType! + guard !tagType.isJSTag else { + // We can't throw a JSTag, so simply create a null value. + function.wasmRefNull(type: .wasmExnRef()) + return + } + // Create a try-catch throwing and catching a tag producing an exnref as + // a result. + function.wasmBuildBlockWithResults(with: [] => (tagType.parameters + [.wasmExnRef()]), args: []) { label, _ in + let args = tagType.parameters.map(function.findOrGenerateWasmVar) + function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { _, _ in + function.WasmBuildThrow(tag: tag, inputs: args) + return [] + } + return args + [function.wasmRefNull(type: .wasmExnRef())] + } + }, + CodeGenerator( "WasmThrowRefGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmExnRef()) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 69ef921eb..5f495f0dc 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3125,6 +3125,7 @@ class ProgramBuilderTests: XCTestCase { test("WasmStructNewDefaultGenerator", expectAny: WasmStructNewDefault.self) test("WasmArrayGetGenerator", expectAny: WasmArrayGet.self, requiresTypes: true) test("WasmStructGetGenerator", expectAny: WasmStructGet.self, requiresTypes: true) + test("WasmThrowRefGenerator", expectAny: WasmThrowRef.self) } func testThatGeneratorsExistAndAreBuildableFromJs() { From 7fb825472f1aefd0fca63ea80948d6fac02d41f3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 23 Mar 2026 13:52:37 +0100 Subject: [PATCH 194/234] [wasm] Properly fix typing issue in WasmBeginCatch The first attempt of fixing this was commit 89691a13e737f342f68dcd19f7ca66a71892d8fc, however this means we might end up not typing the inner outputs (the tag's "elements" available inside the catch) which breaks the typer's assumptions that everything gets typed. Typing it with some dummy value can also lead to issues downstream (e.g. by the next instruction taking now an input that isn't of the needed type any more), so instead we solve this issue by always also adding a signature as an input. As the signature is defined in Wasm, input replacement can only happen with strict type checks, so it is safe to rely on this. It's a bit annoying for the WasmBeginCatch to take an extra input for this specific problem, however, WasmBeginCatch is anyways related to the "legacy" exception handling which isn't a properly spec'ed Wasm feature but a "browsers have been shipping this without a finished spec" kind of thing. Bug: 448860865 Change-Id: I06638ccbb5ed0c9dbb7355ac198b7ace25f521b8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9129497 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 32 ++++++++++++++++---- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 12 +++----- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 4 +-- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 73b2d8258..aa1127564 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4092,18 +4092,28 @@ public class ProgramBuilder { catchAllBody: ((Variable) -> Void)? = nil) { let signature = [] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) + + // Define tag signatures before the try block so they don't interfere with the try/catch + // bodies and their scoping. + // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc + // signature. + let tagSignatures = catchClauses.map { + b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + } + let instr = b.emit(WasmBeginTry( parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) assert(instr.innerOutputs.count == 1) body(instr.innerOutput(0)) - for (tag, generator) in catchClauses { + for (i, (tag, generator)) in catchClauses.enumerated() { b.reportErrorIf(!b.type(of: tag).isWasmTagType, "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + let tagSignatureDef = tagSignatures[i] let instr = b.emit(WasmBeginCatch( blockOutputCount: signature.outputTypes.count, labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), - withInputs: [signatureDef, tag], - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes) + withInputs: [signatureDef, tag, tagSignatureDef], + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody { @@ -4125,18 +4135,28 @@ public class ProgramBuilder { catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = [], catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] { let parameterCount = signature.parameterTypes.count + + // Define tag signatures before the try block so they don't interfere with the try/catch + // bodies and their scoping. + // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc + // signature. + let tagSignatures = catchClauses.map { + b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + } + let instr = b.emit(WasmBeginTry(parameterCount: parameterCount), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) var result = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - for (tag, generator) in catchClauses { + for (i, (tag, generator)) in catchClauses.enumerated() { b.reportErrorIf(!b.type(of: tag).isWasmTagType, "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + let tagSignatureDef = tagSignatures[i] let instr = b.emit(WasmBeginCatch( blockOutputCount: signature.outputTypes.count, labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), - withInputs: [signatureDef, tag] + result, - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes) + withInputs: [signatureDef, tag, tagSignatureDef] + result, + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody = catchAllBody { diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 331599b2d..7741151a6 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -883,13 +883,11 @@ public struct JSTyper: Analyzer { // exception with the legacy exception handling proposal. (This is similar to the // exnref in the standard exception handling spec.) setType(of: instr.innerOutput(1), to: .exceptionLabel) - // Type the tag parameters. - // If the input isn't typed as a Wasm tag any more (this can happen as tags can be - // defined in JS and there a reassign as part of a CodeGenMutator run can loosen the - // inferred type), just act as if there weren't any label parameters. In that case - // the lifter will fail and the test case will be discarded. - let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters ?? [] - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), labelParameters) { + // Type the tag parameters based on the tag's signature definition. + // This guarantees that the inner outputs are properly typed, even if a mutator + // changed the tag variable to something that's not typed as a Wasm tag anymore. + let tagSignature = type(of: instr.input(2)).wasmFunctionSignatureDefSignature + for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) { setType(of: innerOutput, to: paramType) } for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) { diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index f707d1ce9..586c953cd 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1408,9 +1408,9 @@ final class WasmBeginCatch : WasmOperation { // the usage. For now, we just emit a label for branching and the ".exceptionLabel" for // rethrows. super.init( - // Inputs: The block signature, the tag and the outputs of the preceding try or catch + // Inputs: The block signature, the tag, the tag signature, and the outputs of the preceding try or catch // (all) block. - numInputs: 2 + blockOutputCount, + numInputs: 3 + blockOutputCount, // Inner outputs are the branch label, the exception label and the tag parameters. numInnerOutputs: 2 + labelParameterCount, attributes: [ From 323565215d33ef39d0896660abe76da636a092fe Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 23 Mar 2026 18:59:39 +0100 Subject: [PATCH 195/234] [wasm] Fix serialization of WasmBeginCatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue was introduced with commit 7fb825472f1aefd0fca63ea80948d6fac02d41f3 While I was running the fuzzer for multiple hours, the fuzzer is more persmissive in not crashing on invalid programs send over the wire, so this wasn't detected. Change-Id: I34f04902915539cb688c5c6eb6825d28a123ccb0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9130176 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke Reviewed-by: Olivier Flückiger --- Sources/Fuzzilli/FuzzIL/Instruction.swift | 2 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index ccf98f9f6..f6c5c093e 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -2532,7 +2532,7 @@ extension Instruction: ProtobufConvertible { } guard op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count else { - throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs") + throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs for operation \(op)") } opCache?.add(op) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index 586c953cd..cc9daa405 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1421,7 +1421,7 @@ final class WasmBeginCatch : WasmOperation { requiredContext: [.wasmFunction]) } - var blockOutputCount: Int {numInputs - 2} + var blockOutputCount: Int {numInputs - 3} var labelParameterCount: Int {numInnerOutputs - 2} } From 810796a4a011511e7849445dfbfa1c604163a329 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 24 Mar 2026 14:42:42 +0100 Subject: [PATCH 196/234] [github] Update node.js version for CI Change-Id: I6a3f252f20742dac630864ab4b07e493dbde46ec Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9133476 Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 2d630a4a3..bc70a382b 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/setup-node@v4 with: - node-version: 25-nightly + node-version: 26-nightly - name: Swift Version run: swift --version - uses: actions/checkout@v2 From 506d593d3aa600f1692822e38e09c8556d2d396a Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Wed, 25 Mar 2026 12:13:28 +0100 Subject: [PATCH 197/234] Support more property names Similar to method names, this supports all allowed ways to define properties. Approximated valid identifiers will be used as is, everything else will be quoted, except positive integers. Since such a property can leak into the type information of an object or class, also all property accesses are adapted now, similar to method calls. This also refactors the import of object fields and methods, unifying the same property-key logic used in class definitions. Computed getters and setters for object literals and classes are still a TODO. This also lifts some restrictions from runtime assisted mutators, which previously only allowed simple identifiers as property names. Bug: 446634535 Change-Id: I35a65c0073fee9bac238205557958e80c60e1186 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9111376 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Compiler.swift | 77 ++-- Sources/Fuzzilli/Compiler/Parser/parser.js | 30 +- .../Environment/JavaScriptEnvironment.swift | 16 +- .../Lifting/JavaScriptExploreLifting.swift | 2 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 47 ++- .../Lifting/JavaScriptProbeLifting.swift | 2 +- ...aScriptRuntimeAssistedMutatorLifting.swift | 18 +- .../Fuzzilli/Mutators/ProbingMutator.swift | 12 - Sources/Fuzzilli/Protobuf/ast.pb.swift | 336 ++++-------------- Sources/Fuzzilli/Protobuf/ast.proto | 38 +- .../computed_and_indexed_properties.js | 73 ++++ Tests/FuzzilliTests/LifterTest.swift | 195 ++++++++-- 12 files changed, 409 insertions(+), 437 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index d8a4def6e..5a6d5be9e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -774,15 +774,21 @@ public class JavaScriptCompiler { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in object expression") } - if case .property(let property) = field { - propertyValues.append(try compileExpression(property.value)) - if case .expression(let expression) = property.key { - computedKeys.append(try compileExpression(expression)) - } - } else if case .method(let method) = field { - if case .expression(let expression) = method.key { - computedKeys.append(try compileExpression(expression)) - } + + let key : Compiler_Protobuf_PropertyKey + switch field { + case .property(let property): + propertyValues.append(try compileExpression(property.value)) + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key + } + if case .expression(let expression) = key.body { + computedKeys.append(try compileExpression(expression)) } } @@ -795,7 +801,7 @@ public class JavaScriptCompiler { for field in objectExpression.fields { switch field.field! { case .property(let property): - guard let key = property.key else { + guard let key = property.key.body else { throw CompilerError.invalidNodeError("missing key in object expression field") } let inputs = [propertyValues.removeLast()] @@ -809,16 +815,22 @@ public class JavaScriptCompiler { } case .method(let method): let parameters = convertParameters(method.parameters) + let head: Instruction - let instr: Instruction - if case .name(let name) = method.key { - instr = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) - } else { - instr = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) + guard let key = method.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression method") + } + switch key { + case .name(let name): + head = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + case .index(let index): + head = emit(BeginObjectLiteralMethod(methodName: String(index), parameters: parameters)) + case .expression: + head = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) } try enterNewScope { - var parameters = instr.innerOutputs + var parameters = head.innerOutputs map("this", to: parameters.removeFirst()) mapParameters(method.parameters, to: parameters) for statement in method.body { @@ -826,30 +838,47 @@ public class JavaScriptCompiler { } } - if case .name = method.key { + switch key { + case .name, .index: emit(EndObjectLiteralMethod()) - } else { + case .expression: emit(EndObjectLiteralComputedMethod()) } case .getter(let getter): - guard case .name(let name) = getter.key else { + guard let key = getter.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression getter") + } + let head: Instruction + switch key { + case .name(let name): + head = emit(BeginObjectLiteralGetter(propertyName: name)) + case .index(let index): + head = emit(BeginObjectLiteralGetter(propertyName: String(index))) + case .expression: fatalError("Computed getters are not yet supported") } - let instr = emit(BeginObjectLiteralGetter(propertyName: name)) try enterNewScope { - map("this", to: instr.innerOutput) + map("this", to: head.innerOutput) for statement in getter.body { try compileStatement(statement) } } emit(EndObjectLiteralGetter()) case .setter(let setter): - guard case .name(let name) = setter.key else { + guard let key = setter.key.body else { + throw CompilerError.invalidNodeError("Missing key in object expression setter") + } + let head: Instruction + switch key { + case .name(let name): + head = emit(BeginObjectLiteralSetter(propertyName: name)) + case .index(let index): + head = emit(BeginObjectLiteralSetter(propertyName: String(index))) + case .expression: fatalError("Computed setters are not yet supported") } - let instr = emit(BeginObjectLiteralSetter(propertyName: name)) try enterNewScope { - var parameters = instr.innerOutputs + var parameters = head.innerOutputs map("this", to: parameters.removeFirst()) map(setter.parameter.name, to: parameters.removeFirst()) assert(parameters.isEmpty) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 4c5eaace1..0e8b24d16 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -164,7 +164,7 @@ function parse(script, proto) { } else if (member.key.type === 'StringLiteral') { body.name = member.key.value; } else { - throw "Unknown member key type: " + member.key.type + " in class declaration"; + throw "Unknown member key type: " + member.key.type + " in declaration"; } } return make('PropertyKey', body); @@ -468,19 +468,7 @@ function parse(script, proto) { assert(!field.method, "Expected field.method to be false"); let property = {}; property.value = visitExpression(field.value); - if (field.computed) { - property.expression = visitExpression(field.key); - } else { - if (field.key.type === 'Identifier') { - property.name = field.key.name; - } else if (field.key.type === 'NumericLiteral') { - property.index = field.key.value; - } else if (field.key.type === 'StringLiteral') { - property.name = field.key.value; - } else { - throw "Unknown property key type: " + field.key.type; - } - } + property.key = visitMemberKey(field); fields.push(make('ObjectField', { property: make('ObjectProperty', property) })); } else { assert(field.type === 'ObjectMethod', "Expected field.type to be exactly 'ObjectMethod'"); @@ -489,19 +477,7 @@ function parse(script, proto) { let method = field; let out = {}; - if (method.computed) { - out.expression = visitExpression(method.key); - } else { - if (method.key.type === 'Identifier') { - out.name = method.key.name; - } else if (method.key.type === 'NumericLiteral') { - out.name = String(method.key.value); - } else if (method.key.type === 'StringLiteral') { - out.name = method.key.value; - } else { - throw "Unknown method key type: " + method.key.type; - } - } + out.key = visitMemberKey(method); field = {}; if (method.kind === 'method') { diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 87c572104..9461bd760 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -291,7 +291,7 @@ public class JavaScriptEnvironment: ComponentBase { public let interestingRegExpQuantifiers = ["*", "+", "?"] /// Identifiers that should be used for custom properties and methods. - public static let CustomPropertyNames = ["a", "b", "c", "d", "e", "f", "g", "h"] + public static let CustomPropertyNames = ["a", "b", "c", "d", "e", "f", "!", "42"] public static let CustomMethodNames = ["m", "n", "o", "?", "67", "valueOf", "toString"] public static let CustomPrivateMethodNames = ["m", "n", "o", "p"] @@ -318,13 +318,13 @@ public class JavaScriptEnvironment: ComponentBase { private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] - private let validMethodDefinitionName: Regex? + private let validIdentifierOrIndex: Regex? private let validDotNotationName: Regex? private let validPropertyIndex: Regex? public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { // A simple approximation of a valid JS identifier (used in dot - // notation and for method definitions). + // notation and for property and method names). let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" // A non-negative integer (with no leading zero) for index access @@ -334,10 +334,10 @@ public class JavaScriptEnvironment: ComponentBase { // Initialize regular expressions to determine valid property // identifiers: - // At method definition site, we support simple identifiers and - // non-negative numbers. Other names will be quoted. + // We support simple identifiers and non-negative numbers. Other + // names will be quoted. // We don't support unquoted doubles. - self.validMethodDefinitionName = try! Regex("^(\(index)|\(simpleId))$") + self.validIdentifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") // For dot notation we only support simple identifiers. We don't // support all possible names according to JS spec. @@ -1004,8 +1004,8 @@ public class JavaScriptEnvironment: ComponentBase { } } - func isValidNameForMethodDefinition(_ name: String) -> Bool { - return (try? validMethodDefinitionName?.wholeMatch(in: name)) != nil + func isValidIdentifierOrIndex(_ name: String) -> Bool { + return (try? validIdentifierOrIndex?.wholeMatch(in: name)) != nil } func isValidDotNotationName(_ name: String) -> Bool { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index 1863c08b0..835263b95 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -329,7 +329,7 @@ struct JavaScriptExploreLifting { function exploreString(s) { // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. // TODO: sometimes access a character of the string or iterate over it? - if (probability(0.1) && isSimpleString(s)) { + if (probability(0.1) && isShortString(s)) { return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); } else { return exploreObject(new String(s)); diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 680e77f47..0fc5d343a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -383,9 +383,8 @@ public class JavaScriptLifter: Lifter { w.pushTemporaryOutputBuffer(initialIndentionLevel: 0) case .objectLiteralAddProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let VALUE = input(0) - assert(!PROPERTY.contains(" ")) currentObjectLiteral.addField("\(PROPERTY): \(VALUE)") case .objectLiteralAddElement(let op): @@ -409,7 +408,7 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) + let METHOD = quoteIdentifierIfNeeded(op.methodName) currentObjectLiteral.beginMethod("\(METHOD)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -428,7 +427,7 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralGetter(let op): assert(instr.numInnerOutputs == 1) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) currentObjectLiteral.beginMethod("get \(PROPERTY)() {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -436,7 +435,7 @@ public class JavaScriptLifter: Lifter { assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) currentObjectLiteral.beginMethod("set \(PROPERTY)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -497,7 +496,7 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .classAddProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" if op.hasValue { let VALUE = input(0) @@ -538,7 +537,7 @@ public class JavaScriptLifter: Lifter { case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let METHOD = quoteMethodDefinitionIfNeeded(op.methodName) + let METHOD = quoteIdentifierIfNeeded(op.methodName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") w.enterNewBlock() @@ -554,7 +553,7 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .beginClassGetter(let op): - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)get \(PROPERTY)() {") w.enterNewBlock() @@ -564,7 +563,7 @@ public class JavaScriptLifter: Lifter { assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") let PARAMS = liftParameters(op.parameters, as: vars) - let PROPERTY = op.propertyName + let PROPERTY = quoteIdentifierIfNeeded(op.propertyName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)set \(PROPERTY)(\(PARAMS)) {") w.enterNewBlock() @@ -655,29 +654,27 @@ public class JavaScriptLifter: Lifter { case .getProperty(let op): let obj = input(0) - let accessOperator = op.isGuarded ? "?." : "." - let expr = MemberExpression.new() + obj + accessOperator + op.propertyName + let expr = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) w.assign(expr, to: instr.output) case .setProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of an assignment, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let PROPERTY = MemberExpression.new() + obj + "." + op.propertyName + let PROPERTY = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName)) let VALUE = input(1) w.emit("\(PROPERTY) = \(VALUE);") case .updateProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of an assignment, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let PROPERTY = MemberExpression.new() + obj + "." + op.propertyName + let PROPERTY = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName)) let VALUE = input(1) w.emit("\(PROPERTY) \(op.op.token)= \(VALUE);") case .deleteProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of a property deletion, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let accessOperator = op.isGuarded ? "?." : "." - let target = MemberExpression.new() + obj + accessOperator + op.propertyName + let target = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) let expr = UnaryExpression.new() + "delete " + target w.assign(expr, to: instr.output) @@ -1111,13 +1108,13 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .getSuperProperty(let op): - let expr = MemberExpression.new() + "super.\(op.propertyName)" + let expr = MemberExpression.new() + "super" + liftMemberAccess(op.propertyName) w.assign(expr, to: instr.output) case .setSuperProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = liftMemberAccess(op.propertyName) let VALUE = input(0) - w.emit("super.\(PROPERTY) = \(VALUE);") + w.emit("super\(PROPERTY) = \(VALUE);") case .getComputedSuperProperty(_): let expr = MemberExpression.new() + "super[" + input(0).text + "]" @@ -1129,9 +1126,9 @@ public class JavaScriptLifter: Lifter { w.emit("super[\(PROPERTY)] = \(VALUE);") case .updateSuperProperty(let op): - let PROPERTY = op.propertyName + let PROPERTY = liftMemberAccess(op.propertyName) let VALUE = input(0) - w.emit("super.\(PROPERTY) \(op.op.token)= \(VALUE);") + w.emit("super\(PROPERTY) \(op.op.token)= \(VALUE);") case .beginIf(let op): var COND = input(0) @@ -1804,19 +1801,19 @@ public class JavaScriptLifter: Lifter { } } - func quoteMethodDefinitionIfNeeded(_ name: String) -> String { - if environment.isValidNameForMethodDefinition(name) { + func quoteIdentifierIfNeeded(_ name: String) -> String { + if environment.isValidIdentifierOrIndex(name) { return name } return "\"\(name)\"" } - private func liftMemberAccess(_ name: String) -> String { + private func liftMemberAccess(_ name: String, isGuarded: Bool = false) -> String { if environment.isValidDotNotationName(name){ - return "." + name + return (isGuarded ? "?." : ".") + name } let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" - return "[" + safeName + "]" + return (isGuarded ? "?." : "") + "[" + safeName + "]" } private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift index 071c4d8c5..c5347505a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift @@ -64,7 +64,7 @@ struct JavaScriptProbeLifting { } } - if (!isSimpleString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { + if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { // Cannot deal with this property name. Ignore it. return; } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index 6f9882ad8..a1e1a0d69 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -134,12 +134,10 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; } - // Helper function to determine if a string is "simple". We only include simple strings for property/method names or string literals. - // A simple string is basically a valid, property name with a maximum length. - const simpleStringRegExp = /^[0-9a-zA-Z_$]+$/; - function isSimpleString(s) { - if (!isString(s)) throw "Non-string argument to isSimpleString: " + s; - return s.length < 50 && execRegExp(simpleStringRegExp, s) !== null; + // Helper function to determine if a string is short. + function isShortString(s) { + if (!isString(s)) throw "Non-string argument to isShortString: " + s; + return s.length < 50; } // Helper function to determine if a string is numeric and its numeric value representable as an integer. @@ -297,8 +295,8 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // TODO should we allow negative indices here as well? if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { push(allOwnElements, index); - } else if (isSimpleString(p) && tryAccessProperty(p, o)) { - // Only include properties with "simple" names and only if they can be accessed on the original object without raising an exception. + } else if (isShortString(p) && tryAccessProperty(p, o)) { + // Only include properties with short names and only if they can be accessed on the original object without raising an exception. recordProperty(p); } } @@ -453,7 +451,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return { argument: { index } }; } function SpecialInput(name) { - if (!isString(name) || !isSimpleString(name)) throw "SpecialInput name is not a (simple) string: " + name; + if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; return { special: { name } }; } function IntInput(value) { @@ -470,7 +468,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { return { bigint: { value: bigintToString(value) } }; } function StringInput(value) { - if (!isString(value) || !isSimpleString(value)) throw "StringInput value is not a (simple) string: " + value; + if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; return { string: { value } }; } diff --git a/Sources/Fuzzilli/Mutators/ProbingMutator.swift b/Sources/Fuzzilli/Mutators/ProbingMutator.swift index b6dade48e..de3aaba09 100644 --- a/Sources/Fuzzilli/Mutators/ProbingMutator.swift +++ b/Sources/Fuzzilli/Mutators/ProbingMutator.swift @@ -212,7 +212,6 @@ public class ProbingMutator: RuntimeAssistedMutator { switch property { case .regular(let name): - assert(isValidPropertyName(name)) b.setProperty(name, of: obj, to: value) case .element(let index): b.setElement(index, of: obj, to: value) @@ -257,7 +256,6 @@ public class ProbingMutator: RuntimeAssistedMutator { switch property { case .regular(let name): - assert(isValidPropertyName(name)) b.configureProperty(name, of: obj, usingFlags: PropertyFlags.random(), as: config) case .element(let index): b.configureElement(index, of: obj, usingFlags: PropertyFlags.random(), as: config) @@ -312,11 +310,6 @@ public class ProbingMutator: RuntimeAssistedMutator { } } - private func isValidPropertyName(_ name: String) -> Bool { - // Currently only property names containing whitespaces or newlines are invalid. - return name.rangeOfCharacter(from: .whitespacesAndNewlines) == nil - } - private func parsePropertyName(_ propertyName: String) -> Property? { // Anything that parses as an Int64 is an element index. if let index = Int64(propertyName) { @@ -332,11 +325,6 @@ public class ProbingMutator: RuntimeAssistedMutator { } // Everything else is a regular property name. - guard isValidPropertyName(propertyName) else { - // Invalid property names should have been filtered out on the JavaScript side, so receiving them here is an error. - logger.error("Received invalid property name: \(propertyName)") - return nil - } return .regular(propertyName) } diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 8eddca120..dcd757c54 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -1476,34 +1476,14 @@ public struct Compiler_Protobuf_ObjectProperty: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectProperty.OneOf_Key? = nil - - /// A "regular" property. - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - /// An element. - public var index: Int64 { - get { - if case .index(let v)? = key {return v} - return 0 - } - set {key = .index(newValue)} - } - - /// A computed property. - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var value: Compiler_Protobuf_Expression { get {_value ?? Compiler_Protobuf_Expression()} @@ -1516,18 +1496,9 @@ public struct Compiler_Protobuf_ObjectProperty: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - /// A "regular" property. - case name(String) - /// An element. - case index(Int64) - /// A computed property. - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _value: Compiler_Protobuf_Expression? = nil } @@ -1536,23 +1507,14 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectMethod.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var type: Compiler_Protobuf_FunctionType = .plain @@ -1569,14 +1531,9 @@ public struct Compiler_Protobuf_ObjectMethod: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameters: Compiler_Protobuf_Parameters? = nil } @@ -1585,35 +1542,22 @@ public struct Compiler_Protobuf_ObjectGetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectGetter.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var body: [Compiler_Protobuf_Statement] = [] public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil } public struct Compiler_Protobuf_ObjectSetter: Sendable { @@ -1621,23 +1565,14 @@ public struct Compiler_Protobuf_ObjectSetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var key: Compiler_Protobuf_ObjectSetter.OneOf_Key? = nil - - public var name: String { - get { - if case .name(let v)? = key {return v} - return String() - } - set {key = .name(newValue)} - } - - public var expression: Compiler_Protobuf_Expression { - get { - if case .expression(let v)? = key {return v} - return Compiler_Protobuf_Expression() - } - set {key = .expression(newValue)} + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var parameter: Compiler_Protobuf_Parameter { get {_parameter ?? Compiler_Protobuf_Parameter()} @@ -1652,14 +1587,9 @@ public struct Compiler_Protobuf_ObjectSetter: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Key: Equatable, Sendable { - case name(String) - case expression(Compiler_Protobuf_Expression) - - } - public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil } @@ -5374,7 +5304,7 @@ extension Compiler_Protobuf_AssignmentExpression: SwiftProtobuf.Message, SwiftPr extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectProperty" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}index\0\u{1}expression\0\u{1}value\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}value\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5382,36 +5312,8 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Int64? - try decoder.decodeSingularInt64Field(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .index(v) - } - }() - case 3: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 4: try { try decoder.decodeSingularMessageField(value: &self._value) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._value) }() default: break } } @@ -5422,29 +5324,17 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .index?: try { - guard case .index(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularInt64Field(value: v, fieldNumber: 2) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() try { if let v = self._value { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectProperty, rhs: Compiler_Protobuf_ObjectProperty) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs._value != rhs._value {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5453,7 +5343,7 @@ extension Compiler_Protobuf_ObjectProperty: SwiftProtobuf.Message, SwiftProtobuf extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectMethod" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}type\0\u{1}parameters\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}type\0\u{1}parameters\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5461,30 +5351,10 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeSingularEnumField(value: &self.type) }() - case 4: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() - case 5: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self.type) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._parameters) }() + case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5495,31 +5365,23 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.type != .plain { - try visitor.visitSingularEnumField(value: self.type, fieldNumber: 3) + try visitor.visitSingularEnumField(value: self.type, fieldNumber: 2) } try { if let v = self._parameters { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 5) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectMethod, rhs: Compiler_Protobuf_ObjectMethod) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs.type != rhs.type {return false} if lhs._parameters != rhs._parameters {return false} if lhs.body != rhs.body {return false} @@ -5530,7 +5392,7 @@ extension Compiler_Protobuf_ObjectMethod: SwiftProtobuf.Message, SwiftProtobuf._ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5538,28 +5400,8 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5570,25 +5412,17 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 3) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectGetter, rhs: Compiler_Protobuf_ObjectGetter) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -5597,7 +5431,7 @@ extension Compiler_Protobuf_ObjectGetter: SwiftProtobuf.Message, SwiftProtobuf._ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ObjectSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}expression\0\u{1}parameter\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}parameter\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -5605,29 +5439,9 @@ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { - var v: String? - try decoder.decodeSingularStringField(value: &v) - if let v = v { - if self.key != nil {try decoder.handleConflictingOneOf()} - self.key = .name(v) - } - }() - case 2: try { - var v: Compiler_Protobuf_Expression? - var hadOneofValue = false - if let current = self.key { - hadOneofValue = true - if case .expression(let m) = current {v = m} - } - try decoder.decodeSingularMessageField(value: &v) - if let v = v { - if hadOneofValue {try decoder.handleConflictingOneOf()} - self.key = .expression(v) - } - }() - case 3: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() - case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() + case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break } } @@ -5638,28 +5452,20 @@ extension Compiler_Protobuf_ObjectSetter: SwiftProtobuf.Message, SwiftProtobuf._ // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - switch self.key { - case .name?: try { - guard case .name(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularStringField(value: v, fieldNumber: 1) - }() - case .expression?: try { - guard case .expression(let v)? = self.key else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - }() - case nil: break - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() try { if let v = self._parameter { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 4) + try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 3) } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_ObjectSetter, rhs: Compiler_Protobuf_ObjectSetter) -> Bool { - if lhs.key != rhs.key {return false} + if lhs._key != rhs._key {return false} if lhs._parameter != rhs._parameter {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index a3e0bffed..3b4831f1d 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -318,42 +318,26 @@ message AssignmentExpression { } message ObjectProperty { - oneof key { - // A "regular" property. - string name = 1; - // An element. - int64 index = 2; - // A computed property. - Expression expression = 3; - } - Expression value = 4; + PropertyKey key = 1; + Expression value = 2; } message ObjectMethod { - oneof key { - string name = 1; - Expression expression = 2; - } - FunctionType type = 3; - Parameters parameters = 4; - repeated Statement body = 5; + PropertyKey key = 1; + FunctionType type = 2; + Parameters parameters = 3; + repeated Statement body = 4; } message ObjectGetter { - oneof key { - string name = 1; - Expression expression = 2; - } - repeated Statement body = 3; + PropertyKey key = 1; + repeated Statement body = 2; } message ObjectSetter { - oneof key { - string name = 1; - Expression expression = 2; - } - Parameter parameter = 3; - repeated Statement body = 4; + PropertyKey key = 1; + Parameter parameter = 2; + repeated Statement body = 3; } message ObjectField { diff --git a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 264ade1c9..99a5feaf9 100644 --- a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js +++ b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js @@ -8,6 +8,18 @@ console.log("Computed object property"); console.log(obj.theAnswerIs); })(); +console.log("Indexed object property"); +(() => { + const obj = { 67 : 42 }; + console.log(obj[67]); +})(); + +console.log("String literal object property"); +(() => { + const obj = { "?" : 42 }; + console.log(obj["?"]); +})(); + console.log("Computed object method"); (() => { const p = 'theAnswerIs'; @@ -27,6 +39,67 @@ console.log("String literal object method"); console.log(obj["?"]()); })(); +/* +console.log("Computed object property (getter/setter)"); +(() => { + const p = 'theAnswerIs'; + const name = "foo"; + const obj = { + answer: 7, + get [name]() { + console.log("Heavy calculations"); + return this.answer; + }, + set [name](answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj.foo); + obj.foo = 42; + console.log(obj.foo); +})(); +*/ + +console.log("Indexed object property (getter/setter)"); +(() => { + const obj = { + answer: 7, + get 67() { + console.log("Heavy calculations"); + return this.answer; + }, + set 67(answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj[67]); + obj[67] = 42; + console.log(obj[67]); +})(); + +console.log("String literal object property (getter/setter)"); +(() => { + const obj = { + answer: 7, + get "?"() { + console.log("Heavy calculations"); + return this.answer; + }, + set "?"(answer) { + console.log(`The answer was ${this.answer}`); + this.answer = answer; + console.log(`Now the answer is ${this.answer}`); + } + }; + console.log(obj["?"]); + obj["?"] = 42; + console.log(obj["?"]); +})(); + console.log("Computed class property (field)"); (() => { function classify (name) { diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 8f3b5e6fc..872a4b047 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -583,8 +583,10 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() + let v = b.loadInt(42) b.buildObjectLiteral { obj in for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + obj.addProperty(name, as: v) obj.addMethod(name, with: .parameters(n: 0)) { args in } } @@ -594,21 +596,29 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v8 = { + const v9 = { + "???": 42, "???"() { }, + 0: 42, 0() { }, + "01": 42, "01"() { }, + 1: 42, 1() { }, + "0.1": 42, "0.1"() { }, + "-1": 42, "-1"() { }, + $valid_id_42: 42, $valid_id_42() { }, + "42_invalid_id": 42, "42_invalid_id"() { }, }; @@ -861,8 +871,11 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() + let v = b.loadInt(42) b.buildClassDefinition() { cls in for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + cls.addInstanceProperty(name, value: v) + cls.addStaticProperty(name, value: v) cls.addInstanceMethod(name, with: .parameters(n: 0)) { params in } cls.addStaticMethod(name, with: .parameters(n: 0)) { params in @@ -874,35 +887,51 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { + class C1 { + "???" = 42; + static "???" = 42; "???"() { } static "???"() { } + 0 = 42; + static 0 = 42; 0() { } static 0() { } + "01" = 42; + static "01" = 42; "01"() { } static "01"() { } + 1 = 42; + static 1 = 42; 1() { } static 1() { } + "0.1" = 42; + static "0.1" = 42; "0.1"() { } static "0.1"() { } + "-1" = 42; + static "-1" = 42; "-1"() { } static "-1"() { } + $valid_id_42 = 42; + static $valid_id_42 = 42; $valid_id_42() { } static $valid_id_42() { } + "42_invalid_id" = 42; + static "42_invalid_id" = 42; "42_invalid_id"() { } static "42_invalid_id"() { @@ -1960,7 +1989,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj) } @@ -1969,14 +1998,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Funky["???"](); - Funky[0](); - Funky["01"](); - Funky[1](); - Funky["0.1"](); - Funky["-1"](); - Funky.$valid_id_42(); - Funky["42_invalid_id"](); + const v0 = {}; + v0["???"](); + v0[0](); + v0["01"](); + v0[1](); + v0["0.1"](); + v0["-1"](); + v0.$valid_id_42(); + v0["42_invalid_id"](); """ @@ -1987,7 +2017,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) let values = b.createArray(with: []) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj, withArgs: [values], spreading: [true]) @@ -1997,15 +2027,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ + const v0 = {}; const v1 = []; - Funky["???"](...v1); - Funky[0](...v1); - Funky["01"](...v1); - Funky[1](...v1); - Funky["0.1"](...v1); - Funky["-1"](...v1); - Funky.$valid_id_42(...v1); - Funky["42_invalid_id"](...v1); + v0["???"](...v1); + v0[0](...v1); + v0["01"](...v1); + v0[1](...v1); + v0["0.1"](...v1); + v0["-1"](...v1); + v0.$valid_id_42(...v1); + v0["42_invalid_id"](...v1); """ @@ -2016,7 +2047,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let obj = b.createNamedVariable(forBuiltin: "Funky") + let obj = b.createObject(with: [:]) for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { let bound = b.bindMethod(name, on: obj) b.callFunction(bound, withArgs: [obj]) @@ -2026,22 +2057,23 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v1 = Function.prototype.call.bind(Funky["???"]); - v1(Funky); - let v3 = Function.prototype.call.bind(Funky[0]); - v3(Funky); - let v5 = Function.prototype.call.bind(Funky["01"]); - v5(Funky); - let v7 = Function.prototype.call.bind(Funky[1]); - v7(Funky); - let v9 = Function.prototype.call.bind(Funky["0.1"]); - v9(Funky); - let v11 = Function.prototype.call.bind(Funky["-1"]); - v11(Funky); - let v13 = Function.prototype.call.bind(Funky.$valid_id_42); - v13(Funky); - let v15 = Function.prototype.call.bind(Funky["42_invalid_id"]); - v15(Funky); + const v0 = {}; + let v1 = Function.prototype.call.bind(v0["???"]); + v1(v0); + let v3 = Function.prototype.call.bind(v0[0]); + v3(v0); + let v5 = Function.prototype.call.bind(v0["01"]); + v5(v0); + let v7 = Function.prototype.call.bind(v0[1]); + v7(v0); + let v9 = Function.prototype.call.bind(v0["0.1"]); + v9(v0); + let v11 = Function.prototype.call.bind(v0["-1"]); + v11(v0); + let v13 = Function.prototype.call.bind(v0.$valid_id_42); + v13(v0); + let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); + v15(v0); """ @@ -2103,6 +2135,95 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testPropertyLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createObject(with: [:]) + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.setProperty(name, of: obj, to: b.getProperty(name, of: obj)) + b.updateProperty(name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) + b.deleteProperty(name, of: obj) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v0 = {}; + v0["???"] = v0["???"]; + v0["???"] += v0?.["???"]; + delete v0["???"]; + v0[0] = v0[0]; + v0[0] += v0?.[0]; + delete v0[0]; + v0["01"] = v0["01"]; + v0["01"] += v0?.["01"]; + delete v0["01"]; + v0[1] = v0[1]; + v0[1] += v0?.[1]; + delete v0[1]; + v0["0.1"] = v0["0.1"]; + v0["0.1"] += v0?.["0.1"]; + delete v0["0.1"]; + v0["-1"] = v0["-1"]; + v0["-1"] += v0?.["-1"]; + delete v0["-1"]; + v0.$valid_id_42 = v0.$valid_id_42; + v0.$valid_id_42 += v0?.$valid_id_42; + delete v0.$valid_id_42; + v0["42_invalid_id"] = v0["42_invalid_id"]; + v0["42_invalid_id"] += v0?.["42_invalid_id"]; + delete v0["42_invalid_id"]; + + """ + + XCTAssertEqual(actual, expected) + } + + func testSuperPropertyLiftingWeirdNames() { + let fuzzer: Fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildClassDefinition() { cls in + cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.setSuperProperty(name, to: b.getSuperProperty(name)) + b.updateSuperProperty(name, with: b.getSuperProperty(name), using: .Add) + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C0 { + sub() { + super["???"] = super["???"]; + super["???"] += super["???"]; + super[0] = super[0]; + super[0] += super[0]; + super["01"] = super["01"]; + super["01"] += super["01"]; + super[1] = super[1]; + super[1] += super[1]; + super["0.1"] = super["0.1"]; + super["0.1"] += super["0.1"]; + super["-1"] = super["-1"]; + super["-1"] += super["-1"]; + super.$valid_id_42 = super.$valid_id_42; + super.$valid_id_42 += super.$valid_id_42; + super["42_invalid_id"] = super["42_invalid_id"]; + super["42_invalid_id"] += super["42_invalid_id"]; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + func testConstructLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() From 43fa1745355b22d641f1018ba87a0e1020c5464c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 25 Mar 2026 14:37:14 +0100 Subject: [PATCH 198/234] [js] Also generate empty strings Bug: 495679730 Change-Id: I45c1af939f3e1a81fc1c3a2649652e25c644cc82 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9137477 Reviewed-by: Darius Mercadier Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 5 ++++- Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index aa1127564..7160b7c71 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -377,7 +377,10 @@ public class ProgramBuilder { }, { String(self.randomInt()) }, { - String.random(ofLength: Int.random(in: 1...5)) + // Prefer smaller strings both for readability as well as for small string optimizations + // (e.g. optimizations for single character strings) but also generate larger strings + // to hit cons string ("rope" / concatenated string) cases. + String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) }) } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 9461bd760..c13a808a5 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -59,7 +59,7 @@ public class JavaScriptEnvironment: ComponentBase { public let interestingFloats = [-Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan] // TODO more? - public let interestingStrings = jsTypeNames + public let interestingStrings = jsTypeNames + [""] // Copied from // https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/dicts/regexp.dict From e0f0b0b20eccce3be81a37b492c4c0721bbb8ad4 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 27 Mar 2026 11:11:23 +0000 Subject: [PATCH 199/234] Try minimizing crashes of instrumented runs When a program instrumented by RuntimeAssistedMutator crashes, we avoid calling processCrash() on it immediately. This is because the boilerplate code added during instrumentation makes such crashes difficult to minimize (see, e.g., https://g-issues.chromium.org/issues/488963988?pli=1&authuser=0). Instead, we follow this procedure: 1. Always log the crash of the instrumented program. 2. Check if the process()'d version of the instrumented program also crashes. 3. If yes, we call processCrash() on that program instead, as its more straightforward to minimize. Bug: 488963988 Change-Id: Iffefc9435f4ef31a3fbf798d374a04f9f1fc115a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9129498 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Fuzzer.swift | 35 +++++--- .../Mutators/RuntimeAssistedMutator.swift | 34 +++++++- .../CrashingInstrumentationMutator.swift | 55 +++++++++++++ .../RuntimeAssistedMutatorTests.swift | 82 +++++++++++++++++++ 4 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 Tests/FuzzilliTests/CrashingInstrumentationMutator.swift create mode 100644 Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index f7ef762d7..787db836c 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -789,25 +789,34 @@ public class Fuzzer { return true } + /// Collect information about a crash. + func collectCrashInfo(for program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, withExectime exectime: TimeInterval) -> [String] { + var info = [String]() + info.append("CRASH INFO") + info.append("==========") + if let tag = config.tag { + info.append("INSTANCE TAG: \(tag)") + } + info.append("TERMSIG: \(termsig)") + info.append("STDERR:") + info.append(stderr.trimmingCharacters(in: .newlines)) + info.append("STDOUT:") + info.append(stdout.trimmingCharacters(in: .newlines)) + info.append("FUZZER ARGS: \(config.arguments.joined(separator: " "))") + info.append("TARGET ARGS: \(runner.processArguments.joined(separator: " "))") + info.append("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") + info.append("EXECUTION TIME: \(Int(exectime * 1000))ms") + return info + } + /// Process a program that causes a crash. func processCrash(_ program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval) { func processCommon(_ program: Program) { let hasCrashInfo = program.comments.at(.footer)?.contains("CRASH INFO") ?? false if !hasCrashInfo { - program.comments.add("CRASH INFO", at: .footer) - program.comments.add("==========", at: .footer) - if let tag = config.tag { - program.comments.add("INSTANCE TAG: \(tag)", at: .footer) + for line in collectCrashInfo(for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, withExectime: exectime) { + program.comments.add(line, at: .footer) } - program.comments.add("TERMSIG: \(termsig)", at: .footer) - program.comments.add("STDERR:", at: .footer) - program.comments.add(stderr.trimmingCharacters(in: .newlines), at: .footer) - program.comments.add("STDOUT:", at: .footer) - program.comments.add(stdout.trimmingCharacters(in: .newlines), at: .footer) - program.comments.add("FUZZER ARGS: \(config.arguments.joined(separator: " "))", at: .footer) - program.comments.add("TARGET ARGS: \(runner.processArguments.joined(separator: " "))", at: .footer) - program.comments.add("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))", at: .footer) - program.comments.add("EXECUTION TIME: \(Int(exectime * 1000))ms", at: .footer) } assert(program.comments.at(.footer)?.contains("CRASH INFO") ?? false) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index baad473fa..385d663a3 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -32,6 +32,7 @@ public class RuntimeAssistedMutator: Mutator { enum Outcome: String, CaseIterable { case success = "Success" case cannotInstrument = "Cannot instrument input" + case instrumentedProgramCrashed = "Instrumented program crashed" case instrumentedProgramFailed = "Instrumented program failed" case instrumentedProgramTimedOut = "Instrumented program timed out" case noResults = "No results received" @@ -90,6 +91,10 @@ public class RuntimeAssistedMutator: Mutator { // Execute the instrumented program (with a higher timeout) and collect the output. let execution = fuzzer.execute(instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, purpose: .runtimeAssistedMutation) + // We need to cache these because they're invalidated the next time we call execute(). + let oldStdout = execution.stdout + let oldStderr = execution.stderr + let oldFuzzout = execution.fuzzout switch execution.outcome { case .failed(_): // We generally do not expect the instrumentation code itself to cause runtime exceptions. Even if it performs new actions those should be guarded with try-catch. @@ -109,8 +114,31 @@ public class RuntimeAssistedMutator: Mutator { // In this case we still try to process the instrumentation output (if any) and produce the final, uninstrumented program // so that we obtain reliable testcase for crashes due to (1). However, to not loose crashes due to (2), we also // report the instrumented program as crashing here. We may therefore end up with two crashes from one mutation. - let stdout = execution.fuzzout + "\n" + execution.stdout - fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + + let stdout = oldFuzzout + "\n" + oldStdout + + // We log the crash here in case something goes wrong. + let crashInfoText = fuzzer.collectCrashInfo(for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, withExectime: execution.execTime) + logger.error("Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))") + + // Check if the process()'d program also crashes. If yes, we report that crash instead. + // This allows to use Fuzzilli's input minimization, which wouldn't work for the instrumented program. + let (mutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + if let mutatedProgram { + assert(outcome == .success) + + let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) + if case .crashed(let signal) = execution.outcome { + logger.info("Mutated program crashed as well, reporting mutated program instead") + let stdout = execution.fuzzout + "\n" + execution.stdout + fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + return failure(.instrumentedProgramCrashed) + } + } + + // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. + logger.info("Mutated program did not crash, reporting original crash of the instrumented program") + fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. break @@ -119,7 +147,7 @@ public class RuntimeAssistedMutator: Mutator { } // Process the output to build the mutated program. - let (maybeMutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (maybeMutatedProgram, outcome) = process(oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) guard let mutatedProgram = maybeMutatedProgram else { assert(outcome != .success) return failure(outcome) diff --git a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift new file mode 100644 index 000000000..5863b6c18 --- /dev/null +++ b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift @@ -0,0 +1,55 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation +@testable import Fuzzilli + +// This mutator generates a crashing instrumented program. +// It is used for testing: the process()'d program should be +// reported instead of the instrument()'d program, if that program +// also crashes, in order to enable better minimization. + +class CrashingInstrumentationMutator: RuntimeAssistedMutator { + private let shouldProcessedProgramCrash: Bool + + init(shouldProcessedProgramCrash: Bool = true) { + self.shouldProcessedProgramCrash = shouldProcessedProgramCrash + super.init("CrashingInstrumentationMutator", verbose: true) + } + + override func instrument(_ program: Program, for fuzzer: Fuzzer) -> Program? { + let b = fuzzer.makeBuilder() + b.eval("fuzzilli('FUZZILLI_CRASH', 0)"); + + // Add a JsInternalOperation to satisfy the assertion in RuntimeAssistedMutator.swift:89 + let v = b.loadInt(42) + b.doPrint(v) + + b.append(program) + return b.finalize() + } + + + override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + // Purpose of this print: Distinguish crashes originating from instrument() and process(). + let printFct = b.createNamedVariable(forBuiltin: "print") + b.callFunction(printFct, withArgs: [b.loadString("This is the processed program")]) + if self.shouldProcessedProgramCrash { + b.append(instrumentedProgram) + } + return (b.finalize(), .success) + } + + override func logAdditionalStatistics() {} +} diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift new file mode 100644 index 000000000..9105c0544 --- /dev/null +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -0,0 +1,82 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import XCTest +@testable import Fuzzilli + +class RuntimeAssistedMutatorTests: XCTestCase { + class CrashMockScriptRunner: ScriptRunner { + var processArguments: [String] = [] + var env: [(String, String)] = [] + func run(_ script: String, withTimeout timeout: UInt32) -> Execution { + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") { + return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + } else { + return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + } + } + func setEnvironmentVariable(_ key: String, to value: String) {} + func initialize(with fuzzer: Fuzzer) {} + var isInitialized: Bool { true } + } + + // This test checks that if *both* the instrumented and the processed programs crash, + // we report the processed program. + + func testInstrumentedAndProcessedProgramsCrash() { + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner) + + let mutator = CrashingInstrumentationMutator() + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on processed program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let lifted = fuzzer.lifter.lift(ev.program) + if lifted.contains("This is the processed program") { + crashEventTriggered.fulfill() + } + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } + + // This test checks that if *only* the instrumented program crashes, we report it. + + func testOnlyInstrumentedProgramCrashes() { + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner) + + let mutator = CrashingInstrumentationMutator(shouldProcessedProgramCrash: false) + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let lifted = fuzzer.lifter.lift(ev.program) + if !lifted.contains("This is the processed program") { + crashEventTriggered.fulfill() + } + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } +} From 6c0c84705105400011225f441808b99db53c614a Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Mon, 30 Mar 2026 08:53:33 +0000 Subject: [PATCH 200/234] Use logger.warning() instead of logger.info() on instrumentation crash We need at least "warning" level to see logs from worker threads. Change-Id: I4ec5d9d89f5697cf5710a250888e054789716f78 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9151416 Commit-Queue: Leon Bettscheider Reviewed-by: Matthias Liedtke Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 385d663a3..6a8b29c08 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -129,7 +129,7 @@ public class RuntimeAssistedMutator: Mutator { let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) if case .crashed(let signal) = execution.outcome { - logger.info("Mutated program crashed as well, reporting mutated program instead") + logger.warning("Mutated program crashed as well, reporting mutated program instead") let stdout = execution.fuzzout + "\n" + execution.stdout fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) return failure(.instrumentedProgramCrashed) @@ -137,7 +137,7 @@ public class RuntimeAssistedMutator: Mutator { } // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. - logger.info("Mutated program did not crash, reporting original crash of the instrumented program") + logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. From 65ed5fb13e3619f12669fc61e36568bbb4b12882 Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 26 Mar 2026 11:40:05 +0100 Subject: [PATCH 201/234] Work-around false-positive leak reports for regular expressions Fixed: 496097209 Change-Id: Icb0f88bcf619791fa3a45af7f0f2cd73428d37df Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9141456 Auto-Submit: Michael Achenbach Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- .../Environment/JavaScriptEnvironment.swift | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index c13a808a5..cb052d76f 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -318,34 +318,30 @@ public class JavaScriptEnvironment: ComponentBase { private var producingProperties: [ILType: [(group: String, property: String)]] = [:] private var subtypes: [ILType: [ILType]] = [:] - private let validIdentifierOrIndex: Regex? - private let validDotNotationName: Regex? - private let validPropertyIndex: Regex? - - public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { + private struct ValidationRegexes { // A simple approximation of a valid JS identifier (used in dot // notation and for property and method names). - let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" + static let simpleId = "[_$a-zA-Z][_$a-zA-Z0-9]*" // A non-negative integer (with no leading zero) for index access // without quotes. - let index = "[1-9]\\d*|0" - - // Initialize regular expressions to determine valid property - // identifiers: + static let index = "[1-9]\\d*|0" // We support simple identifiers and non-negative numbers. Other // names will be quoted. // We don't support unquoted doubles. - self.validIdentifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") + static let identifierOrIndex = try! Regex("^(\(index)|\(simpleId))$") // For dot notation we only support simple identifiers. We don't // support all possible names according to JS spec. // Unsupported names will be accessed with bracket notation. - self.validDotNotationName = try! Regex("^(\(simpleId))$") + static let dotNotationName = try! Regex("^(\(simpleId))$") // Valid indexes to use in bracket notation without quotes. - self.validPropertyIndex = try! Regex("^(\(index))$") + static let propertyIndex = try! Regex("^(\(index))$") + } + + public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { super.init(name: "JavaScriptEnvironment") @@ -1005,15 +1001,15 @@ public class JavaScriptEnvironment: ComponentBase { } func isValidIdentifierOrIndex(_ name: String) -> Bool { - return (try? validIdentifierOrIndex?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.identifierOrIndex.wholeMatch(in: name)) != nil } func isValidDotNotationName(_ name: String) -> Bool { - return (try? validDotNotationName?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.dotNotationName.wholeMatch(in: name)) != nil } func isValidPropertyIndex(_ name: String) -> Bool { - return (try? validPropertyIndex?.wholeMatch(in: name)) != nil + return (try? ValidationRegexes.propertyIndex.wholeMatch(in: name)) != nil } } From f74d10a0e358454875f8a2e0450146f965fa674b Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 31 Mar 2026 11:50:47 +0200 Subject: [PATCH 202/234] Remove dropped wasm flag in test This was removed in https://crrev.com/c/7708297 Bug: 42202693 Change-Id: Ia3b8b197b28b62ba6eb73aeda498ae748fb093ee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155336 Auto-Submit: Michael Achenbach Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke Commit-Queue: Michael Achenbach --- Tests/FuzzilliTests/EnvironmentTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index 1c55adf57..7819fa883 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -25,7 +25,7 @@ class EnvironmentTests: XCTestCase { /// Test all the builtin objects that are reachable from the global this. /// (This does not include anything that needs a constructor to be called.) func testJSEnvironmentLive() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--experimental-wasm-rab-integration", "--wasm-test-streaming", "--js-staging"]) + let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) let jsProg = buildAndLiftProgram(withLiftingOptions: [.includeComments]) { b in let jsEnvironment = b.fuzzer.environment var seenTypeGroups = Set() From b0b6605a736908245c8a13241f783df1472f790f Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 31 Mar 2026 16:26:57 +0200 Subject: [PATCH 203/234] Enable more getters and setters This enables computed getters and setters for classes and adds the remaining bits to support computed getters and setters for object expressions. Also fully supports and tests getters and setters with non-identifier names for classes. Bug: 446634535 Change-Id: Ib18477c237674b8b9c911f36ba3e53daed136fb8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9100459 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 71 ++++- .../CodeGen/CodeGeneratorWeights.swift | 4 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 164 ++++++----- Sources/Fuzzilli/Compiler/Compiler.swift | 82 ++++-- Sources/Fuzzilli/Compiler/Parser/parser.js | 12 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 32 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 32 +++ Sources/Fuzzilli/FuzzIL/JsOperations.swift | 60 ++++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 8 + Sources/Fuzzilli/FuzzIL/Semantics.swift | 8 + Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 38 +++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 36 ++- .../Fuzzilli/Minimization/BlockReducer.swift | 9 +- .../Minimization/InliningReducer.swift | 14 +- .../Fuzzilli/Mutators/OperationMutator.swift | 8 + Sources/Fuzzilli/Protobuf/ast.pb.swift | 49 +++- Sources/Fuzzilli/Protobuf/ast.proto | 4 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 258 ++++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 26 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 210 +++++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 8 + .../computed_and_indexed_properties.js | 18 -- Tests/FuzzilliTests/LifterTest.swift | 212 +++++++++++++- 23 files changed, 1217 insertions(+), 146 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 7160b7c71..d29c09b88 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -903,6 +903,15 @@ public class ProgramBuilder { return randomVariable(ofType: .jsAnything)! } + /// Tries to find a JavaScript variable that hasn't already been added + /// to the given list. + public func randomJsVariable(notIn variables: [Variable]) -> Variable { + let variable = findVariable { + !variables.contains($0) && type(of: $0).Is(.jsAnything) + } + return variable ?? randomJsVariable() + } + /// Returns up to N (different) random JavaScript variables. /// This method will only return fewer than N variables if the number of currently visible variables is less than N. public func randomJsVariables(upTo n: Int) -> [Variable] { @@ -2529,7 +2538,9 @@ public class ProgramBuilder { public fileprivate(set) var methods: [String] = [] public fileprivate(set) var computedMethods: [Variable] = [] public fileprivate(set) var getters: [String] = [] + public fileprivate(set) var computedGetters: [Variable] = [] public fileprivate(set) var setters: [String] = [] + public fileprivate(set) var computedSetters: [Variable] = [] public fileprivate(set) var hasPrototype = false fileprivate init(in b: ProgramBuilder) { @@ -2577,11 +2588,23 @@ public class ProgramBuilder { b.emit(EndObjectLiteralGetter()) } + public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginObjectLiteralComputedGetter(), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndObjectLiteralComputedGetter()) + } + public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginObjectLiteralSetter(propertyName: name)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralSetter()) } + + public func addComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginObjectLiteralComputedSetter(), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndObjectLiteralComputedSetter()) + } } @discardableResult @@ -2616,7 +2639,9 @@ public class ProgramBuilder { public fileprivate(set) var instanceMethods: [String] = [] public fileprivate(set) var instanceComputedMethods: [Variable] = [] public fileprivate(set) var instanceGetters: [String] = [] + public fileprivate(set) var instanceComputedGetters: [Variable] = [] public fileprivate(set) var instanceSetters: [String] = [] + public fileprivate(set) var instanceComputedSetters: [Variable] = [] public fileprivate(set) var staticProperties: [String] = [] public fileprivate(set) var staticElements: [Int64] = [] @@ -2624,7 +2649,9 @@ public class ProgramBuilder { public fileprivate(set) var staticMethods: [String] = [] public fileprivate(set) var staticComputedMethods: [Variable] = [] public fileprivate(set) var staticGetters: [String] = [] + public fileprivate(set) var staticComputedGetters: [Variable] = [] public fileprivate(set) var staticSetters: [String] = [] + public fileprivate(set) var staticComputedSetters: [Variable] = [] // These sets are required to ensure syntactic correctness, not just as an optimization to // avoid adding duplicate fields: @@ -2688,12 +2715,24 @@ public class ProgramBuilder { b.emit(EndClassGetter()) } + public func addInstanceComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginClassComputedGetter(isStatic: false), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndClassComputedGetter()) + } + public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } + public func addInstanceComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginClassComputedSetter(isStatic: false), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndClassComputedSetter()) + } + public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) @@ -2735,12 +2774,24 @@ public class ProgramBuilder { b.emit(EndClassGetter()) } + public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + let instr = b.emit(BeginClassComputedGetter(isStatic: true), withInputs: [name]) + body(instr.innerOutput) + b.emit(EndClassComputedGetter()) + } + public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } + public func addStaticComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + let instr = b.emit(BeginClassComputedSetter(isStatic: true), withInputs: [name]) + body(instr.innerOutput(0), instr.innerOutput(1)) + b.emit(EndClassComputedSetter()) + } + public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) @@ -4973,12 +5024,18 @@ public class ProgramBuilder { currentObjectLiteral.computedMethods.append(instr.input(0)) case .beginObjectLiteralGetter(let op): currentObjectLiteral.getters.append(op.propertyName) + case .beginObjectLiteralComputedGetter: + currentObjectLiteral.computedGetters.append(instr.input(0)) case .beginObjectLiteralSetter(let op): currentObjectLiteral.setters.append(op.propertyName) + case .beginObjectLiteralComputedSetter: + currentObjectLiteral.computedSetters.append(instr.input(0)) case .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, - .endObjectLiteralSetter: + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter: break case .endObjectLiteral: activeObjectLiterals.pop() @@ -5023,12 +5080,24 @@ public class ProgramBuilder { } else { activeClassDefinitions.top.instanceGetters.append(op.propertyName) } + case .beginClassComputedGetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedGetters.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedGetters.append(instr.input(0)) + } case .beginClassSetter(let op): if op.isStatic { activeClassDefinitions.top.staticSetters.append(op.propertyName) } else { activeClassDefinitions.top.instanceSetters.append(op.propertyName) } + case .beginClassComputedSetter(let op): + if op.isStatic { + activeClassDefinitions.top.staticComputedSetters.append(instr.input(0)) + } else { + activeClassDefinitions.top.instanceComputedSetters.append(instr.input(0)) + } case .classAddPrivateProperty(let op): activeClassDefinitions.top.privateProperties.append(op.propertyName) case .beginClassPrivateMethod(let op): diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index aa026f062..a26982e9c 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -68,6 +68,8 @@ public let codeGeneratorWeights = [ "ObjectLiteralComputedMethodGenerator": 3, "ObjectLiteralGetterGenerator": 3, "ObjectLiteralSetterGenerator": 3, + "ObjectLiteralComputedGetterGenerator": 3, + "ObjectLiteralComputedSetterGenerator": 3, // // // The following generators determine how frequently different // // types of fields are generated in class definitions. @@ -91,6 +93,8 @@ public let codeGeneratorWeights = [ "ClassPrivateInstanceMethodGenerator": 5, "ClassPrivateStaticPropertyGenerator": 5, "ClassPrivateStaticMethodGenerator": 5, + "ClassComputedGetterGenerator": 3, + "ClassComputedSetterGenerator": 3, "ObjectWithSpreadGenerator": 2, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 5a3bed0eb..dfa73e95f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -719,17 +719,8 @@ public let CodeGenerators: [CodeGenerator] = [ inputs: .one ) { b, value in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - if attempts >= 10 { - // Could not find anything. - // Since this CodeGenerator does not produce anything it is fine to bail. - return - } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentObjectLiteral.computedProperties.contains(propertyName) + let propertyName = b.randomJsVariable( + notIn: b.currentObjectLiteral.computedProperties) b.currentObjectLiteral.addComputedProperty(propertyName, as: value) }, @@ -782,19 +773,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method] ) { b in // Try to find a computed method name that hasn't already been added to this literal. - - var methodName: Variable - var attempts = 0 - repeat { - methodName = b.randomJsVariable() - if attempts >= 10 { - // This might lead to having two computed methods with the same name (so one - // will overwrite the other). - break - } - attempts += 1 - } while b.currentObjectLiteral.computedMethods.contains( - methodName) + let methodName = b.randomJsVariable( + notIn: b.currentObjectLiteral.computedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -809,7 +789,6 @@ public let CodeGenerators: [CodeGenerator] = [ ) { b, inp in b.doReturn(inp) b.emit(EndObjectLiteralComputedMethod()) - }, ]), @@ -825,7 +804,6 @@ public let CodeGenerators: [CodeGenerator] = [ let propertyName = b.generateString(b.randomCustomPropertyName, notIn: b.currentObjectLiteral.properties + b.currentObjectLiteral.getters) b.emit(BeginObjectLiteralGetter(propertyName: propertyName)) - }, GeneratorStub( "ObjectLiteralGetterEndGenerator", @@ -858,6 +836,46 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), + CodeGenerator( + "ObjectLiteralComputedGetterGenerator", + [ + GeneratorStub( + "ObjectLiteralComputedGetterBeginGenerator", + inContext: .single(.objectLiteral), + provides: [.javascript, .subroutine, .method] + ) { b in + let propertyName = b.randomJsVariable(notIn: b.currentObjectLiteral.computedGetters) + b.emit(BeginObjectLiteralComputedGetter(), withInputs: [propertyName]) + }, + GeneratorStub( + "ObjectLiteralComputedGetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method]), + inputs: .one + ) { b, inp in + b.doReturn(inp) + b.emit(EndObjectLiteralComputedGetter()) + }, + ]), + + CodeGenerator( + "ObjectLiteralComputedSetterGenerator", + [ + GeneratorStub( + "ObjectLiteralComputedSetterBeginGenerator", + inContext: .single(.objectLiteral), + provides: [.javascript, .subroutine, .method] + ) { b in + let propertyName = b.randomJsVariable(notIn: b.currentObjectLiteral.computedSetters) + b.emit(BeginObjectLiteralComputedSetter(), withInputs: [propertyName]) + }, + GeneratorStub( + "ObjectLiteralComputedSetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method]) + ) { b in + b.emit(EndObjectLiteralComputedSetter()) + }, + ]), + CodeGenerator( "ClassConstructorGenerator", [ @@ -939,15 +957,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassInstanceComputedPropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - guard attempts < 10 else { return } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.instanceComputedProperties.contains( - propertyName) - + let propertyName = b.randomJsVariable( + notIn: b.currentClassDefinition.instanceComputedProperties) let value = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addInstanceComputedProperty( propertyName, value: value) @@ -991,15 +1002,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a method that hasn't already been added to this class. - var methodName = b.randomJsVariable() - var attempts = 0 - repeat { - guard attempts < 10 else { break } - methodName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.instanceComputedMethods.contains( - methodName) - + let methodName = b.randomJsVariable( + notIn: b.currentClassDefinition.instanceComputedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -1089,18 +1093,8 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassStaticComputedPropertyGenerator", inContext: .single(.classDefinition) ) { b in // Try to find a computed property that hasn't already been added to this literal. - var propertyName: Variable - var attempts = 0 - repeat { - guard attempts < 10 else { - // We are in .classDefinition context here and cannot create new JavaScript variables, so just bail here. - return - } - propertyName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.staticComputedProperties.contains( - propertyName) - + let propertyName = b.randomJsVariable( + notIn: b.currentClassDefinition.staticComputedProperties) let value = probability(0.5) ? b.randomJsVariable() : nil b.currentClassDefinition.addStaticComputedProperty( propertyName, value: value) @@ -1163,15 +1157,8 @@ public let CodeGenerators: [CodeGenerator] = [ provides: [.javascript, .subroutine, .method, .classMethod] ) { b in // Try to find a method that hasn't already been added to this class. - var methodName = b.randomJsVariable() - var attempts = 0 - repeat { - guard attempts < 10 else { break } - methodName = b.randomJsVariable() - attempts += 1 - } while b.currentClassDefinition.staticComputedMethods.contains( - methodName) - + let methodName = b.randomJsVariable( + notIn: b.currentClassDefinition.staticComputedMethods) let parameters = b.randomParameters() b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( @@ -1234,6 +1221,53 @@ public let CodeGenerators: [CodeGenerator] = [ }, ]), + CodeGenerator( + "ClassComputedGetterGenerator", + [ + GeneratorStub( + "ClassComputedGetterBeginGenerator", + inContext: .single(.classDefinition), + provides: [.javascript, .subroutine, .method, .classMethod] + ) { b in + let isStatic = probability(0.3) + let existing = isStatic + ? b.currentClassDefinition.staticComputedGetters + : b.currentClassDefinition.instanceComputedGetters + let propertyName = b.randomJsVariable(notIn: existing) + b.emit(BeginClassComputedGetter(isStatic: isStatic), withInputs: [propertyName]) + }, + GeneratorStub( + "ClassComputedGetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]) + ) { b in + b.doReturn(b.randomJsVariable()) + b.emit(EndClassComputedGetter()) + }, + ]), + + CodeGenerator( + "ClassComputedSetterGenerator", + [ + GeneratorStub( + "ClassComputedSetterBeginGenerator", + inContext: .single(.classDefinition), + provides: [.javascript, .subroutine, .method, .classMethod] + ) { b in + let isStatic = probability(0.3) + let existing = isStatic + ? b.currentClassDefinition.staticComputedSetters + : b.currentClassDefinition.instanceComputedSetters + let propertyName = b.randomJsVariable(notIn: existing) + b.emit(BeginClassComputedSetter(isStatic: isStatic), withInputs: [propertyName]) + }, + GeneratorStub( + "ClassComputedSetterEndGenerator", + inContext: .single([.javascript, .subroutine, .method, .classMethod]) + ) { b in + b.emit(EndClassComputedSetter()) + }, + ]), + CodeGenerator( "ClassPrivateInstancePropertyGenerator", inContext: .single(.classDefinition) ) { b in diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 5a6d5be9e..53ad5ccc4 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -76,18 +76,26 @@ public class JavaScriptCompiler { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in class declaration") } - if case .property(let property) = field { + + let key: Compiler_Protobuf_PropertyKey? + switch field { + case .property(let property): if property.hasValue { propertyValues.append(try compileExpression(property.value)) } - if case .expression(let expression) = property.key.body { - computedKeys.append(try compileExpression(expression)) - } + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key + case .ctor, .staticInitializer: + key = nil } - if case .method(let method) = field { - if case .expression(let expression) = method.key.body { - computedKeys.append(try compileExpression(expression)) - } + + if let key, case .expression(let expression) = key.body { + computedKeys.append(try compileExpression(expression)) } } @@ -179,7 +187,18 @@ public class JavaScriptCompiler { } case .getter(let getter): - let head = emit(BeginClassGetter(propertyName: getter.name, isStatic: getter.isStatic)) + let head: Instruction + guard let key = getter.key.body else { + throw CompilerError.invalidNodeError("Missing key in class getter") + } + switch key { + case .name(let name): + head = emit(BeginClassGetter(propertyName: name, isStatic: getter.isStatic)) + case .index(let index): + head = emit(BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) + case .expression: + head = emit(BeginClassComputedGetter(isStatic: getter.isStatic), withInputs: [computedKeys.removeLast()]) + } try enterNewScope { map("this", to: head.innerOutput) @@ -188,10 +207,26 @@ public class JavaScriptCompiler { } } - emit(EndClassGetter()) + switch key { + case .name, .index: + emit(EndClassGetter()) + case .expression: + emit(EndClassComputedGetter()) + } case .setter(let setter): - let head = emit(BeginClassSetter(propertyName: setter.name, isStatic: setter.isStatic)) + let head: Instruction + guard let key = setter.key.body else { + throw CompilerError.invalidNodeError("Missing key in class setter") + } + switch key { + case .name(let name): + head = emit(BeginClassSetter(propertyName: name, isStatic: setter.isStatic)) + case .index(let index): + head = emit(BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) + case .expression: + head = emit(BeginClassComputedSetter(isStatic: setter.isStatic), withInputs: [computedKeys.removeLast()]) + } try enterNewScope { var parameters = head.innerOutputs @@ -203,7 +238,12 @@ public class JavaScriptCompiler { } } - emit(EndClassSetter()) + switch key { + case .name, .index: + emit(EndClassSetter()) + case .expression: + emit(EndClassComputedSetter()) + } case .staticInitializer(let staticInitializer): let head = emit(BeginClassStaticInitializer()) @@ -855,7 +895,7 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralGetter(propertyName: String(index))) case .expression: - fatalError("Computed getters are not yet supported") + head = emit(BeginObjectLiteralComputedGetter(), withInputs: [computedKeys.removeLast()]) } try enterNewScope { map("this", to: head.innerOutput) @@ -863,7 +903,12 @@ public class JavaScriptCompiler { try compileStatement(statement) } } - emit(EndObjectLiteralGetter()) + switch key { + case .name, .index: + emit(EndObjectLiteralGetter()) + case .expression: + emit(EndObjectLiteralComputedGetter()) + } case .setter(let setter): guard let key = setter.key.body else { throw CompilerError.invalidNodeError("Missing key in object expression setter") @@ -875,7 +920,7 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralSetter(propertyName: String(index))) case .expression: - fatalError("Computed setters are not yet supported") + head = emit(BeginObjectLiteralComputedSetter(), withInputs: [computedKeys.removeLast()]) } try enterNewScope { var parameters = head.innerOutputs @@ -886,7 +931,12 @@ public class JavaScriptCompiler { try compileStatement(statement) } } - emit(EndObjectLiteralSetter()) + switch key { + case .name, .index: + emit(EndObjectLiteralSetter()) + case .expression: + emit(EndObjectLiteralComputedSetter()) + } } } return emit(EndObjectLiteral()).output diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 0e8b24d16..4d5ece183 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -214,26 +214,22 @@ function parse(script, proto) { let key = visitMemberKey(method); field.method = make('ClassMethod', { key, isStatic, parameters, body }); } else if (method.kind === 'get') { - assert(!method.computed, 'Expected method.computed to be false'); - assert(method.key.type === 'Identifier', "Expected method.key.type to be exactly 'Identifier'"); assert(method.params.length === 0, "Expected method.params.length to be exactly 0"); assert(!method.generator && !method.async, "Expected both conditions to hold: !method.generator and !method.async"); assert(method.body.type === 'BlockStatement', "Expected method.body.type to be exactly 'BlockStatement'"); let body = visitBody(method.body); - const name = method.key.name; - field.getter = make('ClassGetter', { name, isStatic, body }); + let key = visitMemberKey(method); + field.getter = make('ClassGetter', { key, isStatic, body }); } else if (method.kind === 'set') { - assert(!method.computed, 'Expected method.computed to be false'); - assert(method.key.type === 'Identifier', "Expected method.key.type to be exactly 'Identifier'"); assert(method.params.length === 1, "Expected method.params.length to be exactly 1"); assert(!method.generator && !method.async, "Expected both conditions to hold: !method.generator and !method.async"); assert(method.body.type === 'BlockStatement', "Expected method.body.type to be exactly 'BlockStatement'"); let parameter = visitParameter(method.params[0]); let body = visitBody(method.body); - const name = method.key.name; - field.setter = make('ClassSetter', { name, isStatic, parameter, body }); + let key = visitMemberKey(method); + field.setter = make('ClassSetter', { key, isStatic, parameter, body }); } else { throw "Unknown method kind: " + method.kind; } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index f6c5c093e..35c78eae3 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -598,10 +598,18 @@ extension Instruction: ProtobufConvertible { $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { $0.propertyName = op.propertyName } case .endObjectLiteralGetter: $0.endObjectLiteralGetter = Fuzzilli_Protobuf_EndObjectLiteralGetter() + case .beginObjectLiteralComputedGetter: + $0.beginObjectLiteralComputedGetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + case .endObjectLiteralComputedGetter: + $0.endObjectLiteralComputedGetter = Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let op): $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { $0.propertyName = op.propertyName } case .endObjectLiteralSetter: $0.endObjectLiteralSetter = Fuzzilli_Protobuf_EndObjectLiteralSetter() + case .beginObjectLiteralComputedSetter: + $0.beginObjectLiteralComputedSetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + case .endObjectLiteralComputedSetter: + $0.endObjectLiteralComputedSetter = Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() case .endObjectLiteral: $0.endObjectLiteral = Fuzzilli_Protobuf_EndObjectLiteral() case .beginClassDefinition(let op): @@ -660,6 +668,10 @@ extension Instruction: ProtobufConvertible { } case .endClassGetter: $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() + case .beginClassComputedGetter(let op): + $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { $0.isStatic = op.isStatic } + case .endClassComputedGetter: + $0.endClassComputedGetter = Fuzzilli_Protobuf_EndClassComputedGetter() case .beginClassSetter(let op): $0.beginClassSetter = Fuzzilli_Protobuf_BeginClassSetter.with { $0.propertyName = op.propertyName @@ -667,6 +679,10 @@ extension Instruction: ProtobufConvertible { } case .endClassSetter: $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() + case .beginClassComputedSetter(let op): + $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { $0.isStatic = op.isStatic } + case .endClassComputedSetter: + $0.endClassComputedSetter = Fuzzilli_Protobuf_EndClassComputedSetter() case .beginClassStaticInitializer: $0.beginClassStaticInitializer = Fuzzilli_Protobuf_BeginClassStaticInitializer() case .endClassStaticInitializer: @@ -1851,10 +1867,18 @@ extension Instruction: ProtobufConvertible { op = BeginObjectLiteralGetter(propertyName: p.propertyName) case .endObjectLiteralGetter: op = EndObjectLiteralGetter() + case .beginObjectLiteralComputedGetter: + op = BeginObjectLiteralComputedGetter() + case .endObjectLiteralComputedGetter: + op = EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let p): op = BeginObjectLiteralSetter(propertyName: p.propertyName) case .endObjectLiteralSetter: op = EndObjectLiteralSetter() + case .beginObjectLiteralComputedSetter: + op = BeginObjectLiteralComputedSetter() + case .endObjectLiteralComputedSetter: + op = EndObjectLiteralComputedSetter() case .endObjectLiteral: op = EndObjectLiteral() case .beginClassDefinition(let p): @@ -1881,10 +1905,18 @@ extension Instruction: ProtobufConvertible { op = BeginClassGetter(propertyName: p.propertyName, isStatic: p.isStatic) case .endClassGetter: op = EndClassGetter() + case .beginClassComputedGetter(let p): + op = BeginClassComputedGetter(isStatic: p.isStatic) + case .endClassComputedGetter: + op = EndClassComputedGetter() case .beginClassSetter(let p): op = BeginClassSetter(propertyName: p.propertyName, isStatic: p.isStatic) case .endClassSetter: op = EndClassSetter() + case .beginClassComputedSetter(let p): + op = BeginClassComputedSetter(isStatic: p.isStatic) + case .endClassComputedSetter: + op = EndClassComputedSetter() case .beginClassStaticInitializer: op = BeginClassStaticInitializer() case .endClassStaticInitializer: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 7741151a6..8b55de0a5 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1285,7 +1285,9 @@ public struct JSTyper: Analyzer { case .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, .beginPlainFunction, .beginArrowFunction, .beginGeneratorFunction, @@ -1297,14 +1299,18 @@ public struct JSTyper: Analyzer { .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, + .beginClassComputedSetter, .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, .endPlainFunction, .endArrowFunction, .endGeneratorFunction, @@ -1316,7 +1322,9 @@ public struct JSTyper: Analyzer { .endClassMethod, .endClassComputedMethod, .endClassGetter, + .endClassComputedGetter, .endClassSetter, + .endClassComputedSetter, .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). @@ -1571,6 +1579,10 @@ public struct JSTyper: Analyzer { assert(instr.numInnerOutputs == 1) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + case .beginObjectLiteralComputedGetter(_): + // The first inner output is the explicit |this| parameter for the constructor + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + case .beginObjectLiteralSetter(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) @@ -1578,6 +1590,11 @@ public struct JSTyper: Analyzer { processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) + case .beginObjectLiteralComputedSetter(let op): + // The first inner output is the explicit |this| parameter for the constructor + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .endObjectLiteral: let instanceType = dynamicObjectGroupManager.finalizeObjectLiteral() set(instr.output, instanceType) @@ -1635,6 +1652,13 @@ public struct JSTyper: Analyzer { dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) } + case .beginClassComputedGetter(let op): + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } + case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { @@ -1647,6 +1671,14 @@ public struct JSTyper: Analyzer { assert(instr.numInnerOutputs == 2) processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .beginClassComputedSetter(let op): + if op.isStatic { + set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + } else { + set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) + } + processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| if op.isStatic { diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index f47db65d8..2770d45f1 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -596,6 +596,20 @@ final class EndObjectLiteralGetter: EndAnySubroutine { override var opcode: Opcode { .endObjectLiteralGetter(self) } } +final class BeginObjectLiteralComputedGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginObjectLiteralComputedGetter(self) } + + init() { + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + } +} + +final class EndObjectLiteralComputedGetter: EndAnySubroutine { + override var opcode: Opcode { .endObjectLiteralComputedGetter(self) } +} + // A setter, for example `set prop(a5) {` final class BeginObjectLiteralSetter: BeginAnySubroutine { override var opcode: Opcode { .beginObjectLiteralSetter(self) } @@ -613,6 +627,20 @@ final class EndObjectLiteralSetter: EndAnySubroutine { override var opcode: Opcode { .endObjectLiteralSetter(self) } } +final class BeginObjectLiteralComputedSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginObjectLiteralComputedSetter(self) } + + init() { + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + } +} + +final class EndObjectLiteralComputedSetter: EndAnySubroutine { + override var opcode: Opcode { .endObjectLiteralComputedSetter(self) } +} + final class EndObjectLiteral: JsOperation { override var opcode: Opcode { .endObjectLiteral(self) } @@ -793,6 +821,22 @@ final class EndClassGetter: EndAnySubroutine { override var opcode: Opcode { .endClassGetter(self) } } +final class BeginClassComputedGetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedGetter(self) } + let isStatic: Bool + + init(isStatic: Bool) { + self.isStatic = isStatic + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + } +} + +final class EndClassComputedGetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedGetter(self) } +} + final class BeginClassSetter: BeginAnySubroutine { override var opcode: Opcode { .beginClassSetter(self) } @@ -811,6 +855,22 @@ final class EndClassSetter: EndAnySubroutine { override var opcode: Opcode { .endClassSetter(self) } } +final class BeginClassComputedSetter: BeginAnySubroutine { + override var opcode: Opcode { .beginClassComputedSetter(self) } + let isStatic: Bool + + init(isStatic: Bool) { + self.isStatic = isStatic + // First inner output is the explicit |this| parameter + // The first input is the computed property name + super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + } +} + +final class EndClassComputedSetter: EndAnySubroutine { + override var opcode: Opcode { .endClassComputedSetter(self) } +} + final class BeginClassStaticInitializer: JsOperation { override var opcode: Opcode { .beginClassStaticInitializer(self) } diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 4918d7d14..3a55fc4cb 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -355,4 +355,12 @@ enum Opcode { case wasmRefTest(WasmRefTest) case wasmDefineAdHocModuleSignatureType(WasmDefineAdHocModuleSignatureType) case wasmRefCast(WasmRefCast) + case beginObjectLiteralComputedGetter(BeginObjectLiteralComputedGetter) + case endObjectLiteralComputedGetter(EndObjectLiteralComputedGetter) + case beginObjectLiteralComputedSetter(BeginObjectLiteralComputedSetter) + case endObjectLiteralComputedSetter(EndObjectLiteralComputedSetter) + case beginClassComputedGetter(BeginClassComputedGetter) + case endClassComputedGetter(EndClassComputedGetter) + case beginClassComputedSetter(BeginClassComputedSetter) + case endClassComputedSetter(EndClassComputedSetter) } diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index ab4af0339..567d58756 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -138,8 +138,12 @@ extension Operation { return endOp is EndObjectLiteralComputedMethod case .beginObjectLiteralGetter: return endOp is EndObjectLiteralGetter + case .beginObjectLiteralComputedGetter: + return endOp is EndObjectLiteralComputedGetter case .beginObjectLiteralSetter: return endOp is EndObjectLiteralSetter + case .beginObjectLiteralComputedSetter: + return endOp is EndObjectLiteralComputedSetter case .beginClassDefinition: return endOp is EndClassDefinition case .beginClassConstructor: @@ -150,8 +154,12 @@ extension Operation { return endOp is EndClassComputedMethod case .beginClassGetter: return endOp is EndClassGetter + case .beginClassComputedGetter: + return endOp is EndClassComputedGetter case .beginClassSetter: return endOp is EndClassSetter + case .beginClassComputedSetter: + return endOp is EndClassComputedSetter case .beginClassStaticInitializer: return endOp is EndClassStaticInitializer case .beginClassPrivateMethod: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 7b94c258e..b624f08a4 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -133,6 +133,15 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndObjectLiteralGetter") + case .beginObjectLiteralComputedGetter: + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginObjectLiteralComputedGetter \(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endObjectLiteralComputedGetter: + w.decreaseIndentionLevel() + w.emit("EndObjectLiteralComputedGetter") + case .beginObjectLiteralSetter(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") w.emit("BeginObjectLiteralSetter `\(op.propertyName)` -> \(params)") @@ -142,6 +151,15 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndObjectLiteralSetter") + case .beginObjectLiteralComputedSetter: + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginObjectLiteralComputedSetter \(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endObjectLiteralComputedSetter: + w.decreaseIndentionLevel() + w.emit("EndObjectLiteralComputedSetter") + case .objectLiteralCopyProperties: w.emit("ObjectLiteralCopyProperties \(input(0))") @@ -239,6 +257,26 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassStaticInitializer") + case .beginClassComputedGetter(let op): + let maybeStatic = op.isStatic ? "static " : "" + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassComputedGetter \(maybeStatic)\(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endClassComputedGetter: + w.decreaseIndentionLevel() + w.emit("EndClassComputedGetter") + + case .beginClassComputedSetter(let op): + let maybeStatic = op.isStatic ? "static " : "" + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassComputedSetter \(maybeStatic)\(input(0)) -> \(params)") + w.increaseIndentionLevel() + + case .endClassComputedSetter: + w.decreaseIndentionLevel() + w.emit("EndClassComputedSetter") + case .classAddPrivateProperty(let op): let maybeStatic = op.isStatic ? "static " : "" if op.hasValue { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 0fc5d343a..f38081d9f 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -431,6 +431,11 @@ public class JavaScriptLifter: Lifter { currentObjectLiteral.beginMethod("get \(PROPERTY)() {", &w) bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralComputedGetter: + let PROPERTY = input(0) + currentObjectLiteral.beginMethod("get [\(PROPERTY)]() {", &w) + bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") @@ -439,8 +444,17 @@ public class JavaScriptLifter: Lifter { currentObjectLiteral.beginMethod("set \(PROPERTY)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) + case .beginObjectLiteralComputedSetter: + let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") + let PARAMS = liftParameters(Parameters(count: 1), as: vars) + let PROPERTY = input(0) + currentObjectLiteral.beginMethod("set [\(PROPERTY)](\(PARAMS)) {", &w) + bindVariableToThis(instr.innerOutput(0)) + case .endObjectLiteralGetter, - .endObjectLiteralSetter: + .endObjectLiteralSetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralComputedSetter: currentObjectLiteral.endMethod(&w) case .endObjectLiteral: @@ -559,6 +573,13 @@ public class JavaScriptLifter: Lifter { w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) + case .beginClassComputedGetter(let op): + let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)get [\(PROPERTY)]() {") + w.enterNewBlock() + bindVariableToThis(instr.innerOutput(0)) + case .beginClassSetter(let op): assert(instr.numInnerOutputs == 2) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") @@ -569,10 +590,21 @@ public class JavaScriptLifter: Lifter { w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) + case .beginClassComputedSetter(let op): + let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") + let PARAMS = liftParameters(op.parameters, as: vars) + let PROPERTY = input(0) + let staticStr = op.isStatic ? "static " : "" + w.emit("\(staticStr)set [\(PROPERTY)](\(PARAMS)) {") + w.enterNewBlock() + bindVariableToThis(instr.innerOutput(0)) + case .endClassMethod, .endClassComputedMethod, .endClassGetter, - .endClassSetter: + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter: w.leaveCurrentBlock() w.emit("}") diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index af5ca9fbc..ddc493bc7 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -29,7 +29,9 @@ struct BlockReducer: Reducer { case .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, - .beginObjectLiteralSetter: + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter: assert(group.numBlocks == 1) reduceFunctionInObjectLiteral(group.block(0), with: helper) @@ -40,9 +42,10 @@ struct BlockReducer: Reducer { .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, - .beginClassStaticInitializer, - .beginClassPrivateMethod: + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 7f6cf85d5..dcb039c1f 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -59,14 +59,17 @@ struct InliningReducer: Reducer { .beginObjectLiteralMethod, .beginObjectLiteralComputedMethod, .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, .beginClassConstructor, .beginClassMethod, .beginClassComputedMethod, .beginClassGetter, + .beginClassComputedGetter, .beginClassSetter, - .beginClassStaticInitializer, - .beginClassPrivateMethod: + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, .endArrowFunction, @@ -78,14 +81,17 @@ struct InliningReducer: Reducer { .endObjectLiteralMethod, .endObjectLiteralComputedMethod, .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, .endClassConstructor, .endClassMethod, .endClassComputedMethod, .endClassGetter, + .endClassComputedGetter, .endClassSetter, - .endClassStaticInitializer, - .endClassPrivateMethod: + .endClassComputedSetter, + .endClassStaticInitializer, .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index d87ef0d23..4d7903629 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -527,13 +527,21 @@ public class OperationMutator: BaseInstructionMutator { .beginObjectLiteralComputedMethod(_), .endObjectLiteralComputedMethod(_), .endObjectLiteralGetter(_), + .beginObjectLiteralComputedGetter(_), + .endObjectLiteralComputedGetter(_), .endObjectLiteralSetter(_), + .beginObjectLiteralComputedSetter(_), + .endObjectLiteralComputedSetter(_), .endObjectLiteral(_), .beginClassDefinition(_), .beginClassConstructor(_), .endClassConstructor(_), .beginClassComputedMethod(_), .endClassComputedMethod(_), + .beginClassComputedGetter(_), + .endClassComputedGetter(_), + .beginClassComputedSetter(_), + .endClassComputedSetter(_), .endClassMethod(_), .endClassGetter(_), .endClassSetter(_), diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index dcd757c54..c556a80e6 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -439,7 +439,14 @@ public struct Compiler_Protobuf_ClassGetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} + } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var isStatic: Bool = false @@ -448,6 +455,8 @@ public struct Compiler_Protobuf_ClassGetter: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil } public struct Compiler_Protobuf_ClassSetter: Sendable { @@ -455,7 +464,14 @@ public struct Compiler_Protobuf_ClassSetter: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var key: Compiler_Protobuf_PropertyKey { + get {_key ?? Compiler_Protobuf_PropertyKey()} + set {_key = newValue} + } + /// Returns true if `key` has been explicitly set. + public var hasKey: Bool {self._key != nil} + /// Clears the value of `key`. Subsequent reads from it will return its default value. + public mutating func clearKey() {self._key = nil} public var isStatic: Bool = false @@ -474,6 +490,7 @@ public struct Compiler_Protobuf_ClassSetter: Sendable { public init() {} + fileprivate var _key: Compiler_Protobuf_PropertyKey? = nil fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil } @@ -3000,7 +3017,7 @@ extension Compiler_Protobuf_ClassMethod: SwiftProtobuf.Message, SwiftProtobuf._M extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ClassGetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}isStatic\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}isStatic\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3008,7 +3025,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() case 3: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() default: break @@ -3017,9 +3034,13 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M } public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.isStatic != false { try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) } @@ -3030,7 +3051,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M } public static func ==(lhs: Compiler_Protobuf_ClassGetter, rhs: Compiler_Protobuf_ClassGetter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._key != rhs._key {return false} if lhs.isStatic != rhs.isStatic {return false} if lhs.body != rhs.body {return false} if lhs.unknownFields != rhs.unknownFields {return false} @@ -3040,7 +3061,7 @@ extension Compiler_Protobuf_ClassGetter: SwiftProtobuf.Message, SwiftProtobuf._M extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ClassSetter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}isStatic\0\u{1}parameter\0\u{1}body\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}key\0\u{1}isStatic\0\u{1}parameter\0\u{1}body\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -3048,7 +3069,7 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._key) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() case 3: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() case 4: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() @@ -3062,9 +3083,9 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } + try { if let v = self._key { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() if self.isStatic != false { try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 2) } @@ -3078,7 +3099,7 @@ extension Compiler_Protobuf_ClassSetter: SwiftProtobuf.Message, SwiftProtobuf._M } public static func ==(lhs: Compiler_Protobuf_ClassSetter, rhs: Compiler_Protobuf_ClassSetter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._key != rhs._key {return false} if lhs.isStatic != rhs.isStatic {return false} if lhs._parameter != rhs._parameter {return false} if lhs.body != rhs.body {return false} diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index 3b4831f1d..d53216273 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -109,13 +109,13 @@ message ClassMethod { } message ClassGetter { - string name = 1; + PropertyKey key = 1; bool isStatic = 2; repeated Statement body = 3; } message ClassSetter { - string name = 1; + PropertyKey key = 1; bool isStatic = 2; Parameter parameter = 3; repeated Statement body = 4; diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 90e194e63..03dc972b5 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1906,6 +1906,26 @@ public struct Fuzzilli_Protobuf_EndObjectLiteralGetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndObjectLiteralComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginObjectLiteralSetter: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -1928,6 +1948,26 @@ public struct Fuzzilli_Protobuf_EndObjectLiteralSetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndObjectLiteralComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_EndObjectLiteral: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -2121,6 +2161,28 @@ public struct Fuzzilli_Protobuf_EndClassGetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginClassComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var isStatic: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndClassComputedGetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginClassSetter: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -2145,6 +2207,28 @@ public struct Fuzzilli_Protobuf_EndClassSetter: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginClassComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var isStatic: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndClassComputedSetter: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginClassStaticInitializer: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -6654,6 +6738,44 @@ extension Fuzzilli_Protobuf_EndObjectLiteralGetter: SwiftProtobuf.Message, Swift } } +extension Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter, rhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndObjectLiteralComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteralComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter, rhs: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginObjectLiteralSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0") @@ -6703,6 +6825,44 @@ extension Fuzzilli_Protobuf_EndObjectLiteralSetter: SwiftProtobuf.Message, Swift } } +extension Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginObjectLiteralComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter, rhs: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndObjectLiteralComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteralComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter, rhs: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_EndObjectLiteral: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EndObjectLiteral" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -7100,6 +7260,55 @@ extension Fuzzilli_Protobuf_EndClassGetter: SwiftProtobuf.Message, SwiftProtobuf } } +extension Fuzzilli_Protobuf_BeginClassComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}is_static\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedGetter, rhs: Fuzzilli_Protobuf_BeginClassComputedGetter) -> Bool { + if lhs.isStatic != rhs.isStatic {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassComputedGetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedGetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedGetter, rhs: Fuzzilli_Protobuf_EndClassComputedGetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginClassSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginClassSetter" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}propertyName\0\u{3}is_static\0") @@ -7154,6 +7363,55 @@ extension Fuzzilli_Protobuf_EndClassSetter: SwiftProtobuf.Message, SwiftProtobuf } } +extension Fuzzilli_Protobuf_BeginClassComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginClassComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}is_static\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.isStatic) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.isStatic != false { + try visitor.visitSingularBoolField(value: self.isStatic, fieldNumber: 1) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginClassComputedSetter, rhs: Fuzzilli_Protobuf_BeginClassComputedSetter) -> Bool { + if lhs.isStatic != rhs.isStatic {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndClassComputedSetter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndClassComputedSetter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndClassComputedSetter, rhs: Fuzzilli_Protobuf_EndClassComputedSetter) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginClassStaticInitializer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginClassStaticInitializer" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 4699a27f0..9cfb20633 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -107,6 +107,12 @@ message BeginObjectLiteralGetter { message EndObjectLiteralGetter { } +message BeginObjectLiteralComputedGetter { +} + +message EndObjectLiteralComputedGetter { +} + message BeginObjectLiteralSetter { string propertyName = 1; } @@ -114,6 +120,12 @@ message BeginObjectLiteralSetter { message EndObjectLiteralSetter { } +message BeginObjectLiteralComputedSetter { +} + +message EndObjectLiteralComputedSetter { +} + message EndObjectLiteral { } @@ -171,6 +183,13 @@ message BeginClassGetter { message EndClassGetter { } +message BeginClassComputedGetter { + bool is_static = 1; +} + +message EndClassComputedGetter { +} + message BeginClassSetter { string propertyName = 1; bool is_static = 2; @@ -179,6 +198,13 @@ message BeginClassSetter { message EndClassSetter { } +message BeginClassComputedSetter { + bool is_static = 1; +} + +message EndClassComputedSetter { +} + message BeginClassStaticInitializer { } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 9684e4e6c..a610786ae 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2657,6 +2657,70 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .wasmRefCast(newValue)} } + public var beginObjectLiteralComputedGetter: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter { + get { + if case .beginObjectLiteralComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + } + set {operation = .beginObjectLiteralComputedGetter(newValue)} + } + + public var endObjectLiteralComputedGetter: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter { + get { + if case .endObjectLiteralComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() + } + set {operation = .endObjectLiteralComputedGetter(newValue)} + } + + public var beginObjectLiteralComputedSetter: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter { + get { + if case .beginObjectLiteralComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + } + set {operation = .beginObjectLiteralComputedSetter(newValue)} + } + + public var endObjectLiteralComputedSetter: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter { + get { + if case .endObjectLiteralComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() + } + set {operation = .endObjectLiteralComputedSetter(newValue)} + } + + public var beginClassComputedGetter: Fuzzilli_Protobuf_BeginClassComputedGetter { + get { + if case .beginClassComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedGetter() + } + set {operation = .beginClassComputedGetter(newValue)} + } + + public var endClassComputedGetter: Fuzzilli_Protobuf_EndClassComputedGetter { + get { + if case .endClassComputedGetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedGetter() + } + set {operation = .endClassComputedGetter(newValue)} + } + + public var beginClassComputedSetter: Fuzzilli_Protobuf_BeginClassComputedSetter { + get { + if case .beginClassComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginClassComputedSetter() + } + set {operation = .beginClassComputedSetter(newValue)} + } + + public var endClassComputedSetter: Fuzzilli_Protobuf_EndClassComputedSetter { + get { + if case .endClassComputedSetter(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndClassComputedSetter() + } + set {operation = .endClassComputedSetter(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -2986,6 +3050,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmRefTest(Fuzzilli_Protobuf_WasmRefTest) case wasmDefineAdHocModuleSignatureType(Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType) case wasmRefCast(Fuzzilli_Protobuf_WasmRefCast) + case beginObjectLiteralComputedGetter(Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter) + case endObjectLiteralComputedGetter(Fuzzilli_Protobuf_EndObjectLiteralComputedGetter) + case beginObjectLiteralComputedSetter(Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter) + case endObjectLiteralComputedSetter(Fuzzilli_Protobuf_EndObjectLiteralComputedSetter) + case beginClassComputedGetter(Fuzzilli_Protobuf_BeginClassComputedGetter) + case endClassComputedGetter(Fuzzilli_Protobuf_EndClassComputedGetter) + case beginClassComputedSetter(Fuzzilli_Protobuf_BeginClassComputedSetter) + case endClassComputedSetter(Fuzzilli_Protobuf_EndClassComputedSetter) } @@ -3034,7 +3106,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7276,6 +7348,110 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmRefCast(v) } }() + case 328: try { + var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginObjectLiteralComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginObjectLiteralComputedGetter(v) + } + }() + case 329: try { + var v: Fuzzilli_Protobuf_EndObjectLiteralComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endObjectLiteralComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endObjectLiteralComputedGetter(v) + } + }() + case 330: try { + var v: Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginObjectLiteralComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginObjectLiteralComputedSetter(v) + } + }() + case 331: try { + var v: Fuzzilli_Protobuf_EndObjectLiteralComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endObjectLiteralComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endObjectLiteralComputedSetter(v) + } + }() + case 332: try { + var v: Fuzzilli_Protobuf_BeginClassComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginClassComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginClassComputedGetter(v) + } + }() + case 333: try { + var v: Fuzzilli_Protobuf_EndClassComputedGetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endClassComputedGetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endClassComputedGetter(v) + } + }() + case 334: try { + var v: Fuzzilli_Protobuf_BeginClassComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginClassComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginClassComputedSetter(v) + } + }() + case 335: try { + var v: Fuzzilli_Protobuf_EndClassComputedSetter? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endClassComputedSetter(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endClassComputedSetter(v) + } + }() default: break } } @@ -8594,6 +8770,38 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmRefCast(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 327) }() + case .beginObjectLiteralComputedGetter?: try { + guard case .beginObjectLiteralComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 328) + }() + case .endObjectLiteralComputedGetter?: try { + guard case .endObjectLiteralComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 329) + }() + case .beginObjectLiteralComputedSetter?: try { + guard case .beginObjectLiteralComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 330) + }() + case .endObjectLiteralComputedSetter?: try { + guard case .endObjectLiteralComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 331) + }() + case .beginClassComputedGetter?: try { + guard case .beginClassComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 332) + }() + case .endClassComputedGetter?: try { + guard case .endClassComputedGetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 333) + }() + case .beginClassComputedSetter?: try { + guard case .beginClassComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 334) + }() + case .endClassComputedSetter?: try { + guard case .endClassComputedSetter(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 335) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index abf2a678c..bdea24d6c 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -351,6 +351,14 @@ message Instruction { WasmRefTest wasmRefTest = 325; WasmDefineAdHocModuleSignatureType wasmDefineAdHocModuleSignatureType = 326; WasmRefCast wasmRefCast = 327; + BeginObjectLiteralComputedGetter beginObjectLiteralComputedGetter = 328; + EndObjectLiteralComputedGetter endObjectLiteralComputedGetter = 329; + BeginObjectLiteralComputedSetter beginObjectLiteralComputedSetter = 330; + EndObjectLiteralComputedSetter endObjectLiteralComputedSetter = 331; + BeginClassComputedGetter beginClassComputedGetter = 332; + EndClassComputedGetter endClassComputedGetter = 333; + BeginClassComputedSetter beginClassComputedSetter = 334; + EndClassComputedSetter endClassComputedSetter = 335; } } diff --git a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js index 99a5feaf9..3289a3180 100644 --- a/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js +++ b/Tests/FuzzilliTests/CompilerTests/computed_and_indexed_properties.js @@ -39,7 +39,6 @@ console.log("String literal object method"); console.log(obj["?"]()); })(); -/* console.log("Computed object property (getter/setter)"); (() => { const p = 'theAnswerIs'; @@ -60,7 +59,6 @@ console.log("Computed object property (getter/setter)"); obj.foo = 42; console.log(obj.foo); })(); -*/ console.log("Indexed object property (getter/setter)"); (() => { @@ -122,7 +120,6 @@ console.log("Computed static class property (field)"); console.log((classify("theAnswerIs")).theAnswerIs); })(); -/* console.log("Computed class property (getter/setter)"); (() => { function classify (name) { @@ -147,9 +144,7 @@ console.log("Computed class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ -/* console.log("Computed static class property (getter/setter)"); (() => { function classify (name) { @@ -174,7 +169,6 @@ console.log("Computed static class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ console.log("Computed class property (method)"); (() => { @@ -244,7 +238,6 @@ console.log("Indexed static class property (method)"); console.log(C[42]()); })(); -/* console.log("Indexed class property (getter/setter)"); (() => { class C { @@ -266,9 +259,7 @@ console.log("Indexed class property (getter/setter)"); c[42] = 42; console.log(c[42]); })(); -*/ -/* console.log("Indexed static class property (getter/setter)"); (() => { class C { @@ -289,7 +280,6 @@ console.log("Indexed static class property (getter/setter)"); C[42] = 42; console.log(C[42]); })(); -*/ console.log("String-indexed class property (field)"); (() => { @@ -331,7 +321,6 @@ console.log("String-indexed static class property (method)"); console.log(C["42"]()); })(); -/* console.log("String-indexed class property (getter/setter)"); (() => { class C { @@ -355,9 +344,7 @@ console.log("String-indexed class property (getter/setter)"); c["42"] = 42; console.log(c["42"]); })(); -*/ -/* console.log("String-indexed static class property (getter/setter)"); (() => { class C { @@ -378,7 +365,6 @@ console.log("String-indexed static class property (getter/setter)"); C["42"] = 42; console.log(C["42"]); })(); -*/ console.log("String-literal class property (field)"); (() => { @@ -420,7 +406,6 @@ console.log("String-literal static class property (method)"); console.log(C["theAnswerIs?"]()); })(); -/* console.log("String-literal class property (getter/setter)"); (() => { class C { @@ -442,9 +427,7 @@ console.log("String-literal class property (getter/setter)"); c.theAnswerIs = 42; console.log(c.theAnswerIs); })(); -*/ -/* console.log("String-literal static class property (getter/setter)"); (() => { class C { @@ -465,4 +448,3 @@ console.log("String-literal static class property (getter/setter)"); C.theAnswerIs = 42; console.log(C.theAnswerIs); })(); -*/ diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 872a4b047..9308fa71a 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -542,6 +542,12 @@ class LifterTests: XCTestCase { obj.addSetter(for: "prop") { this, v in b.setProperty("p", of: this, to: v) } + obj.addComputedGetter(for: v3) { this in + b.doReturn(v1) + } + obj.addComputedSetter(for: v3) { this, v in + b.setProperty("p", of: this, to: v) + } obj.copyProperties(from: otherObject) } @@ -551,7 +557,7 @@ class LifterTests: XCTestCase { let expected = """ const v4 = "foobar" + 42; const v7 = Symbol.toPrimitive; - const v17 = { + const v20 = { p1: 42, __proto__: null, 0: 13.37, @@ -572,6 +578,12 @@ class LifterTests: XCTestCase { set prop(a16) { this.p = a16; }, + get ["foobar"]() { + return 42; + }, + set ["foobar"](a19) { + this.p = a19; + }, ...SomeObject, }; @@ -627,6 +639,69 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testObjectLiteralGetterSetterLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v = b.loadInt(42) + b.buildObjectLiteral { obj in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + obj.addGetter(for: name) { _ in b.doReturn(v) } + obj.addSetter(for: name) { _, _ in } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v25 = { + get "???"() { + return 42; + }, + set "???"(a3) { + }, + get 0() { + return 42; + }, + set 0(a6) { + }, + get "01"() { + return 42; + }, + set "01"(a9) { + }, + get 1() { + return 42; + }, + set 1(a12) { + }, + get "0.1"() { + return 42; + }, + set "0.1"(a15) { + }, + get "-1"() { + return 42; + }, + set "-1"(a18) { + }, + get $valid_id_42() { + return 42; + }, + set $valid_id_42(a21) { + }, + get "42_invalid_id"() { + return 42; + }, + set "42_invalid_id"(a24) { + }, + }; + + """ + XCTAssertEqual(actual, expected) + } + func testObjectLiteralIsDistinguishableFromBlockStatement() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -730,6 +805,11 @@ class LifterTests: XCTestCase { } cls.addInstanceSetter(for: "baz") { this, v in } + cls.addInstanceComputedGetter(for: baz) { this in + b.doReturn(b.loadInt(1337)) + } + cls.addInstanceComputedSetter(for: baz) { this, v in + } cls.addStaticProperty("foo") cls.addStaticInitializer { this in @@ -756,6 +836,11 @@ class LifterTests: XCTestCase { } cls.addStaticSetter(for: "baz") { this, v in } + cls.addStaticComputedGetter(for: baz) { this in + b.doReturn(b.loadInt(1337)) + } + cls.addStaticComputedSetter(for: baz) { this, v in + } cls.addPrivateInstanceProperty("ifoo") cls.addPrivateInstanceProperty("ibar", value: baz) @@ -815,6 +900,11 @@ class LifterTests: XCTestCase { } set baz(a17) { } + get ["baz"]() { + return 1337; + } + set ["baz"](a21) { + } static foo; static { this.foo = 42; @@ -834,29 +924,34 @@ class LifterTests: XCTestCase { static get baz() { return 1337; } - static set baz(a26) { + static set baz(a30) { + } + static get ["baz"]() { + return 1337; + } + static set ["baz"](a34) { } #ifoo; #ibar = "baz"; #im() { - const v28 = this.#ifoo; - this.#ibar = v28; - return v28; + const v36 = this.#ifoo; + this.#ibar = v36; + return v36; } - #in(a30) { + #in(a38) { this.#im(); - this.#ibar += a30; + this.#ibar += a38; } static #sfoo; static #sbar = "baz"; static #sm() { - const v33 = this.#sfoo; - this.#sbar = v33; - return v33; + const v41 = this.#sfoo; + this.#sbar = v41; + return v41; } - static #sn(a35) { + static #sn(a43) { this.#sm(); - this.#sbar += a35; + this.#sbar += a43; } } new C7(42); @@ -943,6 +1038,99 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testClassGetterSetterLiftingWeirdNames() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildClassDefinition() { cls in + for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + cls.addInstanceGetter(for: name) { this in + } + cls.addStaticGetter(for: name) { this in + } + cls.addInstanceSetter(for: name) { this, val in + } + cls.addStaticSetter(for: name) { this, val in + } + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C0 { + get "???"() { + } + static get "???"() { + } + set "???"(a4) { + } + static set "???"(a6) { + } + get 0() { + } + static get 0() { + } + set 0(a10) { + } + static set 0(a12) { + } + get "01"() { + } + static get "01"() { + } + set "01"(a16) { + } + static set "01"(a18) { + } + get 1() { + } + static get 1() { + } + set 1(a22) { + } + static set 1(a24) { + } + get "0.1"() { + } + static get "0.1"() { + } + set "0.1"(a28) { + } + static set "0.1"(a30) { + } + get "-1"() { + } + static get "-1"() { + } + set "-1"(a34) { + } + static set "-1"(a36) { + } + get $valid_id_42() { + } + static get $valid_id_42() { + } + set $valid_id_42(a40) { + } + static set $valid_id_42(a42) { + } + get "42_invalid_id"() { + } + static get "42_invalid_id"() { + } + set "42_invalid_id"(a46) { + } + static set "42_invalid_id"(a48) { + } + } + + """ + + XCTAssertEqual(actual, expected) + } + func testClassExpressionLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() From 16efb85be0c3d1648efcecd4d972cbf08561539c Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 1 Apr 2026 13:35:28 +0000 Subject: [PATCH 204/234] Transpile crashing instrumented programs from FuzzIL->JS->FuzzIL This CL transpiles crashing instrumented FuzzIL programs to JS (to insert the JS boilerplate code required for, e.g., explore()), and then transpiles this JS code back to FuzzIL and reports that program. This change will allow to apply Fuzzilli's own program minimization technique also on the boilerplate code. We hope that this will result in smaller reported programs. Bug: 488963988 Change-Id: I1e5ee51409c4c5e26db80e96d4f61060e12f0bd1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155916 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Parser/parser.js | 1 + .../Lifting/JavaScriptExploreLifting.swift | 6 +-- ...aScriptRuntimeAssistedMutatorLifting.swift | 4 +- .../Mutators/RuntimeAssistedMutator.swift | 24 ++++++++- .../RuntimeAssistedMutatorTests.swift | 53 ++++++++++++++++++- 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 4d5ece183..aa06d05ce 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -83,6 +83,7 @@ function parse(script, proto) { return Statement.create(statement); } + // TODO(bettscheider): Add support for default parameters. function visitParameter(param) { switch (param.type) { case 'Identifier': diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index 835263b95..f65dd3cca 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -342,7 +342,7 @@ struct JavaScriptExploreLifting { // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(COMPARISON_OPS, operation)) { if (isNaN(n)) { @@ -374,7 +374,7 @@ struct JavaScriptExploreLifting { // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(COMPARISON_OPS, operation)) { push(action.inputs, Inputs.randomBigintCloseTo(b)); @@ -395,7 +395,7 @@ struct JavaScriptExploreLifting { function exploreBoolean(b) { let operation = randomElement(ALL_BOOLEAN_OPERATIONS); - let action = new Action(operation); + let action = new Action(operation, EmptyArray()); push(action.inputs, exploredValueInput); if (includes(BOOLEAN_BINARY_OPS, operation)) { // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index a1e1a0d69..17fba9d87 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -413,7 +413,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // // Action constructors. // - function Action(operation, inputs = EmptyArray()) { + function Action(operation, inputs) { this.operation = operation; this.inputs = inputs; this.isGuarded = false; @@ -431,7 +431,7 @@ struct JavaScriptRuntimeAssistedMutatorLifting { // // If a guarded action succeeds (doesn't raise an exception), it will be converted to // a regular action to limit the number of generated try-catch blocks. - function GuardedAction(operation, inputs = EmptyArray()) { + function GuardedAction(operation, inputs) { this.operation = operation; this.inputs = inputs; this.isGuarded = true; diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 6a8b29c08..4e43be6e0 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -137,8 +137,30 @@ public class RuntimeAssistedMutator: Mutator { } // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. + // First, get the instrumented JS program and try to compile it back to FuzzIL, so it can be minimized more effectively. + // We need this because instrumentation adds boilerplate JS code. + let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) + var maybeProgramToMinimize: Program? = nil + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".js") + if let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]), + let parser = JavaScriptParser(executor: nodejs) { + do { + try instrumentedJavaScriptProgram.write(to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + } + try? FileManager.default.removeItem(at: tempFile) + } + else { + logger.warning("Unable to compile instrumented JS program to FuzzIL because node.js is not available") + } + + logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") - fuzzer.processCrash(instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + fuzzer.processCrash(maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: // The expected case. break diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift index 9105c0544..4d1182b96 100644 --- a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -20,7 +20,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { var processArguments: [String] = [] var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { - if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") { + // Minimization can change quotation marks. Checking for both here to be on the safe side. + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") { return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } else { return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) @@ -79,4 +80,54 @@ class RuntimeAssistedMutatorTests: XCTestCase { _ = mutator.mutate(program, using: b, for: fuzzer) waitForExpectations(timeout: 5, handler: nil) } + + // This test checks that if *only* the instrumented program crashes, this program is minimized. + + func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { + guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { + throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + } + + // Initialize the parser. This can fail if no node.js executable is found or if the + // parser's node.js dependencies are not installed. In that case, skip these tests. + guard JavaScriptParser(executor: nodejs) != nil else { + throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + } + + class CrashEvaluator: MockEvaluator { + override func hasAspects(_ execution: Execution, _ aspects: ProgramAspects) -> Bool { + return execution.outcome.isCrash() + } + } + + let runner = CrashMockScriptRunner() + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, runner: runner, evaluator: CrashEvaluator()) + + let expectedProgramBuilder = fuzzer.makeBuilder() + let v0 = expectedProgramBuilder.loadString("FUZZILLI_CRASH") + let v1 = expectedProgramBuilder.loadInt(0) + let v2 = expectedProgramBuilder.createNamedVariable(forBuiltin: "fuzzilli") + expectedProgramBuilder.callFunction(v2, withArgs: [v0, v1]) + let expectedProgram = expectedProgramBuilder.finalize() + + let mutator = CrashingInstrumentationMutator(shouldProcessedProgramCrash: false) + let b = fuzzer.makeBuilder() + b.loadInt(42) + let program = b.finalize() + + let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in + let actualProgram = ev.program + XCTAssertEqual(expectedProgram, actualProgram, + "The reported program should be the minimized version of the instrumented program.\n" + + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + crashEventTriggered.fulfill() + } + + _ = mutator.mutate(program, using: b, for: fuzzer) + waitForExpectations(timeout: 5, handler: nil) + } + } From 0ce37491c96ebd036b7299ee30a6682b5713812c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 14:17:58 +0200 Subject: [PATCH 205/234] [format] Add .swift-format with default settings Bug: 430616180 Change-Id: I168f494c2a1c0510fb6524495da4adb10ccd00cc Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155816 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- .swift-format | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .swift-format diff --git a/.swift-format b/.swift-format new file mode 100644 index 000000000..9cfa61292 --- /dev/null +++ b/.swift-format @@ -0,0 +1,79 @@ +{ + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "indentBlankLines" : false, + "indentConditionalCompilationBlocks" : true, + "indentSwitchCaseLabels" : false, + "indentation" : { + "spaces" : 2 + }, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : false, + "lineBreakBeforeEachGenericRequirement" : false, + "lineBreakBetweenDeclarationAttributes" : false, + "lineLength" : 100, + "maximumBlankLines" : 1, + "multiElementCollectionTrailingCommas" : true, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow" + ] + }, + "orderedImports" : { + "includeConditionalImports" : false + }, + "prioritizeKeepingFunctionOutputTogether" : false, + "reflowMultilineStringLiterals" : "never", + "respectsExistingLineBreaks" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : true, + "AmbiguousTrailingClosureOverload" : true, + "AvoidRetroactiveConformances" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyLinesOpeningClosingBraces" : false, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoPlaygroundLiterals" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : false, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "TypeNamesShouldBeCapitalized" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : true, + "UseLetInEveryBoundCaseVariable" : true, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : true, + "UseSynthesizedInitializer" : true, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + }, + "spacesAroundRangeFormationOperators" : false, + "spacesBeforeEndOfLineComments" : 2, + "tabWidth" : 8, + "version" : 1 +} From 0f65b69f8026cec47162b30e5ac818fbc64a2f27 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 14:19:06 +0200 Subject: [PATCH 206/234] [format] Change indentation to 4 spaces To align better with the current formatting. No other reason. Also add a few swift-ignore-format annotations for weights. Bug: 430616180 Change-Id: I07b5dae4938578a49ec393faaf18959e2867e58f Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155817 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- .swift-format | 2 +- Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.swift-format b/.swift-format index 9cfa61292..36423a346 100644 --- a/.swift-format +++ b/.swift-format @@ -6,7 +6,7 @@ "indentConditionalCompilationBlocks" : true, "indentSwitchCaseLabels" : false, "indentation" : { - "spaces" : 2 + "spaces" : 4 }, "lineBreakAroundMultilineExpressionChainComponents" : false, "lineBreakBeforeControlFlowKeywords" : false, diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index a26982e9c..f41d08997 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -13,6 +13,7 @@ // limitations under the License. /// Default weights for the builtin code generators. +// swift-format-ignore public let codeGeneratorWeights = [ // Value generators. These are used to bootstrap code // generation and therefore control the types of variables diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift index f642ceab8..c7274f4ad 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplateWeights.swift @@ -13,6 +13,7 @@ // limitations under the License. /// Default weights for the builtin program templates. +// swift-format-ignore public let programTemplateWeights = [ "Codegen100": 2, "Codegen50": 2, From e4732f007933e842d7125139f30488b953c43ee4 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 15:00:54 +0200 Subject: [PATCH 207/234] [wasm] Make lifting more robust for tags The implicit import mechanism in Wasm needs a rework sooner or later. For now, let's make it more robust in this case. Fixed: 498266575 Change-Id: I17cc0021cbe945d5db16029c451e3ea6bfb55ff1 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159837 Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach Reviewed-by: Michael Achenbach --- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index c3e880992..d57adaf38 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -772,7 +772,7 @@ public class WasmLifter { temp += mutability ? [0x1] : [0x0] continue } - if type.Is(.object(ofGroup: "WasmTag")) { + if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { temp += [0x4, 0x0] + Leb128.unsignedEncode(try getSignatureIndex(signature!)) continue } From eff49a5cbcffc15a69d4ac97d6b1b1dfdc40652b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Wed, 1 Apr 2026 20:55:10 +0200 Subject: [PATCH 208/234] [js] Improve Iterator.zip fuzzing by passing it an iterable of iterables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9e7e47344d5c9fb3e56545be210788e1d8e492ef Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155596 Commit-Queue: Marja Hölttä Reviewed-by: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index f41d08997..3fb6330d7 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -225,6 +225,7 @@ public let codeGeneratorWeights = [ "ApiMethodCallGenerator": 15, "ApiFunctionCallGenerator": 15, "VoidGenerator": 1, + "IteratorZipGenerator": 1, // JS generators for wasm features (e.g. APIs on the WebAssembly global object). "WasmGlobalGenerator": 4, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index dfa73e95f..c7ae98ce8 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1870,6 +1870,38 @@ public let CodeGenerators: [CodeGenerator] = [ b.void(val) }, + CodeGenerator("IteratorZipGenerator", inputs: .one) { b, val in + // Create an iterable of iterables + let iterable : Variable; + let topLevelIterableSize = Int.random(in: 0...10) + if probability(0.8) { + // Use Array as the top level iterable + let iterables = (0.. Date: Wed, 1 Apr 2026 19:52:30 +0200 Subject: [PATCH 209/234] [js] Lower RAB/GSAB related weights back to what they were RAB/GSAB was shipped a while ago, we don't need the boosted weights any more Change-Id: Ic7da221bc2d47b1966906566d1e0ca4616251153 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9160936 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../CodeGen/CodeGeneratorWeights.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 3fb6330d7..69a29a2ef 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -210,13 +210,13 @@ public let codeGeneratorWeights = [ "EvalGenerator": 3, "NumberComputationGenerator": 40, "ImitationGenerator": 30, - "ResizableArrayBufferGenerator": 5*6, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. - "ResizableBufferResizeGenerator": 5*3, - "GrowableSharedArrayBufferGenerator": 5*6, - "GrowableSharedBufferGrowGenerator": 5*3, - "TypedArrayFromBufferGenerator": 10*3, - "DataViewFromBufferGenerator": 5*3, - "TypedArrayLastIndexGenerator": 5*3, + "ResizableArrayBufferGenerator": 5, + "ResizableBufferResizeGenerator": 5, + "GrowableSharedArrayBufferGenerator": 5, + "GrowableSharedBufferGrowGenerator": 5, + "TypedArrayFromBufferGenerator": 10, + "DataViewFromBufferGenerator": 5, + "TypedArrayLastIndexGenerator": 5, "FastToSlowPropertiesGenerator": 10, "IteratorGenerator": 5, "ConstructWithDifferentNewTargetGenerator": 5, @@ -230,9 +230,9 @@ public let codeGeneratorWeights = [ // JS generators for wasm features (e.g. APIs on the WebAssembly global object). "WasmGlobalGenerator": 4, "WasmMemoryGenerator": 4, - "WasmMemoryToResizableBufferGenerator": 5*3, // TODO(tacet): Revert increased fuzzing probability factors by 02/2026 or later. - "WasmMemoryToFixedLengthBufferGenerator": 5*3, - "WasmMemoryJSGrowGenerator": 5*3, + "WasmMemoryToResizableBufferGenerator": 5, + "WasmMemoryToFixedLengthBufferGenerator": 5, + "WasmMemoryJSGrowGenerator": 5, "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, From e270121d8ed2c1101ef1717dc6a5a2aa2607a381 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 12:35:03 +0200 Subject: [PATCH 210/234] [js] Improve labels for ProgramBuilder.reassign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If51387c564c5c4245d23122be751ce46682b0fee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159756 Commit-Queue: Matthias Liedtke Reviewed-by: Marja Hölttä Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 8 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 6 +- .../Fuzzilli/Profiles/V8CommonProfile.swift | 16 ++-- Sources/Fuzzilli/Profiles/XSProfile.swift | 12 +-- Tests/FuzzilliTests/JSTyperTests.swift | 74 ++++++++--------- Tests/FuzzilliTests/LifterTest.swift | 80 +++++++++---------- Tests/FuzzilliTests/MinimizerTest.swift | 40 +++++----- Tests/FuzzilliTests/ProgramBuilderTest.swift | 18 ++--- 8 files changed, 127 insertions(+), 127 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index d29c09b88..657fec431 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3200,8 +3200,8 @@ public class ProgramBuilder { return emit(TernaryOperation(), withInputs: [condition, lhs, rhs]).output } - public func reassign(_ output: Variable, to input: Variable, with op: BinaryOperator) { - emit(Update(op), withInputs: [output, input]) + public func reassign(variable: Variable, value: Variable, with op: BinaryOperator) { + emit(Update(op), withInputs: [variable, value]) } @discardableResult @@ -3209,8 +3209,8 @@ public class ProgramBuilder { return emit(Dup(), withInputs: [v]).output } - public func reassign(_ output: Variable, to input: Variable) { - emit(Reassign(), withInputs: [output, input]) + public func reassign(variable: Variable, value: Variable) { + emit(Reassign(), withInputs: [variable, value]) } @discardableResult diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index c7ae98ce8..05ef29b52 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1420,7 +1420,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("BuiltinOverwriteGenerator", inputs: .one) { b, value in let builtin = b.createNamedVariable( b.randomBuiltin(), declarationMode: .none) - b.reassign(builtin, to: value) + b.reassign(variable: builtin, value: value) }, CodeGenerator("PlainFunctionGenerator", [ @@ -2104,7 +2104,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("UpdateGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) b.reassign( - newValue, to: v, with: chooseUniform(from: BinaryOperator.allCases)) + variable: newValue, value: v, with: chooseUniform(from: BinaryOperator.allCases)) }, CodeGenerator("DupGenerator") { b in @@ -2114,7 +2114,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("ReassignmentGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) guard newValue != v else { return } - b.reassign(newValue, to: v) + b.reassign(variable: newValue, value: v) }, CodeGenerator("DestructArrayGenerator", inputs: .preferred(.iterable)) { diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 43a004e68..6fb2fe379 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -522,11 +522,11 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let symbol = b.createNamedVariable(forBuiltin: "Symbol") withEqualProbability({ let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("match", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("replace", of: symbol) let replacement = withEqualProbability({ @@ -535,11 +535,11 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.loadString(chooseUniform(from: replacementCandidates)) }) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("search", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("split", of: symbol) let randomSplitLimit = withEqualProbability({ @@ -551,10 +551,10 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in }) let limit = b.loadString(randomSplitLimit) let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }) }, catchBody: { _ in }) @@ -590,7 +590,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in b.build(n: 10) b.buildIf(b.compare(counter, with: max, using: .lessThan)) { - b.reassign(counter, to: b.binary(counter, b.loadInt(1), with: .Add)) + b.reassign(variable: counter, value: b.binary(counter, b.loadInt(1), with: .Add)) b.callFunction(dummyFct, withArgs: b.randomArguments(forCalling: dummyFct)) } // Mark the function for deoptimization. Due to the recursive pattern above, on the outer @@ -601,7 +601,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in } // Turn the call into a recursive call. - b.reassign(dummyFct, to: realFct) + b.reassign(variable: dummyFct, value: realFct) let args = b.randomArguments(forCalling: realFct) let guardCalls = probability(0.5) b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); diff --git a/Sources/Fuzzilli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift index 02c500c97..8037aca28 100644 --- a/Sources/Fuzzilli/Profiles/XSProfile.swift +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -181,11 +181,11 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let symbol = b.createNamedVariable(forBuiltin: "Symbol") withEqualProbability({ let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("match", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("replace", of: symbol) let replacement = withEqualProbability({ @@ -194,11 +194,11 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.loadString(chooseUniform(from: replacementCandidates)) }) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("search", of: symbol) let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let prop = b.getProperty("split", of: symbol) let randomSplitLimit = withEqualProbability({ @@ -210,10 +210,10 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in }) let limit = b.loadString(randomSplitLimit) let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }, { let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(resultVar, to: res) + b.reassign(variable: resultVar, value: res) }) }, catchBody: { _ in }) diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index ebc6a7fe3..20f549f2b 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -131,7 +131,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) XCTAssertEqual(b.type(of: params[1]), .string) XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: params[1]) + b.reassign(variable: v, value: params[1]) XCTAssertEqual(b.type(of: v), .string) } @@ -143,7 +143,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) XCTAssertEqual(b.type(of: params[1]), .float) XCTAssertEqual(b.type(of: v), .integer | .string) - b.reassign(v, to: params[1]) + b.reassign(variable: v, value: params[1]) XCTAssertEqual(b.type(of: v), .float) } @@ -205,7 +205,7 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .float) } @@ -214,8 +214,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer | .float) XCTAssertEqual(b.type(of: f), .float) - b.reassign(v, to: b.loadString("bar")) - b.reassign(f, to: b.loadString("baz")) + b.reassign(variable: v, value: b.loadString("bar")) + b.reassign(variable: f, value: b.loadString("baz")) XCTAssertEqual(b.type(of: v), .jsString) XCTAssertEqual(b.type(of: f), .jsString) @@ -225,8 +225,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer | .float | .jsString) XCTAssertEqual(b.type(of: s), .jsString) - b.reassign(v, to: b.loadBool(true)) - b.reassign(s, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadBool(true)) + b.reassign(variable: s, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .boolean) XCTAssertEqual(b.type(of: s), .float) @@ -239,7 +239,7 @@ class JSTyperTests: XCTestCase { cls.addStaticInitializer { this in XCTAssertEqual(b.type(of: f), .float | .jsString) - b.reassign(f, to: b.loadBool(true)) + b.reassign(variable: f, value: b.loadBool(true)) XCTAssertEqual(b.type(of: f), .boolean) } @@ -530,11 +530,11 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) XCTAssertEqual(b.type(of: v), .float) let objVar = b.createObject(with: ["foo": b.loadInt(1337)]) - b.reassign(v, to: objVar) + b.reassign(variable: v, value: objVar) XCTAssertEqual(b.type(of: v), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) } @@ -553,7 +553,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let stringVar = b.loadString("foobar") - b.reassign(v, to: stringVar) + b.reassign(variable: v, value: stringVar) XCTAssertEqual(b.type(of: v), .jsString) }, elseBody: { XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) @@ -563,7 +563,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) }) XCTAssertEqual(b.type(of: v), .string | .float | .object() | .iterable) @@ -577,10 +577,10 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) XCTAssertEqual(b.type(of: v1), .integer) b.buildIfElse(v0, ifBody: { - b.reassign(v0, to: b.loadString("foo")) - b.reassign(v1, to: b.loadString("foo")) + b.reassign(variable: v0, value: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) }, elseBody: { - b.reassign(v1, to: b.loadString("bar")) + b.reassign(variable: v1, value: b.loadString("bar")) }) XCTAssertEqual(b.type(of: v0), .integer | .jsString) @@ -593,7 +593,7 @@ class JSTyperTests: XCTestCase { let i = b.loadInt(42) XCTAssertEqual(b.type(of: i), .integer) b.buildIf(i) { - b.reassign(i, to: b.loadString("foo")) + b.reassign(variable: i, value: b.loadString("foo")) } XCTAssertEqual(b.type(of: i), .integer | .jsString) @@ -609,11 +609,11 @@ class JSTyperTests: XCTestCase { b.buildIfElse(v, ifBody: { b.buildIfElse(v, ifBody: { b.buildIfElse(v, ifBody: { - b.reassign(v, to: b.loadString("foo")) + b.reassign(variable: v, value: b.loadString("foo")) XCTAssertEqual(b.type(of: v), .jsString) }, elseBody: { XCTAssertEqual(b.type(of: v), .integer) - b.reassign(v, to: b.loadBool(true)) + b.reassign(variable: v, value: b.loadBool(true)) XCTAssertEqual(b.type(of: v), .boolean) }) @@ -641,7 +641,7 @@ class JSTyperTests: XCTestCase { params in XCTAssertEqual(b.type(of: params[0]), .integer) } XCTAssertEqual(b.type(of: f), .functionAndConstructor(signature)) - b.reassign(f, to: b.loadString("foo")) + b.reassign(variable: f, value: b.loadString("foo")) XCTAssertEqual(b.type(of: f), .jsString) } } @@ -663,7 +663,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .jsString) let floatVar = b.loadFloat(13.37) - b.reassign(v, to: floatVar) + b.reassign(variable: v, value: floatVar) XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v), .float) @@ -995,14 +995,14 @@ class JSTyperTests: XCTestCase { // Logical operators produce .boolean in any case guard op != .LogicOr && op != .LogicAnd else { continue } - b.reassign(i3, to: i4, with: op) + b.reassign(variable: i3, value: i4, with: op) XCTAssertFalse(b.type(of: i3).MayBe(.bigint)) - b.reassign(i3, to: bi4, with: op) + b.reassign(variable: i3, value: bi4, with: op) // This isn't really necessary, as mixing types in this way // would lead to an exception in JS. Currently, we handle // it like this though. XCTAssert(b.type(of: i3).MayBe(.bigint)) - b.reassign(bi3, to: bi4, with: op) + b.reassign(variable: bi3, value: bi4, with: op) XCTAssert(b.type(of: bi3).Is(.bigint)) } } @@ -1014,8 +1014,8 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // The header executes unconditionally, but the body does not - b.buildWhileLoop({ b.reassign(v1, to: b.loadString("foo")); return b.loadBool(false) }) { - b.reassign(v2, to: b.loadString("bar")) + b.buildWhileLoop({ b.reassign(variable: v1, value: b.loadString("foo")); return b.loadBool(false) }) { + b.reassign(variable: v2, value: b.loadString("bar")) } XCTAssertEqual(b.type(of: v1), .jsString) @@ -1030,8 +1030,8 @@ class JSTyperTests: XCTestCase { let v2 = b.loadInt(1) // Both the header and the body execute unconditionally b.buildDoWhileLoop(do: { - b.reassign(v2, to: b.loadString("foo")) - }, while: { b.reassign(v1, to: b.loadString("bar")); return b.loadBool(false) }) + b.reassign(variable: v2, value: b.loadString("foo")) + }, while: { b.reassign(variable: v1, value: b.loadString("bar")); return b.loadBool(false) }) XCTAssertEqual(b.type(of: v1), .jsString) XCTAssertEqual(b.type(of: v2), .jsString) @@ -1048,14 +1048,14 @@ class JSTyperTests: XCTestCase { // The initializer block and the condition block are always executed. // The afterthought and body block may not be executed. b.buildForLoop({ - b.reassign(v1, to: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) }, { - b.reassign(v2, to: b.loadString("bar")) + b.reassign(variable: v2, value: b.loadString("bar")) return b.loadBool(false) }, { - b.reassign(v3, to: b.loadString("baz")) + b.reassign(variable: v3, value: b.loadString("baz")) }) { - b.reassign(v4, to: b.loadString("bla")) + b.reassign(variable: v4, value: b.loadString("bla")) } XCTAssertEqual(b.type(of: v1), .jsString) @@ -1107,7 +1107,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let stringVar = b.loadString("foobar") - b.reassign(v0, to: stringVar) + b.reassign(variable: v0, value: stringVar) XCTAssertEqual(b.type(of: v0), .jsString) } swtch.addDefaultCase { @@ -1118,7 +1118,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let boolVal = b.loadBool(false) - b.reassign(v0, to: boolVal) + b.reassign(variable: v0, value: boolVal) XCTAssertEqual(b.type(of: v0), .boolean) } swtch.addCase(v4) { @@ -1129,7 +1129,7 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .integer) let floatVar = b.loadFloat(13.37) - b.reassign(v0, to: floatVar) + b.reassign(variable: v0, value: floatVar) XCTAssertEqual(b.type(of: v0), .float) } } @@ -1150,7 +1150,7 @@ class JSTyperTests: XCTestCase { swtch.addDefaultCase { XCTAssertEqual(b.type(of: i1), .integer) XCTAssertEqual(b.type(of: i2), .integer) - b.reassign(i2, to: b.loadString("bar")) + b.reassign(variable: i2, value: b.loadString("bar")) } } @@ -1171,13 +1171,13 @@ class JSTyperTests: XCTestCase { b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { XCTAssertEqual(b.type(of: v), .jsString) - b.reassign(v, to: b.loadFloat(13.37)) + b.reassign(variable: v, value: b.loadFloat(13.37)) XCTAssertEqual(b.type(of: v), .float) } swtch.addCase(i3) { XCTAssertEqual(b.type(of: v), .jsString) - b.reassign(v, to: b.loadBool(false)) + b.reassign(variable: v, value: b.loadBool(false)) XCTAssertEqual(b.type(of: v), .boolean) } } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 9308fa71a..0f1a51621 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -334,7 +334,7 @@ class LifterTests: XCTestCase { b.createArray(with: [n1, n1, n1]) // ... but when it's reassigned, the identifier needs to be stored to a local variable. let n2 = b.loadFloat(Double.nan) - b.reassign(n2, to: b.loadFloat(13.37)) + b.reassign(variable: n2, value: b.loadFloat(13.37)) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -870,7 +870,7 @@ class LifterTests: XCTestCase { } } b.construct(C, withArgs: [b.loadInt(42)]) - b.reassign(C, to: b.createNamedVariable(forBuiltin: "Uint8Array")) + b.reassign(variable: C, value: b.createNamedVariable(forBuiltin: "Uint8Array")) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -1194,7 +1194,7 @@ class LifterTests: XCTestCase { initialValues.append(b.loadUndefined()) initialValues.append(b.loadInt(6)) let v = b.loadString("foobar") - b.reassign(v, to: b.loadUndefined()) + b.reassign(variable: v, value: b.loadUndefined()) initialValues.append(v) let va = b.createArray(with: initialValues) b.createArray(with: [b.loadInt(301), b.loadUndefined()]) @@ -1363,7 +1363,7 @@ class LifterTests: XCTestCase { let f2 = b.buildArrowFunction(with: .parameters(n: 0)) { args in b.doReturn(b.loadString("foobar")) } - b.reassign(f, to: f2) + b.reassign(variable: f, value: f2) b.callFunction(f) let program = b.finalize() @@ -1483,7 +1483,7 @@ class LifterTests: XCTestCase { } b.construct(c1, withArgs: [b.loadInt(42), b.loadInt(43)]) let c2 = b.createNamedVariable(forBuiltin: "Object") - b.reassign(c1, to: c2) + b.reassign(variable: c1, value: c2) b.construct(c1, withArgs: [b.loadInt(44), b.loadInt(45)]) let program = b.finalize() @@ -1569,9 +1569,9 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(1337) let v1 = b.loadFloat(13.37) - b.reassign(v0, to: v1, with: .Add) + b.reassign(variable: v0, value: v1, with: .Add) let v2 = b.loadString("Hello") - b.reassign(v1, to: v2) + b.reassign(variable: v1, value: v2) let v3 = b.loadInt(1336) let v4 = b.unary(.PreInc, v3) b.unary(.PostInc, v4) @@ -1599,12 +1599,12 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(1337) let v1 = b.loadFloat(13.37) - b.reassign(v0, to: v1, with: .Add) - b.reassign(v0, to: v1, with: .Mul) - b.reassign(v0, to: v1, with: .LShift) + b.reassign(variable: v0, value: v1, with: .Add) + b.reassign(variable: v0, value: v1, with: .Mul) + b.reassign(variable: v0, value: v1, with: .LShift) let v2 = b.loadString("hello") let v3 = b.loadString("world") - b.reassign(v2, to: v3, with: .Add) + b.reassign(variable: v2, value: v3, with: .Add) let program = b.finalize() let actual = fuzzer.lifter.lift(program) @@ -1630,38 +1630,38 @@ class LifterTests: XCTestCase { let bar = b.createNamedVariable(forBuiltin: "bar") let baz = b.createNamedVariable(forBuiltin: "baz") let i = b.loadInt(42) - b.reassign(i, to: b.loadInt(43)) + b.reassign(variable: i, value: b.loadInt(43)) b.callFunction(foo, withArgs: [i]) b.callFunction(bar, withArgs: [i]) let j = b.loadInt(44) - b.reassign(j, to: b.loadInt(45)) - b.reassign(j, to: b.loadInt(46)) + b.reassign(variable: j, value: b.loadInt(45)) + b.reassign(variable: j, value: b.loadInt(46)) b.callFunction(foo, withArgs: [j]) let k = b.loadInt(47) b.buildRepeatLoop(n: 10) { i in - b.reassign(k, to: i) + b.reassign(variable: k, value: i) } b.callFunction(foo, withArgs: [k]) let l = b.loadInt(48) - b.reassign(l, to: b.loadInt(49)) + b.reassign(variable: l, value: b.loadInt(49)) b.callFunction(foo, withArgs: [l, l, l]) let m = b.loadInt(50) - b.reassign(m, to: b.loadInt(51)) + b.reassign(variable: m, value: b.loadInt(51)) var t = b.callFunction(baz) t = b.callFunction(bar, withArgs: [m, m, t, m]) b.callFunction(foo, withArgs: [t]) // Some operations such as element stores force the lhs to be an identifier, so test that here. let n = b.loadInt(52) - b.reassign(n, to: b.createArray(with: [])) + b.reassign(variable: n, value: b.createArray(with: [])) b.setElement(42, of: n, to: n) let o = b.loadInt(53) - b.buildWhileLoop({ b.reassign(o, to: i); return b.loadBool(false) }) { + b.buildWhileLoop({ b.reassign(variable: o, value: i); return b.loadBool(false) }) { } b.callFunction(foo, withArgs: [o]) @@ -1803,7 +1803,7 @@ class LifterTests: XCTestCase { b.doReturn(v) } let f2 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.reassign(v, to: args[0]) + b.reassign(variable: v, value: args[0]) } let num = b.loadInt(42) b.configureProperty("foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) @@ -1942,9 +1942,9 @@ class LifterTests: XCTestCase { let v3 = b.callMethod("n", on: o, guard: true) b.callComputedMethod(b.loadString("o"), on: o, withArgs: [v1, v2, v3], guard: true) let v4 = b.callComputedMethod(b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) - b.reassign(v3, to: b.loadString("foo")) - b.reassign(v4, to: b.loadString("bar")) - b.reassign(v3, to: b.loadString("baz")) + b.reassign(variable: v3, value: b.loadString("foo")) + b.reassign(variable: v4, value: b.loadString("bar")) + b.reassign(variable: v3, value: b.loadString("baz")) let program = b.finalize() @@ -2687,7 +2687,7 @@ class LifterTests: XCTestCase { b.callFunction(print, withArgs: [vb1]) b.createNamedVariable("c", declarationMode: .global, initialValue: i2) let vb2 = b.createNamedVariable("b", declarationMode: .var, initialValue: i2) - b.reassign(vb2, to: i1) + b.reassign(variable: vb2, value: i1) let vc = b.createNamedVariable("c", declarationMode: .none) b.callFunction(print, withArgs: [vc]) let undefined = b.loadUndefined() @@ -3196,7 +3196,7 @@ class LifterTests: XCTestCase { b.buildForLoop({ let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")); let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")); b.callFunction(b.createNamedVariable(forBuiltin: "h")); return [x, y] }, { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, - { vs in b.reassign(vs[0], to: vs[1], with: .Add) }) { vs in + { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) }) { vs in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: vs) } @@ -3228,7 +3228,7 @@ class LifterTests: XCTestCase { { let shouldContinue = b.callFunction(b.createNamedVariable(forBuiltin: "shouldContinue")) b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { - b.reassign(shouldContinue, to: b.loadBool(false)) + b.reassign(variable: shouldContinue, value: b.loadBool(false)) } return shouldContinue }) { @@ -3260,7 +3260,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign($0, to: b.loadInt(10), with: .Add) }) { i in + b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) }) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) } @@ -3308,7 +3308,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(i, to: args[2], with: .Sub)}) { vars in + b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(variable: i, value: args[2], with: .Sub)}) { vars in } } @@ -3368,7 +3368,7 @@ class LifterTests: XCTestCase { // Test that context-dependent operations such as LoadArguments are handled correctly inside loop headers b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in let arg = b.getComputedProperty(i, of: b.loadArguments()) - b.reassign(s, to: arg, with: .Add) + b.reassign(variable: s, value: arg, with: .Add) } b.doReturn(s) } @@ -3396,7 +3396,7 @@ class LifterTests: XCTestCase { let s = b.loadInt(0) b.buildRepeatLoop(n: 1337) { i in - b.reassign(s, to: i, with: .Add) + b.reassign(variable: s, value: i, with: .Add) } let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [s]) @@ -3457,10 +3457,10 @@ class LifterTests: XCTestCase { b.buildForInLoop(v1) { v2 in b.blockStatement { let v3 = b.loadInt(1337) - b.reassign(v2, to: v3) + b.reassign(variable: v2, value: v3) b.blockStatement { let v4 = b.createObject(with: ["a" : v1]) - b.reassign(v2, to: v4) + b.reassign(variable: v2, value: v4) } } @@ -3581,24 +3581,24 @@ class LifterTests: XCTestCase { let this = b.loadThis() let v = b.loadInt(42) - b.reassign(this, to: v) + b.reassign(variable: this, value: v) b.buildConstructor(with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } b.buildObjectLiteral { obj in obj.addMethod("foo", with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } } b.buildClassDefinition { cls in cls.addInstanceMethod("bar", with: .parameters(n: 0)) { args in - b.reassign(args[0], to: v) + b.reassign(variable: args[0], value: v) } cls.addStaticGetter(for: "baz") { this in - b.reassign(this, to: v) + b.reassign(variable: this, value: v) } } @@ -3657,7 +3657,7 @@ class LifterTests: XCTestCase { b.unary(.BitwiseNot, v0) b.binary(v0, v2, with: .Add) let v3 = b.loadInt(42) - b.reassign(v3, to: v0) + b.reassign(variable: v3, value: v0) let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [v0, v1, v2]) b.getProperty("foo", of: v1) @@ -3691,7 +3691,7 @@ class LifterTests: XCTestCase { let variable = b.loadNull() b.buildPlainFunction(with: .parameters(n: 0)) { args in let t = b.loadNewTarget() - b.reassign(variable, to: t) + b.reassign(variable: variable, value: t) } let program = b.finalize() @@ -3836,7 +3836,7 @@ class LifterTests: XCTestCase { // We will mutate this to reassign table to be f. // The steps for this to happen during fuzzing are as follows, we emit all of this during generation time, then we emit this reassign later, e.g. during CodeGenMutation or we change an existing reassign during InputMutation. // Then we need to be able to recover from this in the importAnalysis as this is the first code that tries to use the mistyped inputs. - b.reassign(table, to: table) + b.reassign(variable: table, value: table) b.buildWasmModule { m in m.addWasmFunction(with: [] => []) { f, _, _ in diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index b874ca9c6..2878c9431 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -355,7 +355,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -408,7 +408,7 @@ class MinimizerTests: XCTestCase { swtch.addDefaultCase(fallsThrough: false) { evaluator.nextInstructionIsImportant(in: b) let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -466,7 +466,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -510,7 +510,7 @@ class MinimizerTests: XCTestCase { } swtch.addDefaultCase(fallsThrough: false) { let x = b.loadString("foobar") - b.reassign(num, to: x) + b.reassign(variable: num, value: x) } } @@ -637,9 +637,9 @@ class MinimizerTests: XCTestCase { let u = b.loadUndefined() r = b.loadUndefined() b.buildIfElse(a1, ifBody: { - b.reassign(r, to: a2) + b.reassign(variable: r, value: a2) }, elseBody: { - b.reassign(r, to: u) + b.reassign(variable: r, value: u) }) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: r) @@ -711,9 +711,9 @@ class MinimizerTests: XCTestCase { a3 = b.loadInt(2) r = b.loadUndefined() b.buildIf(a1, ifBody: { - b.reassign(r, to: a2) + b.reassign(variable: r, value: a2) }) - b.reassign(r, to: a3) + b.reassign(variable: r, value: a3) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: a3) @@ -835,25 +835,25 @@ class MinimizerTests: XCTestCase { var n1 = b.loadInt(42) var n2 = b.loadInt(43) var n3 = b.loadInt(44) - b.reassign(n3, to: n1) + b.reassign(variable: n3, value: n1) var n4 = b.loadInt(45) - b.reassign(n4, to: n3) + b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 var c = b.loadBool(true) b.buildIfElse(c, ifBody: { let n5 = b.loadInt(46) - b.reassign(n1, to: n5) + b.reassign(variable: n1, value: n5) b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 }, elseBody: { let n6 = b.loadInt(47) - b.reassign(n1, to: n6) + b.reassign(variable: n1, value: n6) b.setProperty( "n3", of: o, to: n3) // This will still store n3, i.e. 42 }) b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 evaluator.operationIsImportant(Reassign.self) @@ -869,26 +869,26 @@ class MinimizerTests: XCTestCase { n1 = b.loadInt(42) n2 = b.loadInt(43) n3 = b.loadInt(44) - b.reassign(n3, to: n1) + b.reassign(variable: n3, value: n1) n4 = b.loadInt(45) - b.reassign(n4, to: n3) + b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n1) c = b.loadBool(true) b.buildIfElse(c, ifBody: { let n5 = b.loadInt(46) - b.reassign(n1, to: n5) + b.reassign(variable: n1, value: n5) b.setProperty("n1", of: o, to: n5) b.setProperty("n1", of: o, to: n5) - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) b.setProperty("n1", of: o, to: n2) }, elseBody: { let n6 = b.loadInt(47) - b.reassign(n1, to: n6) + b.reassign(variable: n1, value: n6) b.setProperty("n3", of: o, to: n3) }) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n1", of: o, to: n1) - b.reassign(n1, to: n2) + b.reassign(variable: n1, value: n2) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n3", of: o, to: n3) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 5f495f0dc..7dc3dfd2a 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2007,7 +2007,7 @@ class ProgramBuilderTests: XCTestCase { b.buildPlainFunction(with: .parameters(n: 1)) { args in let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(f2, to: b.loadFloat(133.7)) + b.reassign(variable: f2, value: b.loadFloat(133.7)) let o = b.createObject(with: ["i": i, "f": f]) let o2 = b.createObject(with: ["i": i, "f": f2]) b.binary(i, args[0], with: .Add) @@ -2035,7 +2035,7 @@ class ProgramBuilderTests: XCTestCase { f2 = b.loadFloat(13.37) let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(f2, to: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included + b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included let o = b.createObject(with: ["i": i, "f": f]) b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included let object = b.createNamedVariable(forBuiltin: "Object") @@ -2343,7 +2343,7 @@ class ProgramBuilderTests: XCTestCase { b.throwException(v) }, catchBody: { e in splicePoint = b.indexOfNextInstruction() - b.reassign(e, to: s) + b.reassign(variable: e, value: s) }) let original = b.finalize() @@ -2459,13 +2459,13 @@ class ProgramBuilderTests: XCTestCase { splicePoint = b.indexOfNextInstruction() b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { - b.reassign(s, to: b.loadString("Bar")) + b.reassign(variable: s, value: b.loadString("Bar")) } swtch.addCase(i3) { - b.reassign(s, to: b.loadString("Baz")) + b.reassign(variable: s, value: b.loadString("Baz")) } swtch.addDefaultCase { - b.reassign(s, to: b.loadString("Bla")) + b.reassign(variable: s, value: b.loadString("Bla")) } } let original = b.finalize() @@ -2493,13 +2493,13 @@ class ProgramBuilderTests: XCTestCase { var s = b.loadString("Foo") b.buildSwitch(on: i1) { swtch in swtch.addCase(i2) { - b.reassign(s, to: b.loadString("Bar")) + b.reassign(variable: s, value: b.loadString("Bar")) } swtch.addCase(i3) { - b.reassign(s, to: b.loadString("Baz")) + b.reassign(variable: s, value: b.loadString("Baz")) } swtch.addDefaultCase { - b.reassign(s, to: b.loadString("Bla")) + b.reassign(variable: s, value: b.loadString("Bla")) } } let original = b.finalize() From c523132767b1e7061307c08d22b75f218b3d7b4b Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 1 Apr 2026 12:39:59 +0200 Subject: [PATCH 211/234] [js] Fix order of reassignment logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostly just to match the naming of `newValue` and the subtyping idea of the forUseAs where we try to find something that is a subtype of the current variable's type, not the other way around. Change-Id: I3144025a0e1850892936087fdf275d318943f963 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9159757 Reviewed-by: Marja Hölttä Commit-Queue: Matthias Liedtke Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 05ef29b52..d8f8890fd 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -2104,7 +2104,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("UpdateGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) b.reassign( - variable: newValue, value: v, with: chooseUniform(from: BinaryOperator.allCases)) + variable: v, value: newValue, with: chooseUniform(from: BinaryOperator.allCases)) }, CodeGenerator("DupGenerator") { b in @@ -2114,7 +2114,7 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("ReassignmentGenerator", inputs: .one) { b, v in let newValue = b.randomVariable(forUseAs: b.type(of: v)) guard newValue != v else { return } - b.reassign(variable: newValue, value: v) + b.reassign(variable: v, value: newValue) }, CodeGenerator("DestructArrayGenerator", inputs: .preferred(.iterable)) { From 96773dbfb1f66483db0c23ed3819ec5249b7709c Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 2 Apr 2026 14:04:02 +0200 Subject: [PATCH 212/234] [format] Apply auto-formatting Bug: 430616180 Change-Id: I12f41e8c87913481f05f3bf350acdb88ac08c163 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9155818 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Package.swift | 92 +- Sources/FuzzILTool/main.swift | 69 +- Sources/Fuzzilli/Base/ContextGraph.swift | 42 +- Sources/Fuzzilli/Base/Contributor.swift | 3 +- Sources/Fuzzilli/Base/Events.swift | 10 +- Sources/Fuzzilli/Base/Logging.swift | 6 +- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2718 ++++++---- Sources/Fuzzilli/Base/Timers.swift | 6 +- Sources/Fuzzilli/CodeGen/CodeGenerator.swift | 330 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 708 +-- .../Fuzzilli/CodeGen/ProgramTemplate.swift | 5 +- .../Fuzzilli/CodeGen/ProgramTemplates.swift | 196 +- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 607 ++- Sources/Fuzzilli/Compiler/Compiler.swift | 444 +- .../Fuzzilli/Compiler/JavaScriptParser.swift | 6 +- Sources/Fuzzilli/Configuration.swift | 43 +- Sources/Fuzzilli/Corpus/BasicCorpus.swift | 2 +- Sources/Fuzzilli/Corpus/Corpus.swift | 6 +- Sources/Fuzzilli/Corpus/MarkovCorpus.swift | 6 +- .../Fuzzilli/DumplingDiffOracle/Oracle.swift | 69 +- Sources/Fuzzilli/Engines/FuzzEngine.swift | 92 +- Sources/Fuzzilli/Engines/HybridEngine.swift | 36 +- Sources/Fuzzilli/Engines/MultiEngine.swift | 8 +- Sources/Fuzzilli/Engines/MutationEngine.swift | 3 +- .../Environment/JavaScriptEnvironment.swift | 3639 +++++++++----- .../Evaluation/ProgramCoverageEvaluator.swift | 46 +- .../Evaluation/ProgramEvaluator.swift | 3 +- Sources/Fuzzilli/Execution/Execution.swift | 25 +- Sources/Fuzzilli/Execution/REPRL.swift | 34 +- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 12 +- Sources/Fuzzilli/FuzzIL/Blocks.swift | 1 - Sources/Fuzzilli/FuzzIL/Code.swift | 31 +- Sources/Fuzzilli/FuzzIL/Context.swift | 30 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 934 ++-- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 963 ++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 520 +- Sources/Fuzzilli/FuzzIL/Operation.swift | 29 +- Sources/Fuzzilli/FuzzIL/Program.swift | 11 +- Sources/Fuzzilli/FuzzIL/ProgramComments.swift | 2 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 39 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 669 ++- Sources/Fuzzilli/FuzzIL/Variable.swift | 4 +- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 740 +-- Sources/Fuzzilli/Fuzzer.swift | 356 +- Sources/Fuzzilli/Lifting/Expression.swift | 20 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 353 +- Sources/Fuzzilli/Lifting/JSExpressions.swift | 53 +- .../Lifting/JavaScriptExploreLifting.swift | 810 +-- .../Lifting/JavaScriptFixupLifting.swift | 196 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 700 +-- .../Lifting/JavaScriptProbeLifting.swift | 224 +- ...aScriptRuntimeAssistedMutatorLifting.swift | 1090 ++-- Sources/Fuzzilli/Lifting/ScriptWriter.swift | 14 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 583 ++- .../Fuzzilli/Minimization/BlockReducer.swift | 157 +- .../Minimization/DataFlowSimplifier.swift | 18 +- .../Minimization/DeduplicatingReducer.swift | 8 +- .../Minimization/InliningReducer.swift | 94 +- .../Minimization/InstructionSimplifier.swift | 43 +- .../Minimization/LoopSimplifier.swift | 110 +- .../Minimization/MinimizationHelper.swift | 70 +- .../MinimizationPostProcessor.swift | 60 +- Sources/Fuzzilli/Minimization/Minimizer.swift | 43 +- .../Minimization/VariadicInputReducer.swift | 32 +- .../Minimization/WasmTypeGroupReducer.swift | 14 +- Sources/Fuzzilli/Modules/NetworkSync.swift | 101 +- Sources/Fuzzilli/Modules/Statistics.swift | 34 +- Sources/Fuzzilli/Modules/Storage.swift | 47 +- Sources/Fuzzilli/Modules/Sync.swift | 87 +- Sources/Fuzzilli/Modules/ThreadSync.swift | 17 +- .../Mutators/BaseInstructionMutator.swift | 7 +- .../Fuzzilli/Mutators/CodeGenMutator.swift | 7 +- Sources/Fuzzilli/Mutators/ConcatMutator.swift | 4 +- .../Mutators/ExplorationMutator.swift | 31 +- Sources/Fuzzilli/Mutators/FixupMutator.swift | 123 +- Sources/Fuzzilli/Mutators/InputMutator.swift | 18 +- .../Fuzzilli/Mutators/MutatorSettings.swift | 3 +- .../Fuzzilli/Mutators/OperationMutator.swift | 793 +-- .../Fuzzilli/Mutators/ProbingMutator.swift | 62 +- .../Mutators/RuntimeAssistedMutator.swift | 122 +- Sources/Fuzzilli/Mutators/SpliceMutator.swift | 3 +- .../Fuzzilli/Profiles/DuktapeProfile.swift | 19 +- Sources/Fuzzilli/Profiles/JSCProfile.swift | 52 +- .../Profiles/JerryscriptProfile.swift | 15 +- Sources/Fuzzilli/Profiles/NjsProfile.swift | 5 +- Sources/Fuzzilli/Profiles/Profile.swift | 3 +- Sources/Fuzzilli/Profiles/QjsProfile.swift | 7 +- Sources/Fuzzilli/Profiles/QtjsProfile.swift | 16 +- Sources/Fuzzilli/Profiles/Serenity.swift | 13 +- .../Profiles/SpidermonkeyProfile.swift | 33 +- .../Fuzzilli/Profiles/V8CommonProfile.swift | 559 ++- .../Fuzzilli/Profiles/V8DumplingProfile.swift | 128 +- .../Profiles/V8HoleFuzzingProfile.swift | 29 +- Sources/Fuzzilli/Profiles/V8Profile.swift | 74 +- .../Fuzzilli/Profiles/V8SandboxProfile.swift | 627 +-- Sources/Fuzzilli/Profiles/XSProfile.swift | 250 +- Sources/Fuzzilli/Protobuf/ProtoUtils.swift | 13 +- Sources/Fuzzilli/Util/Arguments.swift | 4 +- Sources/Fuzzilli/Util/CInterop.swift | 12 +- .../Fuzzilli/Util/JavaScriptExecutor.swift | 88 +- Sources/Fuzzilli/Util/MockFuzzer.swift | 87 +- Sources/Fuzzilli/Util/Random.swift | 8 +- Sources/Fuzzilli/Util/VariableMap.swift | 2 +- Sources/Fuzzilli/Util/VariableSet.swift | 2 +- Sources/FuzzilliCli/TerminalUI.swift | 90 +- Sources/FuzzilliCli/main.swift | 431 +- .../FuzzilliDetectMissingBuiltins/main.swift | 191 +- Sources/REPRLRun/main.swift | 16 +- Sources/RelateTool/main.swift | 7 +- Tests/FuzzilliTests/AnalyzerTest.swift | 94 +- Tests/FuzzilliTests/CompilerTests.swift | 24 +- Tests/FuzzilliTests/ContextGraphTest.swift | 19 +- .../CrashingInstrumentationMutator.swift | 9 +- Tests/FuzzilliTests/DiffOracleTests.swift | 575 +-- Tests/FuzzilliTests/EngineTests.swift | 7 +- Tests/FuzzilliTests/EnvironmentTest.swift | 34 +- Tests/FuzzilliTests/JSTyperTests.swift | 948 ++-- Tests/FuzzilliTests/Leb128Test.swift | 5 +- Tests/FuzzilliTests/LifterTest.swift | 2810 ++++++----- Tests/FuzzilliTests/LiveTests.swift | 92 +- Tests/FuzzilliTests/MinimizerTest.swift | 505 +- Tests/FuzzilliTests/MutatorTests.swift | 9 +- Tests/FuzzilliTests/ProgramBuilderTest.swift | 776 +-- .../ProgramSerializationTest.swift | 15 +- Tests/FuzzilliTests/RingBufferTest.swift | 1 + .../RuntimeAssistedMutatorTests.swift | 44 +- Tests/FuzzilliTests/ScriptWriterTest.swift | 77 +- Tests/FuzzilliTests/TestUtils.swift | 23 +- Tests/FuzzilliTests/TypeSystemTest.swift | 722 ++- Tests/FuzzilliTests/VariableMapTest.swift | 11 +- Tests/FuzzilliTests/VariableSetTest.swift | 2 +- Tests/FuzzilliTests/WasmAtomicsTests.swift | 235 +- Tests/FuzzilliTests/WasmTableTests.swift | 4 +- Tests/FuzzilliTests/WasmTests.swift | 4436 +++++++++++------ 134 files changed, 20842 insertions(+), 13162 deletions(-) diff --git a/Package.swift b/Package.swift index c7f6c90f0..e19a9dbee 100644 --- a/Package.swift +++ b/Package.swift @@ -19,10 +19,10 @@ import PackageDescription let package = Package( name: "Fuzzilli", platforms: [ - .macOS(.v13), + .macOS(.v13) ], products: [ - .library(name: "Fuzzilli",targets: ["Fuzzilli"]), + .library(name: "Fuzzilli", targets: ["Fuzzilli"]) ], dependencies: [ // We use an exact version here as we also use this version to generate the .pb.swift to @@ -31,62 +31,74 @@ let package = Package( // regenerated, whenever the version is bumped. .package(url: "https://github.com/apple/swift-protobuf.git", exact: "1.35.0"), .package( - url: "https://github.com/apple/swift-collections.git", - .upToNextMinor(from: "1.2.0") + url: "https://github.com/apple/swift-collections.git", + .upToNextMinor(from: "1.2.0") ), ], targets: [ - .target(name: "libsocket", - dependencies: []), + .target( + name: "libsocket", + dependencies: []), - .target(name: "libreprl", - dependencies: []), + .target( + name: "libreprl", + dependencies: []), - .target(name: "libcoverage", - dependencies: [], - cSettings: [.unsafeFlags(["-O3"])], // Using '-c release' when building uses '-O2', so '-O3' provides a performance gain - linkerSettings: [.linkedLibrary("rt", .when(platforms: [.linux]))]), + .target( + name: "libcoverage", + dependencies: [], + cSettings: [.unsafeFlags(["-O3"])], // Using '-c release' when building uses '-O2', so '-O3' provides a performance gain + linkerSettings: [.linkedLibrary("rt", .when(platforms: [.linux]))]), - .target(name: "Fuzzilli", - dependencies: [ - .product(name: "SwiftProtobuf", package: "swift-protobuf"), - .product(name: "Collections", package: "swift-collections"), - "libsocket", - "libreprl", - "libcoverage"], - exclude: [ - "Protobuf/operations.proto", - "Protobuf/program.proto", - "Protobuf/sync.proto", - "Protobuf/README.md", - "Protobuf/gen_programproto.py"], - resources: [ - // The ast.proto file is required by the node.js parser - .copy("Protobuf/ast.proto"), - .copy("Compiler/Parser")]), + .target( + name: "Fuzzilli", + dependencies: [ + .product(name: "SwiftProtobuf", package: "swift-protobuf"), + .product(name: "Collections", package: "swift-collections"), + "libsocket", + "libreprl", + "libcoverage", + ], + exclude: [ + "Protobuf/operations.proto", + "Protobuf/program.proto", + "Protobuf/sync.proto", + "Protobuf/README.md", + "Protobuf/gen_programproto.py", + ], + resources: [ + // The ast.proto file is required by the node.js parser + .copy("Protobuf/ast.proto"), + .copy("Compiler/Parser"), + ]), - .executableTarget(name: "REPRLRun", - dependencies: ["libreprl"]), + .executableTarget( + name: "REPRLRun", + dependencies: ["libreprl"]), - .executableTarget(name: "FuzzilliCli", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "FuzzilliCli", + dependencies: ["Fuzzilli"]), - .executableTarget(name: "FuzzILTool", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "FuzzILTool", + dependencies: ["Fuzzilli"]), // Tool that runs d8 in Dumpling mode. First time it runs with Maglev // and Turbofan. Second time without. In both runs frames are dumped // in certain points to the files. The dumps are later compared for // equality. If they are not equal, it means that there's likely a bug // in V8. - .executableTarget(name: "RelateTool", - dependencies: ["Fuzzilli"]), + .executableTarget( + name: "RelateTool", + dependencies: ["Fuzzilli"]), .executableTarget(name: "FuzzilliDetectMissingBuiltins", dependencies: ["Fuzzilli"]), - .testTarget(name: "FuzzilliTests", - dependencies: ["Fuzzilli"], - resources: [.copy("CompilerTests")]), + .testTarget( + name: "FuzzilliTests", + dependencies: ["Fuzzilli"], + resources: [.copy("CompilerTests")]), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/FuzzILTool/main.swift b/Sources/FuzzILTool/main.swift index 3843dbc1f..bc1495653 100644 --- a/Sources/FuzzILTool/main.swift +++ b/Sources/FuzzILTool/main.swift @@ -33,7 +33,7 @@ func loadProgram(from path: String) throws -> Program { func loadAllPrograms(in dirPath: String) -> [(filename: String, program: Program)] { var isDir: ObjCBool = false - if !FileManager.default.fileExists(atPath: dirPath, isDirectory:&isDir) || !isDir.boolValue { + if !FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) || !isDir.boolValue { print("\(dirPath) is not a directory!") exit(-1) } @@ -56,7 +56,7 @@ func loadAllPrograms(in dirPath: String) -> [(filename: String, program: Program } // Takes a program and lifts it to JavaScript. -func liftToJS(_ jsLifter: JavaScriptLifter,_ prog: Program) -> String { +func liftToJS(_ jsLifter: JavaScriptLifter, _ prog: Program) -> String { let res = jsLifter.lift(prog) return res.trimmingCharacters(in: .whitespacesAndNewlines) } @@ -72,10 +72,13 @@ func liftToFuzzIL(_ prog: Program) -> String { func liftAllPrograms(in dirPath: String, with lifter: Lifter, fileExtension: String) -> Int { var numLiftedPrograms = 0 for (filename, program) in loadAllPrograms(in: dirPath) { - let newFilePath = "\(dirPath)/\(filename.dropLast(protoBufFileExtension.count))\(fileExtension)" + let newFilePath = + "\(dirPath)/\(filename.dropLast(protoBufFileExtension.count))\(fileExtension)" let content = lifter.lift(program) do { - try content.write(to: URL(fileURLWithPath: newFilePath), atomically: false, encoding: String.Encoding.utf8) + try content.write( + to: URL(fileURLWithPath: newFilePath), atomically: false, + encoding: String.Encoding.utf8) numLiftedPrograms += 1 } catch { print("Failed to write file \(newFilePath): \(error)") @@ -96,29 +99,32 @@ func loadProgramOrExit(from path: String) -> Program { let args = Arguments.parse(from: CommandLine.arguments) if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != 1 { - print(""" - Usage: - \(args.programName) options path - - Options: - --liftToFuzzIL : Lifts the given protobuf program to FuzzIL's text format and prints it - --liftToJS : Lifts the given protobuf program to JS and prints it - --liftCorpusToJS : Loads all .fzil files in a directory and lifts them to .js files in that same directory - --dumpProtobuf : Dumps the raw content of the given protobuf file - --dumpProgram : Dumps the internal representation of the program stored in the given protobuf file - --checkCorpus : Attempts to load all .fzil files in a directory and checks if they are statically valid - --compile : Compile the given JavaScript program to a FuzzIL program. Requires node.js - --outputPathJS : If given, --compile will write the lifted JS file to the given path after compilation. - --generate : Generate a random program using Fuzzilli's code generators and save it to the specified path. - --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. - """) + print( + """ + Usage: + \(args.programName) options path + + Options: + --liftToFuzzIL : Lifts the given protobuf program to FuzzIL's text format and prints it + --liftToJS : Lifts the given protobuf program to JS and prints it + --liftCorpusToJS : Loads all .fzil files in a directory and lifts them to .js files in that same directory + --dumpProtobuf : Dumps the raw content of the given protobuf file + --dumpProgram : Dumps the internal representation of the program stored in the given protobuf file + --checkCorpus : Attempts to load all .fzil files in a directory and checks if they are statically valid + --compile : Compile the given JavaScript program to a FuzzIL program. Requires node.js + --outputPathJS : If given, --compile will write the lifted JS file to the given path after compilation. + --generate : Generate a random program using Fuzzilli's code generators and save it to the specified path. + --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + """) exit(0) } let path = args[0] let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") -let jsLifter = JavaScriptLifter(prefix: jsPrefix, suffix: jsSuffix, ecmaVersion: ECMAScriptVersion.es6, environment: JavaScriptEnvironment(), alwaysEmitVariables: forDifferentialFuzzing) +let jsLifter = JavaScriptLifter( + prefix: jsPrefix, suffix: jsSuffix, ecmaVersion: ECMAScriptVersion.es6, + environment: JavaScriptEnvironment(), alwaysEmitVariables: forDifferentialFuzzing) // Covert a single IL protobuf file to FuzzIL's text format and print to stdout if args.has("--liftToFuzzIL") { @@ -134,7 +140,8 @@ else if args.has("--liftToJS") { // Lift all protobuf programs to JavaScript else if args.has("--liftCorpusToJS") { - let numLiftedPrograms = liftAllPrograms(in: path, with: jsLifter, fileExtension: jsFileExtension) + let numLiftedPrograms = liftAllPrograms( + in: path, with: jsLifter, fileExtension: jsFileExtension) print("Lifted \(numLiftedPrograms) programs to JS") } @@ -166,7 +173,9 @@ else if args.has("--compile") { exit(-1) } guard let parser = JavaScriptParser(executor: nodejs) else { - print("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for instructions on how to set it up.") + print( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for instructions on how to set it up." + ) exit(-1) } @@ -194,7 +203,9 @@ else if args.has("--compile") { if let js_path = args["--outputPathJS"] { let content = ast.leadingComments + jsLifter.lift(program) do { - try content.write(to: URL(fileURLWithPath: js_path), atomically: false, encoding: String.Encoding.utf8) + try content.write( + to: URL(fileURLWithPath: js_path), atomically: false, encoding: String.Encoding.utf8 + ) } catch { print("Failed to write file \(js_path): \(error)") exit(-1) @@ -205,7 +216,8 @@ else if args.has("--compile") { print(jsLifter.lift(program)) do { - let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension("fzil") + let outputPath = URL(fileURLWithPath: path).deletingPathExtension() + .appendingPathExtension("fzil") try program.asProtobuf().serializedData().write(to: outputPath) print("FuzzIL program written to \(outputPath.relativePath)") } catch { @@ -216,7 +228,9 @@ else if args.has("--compile") { } else if args.has("--generate") { - let fuzzer = makeMockFuzzer(config: Configuration(logLevel: .warning, enableInspection: true), environment: JavaScriptEnvironment()) + let fuzzer = makeMockFuzzer( + config: Configuration(logLevel: .warning, enableInspection: true), + environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() b.buildPrefix() b.build(n: 50, by: .generating) @@ -225,7 +239,8 @@ else if args.has("--generate") { print(jsLifter.lift(program, withOptions: .includeComments)) do { - let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension("fzil") + let outputPath = URL(fileURLWithPath: path).deletingPathExtension().appendingPathExtension( + "fzil") try program.asProtobuf().serializedData().write(to: outputPath) } catch { print("Failed to store output program to disk: \(error)") diff --git a/Sources/Fuzzilli/Base/ContextGraph.swift b/Sources/Fuzzilli/Base/ContextGraph.swift index 153f76541..722801e64 100644 --- a/Sources/Fuzzilli/Base/ContextGraph.swift +++ b/Sources/Fuzzilli/Base/ContextGraph.swift @@ -79,20 +79,25 @@ public class ContextGraph { for i in 1.., withLogger logger: Logger) { + private func warnOfSuspiciousContexts( + in generators: WeightedList, withLogger logger: Logger + ) { // Technically we don't need any generator to emit the .javascript context, as this is provided by the toplevel. var providedContexts = Set([.javascript]) var requiredContexts = Set() @@ -107,7 +112,9 @@ public class ContextGraph { for generator in generators { // Now check which generators don't have providers if !providedContexts.contains(generator.requiredContext) { - logger.warning("Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context.") + logger.warning( + "Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context." + ) } @@ -115,7 +122,9 @@ public class ContextGraph { if !generator.providedContexts.allSatisfy({ requiredContexts.contains($0) }) { - logger.warning("Generator \(generator.name) provides a context that is never required by another generator \(generator.providedContexts)") + logger.warning( + "Generator \(generator.name) provides a context that is never required by another generator \(generator.providedContexts)" + ) } } } @@ -139,7 +148,8 @@ public class ContextGraph { } // Get all possible edges from here on and push all of those to the queue. - for edge in self.edges where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { + for edge in self.edges + where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { // Prevent cycles, we don't care about complicated paths, but rather simple direct paths. seenNodes.insert(edge.key.to) queue.append(currentPath + [edge.key.to]) @@ -155,7 +165,7 @@ public class ContextGraph { for path in paths { var edgePath: [EdgeKey] = [] for i in 0..<(path.count - 1) { - let edge = EdgeKey(from: path[i], to: path[i+1]) + let edge = EdgeKey(from: path[i], to: path[i + 1]) edgePath.append(edge) } edgePaths.append(edgePath) @@ -185,7 +195,8 @@ public class ContextGraph { var stillExploring = false // Get all possible edges from here on and push all of those to the queue. - for edge in self.edges where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { + for edge in self.edges + where edge.key.from == currentNode && !seenNodes.contains(edge.key.to) { // Prevent cycles, we don't care about complicated paths, but rather simple direct paths. stillExploring = true seenNodes.insert(edge.key.to) @@ -220,9 +231,10 @@ public class ContextGraph { } return paths.map { edges in - Path(edges: edges.map { edge in - self.edges[edge]! - }) + Path( + edges: edges.map { edge in + self.edges[edge]! + }) } } } diff --git a/Sources/Fuzzilli/Base/Contributor.swift b/Sources/Fuzzilli/Base/Contributor.swift index 87b668464..b087363d1 100644 --- a/Sources/Fuzzilli/Base/Contributor.swift +++ b/Sources/Fuzzilli/Base/Contributor.swift @@ -93,7 +93,8 @@ public class Contributor: Hashable { } public var totalSamples: Int { - return validSamples + interestingSamples + invalidSamples + timedOutSamples + crashingSamples + differentialSamples + return validSamples + interestingSamples + invalidSamples + timedOutSamples + + crashingSamples + differentialSamples } // If this is low, that means the CodeGenerator has dynamic requirements that are not met most of the time. diff --git a/Sources/Fuzzilli/Base/Events.swift b/Sources/Fuzzilli/Base/Events.swift index 84a6832ec..f353f58ab 100644 --- a/Sources/Fuzzilli/Base/Events.swift +++ b/Sources/Fuzzilli/Base/Events.swift @@ -53,10 +53,14 @@ public class Events { public let InvalidProgramFound = Event() /// Signals that a crashing program has been found. Dispatched after the crashing program has been minimized. - public let CrashFound = Event<(program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin)>() + public let CrashFound = Event< + (program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin) + >() /// Signals that a differential program was found. Dispatched after the differential program has been minimized. - public let DifferentialFound = Event<(program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin)>() + public let DifferentialFound = Event< + (program: Program, behaviour: CrashBehaviour, isUnique: Bool, origin: ProgramOrigin) + >() /// Signals that a program causing a timeout has been found. public let TimeOutFound = Event() @@ -94,7 +98,7 @@ public class Events { /// Crash behavior of a program. public enum CrashBehaviour: String { case deterministic = "deterministic" - case flaky = "flaky" + case flaky = "flaky" } /// Reasons for shutting down a fuzzer instance. diff --git a/Sources/Fuzzilli/Base/Logging.swift b/Sources/Fuzzilli/Base/Logging.swift index abbff0cb4..307fc6c95 100644 --- a/Sources/Fuzzilli/Base/Logging.swift +++ b/Sources/Fuzzilli/Base/Logging.swift @@ -16,10 +16,10 @@ import Foundation public enum LogLevel: Int { case verbose = 0 - case info = 1 + case info = 1 case warning = 2 - case error = 3 - case fatal = 4 + case error = 3 + case fatal = 4 public func isAtLeast(_ level: LogLevel) -> Bool { return self.rawValue <= level.rawValue diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 657fec431..631f5a3f9 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -24,7 +24,7 @@ public class ProgramBuilder { /// code generator. It is strictly required that all pushed values are also popped again in the /// same code generator. public class GeneratorRuntimeData { - private var data = [String : Stack]() + private var data = [String: Stack]() public func push(_ key: String, _ value: Variable) { data[key, default: .init()].push(value) @@ -44,9 +44,9 @@ public class ProgramBuilder { func reset() { #if DEBUG - for (key, value) in data { - assert(value.isEmpty, "Stale entries for runtime data '\(key)'") - } + for (key, value) in data { + assert(value.isEmpty, "Stale entries for runtime data '\(key)'") + } #endif data.removeAll(keepingCapacity: false) } @@ -197,7 +197,7 @@ public class ProgramBuilder { self.jsTyper = JSTyper(for: fuzzer.environment) self.parent = parent - if fuzzer.config.logLevel.isAtLeast(.verbose) { + if fuzzer.config.logLevel.isAtLeast(.verbose) { self.buildLog = BuildLog() } } @@ -228,7 +228,8 @@ public class ProgramBuilder { /// Finalizes and returns the constructed program, then resets this builder so it can be reused for building another program. public func finalize() -> Program { assert(scheduled.isEmpty) - let program = Program(code: code, parent: parent, comments: comments, contributors: contributors) + let program = Program( + code: code, parent: parent, comments: comments, contributors: contributors) reset() return program } @@ -290,39 +291,47 @@ public class ProgramBuilder { if probability(0.5) { return chooseUniform(from: self.fuzzer.environment.interestingIntegers) } else { - return withEqualProbability({ - Int64.random(in: -0x10...0x10) - }, { - Int64.random(in: -0x10000...0x10000) - }, { - Int64.random(in: Int64(Int32.min)...Int64(Int32.max)) - }) + return withEqualProbability( + { + Int64.random(in: -0x10...0x10) + }, + { + Int64.random(in: -0x10000...0x10000) + }, + { + Int64.random(in: Int64(Int32.min)...Int64(Int32.max)) + }) } } /// Returns a random integer value suitable as size of for example an array. /// The returned value is guaranteed to be positive. - public func randomSize(upTo maximum: Int64 = 0x100000000) -> Int64 { + public func randomSize(upTo maximum: Int64 = 0x1_0000_0000) -> Int64 { assert(maximum >= 0) if maximum < 0x1000 { return Int64.random(in: 0...maximum) } else if probability(0.5) { - return chooseUniform(from: fuzzer.environment.interestingIntegers.filter({ $0 >= 0 && $0 <= maximum })) + return chooseUniform( + from: fuzzer.environment.interestingIntegers.filter({ $0 >= 0 && $0 <= maximum })) } else { - return withEqualProbability({ - Int64.random(in: 0...0x10) - }, { - Int64.random(in: 0...0x100) - }, { - Int64.random(in: 0...0x1000) - }, { - Int64.random(in: 0...maximum) - }) + return withEqualProbability( + { + Int64.random(in: 0...0x10) + }, + { + Int64.random(in: 0...0x100) + }, + { + Int64.random(in: 0...0x1000) + }, + { + Int64.random(in: 0...maximum) + }) } } /// Returns a random non-negative integer value suitable as index. - public func randomNonNegativeIndex(upTo max: Int64 = 0x100000000) -> Int64 { + public func randomNonNegativeIndex(upTo max: Int64 = 0x1_0000_0000) -> Int64 { // Prefer small indices. if max > 10 && probability(0.33) { return Int64.random(in: 0...10) @@ -346,51 +355,61 @@ public class ProgramBuilder { if probability(0.5) { return chooseUniform(from: fuzzer.environment.interestingFloats) } else { - return withEqualProbability({ - Double.random(in: 0.0...1.0) - }, { - Double.random(in: -10.0...10.0) - }, { - Double.random(in: -1000.0...1000.0) - }, { - Double.random(in: -1000000.0...1000000.0) - }, { - // We cannot do Double.random(in: -Double.greatestFiniteMagnitude...Double.greatestFiniteMagnitude) here, - // presumably because that range is larger than what doubles can represent? So split the range in two. - if probability(0.5) { - return Double.random(in: -Double.greatestFiniteMagnitude...0) - } else { - return Double.random(in: 0...Double.greatestFiniteMagnitude) - } - }) + return withEqualProbability( + { + Double.random(in: 0.0...1.0) + }, + { + Double.random(in: -10.0...10.0) + }, + { + Double.random(in: -1000.0...1000.0) + }, + { + Double.random(in: -1000000.0...1000000.0) + }, + { + // We cannot do Double.random(in: -Double.greatestFiniteMagnitude...Double.greatestFiniteMagnitude) here, + // presumably because that range is larger than what doubles can represent? So split the range in two. + if probability(0.5) { + return Double.random(in: -Double.greatestFiniteMagnitude...0) + } else { + return Double.random(in: 0...Double.greatestFiniteMagnitude) + } + }) } } /// Returns a random string value. public func randomString() -> String { - return withEqualProbability({ - self.randomPropertyName() - }, { - self.randomMethodName() - }, { - chooseUniform(from: self.fuzzer.environment.interestingStrings) - }, { - String(self.randomInt()) - }, { - // Prefer smaller strings both for readability as well as for small string optimizations - // (e.g. optimizations for single character strings) but also generate larger strings - // to hit cons string ("rope" / concatenated string) cases. - String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) - }) + return withEqualProbability( + { + self.randomPropertyName() + }, + { + self.randomMethodName() + }, + { + chooseUniform(from: self.fuzzer.environment.interestingStrings) + }, + { + String(self.randomInt()) + }, + { + // Prefer smaller strings both for readability as well as for small string optimizations + // (e.g. optimizations for single character strings) but also generate larger strings + // to hit cons string ("rope" / concatenated string) cases. + String.random(ofLength: Int.random(in: Bool.random() ? 0...5 : 0...33)) + }) } public func randomBytes() -> [UInt8] { let size = withProbability(0.9) { Int.random(in: 0...127) } else: { - Int.random(in:128...1024) + Int.random(in: 128...1024) } - return (0.. String { @@ -398,13 +417,17 @@ public class ProgramBuilder { var regex = "" let desiredLength = Int.random(in: 1...4) while regex.count < desiredLength { - regex += withEqualProbability({ - String.random(ofLength: 1) - }, { - // Pick from the available RegExp pattern, based on flags. - let candidates = self.fuzzer.environment.interestingRegExps.filter({ pattern, incompatibleFlags in flags.isDisjoint(with: incompatibleFlags) }) - return chooseUniform(from: candidates).pattern - }) + regex += withEqualProbability( + { + String.random(ofLength: 1) + }, + { + // Pick from the available RegExp pattern, based on flags. + let candidates = self.fuzzer.environment.interestingRegExps.filter({ + pattern, incompatibleFlags in flags.isDisjoint(with: incompatibleFlags) + }) + return chooseUniform(from: candidates).pattern + }) } // Now optionally concatenate with another regexp @@ -413,21 +436,25 @@ public class ProgramBuilder { } // Or add a quantifier, if there is not already a quantifier in the last position. - if probability(0.2) && !self.fuzzer.environment.interestingRegExpQuantifiers.contains(String(regex.last!)) { + if probability(0.2) + && !self.fuzzer.environment.interestingRegExpQuantifiers.contains(String(regex.last!)) + { regex += chooseUniform(from: self.fuzzer.environment.interestingRegExpQuantifiers) } // Or wrap in brackets if probability(0.1) { - withEqualProbability({ - // optionally invert the character set - if probability(0.2) { - regex = "^" + regex - } - regex = "[" + regex + "]" - }, { - regex = "(" + regex + ")" - }) + withEqualProbability( + { + // optionally invert the character set + if probability(0.2) { + regex = "^" + regex + } + regex = "[" + regex + "]" + }, + { + regex = "(" + regex + ")" + }) } return regex } @@ -503,9 +530,10 @@ public class ProgramBuilder { } private static func generateConstrained( - _ generator: () -> T, - notIn: any Collection, - fallback: () -> T) -> T { + _ generator: () -> T, + notIn: any Collection, + fallback: () -> T + ) -> T { var result: T var attempts = 0 repeat { @@ -521,15 +549,17 @@ public class ProgramBuilder { // Generate a string not already contained in `notIn` using the provided `generator`. If it fails // repeatedly, return a random string instead. public func generateString(_ generator: () -> String, notIn: any Collection) -> String { - Self.generateConstrained(generator, notIn: notIn, - fallback: {String.random(ofLength: Int.random(in: 1...5))}) + Self.generateConstrained( + generator, notIn: notIn, + fallback: { String.random(ofLength: Int.random(in: 1...5)) }) } // Find a random variable to use as a string that isn't contained in `notIn`. If it fails // repeatedly, create a random string literal instead. public func findOrGenerateStringLikeVariable(notIn: any Collection) -> Variable { - return Self.generateConstrained(randomJsVariable, notIn: notIn, - fallback: {loadString(String.random(ofLength: Int.random(in: 1...5)))}) + return Self.generateConstrained( + randomJsVariable, notIn: notIn, + fallback: { loadString(String.random(ofLength: Int.random(in: 1...5))) }) } // Settings and constants controlling the behavior of randomParameters() below. @@ -549,8 +579,13 @@ public class ProgramBuilder { // // This will attempt to find a parameter types for which at least a few variables of a compatible types are // currently available to (potentially) later be used as arguments for calling the generated subroutine. - public func randomParameters(n wantedNumberOfParameters: Int? = nil, withRestParameterProbability restProbability: Double = 0.2) -> SubroutineDescriptor { - assert(probabilityOfUsingAnythingAsParameterTypeIfAvoidable >= 0 && probabilityOfUsingAnythingAsParameterTypeIfAvoidable <= 1) + public func randomParameters( + n wantedNumberOfParameters: Int? = nil, + withRestParameterProbability restProbability: Double = 0.2 + ) -> SubroutineDescriptor { + assert( + probabilityOfUsingAnythingAsParameterTypeIfAvoidable >= 0 + && probabilityOfUsingAnythingAsParameterTypeIfAvoidable <= 1) // If the caller didn't specify how many parameters to generated, find an appropriate // number of parameters based on how many variables are currently visible (and can @@ -580,7 +615,8 @@ public class ProgramBuilder { availableVariablesByType[t] = (availableVariablesByType[t] ?? 0) + 1 } - var candidates = Array(availableVariablesByType.filter({ k, v in v >= thresholdForUseAsParameter }).keys) + var candidates = Array( + availableVariablesByType.filter({ k, v in v >= thresholdForUseAsParameter }).keys) if candidates.isEmpty { candidates.append(.jsAnything) } @@ -611,7 +647,9 @@ public class ProgramBuilder { return .parameters(params) } - public func findOrGenerateArguments(forSignature signature: Signature, maxNumberOfVariablesToGenerate: Int = 100) -> [Variable] { + public func findOrGenerateArguments( + forSignature signature: Signature, maxNumberOfVariablesToGenerate: Int = 100 + ) -> [Variable] { assert(context.contains(.javascript)) argumentGenerationVariableBudget.push(numVariables + maxNumberOfVariablesToGenerate) @@ -650,7 +688,7 @@ public class ProgramBuilder { // This should be called whenever we have a type that has known information about its properties but we don't have a constructor for it. // This can be the case for configuration objects, e.g. objects that can be passed into DOMAPIs. - private func createObjectWithProperties(_ type: ILType) -> Variable { + private func createObjectWithProperties(_ type: ILType) -> Variable { assert(type.MayBe(.object())) // Before we do any generation below, let's take into account that we already create a variable with this invocation, i.e. the createObject at the end. @@ -670,7 +708,9 @@ public class ProgramBuilder { return createObject(with: properties) } - public func findOrGenerateType(_ type: ILType, maxNumberOfVariablesToGenerate: Int = 100) -> Variable { + public func findOrGenerateType(_ type: ILType, maxNumberOfVariablesToGenerate: Int = 100) + -> Variable + { assert(context.contains(.javascript)) argumentGenerationVariableBudget.push(numVariables + maxNumberOfVariablesToGenerate) @@ -695,7 +735,9 @@ public class ProgramBuilder { for element in path.dropFirst() { current = getProperty(element, of: current) } - assert(self.type(of: current).Is(type), "Registered constructorPath produces incorrect type for ObjectGroup \(group)") + assert( + self.type(of: current).Is(type), + "Registered constructorPath produces incorrect type for ObjectGroup \(group)") return current } @@ -713,9 +755,13 @@ public class ProgramBuilder { if numVariables >= argumentGenerationVariableBudget.top { if !argumentGenerationSignature.isEmpty { - logger.warning("Reached variable generation limit in generateType for Signature: \(argumentGenerationSignature.top), returning a random variable for use as type \(type).") + logger.warning( + "Reached variable generation limit in generateType for Signature: \(argumentGenerationSignature.top), returning a random variable for use as type \(type)." + ) } else { - logger.warning("Reached variable generation limit in generateType, returning a random variable for use as type \(type).") + logger.warning( + "Reached variable generation limit in generateType, returning a random variable for use as type \(type)." + ) } return randomVariable(forUseAs: type) } @@ -724,78 +770,121 @@ public class ProgramBuilder { // TODO: Not sure how we should handle merge types, e.g. .string + .object(...). let typeGenerators: [(ILType, () -> Variable)] = [ (.integer, { return self.loadInt(self.randomInt()) }), - (.string, { - if type.isEnumeration { - return self.loadEnum(type) - } - if let typeName = type.group, - let customStringGen = self.fuzzer.environment.getNamedStringGenerator(ofName: typeName) { - return self.loadString(customStringGen(), customName: typeName) + ( + .string, + { + if type.isEnumeration { + return self.loadEnum(type) + } + if let typeName = type.group, + let customStringGen = self.fuzzer.environment.getNamedStringGenerator( + ofName: typeName) + { + return self.loadString(customStringGen(), customName: typeName) + } + return self.loadString(self.randomString()) } - return self.loadString(self.randomString()) }), + ), (.boolean, { return self.loadBool(probability(0.5)) }), (.bigint, { return self.loadBigInt(self.randomInt()) }), (.float, { return self.loadFloat(self.randomFloat()) }), - (.regexp, { + ( + .regexp, + { let (pattern, flags) = self.randomRegExpPatternAndFlags() return self.loadRegExp(pattern, flags) - }), + } + ), (.iterable, { return self.createArray(with: [self.randomJsVariable()]) }), - (.function(), { + ( + .function(), + { // TODO: We could technically generate a full function here but then we would enter the full code generation logic which could do anything. // Because we want to avoid this, we will just pick anything that can be a function. // // Note that builtin constructors are handled above in the maybeGenerateConstructorAsPath call. return self.randomVariable(forUseAs: .function()) - }), - (.unboundFunction(), { - // TODO: We have the same issue as above for functions. - // First try to find an existing unbound function. if not present, try to find any - // function. Using any function as an unbound function is fine, it just misses the - // information about the receiver type (which for many functions doesn't matter). - return self.randomVariable(ofType: .unboundFunction()) ?? self.randomVariable(forUseAs: .function()) - }), + } + ), + ( + .unboundFunction(), + { + // TODO: We have the same issue as above for functions. + // First try to find an existing unbound function. if not present, try to find any + // function. Using any function as an unbound function is fine, it just misses the + // information about the receiver type (which for many functions doesn't matter). + return self.randomVariable(ofType: .unboundFunction()) + ?? self.randomVariable(forUseAs: .function()) + } + ), (.undefined, { return self.loadUndefined() }), - (.constructor(), { + ( + .constructor(), + { // TODO: We have the same issue as above for functions. // // Note that builtin constructors are handled above in the maybeGenerateConstructorAsPath call. return self.randomVariable(forUseAs: .constructor()) - }), - (.wasmTypeDef(), { - // Call into the WasmTypeGroup generator (or other that provide a .wasmTypeDef) - let generators = self.fuzzer.codeGenerators.filter { gen in - gen.produces.contains { produces in - produces.type.Is(.wasmTypeDef()) - } } - let _ = self.complete(generator: generators.randomElement(), withBudget: 5) - return self.randomVariable(ofType: .wasmTypeDef())! - }), - (.object(), { - func useMethodToProduce(_ method: (group: String, method: String)) -> Variable { - let group = self.fuzzer.environment.type(ofGroup: method.group) - let obj = self.generateTypeInternal(group) - let sig = chooseUniform( - from: self.fuzzer.environment - .signatures(ofMethod: method.method, on: group).filter({ - self.fuzzer.environment.isSubtype($0.outputType, of: type) - })) - - let args = self.findOrGenerateArgumentsInternal(forSignature: sig) - return self.callMethod(method.method, on: obj, withArgs: args) + ), + ( + .wasmTypeDef(), + { + // Call into the WasmTypeGroup generator (or other that provide a .wasmTypeDef) + let generators = self.fuzzer.codeGenerators.filter { gen in + gen.produces.contains { produces in + produces.type.Is(.wasmTypeDef()) + } + } + let _ = self.complete(generator: generators.randomElement(), withBudget: 5) + return self.randomVariable(ofType: .wasmTypeDef())! } + ), + ( + .object(), + { + func useMethodToProduce(_ method: (group: String, method: String)) -> Variable { + let group = self.fuzzer.environment.type(ofGroup: method.group) + let obj = self.generateTypeInternal(group) + let sig = chooseUniform( + from: self.fuzzer.environment + .signatures(ofMethod: method.method, on: group).filter({ + self.fuzzer.environment.isSubtype($0.outputType, of: type) + })) + + let args = self.findOrGenerateArgumentsInternal(forSignature: sig) + return self.callMethod(method.method, on: obj, withArgs: args) + } - func usePropertyToProduce(_ property: (group: String, property: String)) -> Variable { - // If no ObjectGroup is defined, the property is a builtin. - if property.group == "" { - let builtinType = self.fuzzer.environment.type(ofBuiltin: property.property) - let prop = self.createNamedVariable(forBuiltin: property.property) - if builtinType.Is(type) { + func usePropertyToProduce(_ property: (group: String, property: String)) + -> Variable + { + // If no ObjectGroup is defined, the property is a builtin. + if property.group == "" { + let builtinType = self.fuzzer.environment.type( + ofBuiltin: property.property) + let prop = self.createNamedVariable(forBuiltin: property.property) + if builtinType.Is(type) { + return prop + } else { + // This is a constructor, we have to call it. + let sig = builtinType.signature + if sig == nil { + let result = self.randomJsVariable() + return result + } + let args = self.findOrGenerateArgumentsInternal(forSignature: sig!) + return self.construct(prop, withArgs: args) + } + } + let group = self.fuzzer.environment.type(ofGroup: property.group) + let obj = self.generateTypeInternal(group) + let prop = self.getProperty(property.property, of: obj) + if self.type(of: prop).Is(type) { return prop } else { // This is a constructor, we have to call it. - let sig = builtinType.signature + let sig = self.type(of: prop).signature if sig == nil { let result = self.randomJsVariable() return result @@ -804,78 +893,70 @@ public class ProgramBuilder { return self.construct(prop, withArgs: args) } } - let group = self.fuzzer.environment.type(ofGroup: property.group) - let obj = self.generateTypeInternal(group) - let prop = self.getProperty(property.property, of: obj) - if self.type(of: prop).Is(type) { - return prop - } else { - // This is a constructor, we have to call it. - let sig = self.type(of: prop).signature - if sig == nil { - let result = self.randomJsVariable() - return result + + // If we have a producing generator, we aren't going to get this type from elsewhere + // so try and generate it using the generator in most cases + let producingGenerator = self.fuzzer.environment.getProducingGenerator( + ofType: type) + if let producingGenerator { + if probability(producingGenerator.probability) { + return producingGenerator.generator(self) } - let args = self.findOrGenerateArgumentsInternal(forSignature: sig!) - return self.construct(prop, withArgs: args) } - } - // If we have a producing generator, we aren't going to get this type from elsewhere - // so try and generate it using the generator in most cases - let producingGenerator = self.fuzzer.environment.getProducingGenerator(ofType: type); - if let producingGenerator { - if probability(producingGenerator.probability) { - return producingGenerator.generator(self) + let producingMethods = self.fuzzer.environment.getProducingMethods(ofType: type) + let producingProperties = self.fuzzer.environment.getProducingProperties( + ofType: type) + let globalProperties = producingProperties.filter { + (group: String, property: String) in + // Global properties are those that don't belong to a group, i.e. where the group is empty. + return group == "" } - } - - let producingMethods = self.fuzzer.environment.getProducingMethods(ofType: type) - let producingProperties = self.fuzzer.environment.getProducingProperties(ofType: type) - let globalProperties = producingProperties.filter() {(group: String, property: String) in - // Global properties are those that don't belong to a group, i.e. where the group is empty. - return group == "" - } - // If there is a global property or builtin for this type, use it with high probability. - if !globalProperties.isEmpty && probability(0.9) { - return usePropertyToProduce(globalProperties.randomElement()!) - } - let maybeMethod = producingMethods.randomElement() - let maybeProperty = producingProperties.randomElement() - if let method = maybeMethod ,let property = maybeProperty { - if probability(Double(producingMethods.count) / Double(producingMethods.count + producingProperties.count)) { + // If there is a global property or builtin for this type, use it with high probability. + if !globalProperties.isEmpty && probability(0.9) { + return usePropertyToProduce(globalProperties.randomElement()!) + } + let maybeMethod = producingMethods.randomElement() + let maybeProperty = producingProperties.randomElement() + if let method = maybeMethod, let property = maybeProperty { + if probability( + Double(producingMethods.count) + / Double(producingMethods.count + producingProperties.count)) + { + return useMethodToProduce(method) + } else { + return usePropertyToProduce(property) + } + } else if let method = maybeMethod { return useMethodToProduce(method) - } else { + } else if let property = maybeProperty { return usePropertyToProduce(property) } - } else if let method = maybeMethod { - return useMethodToProduce(method) - } else if let property = maybeProperty { - return usePropertyToProduce(property) - } - let generators = self.fuzzer.codeGenerators.filter({ - // Right now only use generators that require a single context. - $0.parts.last!.requiredContext.isSingle && - $0.parts.last!.requiredContext.satisfied(by: self.context) && - $0.parts.last!.produces.contains(where: { produces in - produces.type.Is(type) + let generators = self.fuzzer.codeGenerators.filter({ + // Right now only use generators that require a single context. + $0.parts.last!.requiredContext.isSingle + && $0.parts.last!.requiredContext.satisfied(by: self.context) + && $0.parts.last!.produces.contains(where: { produces in + produces.type.Is(type) + }) }) - }) - if generators.count > 0 { - let generator = generators.randomElement() - let _ = self.complete(generator: generator, withBudget: 10) - guard let variable = self.randomVariable(ofTypeOrSubtype: type) else { - fatalError("The generator \(generator.name) is supposed to generate type " + - "\(type). Either the generator or its annotation is wrong.") + if generators.count > 0 { + let generator = generators.randomElement() + let _ = self.complete(generator: generator, withBudget: 10) + guard let variable = self.randomVariable(ofTypeOrSubtype: type) else { + fatalError( + "The generator \(generator.name) is supposed to generate type " + + "\(type). Either the generator or its annotation is wrong.") + } + return variable } - return variable + // Otherwise this is one of the following: + // 1. an object with more type information, i.e. it has a group, but no associated builtin, e.g. we cannot construct it with new. + // 2. an object without a group, but it has some required fields. + // In either case, we try to construct such an object. + return self.createObjectWithProperties(type) } - // Otherwise this is one of the following: - // 1. an object with more type information, i.e. it has a group, but no associated builtin, e.g. we cannot construct it with new. - // 2. an object without a group, but it has some required fields. - // In either case, we try to construct such an object. - return self.createObjectWithProperties(type) - }) + ), ] // Make sure that we walk over these tests and their generators randomly. @@ -919,7 +1000,11 @@ public class ProgramBuilder { var variables = [Variable]() while variables.count < n { - guard let newVar = findVariable(satisfying: { !variables.contains($0) && type(of: $0).Is(.jsAnything) }) else { + guard + let newVar = findVariable(satisfying: { + !variables.contains($0) && type(of: $0).Is(.jsAnything) + }) + else { break } variables.append(newVar) @@ -954,7 +1039,8 @@ public class ProgramBuilder { /// is a random JsVariable. /// /// If the variable must be of the specified type, use `randomVariable(ofType:)` instead. - public func randomVariable(forUseAsGuarded type: ILType) -> (variable: Variable, matches: Bool) { + public func randomVariable(forUseAsGuarded type: ILType) -> (variable: Variable, matches: Bool) + { assert(type != .nothing) var result: Variable? = nil @@ -1000,7 +1086,7 @@ public class ProgramBuilder { public func randomVariable(ofTypeOrSubtype type: ILType) -> Variable? { assert(type != .nothing) - return findVariable() { (variable: Variable) in + return findVariable { (variable: Variable) in fuzzer.environment.isSubtype(self.type(of: variable), of: type) } } @@ -1072,7 +1158,9 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling the specified method. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingMethod methodName: String, on object: Variable) -> [Variable] { + public func randomArguments(forCallingMethod methodName: String, on object: Variable) + -> [Variable] + { let signature = chooseUniform(from: methodSignatures(of: methodName, on: object)) return randomArguments(forCallingFunctionWithSignature: signature) } @@ -1080,7 +1168,9 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling the specified method. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingMethod methodName: String, on objType: ILType) -> [Variable] { + public func randomArguments(forCallingMethod methodName: String, on objType: ILType) + -> [Variable] + { let signature = chooseUniform(from: methodSignatures(of: methodName, on: objType)) return randomArguments(forCallingFunctionWithSignature: signature) } @@ -1088,14 +1178,17 @@ public class ProgramBuilder { /// Find random variables to use as arguments for calling a function with the specified signature. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingFunctionWithSignature signature: Signature) -> [Variable] { + public func randomArguments(forCallingFunctionWithSignature signature: Signature) -> [Variable] + { return randomArguments(forCallingFunctionWithParameters: signature.parameters) } /// Find random variables to use as arguments for calling a function with the given parameters. /// /// See the comment above `randomArguments(forCalling function: Variable)` for caveats. - public func randomArguments(forCallingFunctionWithParameters params: ParameterList) -> [Variable] { + public func randomArguments(forCallingFunctionWithParameters params: ParameterList) + -> [Variable] + { assert(params.count == 0 || hasVisibleVariables) let parameterTypes = ProgramBuilder.prepareArgumentTypes(forParameters: params) return parameterTypes.map({ randomVariable(forUseAs: $0) }) @@ -1105,7 +1198,9 @@ public class ProgramBuilder { /// /// If any of the arguments returned does not match the type of its corresponding parameter, /// the boolean this function returns will be true. If everything matches, it will be false. - public func randomArguments(forCallingGuardableFunction function: Variable) -> (arguments: [Variable], allArgsMatch: Bool) { + public func randomArguments(forCallingGuardableFunction function: Variable) -> ( + arguments: [Variable], allArgsMatch: Bool + ) { let signature = type(of: function).signature ?? Signature.forUnknownFunction let params = signature.parameters assert(params.count == 0 || hasVisibleVariables) @@ -1123,7 +1218,6 @@ public class ProgramBuilder { return (variables, allArgsMatch) } - /// Converts the JS world signature into a Wasm world signature. /// In practice this means that we will try to map JS types to corresponding Wasm types. /// E.g. .number becomes .wasmf32, .bigint will become .wasmi64, etc. @@ -1131,7 +1225,9 @@ public class ProgramBuilder { /// I.e. .object might be converted to .wasmf32 or .wasmExternRef. /// Use this function to generate arguments for a WasmJsCall operation and attach the converted signature to /// the WasmJsCall instruction. - public func randomWasmArguments(forCallingJsFunction function: Variable) -> (WasmSignature, [Variable])? { + public func randomWasmArguments(forCallingJsFunction function: Variable) -> ( + WasmSignature, [Variable] + )? { let signature = type(of: function).signature ?? Signature.forUnknownFunction var visibleTypes = [ILType: Int]() @@ -1157,7 +1253,8 @@ public class ProgramBuilder { } // This already does an approximation of the JS signature - let newSignature = ProgramBuilder.convertJsSignatureToWasmSignature(signature, availableTypes: weightedTypes) + let newSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + signature, availableTypes: weightedTypes) guard let variables = randomWasmArguments(forWasmSignature: newSignature) else { return nil @@ -1181,8 +1278,12 @@ public class ProgramBuilder { // We simplify the signature by first converting it into types, approximating this signature by getting the corresponding Wasm world types. // Then we convert that back into a signature with only .plain types and attach that to the WasmJsCall instruction. - public static func convertJsSignatureToWasmSignature(_ signature: Signature, availableTypes types: WeightedList) -> WasmSignature { - let parameterTypes = prepareArgumentTypes(forParameters: signature.parameters).map { approximateWasmTypeFromJsType($0, availableTypes: types) } + public static func convertJsSignatureToWasmSignature( + _ signature: Signature, availableTypes types: WeightedList + ) -> WasmSignature { + let parameterTypes = prepareArgumentTypes(forParameters: signature.parameters).map { + approximateWasmTypeFromJsType($0, availableTypes: types) + } let outputType = mapJsToWasmType(signature.outputType) return WasmSignature(expects: parameterTypes, returns: [outputType]) } @@ -1190,20 +1291,27 @@ public class ProgramBuilder { public static func convertWasmSignatureToJsSignature(_ signature: WasmSignature) -> Signature { let parameterTypes = signature.parameterTypes.map(mapWasmToJsType) // If we return multiple values it will just be an Array in JavaScript. - let returnType = signature.outputTypes.count == 0 ? ILType.undefined - : signature.outputTypes.count == 1 ? mapWasmToJsType(signature.outputTypes[0]) - : .jsArray + let returnType = + signature.outputTypes.count == 0 + ? ILType.undefined + : signature.outputTypes.count == 1 + ? mapWasmToJsType(signature.outputTypes[0]) + : .jsArray return Signature(expects: parameterTypes.map(Parameter.plain), returns: returnType) } - public static func convertJsSignatureToWasmSignatureDeterministic(_ signature: Signature) -> WasmSignature { - let parameterTypes = prepareArgumentTypesDeterministic(forParameters: signature.parameters).map { mapJsToWasmType($0) } + public static func convertJsSignatureToWasmSignatureDeterministic(_ signature: Signature) + -> WasmSignature + { + let parameterTypes = prepareArgumentTypesDeterministic(forParameters: signature.parameters) + .map { mapJsToWasmType($0) } let outputType = mapJsToWasmType(signature.outputType) return WasmSignature(expects: parameterTypes, returns: [outputType]) } /// Find random arguments for a function call and spread some of them. - public func randomCallArgumentsWithSpreading(n: Int) -> (arguments: [Variable], spreads: [Bool]) { + public func randomCallArgumentsWithSpreading(n: Int) -> (arguments: [Variable], spreads: [Bool]) + { var arguments: [Variable] = [] var spreads: [Bool] = [] for _ in 0...n { @@ -1275,7 +1383,7 @@ public class ProgramBuilder { /// /// From being generated, which can happen quite frequently during prefix generation as /// the number of visible variables may be quite small. - private func bodyWithRecursionGuard(_ variableToHide: Variable, body: () -> ()) { + private func bodyWithRecursionGuard(_ variableToHide: Variable, body: () -> Void) { hide(variableToHide) body() unhide(variableToHide) @@ -1326,7 +1434,9 @@ public class ProgramBuilder { return .function() } else if type.Is(.wasmI31Ref()) { return .integer - } else if type.Is(.wasmNullRef()) || type.Is(.wasmNullExternRef()) || type.Is(.wasmNullFuncRef()) { + } else if type.Is(.wasmNullRef()) || type.Is(.wasmNullExternRef()) + || type.Is(.wasmNullFuncRef()) + { // This is slightly imprecise: The null types only accept null, not undefined but // Fuzzilli doesn't differentiate between null and undefined in its type system. return .nullish @@ -1338,10 +1448,13 @@ public class ProgramBuilder { } // Helper function to convert JS Types to an arbitrary matching Wasm type or picks from the other available types- - private static func approximateWasmTypeFromJsType(_ type: ILType, availableTypes: WeightedList) -> ILType { + private static func approximateWasmTypeFromJsType( + _ type: ILType, availableTypes: WeightedList + ) -> ILType { let matchingTypes = matchingWasmTypes(jsType: type) - let intersection = availableTypes.filter({type in matchingTypes.contains(type)}) - return intersection.count != 0 ? intersection.randomElement() : availableTypes.randomElement() + let intersection = availableTypes.filter({ type in matchingTypes.contains(type) }) + return intersection.count != 0 + ? intersection.randomElement() : availableTypes.randomElement() } /// Type information access. @@ -1407,7 +1520,9 @@ public class ProgramBuilder { return argumentTypes } - private static func prepareArgumentTypesDeterministic(forParameters params: ParameterList) -> [ILType] { + private static func prepareArgumentTypesDeterministic(forParameters params: ParameterList) + -> [ILType] + { var argumentTypes = [ILType]() for param in params { @@ -1456,7 +1571,8 @@ public class ProgramBuilder { } /// Maps a list of variables from the program that is currently configured for adoption into the program being constructed. - public func adopt(_ variables: Variables) -> [Variable] where Variables.Element == Variable { + public func adopt(_ variables: Variables) -> [Variable] + where Variables.Element == Variable { return variables.map(adopt) } @@ -1478,7 +1594,7 @@ public class ProgramBuilder { /// This also renames any variable used in the given program so all variables /// from the appended program refer to the same values in the current program. public func append(_ program: Program) { - adopting() { + adopting { for instr in program.code { adopt(instr) } @@ -1493,7 +1609,6 @@ public class ProgramBuilder { // The probability of including an instruction that may mutate a variable required by the slice (but does not itself produce a required variable). var probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable = 0.5 - /// Splice code from the given program into the current program. /// /// Splicing computes a set of dependent (through dataflow) instructions in one program (called a "slice") and inserts it at the current position in this program. @@ -1502,7 +1617,9 @@ public class ProgramBuilder { /// If mergeDataFlow is true, the dataflows of the two programs are potentially integrated by replacing some variables in the slice with "compatible" variables in the host program. /// Returns true on success (if at least one instruction has been spliced), false otherwise. @discardableResult - public func splice(from program: Program, at specifiedIndex: Int? = nil, mergeDataFlow: Bool = true) -> Bool { + public func splice( + from program: Program, at specifiedIndex: Int? = nil, mergeDataFlow: Bool = true + ) -> Bool { // Splicing: // // Invariants: @@ -1568,7 +1685,8 @@ public class ProgramBuilder { var activeBlocks = [Block]() func updateBlockDependencies(_ requiredContext: Context, _ requiredInputs: VariableSet) { guard let current = activeBlocks.last else { return } - current.requiredContext.formUnion(requiredContext.subtracting(current.currentlyOpenedContext)) + current.requiredContext.formUnion( + requiredContext.subtracting(current.currentlyOpenedContext)) current.requiredInputs.formUnion(requiredInputs.subtracting(current.providedInputs)) } func updateBlockProvidedVariables(_ vars: ArraySlice) { @@ -1629,7 +1747,9 @@ public class ProgramBuilder { // Prior to that, it is assumed to be .jsAnything. This may lead to incompatible functions being selected // as replacements (e.g. if the following code assumes that the return value must be of type X), but // is probably fine in practice. - assert(!instr.hasOneOutput || v != instr.output || !(instr.op is BeginAnySubroutine) || (type.signature?.outputType ?? .jsAnything) == .jsAnything) + assert( + !instr.hasOneOutput || v != instr.output || !(instr.op is BeginAnySubroutine) + || (type.signature?.outputType ?? .jsAnything) == .jsAnything) // Try to find a compatible variable in the host program. let replacement: Variable if let match = randomVariable(ofType: type) { @@ -1642,13 +1762,18 @@ public class ProgramBuilder { availableVariables.insert(v) } } - func maybeRemapVariables(_ variables: ArraySlice, of instr: Instruction, withProbability remapProbability: Double) { + func maybeRemapVariables( + _ variables: ArraySlice, of instr: Instruction, + withProbability remapProbability: Double + ) { assert(remapProbability >= 0.0 && remapProbability <= 1.0) if probability(remapProbability) { tryRemapVariables(variables, of: instr) } } - func getRequirements(of instr: Instruction) -> (requiredContext: Context, requiredInputs: VariableSet) { + func getRequirements(of instr: Instruction) -> ( + requiredContext: Context, requiredInputs: VariableSet + ) { if let state = blocks[instr.index] { assert(instr.isBlock) return (state.requiredContext, state.requiredInputs) @@ -1662,14 +1787,20 @@ public class ProgramBuilder { typer.analyze(instr) // Maybe remap the outputs of this instruction to existing and "compatible" (because of their type) variables in the host program. - maybeRemapVariables(instr.outputs, of: instr, withProbability: probabilityOfRemappingAnInstructionsOutputsDuringSplicing) - maybeRemapVariables(instr.innerOutputs, of: instr, withProbability: probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing) + maybeRemapVariables( + instr.outputs, of: instr, + withProbability: probabilityOfRemappingAnInstructionsOutputsDuringSplicing) + maybeRemapVariables( + instr.innerOutputs, of: instr, + withProbability: probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing) // For the purpose of this step, blocks are treated as a single instruction with all the context and input requirements of the // instructions in their body. This is done through the getRequirements function which uses the data computed in step (1). let (requiredContext, requiredInputs) = getRequirements(of: instr) - if requiredContext.isSubset(of: context) && requiredInputs.isSubset(of: availableVariables) { + if requiredContext.isSubset(of: context) + && requiredInputs.isSubset(of: availableVariables) + { candidates.insert(instr.index) // This instruction is available, and so are its outputs... availableVariables.formUnion(instr.allOutputs) @@ -1690,13 +1821,15 @@ public class ProgramBuilder { let rootCandidates = candidates.filter { (!program.code[$0].isSimple || program.code[$0].numInputs > 0 - || !program.code[$0].op.requiredContext.contains(.javascript) - ) && !(program.code[$0].op is WasmReturn) + || !program.code[$0].op.requiredContext.contains(.javascript)) + && !(program.code[$0].op is WasmReturn) } guard !rootCandidates.isEmpty else { return false } let rootIndex = specifiedIndex ?? chooseUniform(from: rootCandidates) guard rootCandidates.contains(rootIndex) else { return false } - trace("Splicing instruction \(rootIndex) (\(program.code[rootIndex].op.name)) from \(program.id)") + trace( + "Splicing instruction \(rootIndex) (\(program.code[rootIndex].op.name)) from \(program.id)" + ) // // Step (4): compute the slice. @@ -1735,7 +1868,8 @@ public class ProgramBuilder { slice.insert(instr.index) // Only those inputs that we haven't picked replacements for are now also required. - let newlyRequiredVariables = instr.inputs.filter({ !remappedVariables.contains($0) }) + let newlyRequiredVariables = instr.inputs.filter({ !remappedVariables.contains($0) } + ) requiredVariables.formUnion(newlyRequiredVariables) if !shouldIncludeCurrentBlock && instr.isBlock { @@ -1817,16 +1951,16 @@ public class ProgramBuilder { var description: String { switch self { - case .success: - return "✅" - case .failed(let reason): - if let reason { - return "❌: \(reason)" - } else { - return "❌" - } - case .started: - return "started" + case .success: + return "✅" + case .failed(let reason): + if let reason { + return "❌: \(reason)" + } else { + return "❌" + } + case .started: + return "started" } } } @@ -1856,17 +1990,19 @@ public class ProgramBuilder { finishedAction.outcome = .success actions.append((finishedAction, indent)) #if DEBUG - // Now Check that we have variables that match the the specified productions. - for requirement in finishedAction.produces { - if !newlyCreatedVariableTypes.contains(where: requirement.fulfilled) { - var fatalErrorString = "" - fatalErrorString += "Action: \(finishedAction.name)\n" - fatalErrorString += "Action guaranteed it would produce: \(finishedAction.produces)\n" - fatalErrorString += "\(getLogString())\n" - fatalErrorString += "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)" - fatalError(fatalErrorString) + // Now Check that we have variables that match the the specified productions. + for requirement in finishedAction.produces { + if !newlyCreatedVariableTypes.contains(where: requirement.fulfilled) { + var fatalErrorString = "" + fatalErrorString += "Action: \(finishedAction.name)\n" + fatalErrorString += + "Action guaranteed it would produce: \(finishedAction.produces)\n" + fatalErrorString += "\(getLogString())\n" + fatalErrorString += + "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)" + fatalError(fatalErrorString) + } } - } #endif } @@ -1887,21 +2023,22 @@ public class ProgramBuilder { } mutating func reset() { - assert(pendingActions.isEmpty, "We should have completed all pending build actions, either failed or succeeded.") + assert( + pendingActions.isEmpty, + "We should have completed all pending build actions, either failed or succeeded.") // This is basically equivalent with the statement above. assert(indent == 0) actions.removeAll() } } - // The BuildLog records all `run` and `complete` calls on this ProgramBuilder, be it through mutation or generation. #if DEBUG - // We definitely want to have the BuildLog in DEBUG builds. - var buildLog: BuildLog? = BuildLog() + // We definitely want to have the BuildLog in DEBUG builds. + var buildLog: BuildLog? = BuildLog() #else - // We initialize this depending on the LogLevel in the initializer. - var buildLog: BuildLog? = nil + // We initialize this depending on the LogLevel in the initializer. + var buildLog: BuildLog? = nil #endif /// Build random code at the current position in the program. @@ -1919,15 +2056,16 @@ public class ProgramBuilder { let splitFactor = 2 // If the corpus is empty, we have to pick generating here, this is only relevant for the first sample. - let mode: BuildingMode = if fuzzer.corpus.isEmpty { - .generating - } else { - if buildingMode == .generatingAndSplicing { - chooseUniform(from: [.generating, .splicing]) + let mode: BuildingMode = + if fuzzer.corpus.isEmpty { + .generating } else { - buildingMode + if buildingMode == .generatingAndSplicing { + chooseUniform(from: [.generating, .splicing]) + } else { + buildingMode + } } - } // Now depending on the budget we will do one of these things: // 1. Large budget is still here. Pick a scheduled CodeGenerator, or a random CodeGenerator. @@ -1947,14 +2085,19 @@ public class ProgramBuilder { let origContext = context while remainingBudget > 0 { - assert(context == origContext, "Code generation or splicing must not change the current context") + assert( + context == origContext, + "Code generation or splicing must not change the current context") let codeSizeBefore = code.count switch mode { case .generating: // This requirement might seem somewhat arbitrary but our JavaScript code generators make use of `b.randomVariable` and as such rely on the availability of // visible Variables. Therefore we should always have some Variables visible if we want to use them. - assert(hasVisibleVariables, "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program") + assert( + hasVisibleVariables, + "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program" + ) var generator: CodeGenerator? = nil @@ -1980,7 +2123,8 @@ public class ProgramBuilder { break } // Select a random CodeGenerator that is reachable from the current context and run it. - let reachableContexts = fuzzer.contextGraph.getReachableContexts(from: context) + let reachableContexts = fuzzer.contextGraph.getReachableContexts( + from: context) let possibleGenerators = fuzzer.codeGenerators.filter({ generator in reachableContexts.reduce(false) { res, reachable in return res || generator.requiredContext.isSubset(of: reachable) @@ -2076,12 +2220,16 @@ public class ProgramBuilder { // Just fully run the generator without yielding back. // Think about changing this and calling into the higher level build logic? // TODO arbitrary budget here right now, change this to some split factor? - let numberOfGeneratedInstructions = self.complete(generator: generator, withBudget: currentBudget / 5) + let numberOfGeneratedInstructions = self.complete( + generator: generator, withBudget: currentBudget / 5) assert(numberOfGeneratedInstructions > 0, "ValueGenerators must always succeed") totalNumberOfGeneratedInstructions += numberOfGeneratedInstructions } - return (totalNumberOfGeneratedInstructions, numberOfVisibleVariables - previousNumberOfVisibleVariables) + return ( + totalNumberOfGeneratedInstructions, + numberOfVisibleVariables - previousNumberOfVisibleVariables + ) } /// Bootstrap program building by creating some variables with statically known types. @@ -2118,16 +2266,19 @@ public class ProgramBuilder { let newVisibleVariables = visibleVariables.filter { v in let t = type(of: v) - return !oldVisibleVariables.contains(v) && t.wasmTypeDefinition?.description != .selfReference && t.Is(.wasmTypeDef()) + return !oldVisibleVariables.contains(v) + && t.wasmTypeDefinition?.description != .selfReference && t.Is(.wasmTypeDef()) } let newOp = WasmEndTypeGroup(typesCount: instr.inputs.count + newVisibleVariables.count) // We need to keep and adopt the inputs that are still there. let newInputs = adopt(instr.inputs) + newVisibleVariables // Adopt the old outputs and allocate new output variables for the new outputs - let newOutputs = adopt(instr.outputs) + newVisibleVariables.map { _ in - nextVariable() - } + let newOutputs = + adopt(instr.outputs) + + newVisibleVariables.map { _ in + nextVariable() + } append(Instruction(newOp, inouts: Array(newInputs) + newOutputs, flags: instr.flags)) } @@ -2147,18 +2298,21 @@ public class ProgramBuilder { var numberOfGeneratedInstructions = 0 // Calculate all input requirements of this CodeGenerator. - let inputRequirements = Set(generator.parts.reduce([]) { res, gen in - return res + gen.inputs.constraints - }) + let inputRequirements = Set( + generator.parts.reduce([]) { res, gen in + return res + gen.inputs.constraints + }) var fulfilledRequirements = inputRequirements.filter { requirement in - findVariable {requirement.fulfilled(by: self.type(of: $0))} != nil + findVariable { requirement.fulfilled(by: self.type(of: $0)) } != nil } // Add the current context to the seen Contexts as well. var seenContexts: [Context] = [context] - let contextsAndRequirements = generator.parts.map { ($0.providedContext, $0.inputs.constraints) } + let contextsAndRequirements = generator.parts.map { + ($0.providedContext, $0.inputs.constraints) + } // Check if the can be produced along this generator, otherwise we need to bail. for (contexts, requirements) in contextsAndRequirements { @@ -2171,7 +2325,14 @@ public class ProgramBuilder { // If we don't have the type available, check if we can produce it in the current context or a seen context. if !fulfilledRequirements.contains(where: requirement.fulfilled) { // Check if we have generators that can produce the type reachable from this context. - let reachableContexts: Context = seenContexts.reduce(Context.empty) { res, ctx in [res, fuzzer.contextGraph.getReachableContexts(from: ctx).reduce(Context.empty) { res, ctx in [res, ctx]}] + let reachableContexts: Context = seenContexts.reduce(Context.empty) { + res, ctx in + [ + res, + fuzzer.contextGraph.getReachableContexts(from: ctx).reduce( + Context.empty + ) { res, ctx in [res, ctx] }, + ] } // Right now this checks if the generator is a subset of the full reachable context (a single bitfield with all reachable contexts). @@ -2189,7 +2350,10 @@ public class ProgramBuilder { // We cannot run if this is false. if !canProduceThisType { // TODO(cffsmith): track some statistics on how often this happens. - buildLog?.reportFailure(reason: "Cannot produce type \(requirement) starting in original context \(context).") + buildLog?.reportFailure( + reason: + "Cannot produce type \(requirement) starting in original context \(context)." + ) return 0 } else { // Mark the type as available. @@ -2217,7 +2381,10 @@ public class ProgramBuilder { return [res, context] } - assert(subsetContext.isSubset(of: context), "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.head.name).") + assert( + subsetContext.isSubset(of: context), + "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.head.name)." + ) // While our local stack is not removed, we need to call into build and call the scheduled stubs. while scheduled.count > depth { @@ -2227,16 +2394,16 @@ public class ProgramBuilder { // Build into the block. buildRecursive(n: budgetPerYieldPoint) // Call the next scheduled stub. - let _ = callNext() + let _ = callNext() numberOfGeneratedInstructions += code.count - codeSizePre } if numberOfGeneratedInstructions > 0 { buildLog?.succeedAction( Set(visibleVariables) - .subtracting(Set(visibleVariablesBefore)) - .map(self.type) - ) + .subtracting(Set(visibleVariablesBefore)) + .map(self.type) + ) } else { buildLog?.reportFailure() } @@ -2255,12 +2422,12 @@ public class ProgramBuilder { // Check if we can produce it with findOrGenerateWasmVar let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) } - if (findVariable {requirement.fulfilled(by: self.type(of: $0))} == nil) { + if findVariable { requirement.fulfilled(by: self.type(of: $0)) } == nil { // Check for other CodeGenerators that can produce the given type in this context. let usableGenerators = fuzzer.codeGenerators.filter { - $0.requiredContext.isSubset(of: context) && - $0.produces.contains(where: requirement.fulfilled) + $0.requiredContext.isSubset(of: context) + && $0.produces.contains(where: requirement.fulfilled) } // Cannot build type here. @@ -2289,7 +2456,9 @@ public class ProgramBuilder { if context.contains(possibleContext) { // Walk through generated Graph and find a path. - let paths = fuzzer.contextGraph.getCodeGeneratorPaths(from: possibleContext, to: mainGenerator.requiredContext) ?? [] + let paths = + fuzzer.contextGraph.getCodeGeneratorPaths( + from: possibleContext, to: mainGenerator.requiredContext) ?? [] return pathArray + paths } @@ -2297,7 +2466,9 @@ public class ProgramBuilder { } if paths.isEmpty { - logger.warning("Found no paths in context \(context) for requested generator \(mainGenerator.name)") + logger.warning( + "Found no paths in context \(context) for requested generator \(mainGenerator.name)" + ) return nil } @@ -2350,8 +2521,10 @@ public class ProgramBuilder { return [res, context] } - assert(subsetContext.isSubset(of: context), "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.name).") - + assert( + subsetContext.isSubset(of: context), + "Generators that claim to provide contexts cannot fail to provide those contexts \(generator.name)." + ) return generatedInstructions } else { @@ -2372,18 +2545,24 @@ public class ProgramBuilder { switch generator.inputs.mode { case .loose: // Find inputs that are probably compatible with the desired input types using randomVariable(forUseAs:) - inputs = generator.inputs.constraints.map {randomVariable(forUseAs: $0.type)} + inputs = generator.inputs.constraints.map { randomVariable(forUseAs: $0.type) } case .strict: // Find inputs of the required type using randomVariable(ofType:) for requirement in generator.inputs.constraints { - guard let input = (findVariable {requirement.fulfilled(by: self.type(of: $0))}) else { + guard let input = (findVariable { requirement.fulfilled(by: self.type(of: $0)) }) + else { // Cannot run this generator if generator.providedContext != [] { - fatalError("This generator is supposed to provide a context but cannot as we've failed to find the necessary inputs.") + fatalError( + "This generator is supposed to provide a context but cannot as we've failed to find the necessary inputs." + ) } // This early return also needs to report a failure. - buildLog?.reportFailure(reason: "Cannot find variable that satifies input constraints \(requirement.type).") + buildLog?.reportFailure( + reason: + "Cannot find variable that satifies input constraints \(requirement.type)." + ) return 0 } inputs.append(input) @@ -2396,9 +2575,9 @@ public class ProgramBuilder { contributors.insert(generator) buildLog?.succeedAction( Set(visibleVariables) - .subtracting(Set(visibleVariablesBefore)) - .map(self.type) - ) + .subtracting(Set(visibleVariablesBefore)) + .map(self.type) + ) } else { buildLog?.reportFailure(reason: "Generator itself failed to produce any instructions.") } @@ -2420,7 +2599,9 @@ public class ProgramBuilder { do { let program = Program(with: self.code) let pb = try program.asProtobuf().serializedData() - fuzzer.dispatchEvent(fuzzer.events.DiagnosticsEvent, data: (name: "WasmProgramBuildingEmissionFail", content: pb)) + fuzzer.dispatchEvent( + fuzzer.events.DiagnosticsEvent, + data: (name: "WasmProgramBuildingEmissionFail", content: pb)) } catch { logger.warning("Could not dump program to disk!") } @@ -2430,7 +2611,9 @@ public class ProgramBuilder { } @discardableResult - public func emit(_ op: Operation, withInputs inputs: [Variable] = [], types: [ILType]? = nil) -> Instruction { + public func emit(_ op: Operation, withInputs inputs: [Variable] = [], types: [ILType]? = nil) + -> Instruction + { var inouts = inputs for _ in 0.. ()) { + public func addMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) + let instr = b.emit( + BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralMethod()) } - public func addComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), withInputs: [name]) + let instr = b.emit( + BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralComputedMethod()) } - public func addGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginObjectLiteralGetter(propertyName: name)) body(instr.innerOutput) b.emit(EndObjectLiteralGetter()) } - public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addComputedGetter(for name: Variable, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginObjectLiteralComputedGetter(), withInputs: [name]) body(instr.innerOutput) b.emit(EndObjectLiteralComputedGetter()) } - public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void) + { let instr = b.emit(BeginObjectLiteralSetter(propertyName: name)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralSetter()) } - public func addComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginObjectLiteralComputedSetter(), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndObjectLiteralComputedSetter()) @@ -2608,7 +2803,7 @@ public class ProgramBuilder { } @discardableResult - public func buildObjectLiteral(_ body: (ObjectLiteral) -> ()) -> Variable { + public func buildObjectLiteral(_ body: (ObjectLiteral) -> Void) -> Variable { emit(BeginObjectLiteral()) body(currentObjectLiteral) return emit(EndObjectLiteral()).output @@ -2672,62 +2867,83 @@ public class ProgramBuilder { self.isDerivedClass = isDerived } - public func addConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addConstructor( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit(BeginClassConstructor(parameters: descriptor.parameters)) body(Array(instr.innerOutputs)) b.emit(EndClassConstructor()) } - public func addInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: false), + withInputs: inputs) } public func addInstanceElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddElement(index: index, hasValue: value != nil, isStatic: false), + withInputs: inputs) } public func addInstanceComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddComputedProperty(hasValue: value != nil, isStatic: false), + withInputs: inputs) } - public func addInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) + let instr = b.emit( + BeginClassMethod( + methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } - public func addInstanceComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addInstanceComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), withInputs: [name]) + let instr = b.emit( + BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } - public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addInstanceGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: false)) body(instr.innerOutput) b.emit(EndClassGetter()) } - public func addInstanceComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addInstanceComputedGetter( + for name: Variable, _ body: (_ this: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedGetter(isStatic: false), withInputs: [name]) body(instr.innerOutput) b.emit(EndClassComputedGetter()) } - public func addInstanceSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addInstanceSetter( + for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: false)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } - public func addInstanceComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addInstanceComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedSetter(isStatic: false), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassComputedSetter()) @@ -2735,58 +2951,77 @@ public class ProgramBuilder { public func addStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddProperty(propertyName: name, hasValue: value != nil, isStatic: true), + withInputs: inputs) } public func addStaticElement(_ index: Int64, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddElement(index: index, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddElement(index: index, hasValue: value != nil, isStatic: true), + withInputs: inputs) } public func addStaticComputedProperty(_ name: Variable, value: Variable? = nil) { let inputs = value != nil ? [name, value!] : [name] - b.emit(ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddComputedProperty(hasValue: value != nil, isStatic: true), withInputs: inputs + ) } - public func addStaticInitializer(_ body: (Variable) -> ()) { + public func addStaticInitializer(_ body: (Variable) -> Void) { let instr = b.emit(BeginClassStaticInitializer()) body(instr.innerOutput) b.emit(EndClassStaticInitializer()) } - public func addStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addStaticMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) + let instr = b.emit( + BeginClassMethod( + methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } - public func addStaticComputedMethod(_ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addStaticComputedMethod( + _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), withInputs: [name]) + let instr = b.emit( + BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), + withInputs: [name]) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } - public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> ()) { + public func addStaticGetter(for name: String, _ body: (_ this: Variable) -> Void) { let instr = b.emit(BeginClassGetter(propertyName: name, isStatic: true)) body(instr.innerOutput) b.emit(EndClassGetter()) } - public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> ()) { + public func addStaticComputedGetter(for name: Variable, _ body: (_ this: Variable) -> Void) + { let instr = b.emit(BeginClassComputedGetter(isStatic: true), withInputs: [name]) body(instr.innerOutput) b.emit(EndClassComputedGetter()) } - public func addStaticSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addStaticSetter( + for name: String, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassSetter(propertyName: name, isStatic: true)) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassSetter()) } - public func addStaticComputedSetter(for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> ()) { + public func addStaticComputedSetter( + for name: Variable, _ body: (_ this: Variable, _ val: Variable) -> Void + ) { let instr = b.emit(BeginClassComputedSetter(isStatic: true), withInputs: [name]) body(instr.innerOutput(0), instr.innerOutput(1)) b.emit(EndClassComputedSetter()) @@ -2794,33 +3029,52 @@ public class ProgramBuilder { public func addPrivateInstanceProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs) + b.emit( + ClassAddPrivateProperty( + propertyName: name, hasValue: value != nil, isStatic: false), withInputs: inputs + ) } - public func addPrivateInstanceMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addPrivateInstanceMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: false)) + let instr = b.emit( + BeginClassPrivateMethod( + methodName: name, parameters: descriptor.parameters, isStatic: false)) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } public func addPrivateStaticProperty(_ name: String, value: Variable? = nil) { let inputs = value != nil ? [value!] : [] - b.emit(ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), withInputs: inputs) + b.emit( + ClassAddPrivateProperty(propertyName: name, hasValue: value != nil, isStatic: true), + withInputs: inputs) } - public func addPrivateStaticMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) { + public func addPrivateStaticMethod( + _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) { b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassPrivateMethod(methodName: name, parameters: descriptor.parameters, isStatic: true)) + let instr = b.emit( + BeginClassPrivateMethod( + methodName: name, parameters: descriptor.parameters, isStatic: true)) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } } @discardableResult - public func buildClassDefinition(withSuperclass superclass: Variable? = nil, isExpression: Bool = false, _ body: (ClassDefinition) -> ()) -> Variable { + public func buildClassDefinition( + withSuperclass superclass: Variable? = nil, isExpression: Bool = false, + _ body: (ClassDefinition) -> Void + ) -> Variable { let inputs = superclass != nil ? [superclass!] : [] - let output = emit(BeginClassDefinition(hasSuperclass: superclass != nil, isExpression: isExpression), withInputs: inputs).output + let output = emit( + BeginClassDefinition(hasSuperclass: superclass != nil, isExpression: isExpression), + withInputs: inputs + ).output bodyWithRecursionGuard(output) { body(currentClassDefinition) } emit(EndClassDefinition()) return output @@ -2828,7 +3082,8 @@ public class ProgramBuilder { @discardableResult public func createArray(with initialValues: [Variable]) -> Variable { - return emit(CreateArray(numInitialValues: initialValues.count), withInputs: initialValues).output + return emit(CreateArray(numInitialValues: initialValues.count), withInputs: initialValues) + .output } @discardableResult @@ -2848,25 +3103,36 @@ public class ProgramBuilder { } @discardableResult - public func createTemplateString(from parts: [String], interpolating interpolatedValues: [Variable]) -> Variable { + public func createTemplateString( + from parts: [String], interpolating interpolatedValues: [Variable] + ) -> Variable { return emit(CreateTemplateString(parts: parts), withInputs: interpolatedValues).output } @discardableResult - public func getProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) -> Variable { - return emit(GetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]).output + public func getProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) + -> Variable + { + return emit(GetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]) + .output } - public func setProperty(_ name: String, of object: Variable, to value: Variable, guard isGuarded: Bool = false) { + public func setProperty( + _ name: String, of object: Variable, to value: Variable, guard isGuarded: Bool = false + ) { emit(SetProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object, value]) } - public func updateProperty(_ name: String, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updateProperty( + _ name: String, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateProperty(propertyName: name, operator: op), withInputs: [object, value]) } @discardableResult - public func deleteProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteProperty(_ name: String, of object: Variable, guard isGuarded: Bool = false) + -> Variable + { emit(DeleteProperty(propertyName: name, isGuarded: isGuarded), withInputs: [object]).output } @@ -2877,21 +3143,34 @@ public class ProgramBuilder { case getterSetter(Variable, Variable) } - public func configureProperty(_ name: String, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureProperty( + _ name: String, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .value), withInputs: [object, value]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .value), + withInputs: [object, value]) case .getter(let getter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .getter), withInputs: [object, getter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .getter), + withInputs: [object, getter]) case .setter(let setter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .setter), withInputs: [object, setter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .setter), + withInputs: [object, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureProperty(propertyName: name, flags: flags, type: .getterSetter), withInputs: [object, getter, setter]) + emit( + ConfigureProperty(propertyName: name, flags: flags, type: .getterSetter), + withInputs: [object, getter, setter]) } } @discardableResult - public func getElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) -> Variable { + public func getElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) + -> Variable + { return emit(GetElement(index: index, isGuarded: isGuarded), withInputs: [array]).output } @@ -2899,30 +3178,47 @@ public class ProgramBuilder { emit(SetElement(index: index), withInputs: [array, value]) } - public func updateElement(_ index: Int64, of array: Variable, with value: Variable, using op: BinaryOperator) { + public func updateElement( + _ index: Int64, of array: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateElement(index: index, operator: op), withInputs: [array, value]) } @discardableResult - public func deleteElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteElement(_ index: Int64, of array: Variable, guard isGuarded: Bool = false) + -> Variable + { emit(DeleteElement(index: index, isGuarded: isGuarded), withInputs: [array]).output } - public func configureElement(_ index: Int64, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureElement( + _ index: Int64, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureElement(index: index, flags: flags, type: .value), withInputs: [object, value]) + emit( + ConfigureElement(index: index, flags: flags, type: .value), + withInputs: [object, value]) case .getter(let getter): - emit(ConfigureElement(index: index, flags: flags, type: .getter), withInputs: [object, getter]) + emit( + ConfigureElement(index: index, flags: flags, type: .getter), + withInputs: [object, getter]) case .setter(let setter): - emit(ConfigureElement(index: index, flags: flags, type: .setter), withInputs: [object, setter]) + emit( + ConfigureElement(index: index, flags: flags, type: .setter), + withInputs: [object, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureElement(index: index, flags: flags, type: .getterSetter), withInputs: [object, getter, setter]) + emit( + ConfigureElement(index: index, flags: flags, type: .getterSetter), + withInputs: [object, getter, setter]) } } @discardableResult - public func getComputedProperty(_ name: Variable, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func getComputedProperty( + _ name: Variable, of object: Variable, guard isGuarded: Bool = false + ) -> Variable { return emit(GetComputedProperty(isGuarded: isGuarded), withInputs: [object, name]).output } @@ -2930,25 +3226,40 @@ public class ProgramBuilder { emit(SetComputedProperty(), withInputs: [object, name, value]) } - public func updateComputedProperty(_ name: Variable, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updateComputedProperty( + _ name: Variable, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdateComputedProperty(operator: op), withInputs: [object, name, value]) } @discardableResult - public func deleteComputedProperty(_ name: Variable, of object: Variable, guard isGuarded: Bool = false) -> Variable { + public func deleteComputedProperty( + _ name: Variable, of object: Variable, guard isGuarded: Bool = false + ) -> Variable { emit(DeleteComputedProperty(isGuarded: isGuarded), withInputs: [object, name]).output } - public func configureComputedProperty(_ name: Variable, of object: Variable, usingFlags flags: PropertyFlags, as config: PropertyConfiguration) { + public func configureComputedProperty( + _ name: Variable, of object: Variable, usingFlags flags: PropertyFlags, + as config: PropertyConfiguration + ) { switch config { case .value(let value): - emit(ConfigureComputedProperty(flags: flags, type: .value), withInputs: [object, name, value]) + emit( + ConfigureComputedProperty(flags: flags, type: .value), + withInputs: [object, name, value]) case .getter(let getter): - emit(ConfigureComputedProperty(flags: flags, type: .getter), withInputs: [object, name, getter]) + emit( + ConfigureComputedProperty(flags: flags, type: .getter), + withInputs: [object, name, getter]) case .setter(let setter): - emit(ConfigureComputedProperty(flags: flags, type: .setter), withInputs: [object, name, setter]) + emit( + ConfigureComputedProperty(flags: flags, type: .setter), + withInputs: [object, name, setter]) case .getterSetter(let getter, let setter): - emit(ConfigureComputedProperty(flags: flags, type: .getterSetter), withInputs: [object, name, getter, setter]) + emit( + ConfigureComputedProperty(flags: flags, type: .getterSetter), + withInputs: [object, name, getter, setter]) } } @@ -2974,7 +3285,9 @@ public class ProgramBuilder { public func explore(_ v: Variable, id: String, withArgs arguments: [Variable]) { let rngSeed = UInt32(truncatingIfNeeded: randomInt()) - emit(Explore(id: id, numArguments: arguments.count, rngSeed: rngSeed), withInputs: [v] + arguments) + emit( + Explore(id: id, numArguments: arguments.count, rngSeed: rngSeed), + withInputs: [v] + arguments) } public func probe(_ v: Variable, id: String) { @@ -2982,8 +3295,14 @@ public class ProgramBuilder { } @discardableResult - public func fixup(id: String, action: String, originalOperation: String, arguments: [Variable], hasOutput: Bool) -> Variable? { - let instr = emit(Fixup(id: id, action: action, originalOperation: originalOperation, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) + public func fixup( + id: String, action: String, originalOperation: String, arguments: [Variable], + hasOutput: Bool + ) -> Variable? { + let instr = emit( + Fixup( + id: id, action: action, originalOperation: originalOperation, + numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) return hasOutput ? instr.output : nil } @@ -3005,8 +3324,11 @@ public class ProgramBuilder { return parameters.count } - public static func parameters(n: Int, hasRestParameter: Bool = false) -> SubroutineDescriptor { - return SubroutineDescriptor(withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) + public static func parameters(n: Int, hasRestParameter: Bool = false) + -> SubroutineDescriptor + { + return SubroutineDescriptor( + withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) } public static func parameters(_ params: Parameter...) -> SubroutineDescriptor { @@ -3014,35 +3336,48 @@ public class ProgramBuilder { } public static func parameters(_ parameterTypes: ParameterList) -> SubroutineDescriptor { - let parameters = Parameters(count: parameterTypes.count, hasRestParameter: parameterTypes.hasRestParameter) + let parameters = Parameters( + count: parameterTypes.count, hasRestParameter: parameterTypes.hasRestParameter) return SubroutineDescriptor(withParameters: parameters, ofTypes: parameterTypes) } - private init(withParameters parameters: Parameters, ofTypes parameterTypes: ParameterList? = nil) { + private init( + withParameters parameters: Parameters, ofTypes parameterTypes: ParameterList? = nil + ) { if let types = parameterTypes { assert(types.areValid()) assert(types.count == parameters.count) assert(types.hasRestParameter == parameters.hasRestParameter) self.parameterTypes = types } else { - self.parameterTypes = ParameterList(numParameters: parameters.count, hasRestParam: parameters.hasRestParameter) - assert(self.parameterTypes.allSatisfy({ $0 == .plain(.jsAnything) || $0 == .rest(.jsAnything) })) + self.parameterTypes = ParameterList( + numParameters: parameters.count, hasRestParam: parameters.hasRestParameter) + assert( + self.parameterTypes.allSatisfy({ + $0 == .plain(.jsAnything) || $0 == .rest(.jsAnything) + })) } self.parameters = parameters } } @discardableResult - public func buildPlainFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil,_ body: ([Variable]) -> ()) -> Variable { + public func buildPlainFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndPlainFunction()) return instr.output } @discardableResult - public func buildArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildArrowFunction( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3051,25 +3386,35 @@ public class ProgramBuilder { } @discardableResult - public func buildGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndGeneratorFunction()) return instr.output } @discardableResult - public func buildAsyncFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncFunction()) return instr.output } @discardableResult - public func buildAsyncArrowFunction(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncArrowFunction( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3078,16 +3423,23 @@ public class ProgramBuilder { } @discardableResult - public func buildAsyncGeneratorFunction(with descriptor: SubroutineDescriptor, named functionName: String? = nil, _ body: ([Variable]) -> ()) -> Variable { + public func buildAsyncGeneratorFunction( + with descriptor: SubroutineDescriptor, named functionName: String? = nil, + _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + let instr = emit( + BeginAsyncGeneratorFunction( + parameters: descriptor.parameters, functionName: functionName)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncGeneratorFunction()) return instr.output } @discardableResult - public func buildConstructor(with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) -> Variable { + public func buildConstructor( + with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + ) -> Variable { setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit(BeginConstructor(parameters: descriptor.parameters)) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } @@ -3132,36 +3484,73 @@ public class ProgramBuilder { } @discardableResult - public func callFunction(_ function: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallFunction(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [function] + arguments).output + public func callFunction( + _ function: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallFunction(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [function] + arguments + ).output } @discardableResult - public func callFunction(_ function: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func callFunction( + _ function: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], + guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return callFunction(function, withArgs: arguments) } - return emit(CallFunctionWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [function] + arguments).output + return emit( + CallFunctionWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [function] + arguments + ).output } @discardableResult - public func construct(_ constructor: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(Construct(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [constructor] + arguments).output + public func construct( + _ constructor: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false + ) -> Variable { + return emit( + Construct(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [constructor] + arguments + ).output } @discardableResult - public func construct(_ constructor: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func construct( + _ constructor: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], + guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return construct(constructor, withArgs: arguments) } - return emit(ConstructWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [constructor] + arguments).output + return emit( + ConstructWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [constructor] + arguments + ).output } @discardableResult - public func callMethod(_ name: String, on object: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallMethod(methodName: name, numArguments: arguments.count, isGuarded: isGuarded), withInputs: [object] + arguments).output + public func callMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable] = [], + guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallMethod(methodName: name, numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [object] + arguments + ).output } @discardableResult - public func callMethod(_ name: String, on object: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { + public func callMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable], + spreading spreads: [Bool], guard isGuarded: Bool = false + ) -> Variable { guard !spreads.isEmpty else { return callMethod(name, on: object, withArgs: arguments) } - return emit(CallMethodWithSpread(methodName: name, numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [object] + arguments).output + return emit( + CallMethodWithSpread( + methodName: name, numArguments: arguments.count, spreads: spreads, + isGuarded: isGuarded), withInputs: [object] + arguments + ).output } @discardableResult @@ -3171,18 +3560,34 @@ public class ProgramBuilder { @discardableResult public func bindFunction(_ fct: Variable, boundArgs arguments: [Variable]) -> Variable { - return emit(BindFunction(numInputs: arguments.count + 1), withInputs: [fct] + arguments).output + return emit(BindFunction(numInputs: arguments.count + 1), withInputs: [fct] + arguments) + .output } @discardableResult - public func callComputedMethod(_ name: Variable, on object: Variable, withArgs arguments: [Variable] = [], guard isGuarded: Bool = false) -> Variable { - return emit(CallComputedMethod(numArguments: arguments.count, isGuarded: isGuarded), withInputs: [object, name] + arguments).output + public func callComputedMethod( + _ name: Variable, on object: Variable, withArgs arguments: [Variable] = [], + guard isGuarded: Bool = false + ) -> Variable { + return emit( + CallComputedMethod(numArguments: arguments.count, isGuarded: isGuarded), + withInputs: [object, name] + arguments + ).output } @discardableResult - public func callComputedMethod(_ name: Variable, on object: Variable, withArgs arguments: [Variable], spreading spreads: [Bool], guard isGuarded: Bool = false) -> Variable { - guard !spreads.isEmpty else { return callComputedMethod(name, on: object, withArgs: arguments) } - return emit(CallComputedMethodWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), withInputs: [object, name] + arguments).output + public func callComputedMethod( + _ name: Variable, on object: Variable, withArgs arguments: [Variable], + spreading spreads: [Bool], guard isGuarded: Bool = false + ) -> Variable { + guard !spreads.isEmpty else { + return callComputedMethod(name, on: object, withArgs: arguments) + } + return emit( + CallComputedMethodWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: isGuarded), + withInputs: [object, name] + arguments + ).output } @discardableResult @@ -3214,35 +3619,59 @@ public class ProgramBuilder { } @discardableResult - public func destruct(_ input: Variable, selecting indices: [Int64], lastIsRest: Bool = false) -> [Variable] { - let outputs = emit(DestructArray(indices: indices, lastIsRest: lastIsRest), withInputs: [input]).outputs + public func destruct(_ input: Variable, selecting indices: [Int64], lastIsRest: Bool = false) + -> [Variable] + { + let outputs = emit( + DestructArray(indices: indices, lastIsRest: lastIsRest), withInputs: [input] + ).outputs return Array(outputs) } - public func destruct(_ input: Variable, selecting indices: [Int64], into outputs: [Variable], lastIsRest: Bool = false) { - emit(DestructArrayAndReassign(indices: indices, lastIsRest: lastIsRest), withInputs: [input] + outputs) + public func destruct( + _ input: Variable, selecting indices: [Int64], into outputs: [Variable], + lastIsRest: Bool = false + ) { + emit( + DestructArrayAndReassign(indices: indices, lastIsRest: lastIsRest), + withInputs: [input] + outputs) } @discardableResult - public func destruct(_ input: Variable, selecting properties: [String], hasRestElement: Bool = false) -> [Variable] { - let outputs = emit(DestructObject(properties: properties, hasRestElement: hasRestElement), withInputs: [input]).outputs + public func destruct( + _ input: Variable, selecting properties: [String], hasRestElement: Bool = false + ) -> [Variable] { + let outputs = emit( + DestructObject(properties: properties, hasRestElement: hasRestElement), + withInputs: [input] + ).outputs return Array(outputs) } - public func destruct(_ input: Variable, selecting properties: [String], into outputs: [Variable], hasRestElement: Bool = false) { - emit(DestructObjectAndReassign(properties: properties, hasRestElement: hasRestElement), withInputs: [input] + outputs) + public func destruct( + _ input: Variable, selecting properties: [String], into outputs: [Variable], + hasRestElement: Bool = false + ) { + emit( + DestructObjectAndReassign(properties: properties, hasRestElement: hasRestElement), + withInputs: [input] + outputs) } @discardableResult - public func compare(_ lhs: Variable, with rhs: Variable, using comparator: Comparator) -> Variable { + public func compare(_ lhs: Variable, with rhs: Variable, using comparator: Comparator) + -> Variable + { return emit(Compare(comparator), withInputs: [lhs, rhs]).output } @discardableResult - public func createNamedVariable(_ name: String, declarationMode: NamedVariableDeclarationMode, initialValue: Variable? = nil) -> Variable { + public func createNamedVariable( + _ name: String, declarationMode: NamedVariableDeclarationMode, initialValue: Variable? = nil + ) -> Variable { assert((declarationMode == .none) == (initialValue == nil)) let inputs = initialValue != nil ? [initialValue!] : [] - return emit(CreateNamedVariable(name, declarationMode: declarationMode), withInputs: inputs).output + return emit(CreateNamedVariable(name, declarationMode: declarationMode), withInputs: inputs) + .output } @discardableResult @@ -3251,12 +3680,15 @@ public class ProgramBuilder { } @discardableResult - public func createNamedDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable { + public func createNamedDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable + { return emit(CreateNamedDisposableVariable(name), withInputs: [initialValue]).output } @discardableResult - public func createNamedAsyncDisposableVariable(_ name: String, _ initialValue: Variable) -> Variable { + public func createNamedAsyncDisposableVariable(_ name: String, _ initialValue: Variable) + -> Variable + { return emit(CreateNamedAsyncDisposableVariable(name), withInputs: [initialValue]).output } @@ -3270,8 +3702,12 @@ public class ProgramBuilder { } @discardableResult - public func eval(_ string: String, with arguments: [Variable] = [], hasOutput: Bool = false) -> Variable? { - let instr = emit(Eval(string, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) + public func eval(_ string: String, with arguments: [Variable] = [], hasOutput: Bool = false) + -> Variable? + { + let instr = emit( + Eval(string, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments + ) return hasOutput ? instr.output : nil } @@ -3291,7 +3727,9 @@ public class ProgramBuilder { @discardableResult public func callSuperMethod(_ name: String, withArgs arguments: [Variable] = []) -> Variable { - return emit(CallSuperMethod(methodName: name, numArguments: arguments.count), withInputs: arguments).output + return emit( + CallSuperMethod(methodName: name, numArguments: arguments.count), withInputs: arguments + ).output } @discardableResult @@ -3303,13 +3741,20 @@ public class ProgramBuilder { emit(SetPrivateProperty(propertyName: name), withInputs: [object, value]) } - public func updatePrivateProperty(_ name: String, of object: Variable, with value: Variable, using op: BinaryOperator) { + public func updatePrivateProperty( + _ name: String, of object: Variable, with value: Variable, using op: BinaryOperator + ) { emit(UpdatePrivateProperty(propertyName: name, operator: op), withInputs: [object, value]) } @discardableResult - public func callPrivateMethod(_ name: String, on object: Variable, withArgs arguments: [Variable] = []) -> Variable { - return emit(CallPrivateMethod(methodName: name, numArguments: arguments.count), withInputs: [object] + arguments).output + public func callPrivateMethod( + _ name: String, on object: Variable, withArgs arguments: [Variable] = [] + ) -> Variable { + return emit( + CallPrivateMethod(methodName: name, numArguments: arguments.count), + withInputs: [object] + arguments + ).output } @discardableResult @@ -3330,7 +3775,8 @@ public class ProgramBuilder { emit(SetComputedSuperProperty(), withInputs: [property, value]) } - public func updateSuperProperty(_ name: String, with value: Variable, using op: BinaryOperator) { + public func updateSuperProperty(_ name: String, with value: Variable, using op: BinaryOperator) + { emit(UpdateSuperProperty(propertyName: name, operator: op), withInputs: [value]) } @@ -3357,20 +3803,20 @@ public class ProgramBuilder { self.b = b } - public func addDefaultCase(fallsThrough: Bool = false, body: @escaping () -> ()) { + public func addDefaultCase(fallsThrough: Bool = false, body: @escaping () -> Void) { b.emit(BeginSwitchDefaultCase(), withInputs: []) body() b.emit(EndSwitchCase(fallsThrough: fallsThrough)) } - public func addCase(_ v: Variable, fallsThrough: Bool = false, body: @escaping () -> ()) { + public func addCase(_ v: Variable, fallsThrough: Bool = false, body: @escaping () -> Void) { b.emit(BeginSwitchCase(), withInputs: [v]) body() b.emit(EndSwitchCase(fallsThrough: fallsThrough)) } } - public func buildSwitch(on switchVar: Variable, body: (SwitchBlock) -> ()) { + public func buildSwitch(on switchVar: Variable, body: (SwitchBlock) -> Void) { emit(BeginSwitch(), withInputs: [switchVar]) body(currentSwitchBlock) emit(EndSwitch()) @@ -3397,12 +3843,17 @@ public class ProgramBuilder { } // Build a simple for loop that declares one loop variable. - public func buildForLoop(i initializer: () -> Variable, _ cond: (Variable) -> Variable, _ afterthought: (Variable) -> (), _ body: (Variable) -> ()) { + public func buildForLoop( + i initializer: () -> Variable, _ cond: (Variable) -> Variable, + _ afterthought: (Variable) -> Void, _ body: (Variable) -> Void + ) { emit(BeginForLoopInitializer()) let initialValue = initializer() - var loopVar = emit(BeginForLoopCondition(numLoopVariables: 1), withInputs: [initialValue]).innerOutput + var loopVar = emit(BeginForLoopCondition(numLoopVariables: 1), withInputs: [initialValue]) + .innerOutput let cond = cond(loopVar) - loopVar = emit(BeginForLoopAfterthought(numLoopVariables: 1), withInputs: [cond]).innerOutput + loopVar = + emit(BeginForLoopAfterthought(numLoopVariables: 1), withInputs: [cond]).innerOutput afterthought(loopVar) loopVar = emit(BeginForLoopBody(numLoopVariables: 1)).innerOutput body(loopVar) @@ -3410,7 +3861,10 @@ public class ProgramBuilder { } // Build arbitrarily complex for loops without any loop variables. - public func buildForLoop(_ initializer: (() -> ())? = nil, _ cond: (() -> Variable)? = nil, _ afterthought: (() -> ())? = nil, _ body: () -> ()) { + public func buildForLoop( + _ initializer: (() -> Void)? = nil, _ cond: (() -> Variable)? = nil, + _ afterthought: (() -> Void)? = nil, _ body: () -> Void + ) { emit(BeginForLoopInitializer()) initializer?() emit(BeginForLoopCondition(numLoopVariables: 0)) @@ -3423,43 +3877,56 @@ public class ProgramBuilder { } // Build arbitrarily complex for loops with one or more loop variables. - public func buildForLoop(_ initializer: () -> [Variable], _ cond: (([Variable]) -> Variable)? = nil, _ afterthought: (([Variable]) -> ())? = nil, _ body: ([Variable]) -> ()) { + public func buildForLoop( + _ initializer: () -> [Variable], _ cond: (([Variable]) -> Variable)? = nil, + _ afterthought: (([Variable]) -> Void)? = nil, _ body: ([Variable]) -> Void + ) { emit(BeginForLoopInitializer()) let initialValues = initializer() - var loopVars = emit(BeginForLoopCondition(numLoopVariables: initialValues.count), withInputs: initialValues).innerOutputs + var loopVars = emit( + BeginForLoopCondition(numLoopVariables: initialValues.count), withInputs: initialValues + ).innerOutputs let cond = cond?(Array(loopVars)) ?? loadBool(true) - loopVars = emit(BeginForLoopAfterthought(numLoopVariables: initialValues.count), withInputs: [cond]).innerOutputs + loopVars = + emit( + BeginForLoopAfterthought(numLoopVariables: initialValues.count), withInputs: [cond] + ).innerOutputs afterthought?(Array(loopVars)) loopVars = emit(BeginForLoopBody(numLoopVariables: initialValues.count)).innerOutputs body(Array(loopVars)) emit(EndForLoop()) } - public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> ()) { + public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> Void) { let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForInLoop()) } - public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) { + public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> Void) { let i = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForOfLoop()) } - public func buildForOfLoop(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) { - let instr = emit(BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), withInputs: [obj]) + public func buildForOfLoop( + _ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, + _ body: ([Variable]) -> Void + ) { + let instr = emit( + BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), + withInputs: [obj]) body(Array(instr.innerOutputs)) emit(EndForOfLoop()) } - public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> ()) { + public func buildRepeatLoop(n numIterations: Int, _ body: (Variable) -> Void) { let i = emit(BeginRepeatLoop(iterations: numIterations)).innerOutput body(i) emit(EndRepeatLoop()) } - public func buildRepeatLoop(n numIterations: Int, _ body: () -> ()) { + public func buildRepeatLoop(n numIterations: Int, _ body: () -> Void) { emit(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) body() emit(EndRepeatLoop()) @@ -3473,8 +3940,13 @@ public class ProgramBuilder { emit(LoopContinue(), withInputs: []) } - public func buildTryCatchFinally(tryBody: () -> (), catchBody: ((Variable) -> ())? = nil, finallyBody: (() -> ())? = nil) { - assert(catchBody != nil || finallyBody != nil, "Must have either a Catch or a Finally block (or both)") + public func buildTryCatchFinally( + tryBody: () -> Void, catchBody: ((Variable) -> Void)? = nil, + finallyBody: (() -> Void)? = nil + ) { + assert( + catchBody != nil || finallyBody != nil, + "Must have either a Catch or a Finally block (or both)") emit(BeginTry()) tryBody() if let catchBody = catchBody { @@ -3492,7 +3964,7 @@ public class ProgramBuilder { emit(ThrowException(), withInputs: [value]) } - public func buildCodeString(_ body: () -> ()) -> Variable { + public func buildCodeString(_ body: () -> Void) -> Variable { let instr = emit(BeginCodeString()) body() emit(EndCodeString()) @@ -3509,7 +3981,6 @@ public class ProgramBuilder { emit(Print(), withInputs: [value]) } - @discardableResult public func createWasmGlobal(value: WasmGlobal, isMutable: Bool) -> Variable { let variable = emit(CreateWasmGlobal(value: value, isMutable: isMutable)).output @@ -3517,13 +3988,20 @@ public class ProgramBuilder { } @discardableResult - public func createWasmMemory(minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false) -> Variable { + public func createWasmMemory( + minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false + ) -> Variable { assert(!isShared || maxPages != nil, "Shared memories must have a maximum size") - return emit(CreateWasmMemory(limits: Limits(min: minPages, max: maxPages), isShared: isShared, isMemory64: isMemory64)).output + return emit( + CreateWasmMemory( + limits: Limits(min: minPages, max: maxPages), isShared: isShared, + isMemory64: isMemory64) + ).output } public func createWasmTable(elementType: ILType, limits: Limits, isTable64: Bool) -> Variable { - return emit(CreateWasmTable(elementType: elementType, limits: limits, isTable64: isTable64)).output + return emit(CreateWasmTable(elementType: elementType, limits: limits, isTable64: isTable64)) + .output } @discardableResult @@ -3573,7 +4051,7 @@ public class ProgramBuilder { @discardableResult public func memoryArgument(_ value: Int64, _ memoryTypeInfo: WasmMemoryType) -> Variable { - if (memoryTypeInfo.isMemory64) { + if memoryTypeInfo.isMemory64 { return self.consti64(value) } else { return self.consti32(Int32(value)) @@ -3591,43 +4069,67 @@ public class ProgramBuilder { } @discardableResult - public func wasmi64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind) -> Variable { - return b.emit(Wasmi64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmi64, .wasmi64]).output + public func wasmi64BinOp( + _ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind + ) -> Variable { + return b.emit( + Wasmi64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmi64, .wasmi64] + ).output } @discardableResult - public func wasmi32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind) -> Variable { - return b.emit(Wasmi32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmi32, .wasmi32]).output + public func wasmi32BinOp( + _ lhs: Variable, _ rhs: Variable, binOpKind: WasmIntegerBinaryOpKind + ) -> Variable { + return b.emit( + Wasmi32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmi32, .wasmi32] + ).output } @discardableResult - public func wasmf32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) -> Variable { - return b.emit(Wasmf32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmf32, .wasmf32]).output + public func wasmf32BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) + -> Variable + { + return b.emit( + Wasmf32BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmf32, .wasmf32] + ).output } @discardableResult - public func wasmf64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) -> Variable { - return b.emit(Wasmf64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], types: [.wasmf64, .wasmf64]).output + public func wasmf64BinOp(_ lhs: Variable, _ rhs: Variable, binOpKind: WasmFloatBinaryOpKind) + -> Variable + { + return b.emit( + Wasmf64BinOp(binOpKind: binOpKind), withInputs: [lhs, rhs], + types: [.wasmf64, .wasmf64] + ).output } @discardableResult public func wasmi32UnOp(_ input: Variable, unOpKind: WasmIntegerUnaryOpKind) -> Variable { - return b.emit(Wasmi32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi32]).output + return b.emit(Wasmi32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi32]) + .output } @discardableResult public func wasmi64UnOp(_ input: Variable, unOpKind: WasmIntegerUnaryOpKind) -> Variable { - return b.emit(Wasmi64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi64]).output + return b.emit(Wasmi64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmi64]) + .output } @discardableResult public func wasmf32UnOp(_ input: Variable, unOpKind: WasmFloatUnaryOpKind) -> Variable { - return b.emit(Wasmf32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf32]).output + return b.emit(Wasmf32UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf32]) + .output } @discardableResult public func wasmf64UnOp(_ input: Variable, unOpKind: WasmFloatUnaryOpKind) -> Variable { - return b.emit(Wasmf64UnOp(unOpKind: unOpKind), withInputs: [input],types: [.wasmf64]).output + return b.emit(Wasmf64UnOp(unOpKind: unOpKind), withInputs: [input], types: [.wasmf64]) + .output } @discardableResult @@ -3641,23 +4143,43 @@ public class ProgramBuilder { } @discardableResult - public func wasmi32CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind) -> Variable { - return b.emit(Wasmi32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmi32, .wasmi32]).output + public func wasmi32CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind + ) -> Variable { + return b.emit( + Wasmi32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmi32, .wasmi32] + ).output } @discardableResult - public func wasmi64CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind) -> Variable { - return b.emit(Wasmi64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmi64, .wasmi64]).output + public func wasmi64CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmIntegerCompareOpKind + ) -> Variable { + return b.emit( + Wasmi64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmi64, .wasmi64] + ).output } @discardableResult - public func wasmf64CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind) -> Variable { - return b.emit(Wasmf64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmf64, .wasmf64]).output + public func wasmf64CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind + ) -> Variable { + return b.emit( + Wasmf64CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmf64, .wasmf64] + ).output } @discardableResult - public func wasmf32CompareOp(_ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind) -> Variable { - return b.emit(Wasmf32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], types: [.wasmf32, .wasmf32]).output + public func wasmf32CompareOp( + _ lhs: Variable, _ rhs: Variable, using compareOperator: WasmFloatCompareOpKind + ) -> Variable { + return b.emit( + Wasmf32CompareOp(compareOpKind: compareOperator), withInputs: [lhs, rhs], + types: [.wasmf32, .wasmf32] + ).output } @discardableResult @@ -3667,37 +4189,51 @@ public class ProgramBuilder { @discardableResult public func truncatef32Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncatef32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncatef64Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncatef64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func extendi32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmExtendi32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmExtendi32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func truncatef32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncatef32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncatef64Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncatef64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncatef64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func converti32Tof32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti32Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmConverti32Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func converti64Tof32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti64Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi64]).output + return b.emit( + WasmConverti64Tof32(isSigned: isSigned), withInputs: [input], types: [.wasmi64] + ).output } @discardableResult @@ -3707,12 +4243,16 @@ public class ProgramBuilder { @discardableResult public func converti32Tof64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti32Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi32]).output + return b.emit( + WasmConverti32Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi32] + ).output } @discardableResult public func converti64Tof64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmConverti64Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi64]).output + return b.emit( + WasmConverti64Tof64(isSigned: isSigned), withInputs: [input], types: [.wasmi64] + ).output } @discardableResult @@ -3767,102 +4307,157 @@ public class ProgramBuilder { @discardableResult public func truncateSatf32Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncateSatf32Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncateSatf64Toi32(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncateSatf64Toi32(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func truncateSatf32Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32]).output + return b.emit( + WasmTruncateSatf32Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf32] + ).output } @discardableResult public func truncateSatf64Toi64(_ input: Variable, isSigned: Bool) -> Variable { - return b.emit(WasmTruncateSatf64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64]).output + return b.emit( + WasmTruncateSatf64Toi64(isSigned: isSigned), withInputs: [input], types: [.wasmf64] + ).output } @discardableResult public func wasmLoadGlobal(globalVariable: Variable) -> Variable { let type = b.type(of: globalVariable).wasmGlobalType!.valueType - return b.emit(WasmLoadGlobal(globalType: type), withInputs:[globalVariable], types: [ILType.object(ofGroup: "WasmGlobal")]).output + return b.emit( + WasmLoadGlobal(globalType: type), withInputs: [globalVariable], + types: [ILType.object(ofGroup: "WasmGlobal")] + ).output } public func wasmStoreGlobal(globalVariable: Variable, to value: Variable) { let type = b.type(of: globalVariable).wasmGlobalType!.valueType - let inputTypes = [ILType.object(ofGroup: "WasmGlobal", withWasmType: WasmGlobalType(valueType: type, isMutable: true)), type] - b.emit(WasmStoreGlobal(globalType: type), withInputs: [globalVariable, value], types: inputTypes) + let inputTypes = [ + ILType.object( + ofGroup: "WasmGlobal", + withWasmType: WasmGlobalType(valueType: type, isMutable: true)), type, + ] + b.emit( + WasmStoreGlobal(globalType: type), withInputs: [globalVariable, value], + types: inputTypes) } @discardableResult public func wasmTableGet(tableRef: Variable, idx: Variable) -> Variable { let tableType = b.type(of: tableRef) let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType]).output + return b.emit( + WasmTableGet(), withInputs: [tableRef, idx], types: [tableType, offsetType] + ).output } public func wasmTableSet(tableRef: Variable, idx: Variable, to value: Variable) { let tableType = b.type(of: tableRef) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableSet(), withInputs: [tableRef, idx, value], types: [tableType, offsetType, elementType]) + b.emit( + WasmTableSet(), withInputs: [tableRef, idx, value], + types: [tableType, offsetType, elementType]) } @discardableResult public func wasmTableSize(table: Variable) -> Variable { - return b.emit(WasmTableSize(), withInputs: [table], - types: [.object(ofGroup: "WasmTable")]).output + return b.emit( + WasmTableSize(), withInputs: [table], + types: [.object(ofGroup: "WasmTable")] + ).output } @discardableResult - public func wasmTableGrow(table: Variable, with initialValue: Variable, by delta: Variable) -> Variable { + public func wasmTableGrow(table: Variable, with initialValue: Variable, by delta: Variable) + -> Variable + { let tableType = b.type(of: table) let elementType = tableType.wasmTableType!.elementType let offsetType = tableType.wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmTableGrow(), withInputs: [table, initialValue, delta], - types: [.object(ofGroup: "WasmTable"), elementType, offsetType]).output + return b.emit( + WasmTableGrow(), withInputs: [table, initialValue, delta], + types: [.object(ofGroup: "WasmTable"), elementType, offsetType] + ).output } @discardableResult - public func wasmCallIndirect(signature: WasmSignature, table: Variable, functionArgs: [Variable], tableIndex: Variable) -> [Variable] { + public func wasmCallIndirect( + signature: WasmSignature, table: Variable, functionArgs: [Variable], + tableIndex: Variable + ) -> [Variable] { let isTable64 = b.type(of: table).wasmTableType!.isTable64 - return Array(b.emit(WasmCallIndirect(signature: signature), - withInputs: [table] + functionArgs + [tableIndex], - types: [.wasmTable] + signature.parameterTypes + [isTable64 ? .wasmi64 : .wasmi32] - ).outputs) + return Array( + b.emit( + WasmCallIndirect(signature: signature), + withInputs: [table] + functionArgs + [tableIndex], + types: [.wasmTable] + signature.parameterTypes + [ + isTable64 ? .wasmi64 : .wasmi32 + ] + ).outputs) } @discardableResult - public func wasmCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) -> [Variable] { - return Array(b.emit(WasmCallDirect(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), - withInputs: [function] + functionArgs, - types: [.wasmFunctionDef(signature)] + signature.parameterTypes - ).outputs) - } - - public func wasmReturnCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) { + public func wasmCallDirect( + signature: WasmSignature, function: Variable, functionArgs: [Variable] + ) -> [Variable] { + return Array( + b.emit( + WasmCallDirect( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), + withInputs: [function] + functionArgs, + types: [.wasmFunctionDef(signature)] + signature.parameterTypes + ).outputs) + } + + public func wasmReturnCallDirect( + signature: WasmSignature, function: Variable, functionArgs: [Variable] + ) { assert(self.signature.outputTypes == signature.outputTypes) - b.emit(WasmReturnCallDirect(parameterCount: signature.parameterTypes.count), + b.emit( + WasmReturnCallDirect(parameterCount: signature.parameterTypes.count), withInputs: [function] + functionArgs, types: [.wasmFunctionDef(signature)] + signature.parameterTypes) } - public func wasmReturnCallIndirect(signature: WasmSignature, table: Variable, functionArgs: [Variable], tableIndex: Variable) { + public func wasmReturnCallIndirect( + signature: WasmSignature, table: Variable, functionArgs: [Variable], + tableIndex: Variable + ) { let isTable64 = b.type(of: table).wasmTableType!.isTable64 assert(self.signature.outputTypes == signature.outputTypes) - b.emit(WasmReturnCallIndirect(signature: signature), + b.emit( + WasmReturnCallIndirect(signature: signature), withInputs: [table] + functionArgs + [tableIndex], types: [.wasmTable] + signature.parameterTypes + [isTable64 ? .wasmi64 : .wasmi32]) } @discardableResult - public func wasmJsCall(function: Variable, withArgs args: [Variable], withWasmSignature signature: WasmSignature) -> Variable? { + public func wasmJsCall( + function: Variable, withArgs args: [Variable], + withWasmSignature signature: WasmSignature + ) -> Variable? { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmJsCall(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), withInputs: [signatureDef, function] + args, - types: [.wasmTypeDef(), .function() | .object(ofGroup: "WasmSuspendingObject")] + signature.parameterTypes) + let instr = b.emit( + WasmJsCall( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), + withInputs: [signatureDef, function] + args, + types: [.wasmTypeDef(), .function() | .object(ofGroup: "WasmSuspendingObject")] + + signature.parameterTypes) if signature.outputTypes.isEmpty { assert(!instr.hasOutputs) return nil @@ -3873,78 +4468,132 @@ public class ProgramBuilder { } @discardableResult - public func wasmMemoryLoad(memory: Variable, dynamicOffset: Variable, loadType: WasmMemoryLoadType, staticOffset: Int64) -> Variable { + public func wasmMemoryLoad( + memory: Variable, dynamicOffset: Variable, loadType: WasmMemoryLoadType, + staticOffset: Int64 + ) -> Variable { let addrType = b.type(of: memory).wasmMemoryType!.addrType - return b.emit(WasmMemoryLoad(loadType: loadType, staticOffset: staticOffset), withInputs: [memory, dynamicOffset], types: [.object(ofGroup: "WasmMemory"), addrType]).output + return b.emit( + WasmMemoryLoad(loadType: loadType, staticOffset: staticOffset), + withInputs: [memory, dynamicOffset], + types: [.object(ofGroup: "WasmMemory"), addrType] + ).output } - public func wasmMemoryStore(memory: Variable, dynamicOffset: Variable, value: Variable, storeType: WasmMemoryStoreType, staticOffset: Int64) { + public func wasmMemoryStore( + memory: Variable, dynamicOffset: Variable, value: Variable, + storeType: WasmMemoryStoreType, staticOffset: Int64 + ) { assert(b.type(of: value) == storeType.numberType()) let addrType = b.type(of: memory).wasmMemoryType!.addrType - let inputTypes = [ILType.object(ofGroup: "WasmMemory"), addrType, storeType.numberType()] - b.emit(WasmMemoryStore(storeType: storeType, staticOffset: staticOffset), withInputs: [memory, dynamicOffset, value], types: inputTypes) + let inputTypes = [ + ILType.object(ofGroup: "WasmMemory"), addrType, storeType.numberType(), + ] + b.emit( + WasmMemoryStore(storeType: storeType, staticOffset: staticOffset), + withInputs: [memory, dynamicOffset, value], types: inputTypes) } @discardableResult - func wasmAtomicLoad(memory: Variable, address: Variable, loadType: WasmAtomicLoadType, offset: Int64) -> Variable { + func wasmAtomicLoad( + memory: Variable, address: Variable, loadType: WasmAtomicLoadType, offset: Int64 + ) -> Variable { let op = WasmAtomicLoad(loadType: loadType, offset: offset) return b.emit(op, withInputs: [memory, address]).output } - func wasmAtomicStore(memory: Variable, address: Variable, value: Variable, storeType: WasmAtomicStoreType, offset: Int64) { + func wasmAtomicStore( + memory: Variable, address: Variable, value: Variable, storeType: WasmAtomicStoreType, + offset: Int64 + ) { let op = WasmAtomicStore(storeType: storeType, offset: offset) b.emit(op, withInputs: [memory, address, value]) } @discardableResult - func wasmAtomicRMW(memory: Variable, lhs: Variable, rhs: Variable, op: WasmAtomicRMWType, offset: Int64) -> Variable { + func wasmAtomicRMW( + memory: Variable, lhs: Variable, rhs: Variable, op: WasmAtomicRMWType, offset: Int64 + ) -> Variable { let op = WasmAtomicRMW(op: op, offset: offset) let anyInt: ILType = .wasmi32 | .wasmi64 let valueType = op.op.type() - return b.emit(op, withInputs: [memory, lhs, rhs], types: [.object(ofGroup: "WasmMemory"), anyInt, valueType]).output + return b.emit( + op, withInputs: [memory, lhs, rhs], + types: [.object(ofGroup: "WasmMemory"), anyInt, valueType] + ).output } @discardableResult - func wasmAtomicCmpxchg(memory: Variable, address: Variable, expected: Variable, replacement: Variable, op: WasmAtomicCmpxchgType, offset: Int64) -> Variable { + func wasmAtomicCmpxchg( + memory: Variable, address: Variable, expected: Variable, replacement: Variable, + op: WasmAtomicCmpxchgType, offset: Int64 + ) -> Variable { let op = WasmAtomicCmpxchg(op: op, offset: offset) let anyInt: ILType = .wasmi32 | .wasmi64 let valueType = op.op.type() - return b.emit(op, withInputs: [memory, address, expected, replacement], types: [.object(ofGroup: "WasmMemory"), anyInt, valueType, valueType]).output + return b.emit( + op, withInputs: [memory, address, expected, replacement], + types: [.object(ofGroup: "WasmMemory"), anyInt, valueType, valueType] + ).output } @discardableResult public func wasmMemorySize(memory: Variable) -> Variable { - return b.emit(WasmMemorySize(), withInputs: [memory], - types: [.object(ofGroup: "WasmMemory")]).output + return b.emit( + WasmMemorySize(), withInputs: [memory], + types: [.object(ofGroup: "WasmMemory")] + ).output } @discardableResult public func wasmMemoryGrow(memory: Variable, growByPages: Variable) -> Variable { let addrType = b.type(of: memory).wasmMemoryType!.addrType - return b.emit(WasmMemoryGrow(), withInputs: [memory, growByPages], - types: [.object(ofGroup: "WasmMemory"), addrType]).output + return b.emit( + WasmMemoryGrow(), withInputs: [memory, growByPages], + types: [.object(ofGroup: "WasmMemory"), addrType] + ).output } - public func wasmMemoryCopy(dstMemory: Variable, srcMemory: Variable, dstOffset: Variable, srcOffset: Variable, size: Variable) { + public func wasmMemoryCopy( + dstMemory: Variable, srcMemory: Variable, dstOffset: Variable, srcOffset: Variable, + size: Variable + ) { let dstMemoryType = b.type(of: dstMemory).wasmMemoryType! let srcMemoryType = b.type(of: srcMemory).wasmMemoryType! assert(dstMemoryType.isMemory64 == srcMemoryType.isMemory64) let addrType = dstMemoryType.addrType - b.emit(WasmMemoryCopy(), withInputs: [dstMemory, srcMemory, dstOffset, srcOffset, size], - types: [.object(ofGroup: "WasmMemory"), .object(ofGroup: "WasmMemory"), addrType, addrType, addrType]) + b.emit( + WasmMemoryCopy(), withInputs: [dstMemory, srcMemory, dstOffset, srcOffset, size], + types: [ + .object(ofGroup: "WasmMemory"), .object(ofGroup: "WasmMemory"), addrType, + addrType, addrType, + ]) } - public func wasmMemoryFill(memory: Variable, offset: Variable, byteToSet: Variable, nrOfBytesToUpdate: Variable) { + public func wasmMemoryFill( + memory: Variable, offset: Variable, byteToSet: Variable, nrOfBytesToUpdate: Variable + ) { let addrType = b.type(of: memory).wasmMemoryType!.addrType - b.emit(WasmMemoryFill(), withInputs: [memory, offset, byteToSet, nrOfBytesToUpdate], + b.emit( + WasmMemoryFill(), withInputs: [memory, offset, byteToSet, nrOfBytesToUpdate], types: [.object(ofGroup: "WasmMemory"), addrType, .wasmi32, addrType]) } - public func wasmMemoryInit(dataSegment: Variable, memory: Variable, memoryOffset: Variable, dataSegmentOffset: Variable, nrOfBytesToUpdate: Variable) { + public func wasmMemoryInit( + dataSegment: Variable, memory: Variable, memoryOffset: Variable, + dataSegmentOffset: Variable, nrOfBytesToUpdate: Variable + ) { let addrType = b.type(of: memory).wasmMemoryType!.addrType - b.emit(WasmMemoryInit(), withInputs: [dataSegment, memory, memoryOffset, dataSegmentOffset, nrOfBytesToUpdate], - types: [.wasmDataSegment(), .object(ofGroup: "WasmMemory"), addrType, .wasmi32, .wasmi32]) + b.emit( + WasmMemoryInit(), + withInputs: [ + dataSegment, memory, memoryOffset, dataSegmentOffset, nrOfBytesToUpdate, + ], + types: [ + .wasmDataSegment(), .object(ofGroup: "WasmMemory"), addrType, .wasmi32, + .wasmi32, + ]) } public func wasmDropDataSegment(dataSegment: Variable) { @@ -3952,29 +4601,49 @@ public class ProgramBuilder { } public func wasmDropElementSegment(elementSegment: Variable) { - b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()]) + b.emit( + WasmDropElementSegment(), withInputs: [elementSegment], + types: [.wasmElementSegment()]) } // TODO(pawkra): support shared tables and element segments. - public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) { + public func wasmTableInit( + elementSegment: Variable, table: Variable, tableOffset: Variable, + elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable + ) { let elementSegmentType = ILType.wasmFuncRef() let tableElemType = b.type(of: table).wasmTableType!.elementType assert(elementSegmentType.Is(tableElemType)) - let addrType = b.type(of: table).wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableInit(), withInputs: [elementSegment, table, tableOffset, elementSegmentOffset, nrOfElementsToUpdate], - types: [.wasmElementSegment(), .object(ofGroup: "WasmTable"), addrType, .wasmi32, .wasmi32]) - } - - public func wasmTableCopy(dstTable: Variable, srcTable: Variable, dstOffset: Variable, srcOffset: Variable, count: Variable) { + let addrType = + b.type(of: table).wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32 + b.emit( + WasmTableInit(), + withInputs: [ + elementSegment, table, tableOffset, elementSegmentOffset, nrOfElementsToUpdate, + ], + types: [ + .wasmElementSegment(), .object(ofGroup: "WasmTable"), addrType, .wasmi32, + .wasmi32, + ]) + } + + public func wasmTableCopy( + dstTable: Variable, srcTable: Variable, dstOffset: Variable, srcOffset: Variable, + count: Variable + ) { let dstTableType = b.type(of: dstTable).wasmTableType! let srcTableType = b.type(of: srcTable).wasmTableType! assert(dstTableType.isTable64 == srcTableType.isTable64) assert(srcTableType.elementType.Is(dstTableType.elementType)) let addrType = dstTableType.isTable64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmTableCopy(), withInputs: [dstTable, srcTable, dstOffset, srcOffset, count], - types: [.object(ofGroup: "WasmTable"), .object(ofGroup: "WasmTable"), addrType, addrType, addrType]) + b.emit( + WasmTableCopy(), withInputs: [dstTable, srcTable, dstOffset, srcOffset, count], + types: [ + .object(ofGroup: "WasmTable"), .object(ofGroup: "WasmTable"), addrType, + addrType, addrType, + ]) } public func wasmReassign(variable: Variable, to: Variable) { @@ -3983,7 +4652,9 @@ public class ProgramBuilder { } // The first innerOutput of this block is a label variable, which is just there to explicitly mark control-flow and allow branches. - public func wasmBuildBlock(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> ()) { + public func wasmBuildBlock( + with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void + ) { assert(signature.outputTypes.count == 0) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let instr = b.emit( @@ -3995,36 +4666,46 @@ public class ProgramBuilder { } @discardableResult - public func wasmBuildBlockWithResults(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildBlockWithResults( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let instr = b.emit( WasmBeginBlock(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit( - WasmEndBlock(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + results, - types: [.wasmTypeDef()] + signature.outputTypes - ).outputs) + return Array( + b.emit( + WasmEndBlock(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + results, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } private func checkArgumentsMatchLabelType(label: ILType, args: [Variable]) { let parameterTypes = label.wasmLabelType!.parameters - let errorMsg = "label type \(label) doesn't match argument types \(args.map({b.type(of: $0)}))" + let errorMsg = + "label type \(label) doesn't match argument types \(args.map({b.type(of: $0)}))" assert(parameterTypes.count == args.count, errorMsg) // Each argument type must be a subtype of the corresponding label's parameter type. - assert(zip(parameterTypes, args).allSatisfy {b.type(of: $0.1).Is($0.0)}, errorMsg) + assert(zip(parameterTypes, args).allSatisfy { b.type(of: $0.1).Is($0.0) }, errorMsg) } // This can branch to label variables only, has a variable input for dataflow purposes. public func wasmBranch(to label: Variable, args: [Variable] = []) { let labelType = b.type(of: label) checkArgumentsMatchLabelType(label: labelType, args: args) - b.emit(WasmBranch(parameterCount: labelType.wasmLabelType!.parameters.count), withInputs: [label] + args) + b.emit( + WasmBranch(parameterCount: labelType.wasmLabelType!.parameters.count), + withInputs: [label] + args) } - public func wasmBranchIf(_ condition: Variable, to label: Variable, args: [Variable] = [], hint: WasmBranchHint = .None) { + public func wasmBranchIf( + _ condition: Variable, to label: Variable, args: [Variable] = [], + hint: WasmBranchHint = .None + ) { let labelType = b.type(of: label) checkArgumentsMatchLabelType(label: labelType, args: args) assert(b.type(of: condition).Is(.wasmi32)) @@ -4035,19 +4716,29 @@ public class ProgramBuilder { public func wasmBranchTable(on: Variable, labels: [Variable], args: [Variable]) { labels.forEach { checkArgumentsMatchLabelType(label: b.type(of: $0), args: args) } - b.emit(WasmBranchTable(parameterCount: args.count, valueCount: labels.count - 1), + b.emit( + WasmBranchTable(parameterCount: args.count, valueCount: labels.count - 1), withInputs: labels + args + [on]) } - public func wasmBuildIfElse(_ condition: Variable, signature: WasmSignature = [] => [], args: [Variable] = [], hint: WasmBranchHint = .None, inverted: Bool = false, ifBody: (Variable, [Variable]) -> Void, elseBody: ((Variable, [Variable]) -> Void)? = nil) { + public func wasmBuildIfElse( + _ condition: Variable, signature: WasmSignature = [] => [], args: [Variable] = [], + hint: WasmBranchHint = .None, inverted: Bool = false, + ifBody: (Variable, [Variable]) -> Void, + elseBody: ((Variable, [Variable]) -> Void)? = nil + ) { assert(signature.outputTypes.count == 0) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let beginBlock = b.emit(WasmBeginIf(parameterCount: signature.parameterTypes.count, inverted: inverted), + let beginBlock = b.emit( + WasmBeginIf(parameterCount: signature.parameterTypes.count, inverted: inverted), withInputs: [signatureDef] + args + [condition], types: [.wasmTypeDef()] + signature.parameterTypes + [.wasmi32]) ifBody(beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) if let elseBody { - let elseBlock = b.emit(WasmBeginElse(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), + let elseBlock = b.emit( + WasmBeginElse( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), withInputs: [signatureDef], types: [.wasmTypeDef()]) elseBody(elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) @@ -4058,53 +4749,81 @@ public class ProgramBuilder { // TODO(mliedtke): Instead of taking a WasmSignature also allow taking an existing signature // definition (Variable) as input and add a code generator for it. @discardableResult - public func wasmBuildIfElseWithResult(_ condition: Variable, hint: WasmBranchHint = .None, signature: WasmSignature, args: [Variable], ifBody: (Variable, [Variable]) -> [Variable], elseBody: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildIfElseWithResult( + _ condition: Variable, hint: WasmBranchHint = .None, signature: WasmSignature, + args: [Variable], ifBody: (Variable, [Variable]) -> [Variable], + elseBody: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) let beginBlock = b.emit( WasmBeginIf(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args + [condition], types: [.wasmTypeDef()] + signature.parameterTypes + [.wasmi32]) - let trueResults = ifBody(beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) + let trueResults = ifBody( + beginBlock.innerOutput(0), Array(beginBlock.innerOutputs(1...))) let elseBlock = b.emit( - WasmBeginElse(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), + WasmBeginElse( + parameterCount: signature.parameterTypes.count, + outputCount: signature.outputTypes.count), withInputs: [signatureDef] + trueResults, types: [.wasmTypeDef()] + signature.outputTypes) - let falseResults = elseBody(elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) - return Array(b.emit( - WasmEndIf(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + falseResults, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + let falseResults = elseBody( + elseBlock.innerOutput(0), Array(elseBlock.innerOutputs(1...))) + return Array( + b.emit( + WasmEndIf(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + falseResults, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } @discardableResult - public func wasmBuildLoop(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildLoop( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - return wasmBuildLoopImpl(signature: signature, signatureDef: signatureDef, args: args, body: body) + return wasmBuildLoopImpl( + signature: signature, signatureDef: signatureDef, args: args, body: body) } // TODO(mliedtke): Also use this inside the code generator. @discardableResult - public func wasmBuildLoop(with signatureDef: Variable, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { + public func wasmBuildLoop( + with signatureDef: Variable, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { let signature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature - return wasmBuildLoopImpl(signature: signature, signatureDef: signatureDef, args: args, body: body) + return wasmBuildLoopImpl( + signature: signature, signatureDef: signatureDef, args: args, body: body) } - private func wasmBuildLoopImpl(signature: WasmSignature, signatureDef: Variable, args: [Variable], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - let instr = b.emit(WasmBeginLoop(with: signature), withInputs: [signatureDef] + args, + private func wasmBuildLoopImpl( + signature: WasmSignature, signatureDef: Variable, args: [Variable], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { + let instr = b.emit( + WasmBeginLoop(with: signature), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let fallthroughResults = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndLoop(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + fallthroughResults, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + return Array( + b.emit( + WasmEndLoop(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + fallthroughResults, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } // TODO(pawkra): enable shared types. @discardableResult - func wasmBuildTryTable(with signature: WasmSignature, args: [Variable], catches: [WasmBeginTryTable.CatchKind], body: (Variable, [Variable]) -> [Variable]) -> [Variable] { - assert(zip(signature.parameterTypes, args).allSatisfy {b.type(of: $1).Is($0)}) + func wasmBuildTryTable( + with signature: WasmSignature, args: [Variable], catches: [WasmBeginTryTable.CatchKind], + body: (Variable, [Variable]) -> [Variable] + ) -> [Variable] { + assert(zip(signature.parameterTypes, args).allSatisfy { b.type(of: $1).Is($0) }) #if DEBUG var argIndex = signature.parameterTypes.count - let assertLabelTypeData: (ILType) -> () = { labelType in + let assertLabelTypeData: (ILType) -> Void = { labelType in assert(labelType.Is(.anyLabel)) assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef())) } @@ -4134,16 +4853,20 @@ public class ProgramBuilder { WasmBeginTryTable(parameterCount: signature.parameterTypes.count, catches: catches), withInputs: [signatureDef] + args) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndTryTable(outputCount: signature.outputTypes.count), - withInputs: [signatureDef] + results).outputs) + return Array( + b.emit( + WasmEndTryTable(outputCount: signature.outputTypes.count), + withInputs: [signatureDef] + results + ).outputs) } // Create a legacy try-catch with a void block signature. Mostly a convenience helper for // test cases. public func wasmBuildLegacyTryVoid( - body: (Variable) -> Void, - catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> Void)] = [], - catchAllBody: ((Variable) -> Void)? = nil) { + body: (Variable) -> Void, + catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> Void)] = [], + catchAllBody: ((Variable) -> Void)? = nil + ) { let signature = [] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) @@ -4152,26 +4875,34 @@ public class ProgramBuilder { // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc // signature. let tagSignatures = catchClauses.map { - b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + b.wasmDefineAdHocSignatureType( + signature: b.type(of: $0.tag).wasmTagType!.parameters => []) } - let instr = b.emit(WasmBeginTry( - parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) + let instr = b.emit( + WasmBeginTry( + parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()]) assert(instr.innerOutputs.count == 1) body(instr.innerOutput(0)) for (i, (tag, generator)) in catchClauses.enumerated() { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + b.reportErrorIf( + !b.type(of: tag).isWasmTagType, + "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag))." + ) let tagSignatureDef = tagSignatures[i] - let instr = b.emit(WasmBeginCatch( + let instr = b.emit( + WasmBeginCatch( blockOutputCount: signature.outputTypes.count, - labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), withInputs: [signatureDef, tag, tagSignatureDef], - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) - generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + + signature.outputTypes) + generator( + instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody { - let instr = b.emit(WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef]) + let instr = b.emit( + WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef]) catchAllBody(instr.innerOutput(0)) } b.emit(WasmEndTry(blockOutputCount: 0), withInputs: [signatureDef]) @@ -4182,12 +4913,14 @@ public class ProgramBuilder { // tag arguments. @discardableResult public func wasmBuildLegacyTryWithResult( - signature: WasmSignature, - signatureDef: Variable, - args: [Variable], - body: (Variable, [Variable]) -> [Variable], - catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = [], - catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] { + signature: WasmSignature, + signatureDef: Variable, + args: [Variable], + body: (Variable, [Variable]) -> [Variable], + catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = + [], + catchAllBody: ((Variable) -> [Variable])? = nil + ) -> [Variable] { let parameterCount = signature.parameterTypes.count // Define tag signatures before the try block so they don't interfere with the try/catch @@ -4195,38 +4928,51 @@ public class ProgramBuilder { // TODO(mliedtke): We should reuse the signature of the tag once tags use a wasm-gc // signature. let tagSignatures = catchClauses.map { - b.wasmDefineAdHocSignatureType(signature: b.type(of: $0.tag).wasmTagType!.parameters => []) + b.wasmDefineAdHocSignatureType( + signature: b.type(of: $0.tag).wasmTagType!.parameters => []) } - let instr = b.emit(WasmBeginTry(parameterCount: parameterCount), + let instr = b.emit( + WasmBeginTry(parameterCount: parameterCount), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) var result = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) for (i, (tag, generator)) in catchClauses.enumerated() { - b.reportErrorIf(!b.type(of: tag).isWasmTagType, - "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).") + b.reportErrorIf( + !b.type(of: tag).isWasmTagType, + "Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag))." + ) let tagSignatureDef = tagSignatures[i] - let instr = b.emit(WasmBeginCatch( + let instr = b.emit( + WasmBeginCatch( blockOutputCount: signature.outputTypes.count, - labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), + labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count), withInputs: [signatureDef, tag, tagSignatureDef] + result, - types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + signature.outputTypes) - result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) + types: [.wasmTypeDef(), .object(ofGroup: "WasmTag"), .wasmTypeDef()] + + signature.outputTypes) + result = generator( + instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...))) } if let catchAllBody = catchAllBody { - let instr = b.emit(WasmBeginCatchAll(blockOutputCount: signature.outputTypes.count), + let instr = b.emit( + WasmBeginCatchAll(blockOutputCount: signature.outputTypes.count), withInputs: [signatureDef] + result, types: [.wasmTypeDef()] + signature.outputTypes) result = catchAllBody(instr.innerOutput(0)) } - return Array(b.emit(WasmEndTry(blockOutputCount: signature.outputTypes.count), - withInputs: [signatureDef] + result, - types: [.wasmTypeDef()] + signature.outputTypes).outputs) + return Array( + b.emit( + WasmEndTry(blockOutputCount: signature.outputTypes.count), + withInputs: [signatureDef] + result, + types: [.wasmTypeDef()] + signature.outputTypes + ).outputs) } public func WasmBuildThrow(tag: Variable, inputs: [Variable]) { let tagType = b.type(of: tag).wasmType as! WasmTagType - b.emit(WasmThrow(parameterCount: tagType.parameters.count), withInputs: [tag] + inputs, types: [.object(ofGroup: "WasmTag")] + tagType.parameters) + b.emit( + WasmThrow(parameterCount: tagType.parameters.count), withInputs: [tag] + inputs, + types: [.object(ofGroup: "WasmTag")] + tagType.parameters) } public func wasmBuildThrowRef(exception: Variable) { @@ -4237,10 +4983,14 @@ public class ProgramBuilder { b.emit(WasmRethrow(), withInputs: [exceptionLabel], types: [.exceptionLabel]) } - public func wasmBuildLegacyTryDelegate(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, delegate: Variable) { + public func wasmBuildLegacyTryDelegate( + with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, + delegate: Variable + ) { assert(signature.outputTypes.isEmpty) let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), + let instr = b.emit( + WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) @@ -4248,16 +4998,22 @@ public class ProgramBuilder { } @discardableResult - public func wasmBuildLegacyTryDelegateWithResult(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> [Variable], delegate: Variable) -> [Variable] { + public func wasmBuildLegacyTryDelegateWithResult( + with signature: WasmSignature, args: [Variable], + body: (Variable, [Variable]) -> [Variable], delegate: Variable + ) -> [Variable] { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let instr = b.emit(WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), + let instr = b.emit( + WasmBeginTryDelegate(parameterCount: signature.parameterTypes.count), withInputs: [signatureDef] + args, types: [.wasmTypeDef()] + signature.parameterTypes) let results = body(instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return Array(b.emit(WasmEndTryDelegate(outputCount: signature.outputTypes.count), - withInputs: [signatureDef, delegate] + results, - types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes - ).outputs) + return Array( + b.emit( + WasmEndTryDelegate(outputCount: signature.outputTypes.count), + withInputs: [signatureDef, delegate] + results, + types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes + ).outputs) } public func generateRandomWasmVar(ofType type: ILType) -> Variable? { @@ -4271,7 +5027,8 @@ public class ProgramBuilder { case .wasmf64: return self.constf64(b.randomFloat()) case .wasmSimd128: - return self.constSimd128(value: (0 ..< 16).map{ _ in UInt8.random(in: UInt8.min ... UInt8.max) }) + return self.constSimd128( + value: (0..<16).map { _ in UInt8.random(in: UInt8.min...UInt8.max) }) default: if type.Is(.wasmGenericRef) { // TODO(cffsmith): Can we improve this once we have better support for ad hoc @@ -4285,14 +5042,15 @@ public class ProgramBuilder { } // Prefer generating a non-null value. if heapTypeInfo.heapType == .WasmI31 { - return self.wasmRefI31(self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) + return self.wasmRefI31( + self.consti32(Int32(truncatingIfNeeded: b.randomInt()))) } // TODO(pawkra): support other non-nullable types. - if (type.wasmReferenceType!.nullability) { + if type.wasmReferenceType!.nullability { return self.wasmRefNull(type: type) } case .Index(_): - if (type.wasmReferenceType?.nullability ?? false) { + if type.wasmReferenceType?.nullability ?? false { return self.wasmRefNull(typeDef: b.jsTyper.getWasmTypeDef(for: type)) } case .none: @@ -4315,17 +5073,26 @@ public class ProgramBuilder { } @discardableResult - public func wasmSelect(on condition: Variable, trueValue: Variable, falseValue: Variable) -> Variable { + public func wasmSelect(on condition: Variable, trueValue: Variable, falseValue: Variable) + -> Variable + { let lhsType = b.type(of: trueValue) - return b.emit(WasmSelect(), withInputs: [trueValue, falseValue, condition], types: [lhsType, lhsType, .wasmi32]).output + return b.emit( + WasmSelect(), withInputs: [trueValue, falseValue, condition], + types: [lhsType, lhsType, .wasmi32] + ).output } public func wasmReturn(_ values: [Variable]) { - b.emit(WasmReturn(returnCount: values.count), withInputs: values, types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: values.count), withInputs: values, + types: signature.outputTypes) } public func wasmReturn(_ returnVariable: Variable) { - b.emit(WasmReturn(returnCount: 1), withInputs: [returnVariable], types: signature.outputTypes) + b.emit( + WasmReturn(returnCount: 1), withInputs: [returnVariable], + types: signature.outputTypes) } public func wasmReturn() { @@ -4339,45 +5106,87 @@ public class ProgramBuilder { } @discardableResult - public func wasmSimd128IntegerUnOp(_ input: Variable, _ shape: WasmSimd128Shape, _ integerUnOpKind: WasmSimd128IntegerUnOpKind) -> Variable { - return b.emit(WasmSimd128IntegerUnOp(shape: shape, unOpKind: integerUnOpKind), withInputs: [input], types: [.wasmSimd128]).output + public func wasmSimd128IntegerUnOp( + _ input: Variable, _ shape: WasmSimd128Shape, + _ integerUnOpKind: WasmSimd128IntegerUnOpKind + ) -> Variable { + return b.emit( + WasmSimd128IntegerUnOp(shape: shape, unOpKind: integerUnOpKind), + withInputs: [input], types: [.wasmSimd128] + ).output } @discardableResult - public func wasmSimd128IntegerBinOp(_ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ integerBinOpKind: WasmSimd128IntegerBinOpKind) -> Variable { + public func wasmSimd128IntegerBinOp( + _ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ integerBinOpKind: WasmSimd128IntegerBinOpKind + ) -> Variable { // Shifts take an i32 as an rhs input, the others take a regular .wasmSimd128 input. - let rhsInputType: ILType = switch integerBinOpKind { - case .shl, .shr_s, .shr_u: - .wasmi32 - default: - .wasmSimd128 - } - return b.emit(WasmSimd128IntegerBinOp(shape: shape, binOpKind: integerBinOpKind), withInputs: [left, right], types: [.wasmSimd128, rhsInputType]).output + let rhsInputType: ILType = + switch integerBinOpKind { + case .shl, .shr_s, .shr_u: + .wasmi32 + default: + .wasmSimd128 + } + return b.emit( + WasmSimd128IntegerBinOp(shape: shape, binOpKind: integerBinOpKind), + withInputs: [left, right], types: [.wasmSimd128, rhsInputType] + ).output } @discardableResult - public func wasmSimd128IntegerTernaryOp(_ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ integerTernaryOpKind: WasmSimd128IntegerTernaryOpKind) -> Variable { - return b.emit(WasmSimd128IntegerTernaryOp(shape: shape, ternaryOpKind: integerTernaryOpKind), withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128]).output + public func wasmSimd128IntegerTernaryOp( + _ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ integerTernaryOpKind: WasmSimd128IntegerTernaryOpKind + ) -> Variable { + return b.emit( + WasmSimd128IntegerTernaryOp(shape: shape, ternaryOpKind: integerTernaryOpKind), + withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatUnOp(_ input: Variable, _ shape: WasmSimd128Shape, _ floatUnOpKind: WasmSimd128FloatUnOpKind) -> Variable { - return b.emit(WasmSimd128FloatUnOp(shape: shape, unOpKind: floatUnOpKind), withInputs: [input], types: [.wasmSimd128]).output + public func wasmSimd128FloatUnOp( + _ input: Variable, _ shape: WasmSimd128Shape, _ floatUnOpKind: WasmSimd128FloatUnOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatUnOp(shape: shape, unOpKind: floatUnOpKind), withInputs: [input], + types: [.wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatBinOp(_ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ floatBinOpKind: WasmSimd128FloatBinOpKind) -> Variable { - return b.emit(WasmSimd128FloatBinOp(shape: shape, binOpKind: floatBinOpKind), withInputs: [left, right], types: [.wasmSimd128, .wasmSimd128]).output + public func wasmSimd128FloatBinOp( + _ left: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ floatBinOpKind: WasmSimd128FloatBinOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatBinOp(shape: shape, binOpKind: floatBinOpKind), + withInputs: [left, right], types: [.wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128FloatTernaryOp(_ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, _ floatTernaryOpKind: WasmSimd128FloatTernaryOpKind) -> Variable { - return b.emit(WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: floatTernaryOpKind), withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128]).output + public func wasmSimd128FloatTernaryOp( + _ left: Variable, _ mid: Variable, _ right: Variable, _ shape: WasmSimd128Shape, + _ floatTernaryOpKind: WasmSimd128FloatTernaryOpKind + ) -> Variable { + return b.emit( + WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: floatTernaryOpKind), + withInputs: [left, mid, right], types: [.wasmSimd128, .wasmSimd128, .wasmSimd128] + ).output } @discardableResult - public func wasmSimd128Compare(_ lhs: Variable, _ rhs: Variable, _ shape: WasmSimd128Shape, _ compareOpKind: WasmSimd128CompareOpKind) -> Variable { - return b.emit(WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind), withInputs: [lhs, rhs], types: [.wasmSimd128, .wasmSimd128]).output + public func wasmSimd128Compare( + _ lhs: Variable, _ rhs: Variable, _ shape: WasmSimd128Shape, + _ compareOpKind: WasmSimd128CompareOpKind + ) -> Variable { + return b.emit( + WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind), + withInputs: [lhs, rhs], types: [.wasmSimd128, .wasmSimd128] + ).output } @discardableResult @@ -4386,47 +5195,72 @@ public class ProgramBuilder { } @discardableResult - func wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind, _ input: Variable, _ lane: Int) -> Variable { - return b.emit(WasmSimdExtractLane(kind: kind, lane: lane), withInputs: [input], types: [.wasmSimd128]).output + func wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind, _ input: Variable, _ lane: Int) + -> Variable + { + return b.emit( + WasmSimdExtractLane(kind: kind, lane: lane), withInputs: [input], + types: [.wasmSimd128] + ).output } @discardableResult - func wasmSimdReplaceLane(kind: WasmSimdReplaceLane.Kind, _ input: Variable, _ laneValue: Variable, _ lane: Int) -> Variable { - return b.emit(WasmSimdReplaceLane(kind: kind, lane: lane), - withInputs: [input, laneValue], types: [.wasmSimd128, kind.laneType()]).output - } - - func wasmSimdStoreLane(kind: WasmSimdStoreLane.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64, from: Variable, lane: Int) { + func wasmSimdReplaceLane( + kind: WasmSimdReplaceLane.Kind, _ input: Variable, _ laneValue: Variable, _ lane: Int + ) -> Variable { + return b.emit( + WasmSimdReplaceLane(kind: kind, lane: lane), + withInputs: [input, laneValue], types: [.wasmSimd128, kind.laneType()] + ).output + } + + func wasmSimdStoreLane( + kind: WasmSimdStoreLane.Kind, memory: Variable, dynamicOffset: Variable, + staticOffset: Int64, from: Variable, lane: Int + ) { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - b.emit(WasmSimdStoreLane(kind: kind, staticOffset: staticOffset, lane: lane), + b.emit( + WasmSimdStoreLane(kind: kind, staticOffset: staticOffset, lane: lane), withInputs: [memory, dynamicOffset, from], types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128]) } @discardableResult - func wasmSimdLoadLane(kind: WasmSimdLoadLane.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64, into: Variable, lane: Int) -> Variable { + func wasmSimdLoadLane( + kind: WasmSimdLoadLane.Kind, memory: Variable, dynamicOffset: Variable, + staticOffset: Int64, into: Variable, lane: Int + ) -> Variable { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmSimdLoadLane(kind: kind, staticOffset: staticOffset, lane: lane), + return b.emit( + WasmSimdLoadLane(kind: kind, staticOffset: staticOffset, lane: lane), withInputs: [memory, dynamicOffset, into], - types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128]).output + types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType, .wasmSimd128] + ).output } @discardableResult - func wasmSimdLoad(kind: WasmSimdLoad.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64) -> Variable { + func wasmSimdLoad( + kind: WasmSimdLoad.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64 + ) -> Variable { let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64 let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32 - return b.emit(WasmSimdLoad(kind: kind, staticOffset: staticOffset), + return b.emit( + WasmSimdLoad(kind: kind, staticOffset: staticOffset), withInputs: [memory, dynamicOffset], - types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType]).output + types: [.object(ofGroup: "WasmMemory"), dynamicOffsetType] + ).output } @discardableResult public func wasmArrayNewFixed(arrayType: Variable, elements: [Variable]) -> Variable { let arrayDesc = b.jsTyper.getTypeDescription(of: arrayType) as! WasmArrayTypeDescription - assert(elements.allSatisfy {b.jsTyper.type(of: $0).Is(arrayDesc.elementType.unpacked())}) - return b.emit(WasmArrayNewFixed(size: elements.count), withInputs: [arrayType] + elements).output + assert( + elements.allSatisfy { b.jsTyper.type(of: $0).Is(arrayDesc.elementType.unpacked()) }) + return b.emit( + WasmArrayNewFixed(size: elements.count), withInputs: [arrayType] + elements + ).output } @discardableResult @@ -4440,21 +5274,28 @@ public class ProgramBuilder { } @discardableResult - public func wasmArrayGet(array: Variable, index: Variable, isSigned: Bool = false) -> Variable { - return b.emit(WasmArrayGet(isSigned: isSigned), withInputs: [array, index], - types: [.wasmGenericRef, .wasmi32]).output + public func wasmArrayGet(array: Variable, index: Variable, isSigned: Bool = false) + -> Variable + { + return b.emit( + WasmArrayGet(isSigned: isSigned), withInputs: [array, index], + types: [.wasmGenericRef, .wasmi32] + ).output } public func wasmArraySet(array: Variable, index: Variable, element: Variable) { let arrayDesc = b.jsTyper.getTypeDescription(of: array) as! WasmArrayTypeDescription assert(arrayDesc.mutability) - b.emit(WasmArraySet(), withInputs: [array, index, element], - types: [.wasmGenericRef, .wasmi32, arrayDesc.elementType.unpacked()]) + b.emit( + WasmArraySet(), withInputs: [array, index, element], + types: [.wasmGenericRef, .wasmi32, arrayDesc.elementType.unpacked()]) } @discardableResult public func wasmStructNew(structType: Variable, fields: [Variable]) -> Variable { - return b.emit(WasmStructNew(fieldCount: fields.count), withInputs: [structType] + fields).output + return b.emit( + WasmStructNew(fieldCount: fields.count), withInputs: [structType] + fields + ).output } @discardableResult @@ -4463,12 +5304,17 @@ public class ProgramBuilder { } @discardableResult - public func wasmStructGet(theStruct: Variable, fieldIndex: Int, isSigned: Bool = false) -> Variable { - return b.emit(WasmStructGet(fieldIndex: fieldIndex, isSigned: isSigned), withInputs: [theStruct]).output + public func wasmStructGet(theStruct: Variable, fieldIndex: Int, isSigned: Bool = false) + -> Variable + { + return b.emit( + WasmStructGet(fieldIndex: fieldIndex, isSigned: isSigned), withInputs: [theStruct] + ).output } public func wasmStructSet(theStruct: Variable, fieldIndex: Int, value: Variable) { - let structDesc = b.jsTyper.getTypeDescription(of: theStruct) as! WasmStructTypeDescription + let structDesc = + b.jsTyper.getTypeDescription(of: theStruct) as! WasmStructTypeDescription assert(structDesc.fields[fieldIndex].mutability) b.emit(WasmStructSet(fieldIndex: fieldIndex), withInputs: [theStruct, value]) } @@ -4476,7 +5322,8 @@ public class ProgramBuilder { @discardableResult public func wasmRefNull(type: ILType) -> Variable { assert(type.isWasmReferenceType) - assert(type.wasmReferenceType!.isAbstract(), "index types must use .wasmRefNull(Variable)") + assert( + type.wasmReferenceType!.isAbstract(), "index types must use .wasmRefNull(Variable)") return b.emit(WasmRefNull(type: type)).output } @@ -4493,12 +5340,15 @@ public class ProgramBuilder { @discardableResult // TODO(pawkra): Support shared references. public func wasmRefEq(_ lhs: Variable, _ rhs: Variable) -> Variable { - return b.emit(WasmRefEq(), withInputs: [lhs, rhs], types: [.wasmEqRef(), .wasmEqRef()]).output + return b.emit( + WasmRefEq(), withInputs: [lhs, rhs], types: [.wasmEqRef(), .wasmEqRef()] + ).output } @discardableResult public func wasmRefI31(_ number: Variable, shared: Bool = false) -> Variable { - return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]).output + return b.emit(WasmRefI31(isShared: shared), withInputs: [number], types: [.wasmi32]) + .output } @discardableResult @@ -4517,16 +5367,22 @@ public class ProgramBuilder { } @discardableResult - public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { + public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) + -> Variable + { let inputs = typeDef == nil ? [ref] : [ref, typeDef!] - let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] + let types: [ILType] = + typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] return b.emit(WasmRefTest(refType: refType), withInputs: inputs, types: types).output } @discardableResult - public func wasmRefCast(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable { + public func wasmRefCast(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) + -> Variable + { let inputs = typeDef == nil ? [ref] : [ref, typeDef!] - let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] + let types: [ILType] = + typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()] return b.emit(WasmRefCast(refType: refType), withInputs: inputs, types: types).output } @@ -4577,17 +5433,29 @@ public class ProgramBuilder { // TODO: distinguish between exported and non-exported functions @discardableResult - public func addWasmFunction(with signature: WasmSignature, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + public func addWasmFunction( + with signature: WasmSignature, + _ body: (WasmFunction, Variable, [Variable]) -> [Variable] + ) -> Variable { let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) return addWasmFunction(signature: signatureDef, body) } @discardableResult - public func addWasmFunction(signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable]) -> Variable { + public func addWasmFunction( + signature: Variable, _ body: (WasmFunction, Variable, [Variable]) -> [Variable] + ) -> Variable { let signatureType = b.type(of: signature).wasmFunctionSignatureDefSignature - let instr = b.emit(BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), withInputs: [signature]) - let results = body(currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) - return b.emit(EndWasmFunction(outputCount: signatureType.outputTypes.count), withInputs: [signature] + results, types: [.wasmTypeDef()] + signatureType.outputTypes).output + let instr = b.emit( + BeginWasmFunction(parameterCount: signatureType.parameterTypes.count), + withInputs: [signature]) + let results = body( + currentWasmFunction, instr.innerOutput(0), Array(instr.innerOutputs(1...))) + return b.emit( + EndWasmFunction(outputCount: signatureType.outputTypes.count), + withInputs: [signature] + results, + types: [.wasmTypeDef()] + signatureType.outputTypes + ).output } @discardableResult @@ -4596,34 +5464,54 @@ public class ProgramBuilder { } @discardableResult - public func addTable(elementType: ILType, minSize: Int, maxSize: Int? = nil, definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [], definedEntryValues: [Variable] = [], isTable64: Bool) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: elementType), count: definedEntries.count) - return b.emit(WasmDefineTable(elementType: elementType, limits: Limits(min: minSize, max: maxSize), definedEntries: definedEntries, isTable64: isTable64), - withInputs: definedEntryValues, types: inputTypes).output + public func addTable( + elementType: ILType, minSize: Int, maxSize: Int? = nil, + definedEntries: [WasmTableType.IndexInTableAndWasmSignature] = [], + definedEntryValues: [Variable] = [], isTable64: Bool + ) -> Variable { + let inputTypes = Array( + repeating: getEntryTypeForTable(elementType: elementType), + count: definedEntries.count) + return b.emit( + WasmDefineTable( + elementType: elementType, limits: Limits(min: minSize, max: maxSize), + definedEntries: definedEntries, isTable64: isTable64), + withInputs: definedEntryValues, types: inputTypes + ).output } @discardableResult public func addElementSegment(elements: [Variable]) -> Variable { - let inputTypes = Array(repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef()), count: elements.count) - return b.emit(WasmDefineElementSegment(size: UInt32(elements.count)), withInputs: elements, types: inputTypes).output + let inputTypes = Array( + repeating: getEntryTypeForTable(elementType: ILType.wasmFuncRef()), + count: elements.count) + return b.emit( + WasmDefineElementSegment(size: UInt32(elements.count)), withInputs: elements, + types: inputTypes + ).output } // TODO(pawkra): support tables of shared elements. public func getEntryTypeForTable(elementType: ILType) -> ILType { switch elementType { - case .wasmFuncRef(): - return .wasmFunctionDef() | .function() - default: - return .object() + case .wasmFuncRef(): + return .wasmFunctionDef() | .function() + default: + return .object() } } - // This result can be ignored right now, as we can only define one memory per module // Also this should be tracked like a global / table. @discardableResult - public func addMemory(minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false) -> Variable { - return b.emit(WasmDefineMemory(limits: Limits(min: minPages, max: maxPages), isShared: isShared, isMemory64: isMemory64)).output + public func addMemory( + minPages: Int, maxPages: Int? = nil, isShared: Bool = false, isMemory64: Bool = false + ) -> Variable { + return b.emit( + WasmDefineMemory( + limits: Limits(min: minPages, max: maxPages), isShared: isShared, + isMemory64: isMemory64) + ).output } @discardableResult @@ -4669,7 +5557,9 @@ public class ProgramBuilder { // (dynamicOffset + alignedStaticOffset) % alignment == 0 // // Note: In rare cases, the returned values may lead to an out-of-bounds memory access. - func generateAlignedMemoryIndexes(forMemory memory: Variable, alignment: Int64) -> (address: Variable, offset: Int64) { + func generateAlignedMemoryIndexes(forMemory memory: Variable, alignment: Int64) -> ( + address: Variable, offset: Int64 + ) { assert(alignment > 0, "Alignment must be positive") let memoryTypeInfo = self.type(of: memory).wasmMemoryType! let memSize = Int64(memoryTypeInfo.limits.min * WasmConstants.specWasmMemPageSize) @@ -4683,7 +5573,8 @@ public class ProgramBuilder { // The '+1' allows out-of-bounds access (dynamicOffset + alignedStaticOffset == memSize) let dynamicOffsetValue = self.randomNonNegativeIndex(upTo: memSize - alignment + 1) let dynamicOffset = function.memoryArgument(dynamicOffsetValue, memoryTypeInfo) - let staticOffset = self.randomNonNegativeIndex(upTo: memSize - alignment + 1 - dynamicOffsetValue) + let staticOffset = self.randomNonNegativeIndex( + upTo: memSize - alignment + 1 - dynamicOffsetValue) let currentAddress = dynamicOffsetValue + staticOffset // Calculate the minimal value needed to make the total address aligned. @@ -4692,7 +5583,9 @@ public class ProgramBuilder { return (dynamicOffset, alignedStaticOffset) } - func generateRandomWasmStructFields() -> (fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) { + func generateRandomWasmStructFields() -> ( + fields: [WasmStructTypeDescription.Field], indexTypes: [Variable] + ) { var indexTypes: [Variable] = [] let fields = (0.. WasmSignature { @@ -4769,13 +5670,14 @@ public class ProgramBuilder { chooseUniform( from: chooseBiased(from: [nullTypes, abstractRefTypes, valueTypes], factor: 1.5)) } - let returnTypes: [ILType] = (0.. returnTypes } public func randomWasmGcSignature(withResults: Bool = true, allowNonNullable: Bool = true) - -> (signature: WasmSignature, indexTypes: [Variable]) { + -> (signature: WasmSignature, indexTypes: [Variable]) + { let typeCount = Int.random(in: 0...10) let returnCount = withResults ? Int.random(in: 0...typeCount) : 0 let parameterCount = typeCount - returnCount @@ -4783,19 +5685,24 @@ public class ProgramBuilder { var indexTypes: [Variable] = [] let chooseType = { if let elementType = self.randomVariable(ofType: .wasmTypeDef()), probability(0.25) { - let nullability = !allowNonNullable + let nullability = + !allowNonNullable || self.type(of: elementType).wasmTypeDefinition!.description == .selfReference || probability(0.5) indexTypes.append(elementType) return ILType.wasmRef(.Index(), nullability: nullability) } else { let nullability = !allowNonNullable || probability(0.5) - return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128] - + WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: nullability)}) + return chooseUniform( + from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128] + + WasmAbstractHeapType.allCases.map { + ILType.wasmRef($0, nullability: nullability) + }) } } - let signature = (0.. (0.. (0.. [Variable] { - (0.. WasmBranchHint { @@ -4828,10 +5740,12 @@ public class ProgramBuilder { } else { if shape == .i64x2 { // i64x2 does not provide unsigned comparison. - return .iKind(value: - chooseUniform(from: WasmIntegerCompareOpKind.allCases.filter{ - return $0 != .Lt_u && $0 != .Le_u && $0 != .Gt_u && $0 != .Ge_u - })) + return .iKind( + value: + chooseUniform( + from: WasmIntegerCompareOpKind.allCases.filter { + return $0 != .Lt_u && $0 != .Le_u && $0 != .Gt_u && $0 != .Ge_u + })) } else { return .iKind(value: chooseUniform(from: WasmIntegerCompareOpKind.allCases)) } @@ -4839,7 +5753,7 @@ public class ProgramBuilder { } @discardableResult - public func buildWasmModule(_ body: (WasmModule) -> ()) -> WasmModule { + public func buildWasmModule(_ body: (WasmModule) -> Void) -> WasmModule { emit(BeginWasmModule()) let module = self.currentWasmModule body(module) @@ -4856,7 +5770,7 @@ public class ProgramBuilder { } @discardableResult - public func wasmDefineTypeGroup(recursiveGenerator: () -> ()) -> [Variable] { + public func wasmDefineTypeGroup(recursiveGenerator: () -> Void) -> [Variable] { emit(WasmBeginTypeGroup()) recursiveGenerator() return wasmEndTypeGroup() @@ -4882,33 +5796,48 @@ public class ProgramBuilder { /// This takes a signature with resolved index types for ease-of-use (meaning it accepts full /// index reference types directly inside the signature). @discardableResult - func wasmDefineAdHocSignatureType(signature: WasmSignature, indexTypes: [Variable]? = nil) -> Variable { - let indexTypes = indexTypes ?? (signature.parameterTypes + signature.outputTypes) - .filter {$0.Is(.anyIndexRef)} - .map(getWasmTypeDef) - let cleanIndexTypes = {(type: ILType) -> ILType in + func wasmDefineAdHocSignatureType(signature: WasmSignature, indexTypes: [Variable]? = nil) + -> Variable + { + let indexTypes = + indexTypes + ?? (signature.parameterTypes + signature.outputTypes) + .filter { $0.Is(.anyIndexRef) } + .map(getWasmTypeDef) + let cleanIndexTypes = { (type: ILType) -> ILType in type.Is(.anyIndexRef) ? .wasmRef(.Index(), nullability: type.wasmReferenceType!.nullability) : type } - let signature = signature.parameterTypes.map(cleanIndexTypes) + let signature = + signature.parameterTypes.map(cleanIndexTypes) => signature.outputTypes.map(cleanIndexTypes) if context.contains(.wasmFunction) { - return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes).output + return emit(WasmDefineAdHocSignatureType(signature: signature), withInputs: indexTypes) + .output } else { assert(context.contains(.wasm)) - return emit(WasmDefineAdHocModuleSignatureType(signature: signature), withInputs: indexTypes).output + return emit( + WasmDefineAdHocModuleSignatureType(signature: signature), withInputs: indexTypes + ).output } } @discardableResult - func wasmDefineArrayType(elementType: ILType, mutability: Bool, indexType: Variable? = nil) -> Variable { + func wasmDefineArrayType(elementType: ILType, mutability: Bool, indexType: Variable? = nil) + -> Variable + { let inputs = indexType != nil ? [indexType!] : [] - return emit(WasmDefineArrayType(elementType: elementType, mutability: mutability), withInputs: inputs).output + return emit( + WasmDefineArrayType(elementType: elementType, mutability: mutability), + withInputs: inputs + ).output } @discardableResult - func wasmDefineStructType(fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) -> Variable { + func wasmDefineStructType(fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) + -> Variable + { return emit(WasmDefineStructType(fields: fields), withInputs: indexTypes).output } @@ -4923,20 +5852,25 @@ public class ProgramBuilder { } // Converts an array to a string separating elements by comma. This is used for testing only. func arrayToStringForTesting(_ array: Variable) -> Variable { - let stringified = callMethod("map", on: array, - withArgs: [buildArrowFunction(with: .parameters(n: 1)) { args in - doReturn(callMethod("toString", on: args[0])) - }]) + let stringified = callMethod( + "map", on: array, + withArgs: [ + buildArrowFunction(with: .parameters(n: 1)) { args in + doReturn(callMethod("toString", on: args[0])) + } + ]) return callMethod("join", on: stringified, withArgs: [loadString(",")]) } - func wasmDefineAndResolveForwardReference(recursiveGenerator: () -> ()) { - let previousTypes = Set(scopes.elementsStartingAtTop().joined().filter {type(of: $0).Is(.wasmTypeDef())}) + func wasmDefineAndResolveForwardReference(recursiveGenerator: () -> Void) { + let previousTypes = Set( + scopes.elementsStartingAtTop().joined().filter { type(of: $0).Is(.wasmTypeDef()) }) let ref = wasmDefineForwardOrSelfReference() recursiveGenerator() let newTypes = scopes.elementsStartingAtTop().joined().filter { let t = type(of: $0) - return !previousTypes.contains($0) && t.Is(.wasmTypeDef()) && t.wasmTypeDefinition?.description != .selfReference + return !previousTypes.contains($0) && t.Is(.wasmTypeDef()) + && t.wasmTypeDefinition?.description != .selfReference } if !newTypes.isEmpty { wasmResolveForwardReference(ref, to: chooseUniform(from: newTypes)) @@ -5031,11 +5965,11 @@ public class ProgramBuilder { case .beginObjectLiteralComputedSetter: currentObjectLiteral.computedSetters.append(instr.input(0)) case .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter: + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter: break case .endObjectLiteral: activeObjectLiterals.pop() @@ -5128,21 +6062,22 @@ public class ProgramBuilder { case .endWasmFunction: activeWasmModule!.methods.append("w\(activeWasmModule!.methods.count)") case .wasmDefineGlobal(_), - .wasmDefineTable(_), - .wasmDefineMemory(_), - .wasmDefineDataSegment(_), - .wasmDefineElementSegment(_): + .wasmDefineTable(_), + .wasmDefineMemory(_), + .wasmDefineDataSegment(_), + .wasmDefineElementSegment(_): break case .wasmDefineTag(_): break case .beginWasmFunction(_): - activeWasmModule!.functions.append(WasmFunction(forBuilder: self, signatureDef: instr.input(0))) + activeWasmModule!.functions.append( + WasmFunction(forBuilder: self, signatureDef: instr.input(0))) case .wasmBeginTry(_), - .wasmEndTryDelegate(_), - .wasmBeginTryDelegate(_), - .wasmBeginTryTable(_), - .wasmEndTryTable(_), - .wasmDefineAdHocModuleSignatureType(_): + .wasmEndTryDelegate(_), + .wasmBeginTryDelegate(_), + .wasmBeginTryTable(_), + .wasmEndTryTable(_), + .wasmDefineAdHocModuleSignatureType(_): break default: @@ -5166,29 +6101,39 @@ public class ProgramBuilder { func createOptionsBag(_ bag: OptionsBag, predefined: [String: Variable] = [:]) -> Variable { // We run .filter() to pick a subset of fields, but we generally want to set as many as possible // and let the mutator prune things - let dict = [String : Variable](uniqueKeysWithValues: bag.properties.filter {_ in probability(0.8)}.map { - let (propertyName, type) = $0 - if let predefinedVar = predefined[propertyName] { - return (propertyName, predefinedVar) - } else if type.isEnumeration { - return (propertyName, loadEnum(type)) - // relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it - } else if type.Is(OptionsBag.jsTemporalRelativeTo) { - return (propertyName, findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime, - .jsTemporalPlainDate, .string]))) - } else { - return (propertyName, findOrGenerateType(type)) - } - }) + let dict = [String: Variable]( + uniqueKeysWithValues: bag.properties.filter { _ in probability(0.8) }.map { + let (propertyName, type) = $0 + if let predefinedVar = predefined[propertyName] { + return (propertyName, predefinedVar) + } else if type.isEnumeration { + return (propertyName, loadEnum(type)) + // relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it + } else if type.Is(OptionsBag.jsTemporalRelativeTo) { + return ( + propertyName, + findOrGenerateType( + chooseUniform(from: [ + .jsTemporalZonedDateTime, .jsTemporalPlainDateTime, + .jsTemporalPlainDate, .string, + ])) + ) + } else { + return (propertyName, findOrGenerateType(type)) + } + }) return createObject(with: dict) } // Generate a Temporal.Duration object @discardableResult func createTemporalDurationFieldsObject() -> Variable { - var properties: [String : Variable] = [:] + var properties: [String: Variable] = [:] // Durations are simple, they accept an object with optional integer fields for each duration field. - for field in ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"] { + for field in [ + "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", + "microseconds", "nanoseconds", + ] { if Bool.random() { properties[field] = randomVariable(forUseAs: .number) } @@ -5199,7 +6144,8 @@ public class ProgramBuilder { // Generate a random time zone identifier @discardableResult func randomTimeZone() -> Variable { - return loadString(ProgramBuilder.randomTimeZoneString(), customName: "TemporalTimeZoneString") + return loadString( + ProgramBuilder.randomTimeZoneString(), customName: "TemporalTimeZoneString") } @discardableResult @@ -5214,7 +6160,9 @@ public class ProgramBuilder { @discardableResult func randomUTCOffset(mayHaveSeconds: Bool) -> Variable { - return loadString(ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: mayHaveSeconds), customName: "TemporalTimeZoneString") + return loadString( + ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: mayHaveSeconds), + customName: "TemporalTimeZoneString") } @discardableResult @@ -5223,13 +6171,13 @@ public class ProgramBuilder { // Bias towards zero minutes since that's what most time zones do. let zeroMinutes = probability(0.8) let minutes = zeroMinutes ? 0 : Int.random(in: 0..<60) - let plusminus = Bool.random() ? "+" : "-"; + let plusminus = Bool.random() ? "+" : "-" var offset = String(format: "%@%02d:%02d", plusminus, hours, minutes) if !zeroMinutes && mayHaveSeconds && probability(0.3) { let seconds = Int.random(in: 0..<60) offset = String(format: "%@:%02d", offset, seconds) - if probability(0.3) { - offset = String(format: "%@:.%09d", offset, Int.random(in: 0...999999999)) + if probability(0.3) { + offset = String(format: "%@:.%09d", offset, Int.random(in: 0...999_999_999)) } } return offset @@ -5241,8 +6189,10 @@ public class ProgramBuilder { // with() will error when given a calendar; so we allow control over omitting // a `calendar` field. @discardableResult - func createTemporalFieldsObject(forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool) -> Variable { - var properties: [String : Variable] = [:] + func createTemporalFieldsObject( + forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool + ) -> Variable { + var properties: [String: Variable] = [:] if dateFields { var chosenCalendar: String? = nil @@ -5256,7 +6206,8 @@ public class ProgramBuilder { "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", "islamicc", "iso8601", "japanese", - "persian", "roc"]) + "persian", "roc", + ]) properties["calendar"] = loadString(chosenCalendar!) } @@ -5266,7 +6217,7 @@ public class ProgramBuilder { // If the "year" is set, reduce the chance of emitting an "eraYear" which in most cases // would contradict. - let eraProbability = properties["year"] == nil ? 0.8 : 0.2; + let eraProbability = properties["year"] == nil ? 0.8 : 0.2 if probability(eraProbability) { properties["eraYear"] = randomVariable(forUseAs: .integer) // https://tc39.es/proposal-intl-era-monthcode/#table-eras @@ -5274,7 +6225,8 @@ public class ProgramBuilder { let japaneseEras = ["reiwa", "heisei", "showa", "taisho", "meiji"] let rocEras = ["roc", "broc", "minguo", "before-roc", "minguo-qian"] // If we know the calendar, we should choose from the list of valid eras. - let eras = switch chosenCalendar { + let eras = + switch chosenCalendar { case "buddhist": ["be"] case "coptic": @@ -5294,12 +6246,12 @@ public class ProgramBuilder { case "roc": rocEras default: - ["be", "am", "aa", "mundi", "incar", "shaka", "ah", "bh", "ap"] + gregoryEras + japaneseEras + rocEras - } + ["be", "am", "aa", "mundi", "incar", "shaka", "ah", "bh", "ap"] + + gregoryEras + japaneseEras + rocEras + } properties["era"] = loadString(chooseUniform(from: eras)) } - if probability(0.8) { // Sometimes generates out of range values to test "constrain" // behavior. @@ -5308,7 +6260,7 @@ public class ProgramBuilder { // We don't wish to have clashing month/monthCode // *most* of the time, but we still wish to also test those codepaths. - let monthCodeProbability = properties["month"] == nil ? 0.8 : 0.2; + let monthCodeProbability = properties["month"] == nil ? 0.8 : 0.2 if probability(monthCodeProbability) { // Month codes go from M00 to M13. var code = String(format: "M%02d", Int.random(in: 0...13)) @@ -5359,7 +6311,7 @@ public class ProgramBuilder { // or the time zone first (and it's not a *useful* ambiguity). // Instead, you are expected to use `.with()` and `.withTimeZone()` // in whatever order you need. - if (!forWith) { + if !forWith { if Bool.random() { // Time zones can be offsets, but cannot have seconds generatedOffset = randomUTCOffset(mayHaveSeconds: false) @@ -5414,20 +6366,22 @@ public class ProgramBuilder { // Whether to pass a Temporal-like object or a string if Bool.random() { let fields = createTemporalDurationFieldsObject() - return callMethod("", on: constructor, withArgs: [ fields ] ) + return callMethod("", on: constructor, withArgs: [fields]) } else { // TODO(manishearth, 439921647) Generate Temporal-like strings let string = randomVariable(forUseAs: .string) return callMethod("from", on: constructor, withArgs: [string]) - } - } + } + } } // Generic generators for Temporal date/time types. // Pass in a closure that knows how to construct the type with `new()`. - private func constructTemporalType(type: String, - dateFields: Bool, timeFields: Bool, zonedFields: Bool, optionsBag: OptionsBag, - generateWithConstructor: (Variable) -> Variable) -> Variable { + private func constructTemporalType( + type: String, + dateFields: Bool, timeFields: Bool, zonedFields: Bool, optionsBag: OptionsBag, + generateWithConstructor: (Variable) -> Variable + ) -> Variable { let temporal = createNamedVariable(forBuiltin: "Temporal") let useConstructor = Bool.random() let constructor = getProperty(type, of: temporal) @@ -5436,12 +6390,14 @@ public class ProgramBuilder { } else { // Whether to pass a Temporal-like object or a string if Bool.random() { - let fields = createTemporalFieldsObject(forWith: false, dateFields: dateFields, timeFields: timeFields, zonedFields: zonedFields) + let fields = createTemporalFieldsObject( + forWith: false, dateFields: dateFields, timeFields: timeFields, + zonedFields: zonedFields) var args = [fields] if Bool.random() { args.append(createOptionsBag(optionsBag)) } - return callMethod("from", on: constructor, withArgs: args ) + return callMethod("from", on: constructor, withArgs: args) } else { // TODO(manishearth, 439921647) Generate Temporal-like strings let string = randomVariable(forUseAs: .string) @@ -5452,7 +6408,10 @@ public class ProgramBuilder { @discardableResult func constructTemporalTime() -> Variable { - return constructTemporalType(type: "PlainTime", dateFields: false, timeFields: true, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainTime", dateFields: false, timeFields: true, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes between 0 and 6 integer args. let numArgs = Int.random(in: 0...6) // Should we be constraining these to valid range? @@ -5463,9 +6422,12 @@ public class ProgramBuilder { @discardableResult func constructTemporalYearMonth() -> Variable { - return constructTemporalType(type: "PlainYearMonth", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainYearMonth", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args, an optional calendar, and an optional reference day. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) if Bool.random() { @@ -5477,9 +6439,12 @@ public class ProgramBuilder { } @discardableResult func constructTemporalMonthDay() -> Variable { - return constructTemporalType(type: "PlainMonthDay", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainMonthDay", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args, an optional calendar, and an optional reference day. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) if Bool.random() { @@ -5492,9 +6457,12 @@ public class ProgramBuilder { @discardableResult func constructTemporalDate() -> Variable { - return constructTemporalType(type: "PlainDate", dateFields: true, timeFields: false, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainDate", dateFields: true, timeFields: false, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 int args and an optional calendar. - var args = (0..<3).map {_ in randomVariable(forUseAs: .integer) } + var args = (0..<3).map { _ in randomVariable(forUseAs: .integer) } if Bool.random() { args.append(randomVariable(forUseAs: .jsTemporalCalendarEnum)) } @@ -5503,7 +6471,10 @@ public class ProgramBuilder { } @discardableResult func constructTemporalDateTime() -> Variable { - return constructTemporalType(type: "PlainDateTime", dateFields: true, timeFields: true, zonedFields: false, optionsBag: .jsTemporalOverflowSettings) { constructor in + return constructTemporalType( + type: "PlainDateTime", dateFields: true, timeFields: true, zonedFields: false, + optionsBag: .jsTemporalOverflowSettings + ) { constructor in // The constructor takes 3 mandatory integer args and between 0 and 6 additional integer args. let timeArgs = Int.random(in: 0...6) let totalIntArgs = 3 + timeArgs @@ -5517,7 +6488,10 @@ public class ProgramBuilder { @discardableResult func constructTemporalZonedDateTime() -> Variable { - return constructTemporalType(type: "ZonedDateTime", dateFields: true, timeFields: true, zonedFields: true, optionsBag: .jsTemporalZonedInterpretationSettings) { constructor in + return constructTemporalType( + type: "ZonedDateTime", dateFields: true, timeFields: true, zonedFields: true, + optionsBag: .jsTemporalZonedInterpretationSettings + ) { constructor in // The constructor takes one integer arg, one timezone arg, one optional calendar arg. // TODO(manishearth, 439921647) Generate timezone strings var args = [randomVariable(forUseAs: .bigint), randomVariable(forUseAs: .string)] @@ -5534,7 +6508,6 @@ public class ProgramBuilder { return constructIntlLanguageString() } - @discardableResult static func constructIntlLanguageString() -> String { // TODO(Manishearth) Generate more interesting locales than just the builtins @@ -5542,10 +6515,39 @@ public class ProgramBuilder { } // Obtained by calling Intl.supportedValuesOf("unit") in a browser - fileprivate static let allUnits = ["acre", "bit", "byte", "celsius", "centimeter", "day", "degree", "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram", "kilometer", "liter", "megabit", "megabyte", "meter", "microsecond", "mile", "mile-scandinavian", "milliliter", "millimeter", "millisecond", "minute", "month", "nanosecond", "ounce", "percent", "petabyte", "pound", "second", "stone", "terabit", "terabyte", "week", "yard", "year"] + fileprivate static let allUnits = [ + "acre", "bit", "byte", "celsius", "centimeter", "day", "degree", "fahrenheit", + "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", "gram", "hectare", "hour", "inch", + "kilobit", "kilobyte", "kilogram", "kilometer", "liter", "megabit", "megabyte", "meter", + "microsecond", "mile", "mile-scandinavian", "milliliter", "millimeter", "millisecond", + "minute", "month", "nanosecond", "ounce", "percent", "petabyte", "pound", "second", "stone", + "terabit", "terabyte", "week", "yard", "year", + ] // https://en.wikipedia.org/wiki/ISO_15924#List_of_codes // Unfortunately this list grows over time, but constructIntlScript can at least randomly generate other four-char script codes - fileprivate static let allScripts = ["Adlm", "Afak", "Aghb", "Ahom", "Arab", "Aran", "Armi", "Armn", "Avst", "Bali", "Bamu", "Bass", "Batk", "Beng", "Berf", "Bhks", "Blis", "Bopo", "Brah", "Brai", "Bugi", "Buhd", "Cakm", "Cans", "Cari", "Cham", "Cher", "Chis", "Chrs", "Cirt", "Copt", "Cpmn", "Cprt", "Cyrl", "Cyrs", "Deva", "Diak", "Dogr", "Dsrt", "Dupl", "Egyd", "Egyh", "Egyp", "Elba", "Elym", "Ethi", "Gara", "Geok", "Geor", "Glag", "Gong", "Gonm", "Goth", "Gran", "Grek", "Gujr", "Gukh", "Guru", "Hanb", "Hang", "Hani", "Hano", "Hans", "Hant", "Hatr", "Hebr", "Hira", "Hluw", "Hmng", "Hmnp", "Hntl", "Hrkt", "Hung", "Inds", "Ital", "Jamo", "Java", "Jpan", "Jurc", "Kali", "Kana", "Kawi", "Khar", "Khmr", "Khoj", "Kitl", "Kits", "Knda", "Kore", "Kpel", "Krai", "Kthi", "Lana", "Laoo", "Latf", "Latg", "Latn", "Leke", "Lepc", "Limb", "Lina", "Linb", "Lisu", "Loma", "Lyci", "Lydi", "Mahj", "Maka", "Mand", "Mani", "Marc", "Maya", "Medf", "Mend", "Merc", "Mero", "Mlym", "Modi", "Mong", "Moon", "Mroo", "Mtei", "Mult", "Mymr", "Nagm", "Nand", "Narb", "Nbat", "Newa", "Nkdb", "Nkgb", "Nkoo", "Nshu", "Ogam", "Olck", "Onao", "Orkh", "Orya", "Osge", "Osma", "Ougr", "Palm", "Pauc", "Pcun", "Pelm", "Perm", "Phag", "Phli", "Phlp", "Phlv", "Phnx", "Piqd", "Plrd", "Prti", "Psin", "Qaaa-Qabx", "Ranj", "Rjng", "Rohg", "Roro", "Runr", "Samr", "Sara", "Sarb", "Saur", "Seal", "Sgnw", "Shaw", "Shrd", "Shui", "Sidd", "Sidt", "Sind", "Sinh", "Sogd", "Sogo", "Sora", "Soyo", "Sund", "Sunu", "Sylo", "Syrc", "Syre", "Syrj", "Syrn", "Tagb", "Takr", "Tale", "Talu", "Taml", "Tang", "Tavt", "Tayo", "Telu", "Teng", "Tfng", "Tglg", "Thaa", "Thai", "Tibt", "Tirh", "Tnsa", "Todr", "Tols", "Toto", "Tutg", "Ugar", "Vaii", "Visp", "Vith", "Wara", "Wcho", "Wole", "Xpeo", "Xsux", "Yezi", "Yiii", "Zanb", "Zinh", "Zmth", "Zsye", "Zsym", "Zxxx", "Zyyy", "Zzzz"] + fileprivate static let allScripts = [ + "Adlm", "Afak", "Aghb", "Ahom", "Arab", "Aran", "Armi", "Armn", "Avst", "Bali", "Bamu", + "Bass", "Batk", "Beng", "Berf", "Bhks", "Blis", "Bopo", "Brah", "Brai", "Bugi", "Buhd", + "Cakm", "Cans", "Cari", "Cham", "Cher", "Chis", "Chrs", "Cirt", "Copt", "Cpmn", "Cprt", + "Cyrl", "Cyrs", "Deva", "Diak", "Dogr", "Dsrt", "Dupl", "Egyd", "Egyh", "Egyp", "Elba", + "Elym", "Ethi", "Gara", "Geok", "Geor", "Glag", "Gong", "Gonm", "Goth", "Gran", "Grek", + "Gujr", "Gukh", "Guru", "Hanb", "Hang", "Hani", "Hano", "Hans", "Hant", "Hatr", "Hebr", + "Hira", "Hluw", "Hmng", "Hmnp", "Hntl", "Hrkt", "Hung", "Inds", "Ital", "Jamo", "Java", + "Jpan", "Jurc", "Kali", "Kana", "Kawi", "Khar", "Khmr", "Khoj", "Kitl", "Kits", "Knda", + "Kore", "Kpel", "Krai", "Kthi", "Lana", "Laoo", "Latf", "Latg", "Latn", "Leke", "Lepc", + "Limb", "Lina", "Linb", "Lisu", "Loma", "Lyci", "Lydi", "Mahj", "Maka", "Mand", "Mani", + "Marc", "Maya", "Medf", "Mend", "Merc", "Mero", "Mlym", "Modi", "Mong", "Moon", "Mroo", + "Mtei", "Mult", "Mymr", "Nagm", "Nand", "Narb", "Nbat", "Newa", "Nkdb", "Nkgb", "Nkoo", + "Nshu", "Ogam", "Olck", "Onao", "Orkh", "Orya", "Osge", "Osma", "Ougr", "Palm", "Pauc", + "Pcun", "Pelm", "Perm", "Phag", "Phli", "Phlp", "Phlv", "Phnx", "Piqd", "Plrd", "Prti", + "Psin", "Qaaa-Qabx", "Ranj", "Rjng", "Rohg", "Roro", "Runr", "Samr", "Sara", "Sarb", "Saur", + "Seal", "Sgnw", "Shaw", "Shrd", "Shui", "Sidd", "Sidt", "Sind", "Sinh", "Sogd", "Sogo", + "Sora", "Soyo", "Sund", "Sunu", "Sylo", "Syrc", "Syre", "Syrj", "Syrn", "Tagb", "Takr", + "Tale", "Talu", "Taml", "Tang", "Tavt", "Tayo", "Telu", "Teng", "Tfng", "Tglg", "Thaa", + "Thai", "Tibt", "Tirh", "Tnsa", "Todr", "Tols", "Toto", "Tutg", "Ugar", "Vaii", "Visp", + "Vith", "Wara", "Wcho", "Wole", "Xpeo", "Xsux", "Yezi", "Yiii", "Zanb", "Zinh", "Zmth", + "Zsye", "Zsym", "Zxxx", "Zyyy", "Zzzz", + ] fileprivate static let allAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" fileprivate static let allAlphaNum = allAlpha + "0123456789" fileprivate static let allRegionsTwoDigit = [ @@ -5583,7 +6585,6 @@ public class ProgramBuilder { } } - @discardableResult static func constructIntlScriptString() -> String { if probability(0.7) { @@ -5624,7 +6625,7 @@ public class ProgramBuilder { } } - @discardableResult + @discardableResult func constructIntlLocale() -> Variable { let intl = createNamedVariable(forBuiltin: "Intl") let constructor = getProperty("Locale", of: intl) @@ -5685,7 +6686,8 @@ public class ProgramBuilder { @discardableResult func constructIntlRelativeTimeFormat() -> Variable { - return constructIntlType(type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) + return constructIntlType( + type: "RelativeTimeFormat", optionsBag: .jsIntlRelativeTimeFormatSettings) } @discardableResult @@ -5703,10 +6705,12 @@ public class ProgramBuilder { let types = fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues let type = types.randomElement()! let locale = loadString(ProgramBuilder.constructIntlLocaleString()) - let options = createOptionsBag(.jsIntlDisplayNamesSettings, + let options = createOptionsBag( + .jsIntlDisplayNamesSettings, predefined: ["type": loadString(type)]) construct(ctor, withArgs: [locale, options]) - let code = switch type { + let code = + switch type { case "language": ProgramBuilder.constructIntlLanguageString() case "region": @@ -5718,11 +6722,13 @@ public class ProgramBuilder { case "calendar": fuzzer.environment.getEnum(ofName: "temporalCalendar")!.enumValues.randomElement()! case "dateTimeField": - ["era", "year", "quarter", "month", "weekOfYear", "weekday", "day", - "dayPeriod", "hour", "minute", "second", "timeZoneName"].randomElement()! + [ + "era", "year", "quarter", "month", "weekOfYear", "weekday", "day", + "dayPeriod", "hour", "minute", "second", "timeZoneName", + ].randomElement()! default: String.random(ofLength: 4) - } + } return callMethod("of", on: ctor, withArgs: [loadString(code)]) } } diff --git a/Sources/Fuzzilli/Base/Timers.swift b/Sources/Fuzzilli/Base/Timers.swift index f1d3ed899..eda2a07f0 100644 --- a/Sources/Fuzzilli/Base/Timers.swift +++ b/Sources/Fuzzilli/Base/Timers.swift @@ -16,7 +16,7 @@ import Foundation let Seconds = 1.0 let Minutes = 60.0 * Seconds -let Hours = 60.0 * Minutes +let Hours = 60.0 * Minutes /// API to schedule tasks to run after a specified interval and possibly repeatedly on the DispatchQueue of the associated fuzzer instance. public class Timers { @@ -47,7 +47,9 @@ public class Timers { /// - interval: The interval (in seconds) between two executions of the task. /// - repetitions: The total number of executions of the task. /// - task: The task to execute. - public func scheduleTask(every interval: TimeInterval, repeat repetitions: Int, _ task: @escaping () -> Void) { + public func scheduleTask( + every interval: TimeInterval, repeat repetitions: Int, _ task: @escaping () -> Void + ) { guard repetitions > 0 else { return } diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift index 61d9e181e..e4d7dfc7f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerator.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerator.swift @@ -17,8 +17,8 @@ protocol GeneratorAdapter { func run(in b: ProgramBuilder, with inputs: [Variable]) } -public typealias GeneratorFuncNoArgs = (ProgramBuilder) -> () -fileprivate struct GeneratorAdapterNoArgs: GeneratorAdapter { +public typealias GeneratorFuncNoArgs = (ProgramBuilder) -> Void +private struct GeneratorAdapterNoArgs: GeneratorAdapter { let expectedNumberOfInputs = 0 let f: GeneratorFuncNoArgs func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -27,8 +27,8 @@ fileprivate struct GeneratorAdapterNoArgs: GeneratorAdapter { } } -public typealias GeneratorFunc1Arg = (ProgramBuilder, Variable) -> () -fileprivate struct GeneratorAdapter1Arg: GeneratorAdapter { +public typealias GeneratorFunc1Arg = (ProgramBuilder, Variable) -> Void +private struct GeneratorAdapter1Arg: GeneratorAdapter { let expectedNumberOfInputs = 1 let f: GeneratorFunc1Arg func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -37,8 +37,8 @@ fileprivate struct GeneratorAdapter1Arg: GeneratorAdapter { } } -public typealias GeneratorFunc2Args = (ProgramBuilder, Variable, Variable) -> () -fileprivate struct GeneratorAdapter2Args: GeneratorAdapter { +public typealias GeneratorFunc2Args = (ProgramBuilder, Variable, Variable) -> Void +private struct GeneratorAdapter2Args: GeneratorAdapter { let expectedNumberOfInputs = 2 let f: GeneratorFunc2Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -47,8 +47,8 @@ fileprivate struct GeneratorAdapter2Args: GeneratorAdapter { } } -public typealias GeneratorFunc3Args = (ProgramBuilder, Variable, Variable, Variable) -> () -fileprivate struct GeneratorAdapter3Args: GeneratorAdapter { +public typealias GeneratorFunc3Args = (ProgramBuilder, Variable, Variable, Variable) -> Void +private struct GeneratorAdapter3Args: GeneratorAdapter { let expectedNumberOfInputs = 3 let f: GeneratorFunc3Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -57,8 +57,9 @@ fileprivate struct GeneratorAdapter3Args: GeneratorAdapter { } } -public typealias GeneratorFunc4Args = (ProgramBuilder, Variable, Variable, Variable, Variable) -> () -fileprivate struct GeneratorAdapter4Args: GeneratorAdapter { +public typealias GeneratorFunc4Args = (ProgramBuilder, Variable, Variable, Variable, Variable) -> + Void +private struct GeneratorAdapter4Args: GeneratorAdapter { let expectedNumberOfInputs = 4 let f: GeneratorFunc4Args func run(in b: ProgramBuilder, with inputs: [Variable]) { @@ -82,10 +83,10 @@ public class GeneratorStub: Contributor { case None case IsWasmArray case IsWasmStruct - case IsWasmFunction // On a type definition this means "signature". + case IsWasmFunction // On a type definition this means "signature". } - public struct Constraint : Hashable { + public struct Constraint: Hashable { let type: ILType let additional: AdditionalConstraints @@ -99,32 +100,32 @@ public class GeneratorStub: Contributor { return false } return switch additional { - case .None: - true - case .IsWasmArray: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmArrayTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmArrayRef()) - } else { - false - } - case .IsWasmStruct: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmStructTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmStructRef()) - } else { - false - } - case .IsWasmFunction: - if type.Is(.wasmTypeDef()) { - type.wasmTypeDefinition?.description is WasmSignatureTypeDescription - } else if type.Is(.anyNonNullableIndexRef) { - type.Is(.wasmFuncRef()) - } else { - false - } + case .None: + true + case .IsWasmArray: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmArrayTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmArrayRef()) + } else { + false + } + case .IsWasmStruct: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmStructTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmStructRef()) + } else { + false + } + case .IsWasmFunction: + if type.Is(.wasmTypeDef()) { + type.wasmTypeDefinition?.description is WasmSignatureTypeDescription + } else if type.Is(.anyNonNullableIndexRef) { + type.Is(.wasmFuncRef()) + } else { + false + } } } @@ -195,20 +196,19 @@ public class GeneratorStub: Contributor { return Inputs(constraints: [jsAny, jsAny, jsAny, jsAny], mode: .loose) } - // A number of inputs that should have the specified type, but may also be of a wider, or even different, type. // This should usually be used instead of .required since it will ensure that also variables of unknown type can // be used as inputs during code generation. public static func preferred(_ types: ILType...) -> Inputs { assert(!types.isEmpty) - return Inputs(constraints: types.map {Constraint($0)}, mode: .loose) + return Inputs(constraints: types.map { Constraint($0) }, mode: .loose) } // A number of inputs that must have the specified type. // Only use this if the code generator cannot do anything meaningful if it receives a value of the wrong type. public static func required(_ types: ILType...) -> Inputs { assert(!types.isEmpty) - return Inputs(constraints: types.map {Constraint($0)}, mode: .strict) + return Inputs(constraints: types.map { Constraint($0) }, mode: .strict) } public static func requiredComplex(_ constraints: Constraint...) -> Inputs { @@ -231,7 +231,7 @@ public class GeneratorStub: Contributor { // E.g. .either([.javascript, .classDefinition]) which is basically either one of .javascript or .classDefinition case either([Context]) - var isSingle : Bool { + var isSingle: Bool { self.getSingle() != nil } @@ -241,25 +241,27 @@ public class GeneratorStub: Contributor { func getSingle() -> Context? { switch self { - case .single(let ctx): - return ctx - default: - return nil + case .single(let ctx): + return ctx + default: + return nil } } // Whether the ContextRequirement is satisified for the given (current) context. func satisfied(by context: Context) -> Bool { switch self { - case .single(let ctx): - return ctx.isSubset(of: context) - case .either(let ctxs): - // We do this check here since we cannot check on construction whether we have used .either correctly. - assert(ctxs.count > 1, "Something seems wrong, one should have more than a single context here") - // Any of the Contexts needs to be satisfied. - return ctxs.contains(where: { ctx in - ctx.isSubset(of: context) - }) + case .single(let ctx): + return ctx.isSubset(of: context) + case .either(let ctxs): + // We do this check here since we cannot check on construction whether we have used .either correctly. + assert( + ctxs.count > 1, + "Something seems wrong, one should have more than a single context here") + // Any of the Contexts needs to be satisfied. + return ctxs.contains(where: { ctx in + ctx.isSubset(of: context) + }) } } @@ -268,15 +270,17 @@ public class GeneratorStub: Contributor { // This is used in consistency checking in `ContextGraph` initialization where a previous generator might open multiple contexts. func matches(_ context: Context) -> Bool { switch self { - case .single(let ctx): - return ctx == context - case .either(let ctxs): - // We do this check here since we cannot check on construction whether we have used .either correctly. - assert(ctxs.count > 1, "Something seems wrong, one should have more than a single context here") - // All contexts need to be in the current context. - return ctxs.allSatisfy { ctx in - ctx.isSubset(of: context) - } + case .single(let ctx): + return ctx == context + case .either(let ctxs): + // We do this check here since we cannot check on construction whether we have used .either correctly. + assert( + ctxs.count > 1, + "Something seems wrong, one should have more than a single context here") + // All contexts need to be in the current context. + return ctxs.allSatisfy { ctx in + ctx.isSubset(of: context) + } } } } @@ -295,7 +299,10 @@ public class GeneratorStub: Contributor { /// Wrapper around the actual generator function called. private let adapter: GeneratorAdapter - fileprivate init(name: String, inputs: Inputs, produces: [Constraint] = [], context: ContextRequirement, providedContext: [Context] = [], adapter: GeneratorAdapter) { + fileprivate init( + name: String, inputs: Inputs, produces: [Constraint] = [], context: ContextRequirement, + providedContext: [Context] = [], adapter: GeneratorAdapter + ) { self.inputs = inputs self.produces = produces @@ -307,8 +314,13 @@ public class GeneratorStub: Contributor { assert(inputs.count == adapter.expectedNumberOfInputs) } - fileprivate convenience init(name: String, inputs: Inputs, produces: [ILType] = [], context: ContextRequirement, providedContext: [Context] = [], adapter: GeneratorAdapter) { - self.init(name: name, inputs: inputs, produces: produces.map {Constraint($0)}, context: context, providedContext: providedContext, adapter: adapter) + fileprivate convenience init( + name: String, inputs: Inputs, produces: [ILType] = [], context: ContextRequirement, + providedContext: [Context] = [], adapter: GeneratorAdapter + ) { + self.init( + name: name, inputs: inputs, produces: produces.map { Constraint($0) }, context: context, + providedContext: providedContext, adapter: adapter) } /// Execute this code generator, generating new code at the current position in the ProgramBuilder. @@ -323,32 +335,66 @@ public class GeneratorStub: Contributor { return addedInstructions } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name: name, inputs: .none, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), producesComplex: [Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + producesComplex: [Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name: name, inputs: .none, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc2Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc2Args + ) { assert(inputs.count == 2) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc3Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc3Args + ) { assert(inputs.count == 3) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) } - public convenience init(_ name: String, inContext context: ContextRequirement = .single(.javascript), inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc4Args) { + public convenience init( + _ name: String, inContext context: ContextRequirement = .single(.javascript), + inputs: Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc4Args + ) { assert(inputs.count == 4) - self.init(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) + self.init( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) } } @@ -359,7 +405,6 @@ public class CodeGenerator { // Here, I think we might have different Contexts that each yield point could provide, e.g. [.javascript | .subroutine, .wasmFunction]. Unsure if there is a situation where this matters? instead of having .javascript | .subroutine | .wasmFunction? public let providedContexts: [Context] - public init(_ name: String, _ generators: [GeneratorStub]) { self.parts = generators self.name = name @@ -378,7 +423,7 @@ public class CodeGenerator { // This essentially means that all stubs have no requirements. // Usually there is only a single element in the CodeGenerator if it is a ValueGenerator. public var isValueGenerator: Bool { - return self.parts.allSatisfy {$0.isValueStub} + return self.parts.allSatisfy { $0.isValueStub } } // This is the context required by the first part of the CodeGenerator. @@ -405,7 +450,7 @@ public class CodeGenerator { return self.parts[1...] } - public var expandedName : String { + public var expandedName: String { if self.name == "Synthetic" { return "Synthetic(\(self.parts.map{$0.name}.joined(separator: ",")))" } else { @@ -413,37 +458,106 @@ public class CodeGenerator { } } - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name, [GeneratorStub(name: name, inputs: .none, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs) { - self.init(name, [GeneratorStub(name: name, inputs: .none, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: .none, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], + _ f: @escaping GeneratorFuncNoArgs + ) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: .none, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapterNoArgs(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, producesComplex: [GeneratorStub.Constraint], provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, producesComplex: [GeneratorStub.Constraint], + provides: [Context] = [], _ f: @escaping GeneratorFunc1Arg + ) { assert(inputs.count == 1) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: producesComplex, context: context, providedContext: provides, adapter: GeneratorAdapter1Arg(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc2Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: producesComplex, context: context, + providedContext: provides, adapter: GeneratorAdapter1Arg(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc2Args + ) { assert(inputs.count == 2) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter2Args(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc3Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter2Args(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc3Args + ) { assert(inputs.count == 3) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter3Args(f: f))]) - } - - public convenience init(_ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], _ f: @escaping GeneratorFunc4Args) { + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter3Args(f: f)) + ]) + } + + public convenience init( + _ name: String, inContext context: GeneratorStub.ContextRequirement = .single(.javascript), + inputs: GeneratorStub.Inputs, produces: [ILType] = [], provides: [Context] = [], + _ f: @escaping GeneratorFunc4Args + ) { assert(inputs.count == 4) - self.init(name, [GeneratorStub(name: name, inputs: inputs, produces: produces, context: context, providedContext: provides, adapter: GeneratorAdapter4Args(f: f))]) + self.init( + name, + [ + GeneratorStub( + name: name, inputs: inputs, produces: produces, context: context, + providedContext: provides, adapter: GeneratorAdapter4Args(f: f)) + ]) } } diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index d8f8890fd..f759f51ff 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -16,9 +16,10 @@ import Foundation // Generator stubs for disposable and async-disposable object variables. func disposableObjVariableGeneratorStubs( - inContext contextRequirement : Context, - withSymbol symbolProperty : String, - genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { + inContext contextRequirement: Context, + withSymbol symbolProperty: String, + genDisposableVariable: @escaping (ProgramBuilder, Variable) -> Void +) -> [GeneratorStub] { return [ GeneratorStub( "DisposableObjectLiteralBeginGenerator", @@ -64,9 +65,10 @@ func disposableObjVariableGeneratorStubs( // Generator stubs for disposable and async-disposable class variables. func disposableClassVariableGeneratorStubs( - inContext contextRequirement : Context, - withSymbol symbolProperty : String, - genDisposableVariable : @escaping (ProgramBuilder, Variable) -> Void) -> [GeneratorStub] { + inContext contextRequirement: Context, + withSymbol symbolProperty: String, + genDisposableVariable: @escaping (ProgramBuilder, Variable) -> Void +) -> [GeneratorStub] { return [ GeneratorStub( "DisposableClassDefinitionBeginGenerator", @@ -85,10 +87,12 @@ func disposableClassVariableGeneratorStubs( superclass = b.randomVariable(ofType: .constructor()) } let inputs = superclass != nil ? [superclass!] : [] - let cls = b.emit(BeginClassDefinition( + let cls = b.emit( + BeginClassDefinition( hasSuperclass: superclass != nil, isExpression: probability(0.3)), - withInputs: inputs).output + withInputs: inputs + ).output b.runtimeData.push("class", cls) }, GeneratorStub( @@ -164,7 +168,8 @@ public let CodeGenerators: [CodeGenerator] = [ b.loadString(b.randomString()) }, - CodeGenerator("ConcatenatedStringGenerator", inputs: .required(.string), produces: [.string]) { b, inputString in + CodeGenerator("ConcatenatedStringGenerator", inputs: .required(.string), produces: [.string]) { + b, inputString in // Emit a dynamically concatenated string, e.g. something like: // let select = someVar ? "string a" : "string b"; // let result = select + "other string"; @@ -227,20 +232,21 @@ public let CodeGenerators: [CodeGenerator] = [ var elements = [Variable]() // Randomly select the type of elements to surround the holes with. - let getElementOptions : [() -> Variable] = [ + let getElementOptions: [() -> Variable] = [ // Holey Smi (in most cases) - {b.randomVariable(ofType: .integer) ?? b.loadInt(b.randomInt())}, + { b.randomVariable(ofType: .integer) ?? b.loadInt(b.randomInt()) }, // Holey Double - {b.randomVariable(ofType: .float) ?? b.loadFloat(b.randomFloat())}, + { b.randomVariable(ofType: .float) ?? b.loadFloat(b.randomFloat()) }, // Holey Elements - {b.randomJsVariable()} + { b.randomJsVariable() }, ] let getElement = getElementOptions.randomElement()! - let guaranteeHole = Int.random(in: 0.. () + private let f: (ProgramBuilder) -> Void - public init(_ name: String, _ f: @escaping (_: ProgramBuilder) -> ()) { + public init(_ name: String, _ f: @escaping (_: ProgramBuilder) -> Void) { self.f = f super.init(name: name) } @@ -28,4 +28,3 @@ public class ProgramTemplate: Contributor { /// Strongly typed ProgramTemplate that can be used to differentiate templates that make use of Wasm. public class WasmProgramTemplate: ProgramTemplate { } - diff --git a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift index 9fce1cfd4..a1fc15184 100644 --- a/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift +++ b/Sources/Fuzzilli/CodeGen/ProgramTemplates.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - /// Builtin program templates to target specific types of bugs. public let ProgramTemplates = [ ProgramTemplate("Codegen100") { b in @@ -29,7 +28,7 @@ public let ProgramTemplates = [ WasmProgramTemplate("WasmCodegen50") { b in b.buildPrefix() - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 50) } b.build(n: 10) @@ -41,7 +40,7 @@ public let ProgramTemplates = [ WasmProgramTemplate("WasmCodegen100") { b in b.buildPrefix() - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 100) } b.build(n: 10) @@ -54,8 +53,8 @@ public let ProgramTemplates = [ WasmProgramTemplate("MixedJsAndWasm1") { b in b.buildPrefix() b.build(n: 10) - let m = b.buildWasmModule() { _ in - b.build(n:30) + let m = b.buildWasmModule { _ in + b.build(n: 30) } b.build(n: 20) @@ -67,11 +66,11 @@ public let ProgramTemplates = [ WasmProgramTemplate("MixedJsAndWasm2") { b in b.buildPrefix() b.build(n: 10) - b.buildWasmModule() { _ in + b.buildWasmModule { _ in b.build(n: 20) } b.build(n: 10) - let m = b.buildWasmModule() { _ in + let m = b.buildWasmModule { _ in b.build(n: 20) } b.build(n: 20) @@ -87,25 +86,31 @@ public let ProgramTemplates = [ var f: Variable? = nil - withEqualProbability({ - f = b.buildAsyncFunction(with: b.randomParameters()) { _ in - b.build(n: Int.random(in: 5...20)) - } - }, { - f = b.buildPlainFunction(with: b.randomParameters()) { _ in - b.build(n: Int.random(in: 5...20)) - } - }) + withEqualProbability( + { + f = b.buildAsyncFunction(with: b.randomParameters()) { _ in + b.build(n: Int.random(in: 5...20)) + } + }, + { + f = b.buildPlainFunction(with: b.randomParameters()) { _ in + b.build(n: Int.random(in: 5...20)) + } + }) let signature = b.type(of: f!).signature ?? Signature.forUnknownFunction // As we do not yet know what types we have in the Wasm module when we try to call this, let Fuzzilli know that it could potentially use all Wasm types here. - let allWasmTypes: WeightedList = WeightedList([(.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), (.wasmFuncRef(), 1)]) + let allWasmTypes: WeightedList = WeightedList([ + (.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), + (.wasmFuncRef(), 1), + ]) - var wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(signature, availableTypes: allWasmTypes) + var wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + signature, availableTypes: allWasmTypes) let wrapped = b.wrapSuspending(function: f!) let m = b.buildWasmModule { mod in - mod.addWasmFunction(with: [] => []) { fbuilder, _, _ in + mod.addWasmFunction(with: [] => []) { fbuilder, _, _ in // This will create a bunch of locals, which should create large (>4KB) frames. if probability(0.02) { for _ in 0..<1000 { @@ -117,7 +122,8 @@ public let ProgramTemplates = [ // Best effort call... // TODO: Extend findOrGenerateArguments to work in Wasm as well. if let args { - fbuilder.wasmJsCall(function: wrapped, withArgs: args, withWasmSignature: wasmSignature) + fbuilder.wasmJsCall( + function: wrapped, withArgs: args, withWasmSignature: wasmSignature) } b.build(n: 4) return [] @@ -135,7 +141,8 @@ public let ProgramTemplates = [ b.build(n: 10) - b.callFunction(exportedMethod, withArgs: b.randomArguments(forCallingFunctionWithSignature: signature)) + b.callFunction( + exportedMethod, withArgs: b.randomArguments(forCallingFunctionWithSignature: signature)) b.build(n: 5) }, @@ -152,22 +159,29 @@ public let ProgramTemplates = [ let tagToThrow = chooseUniform(from: wasmTags) let throwParamTypes = b.type(of: tagToThrow).wasmTagType!.parameters let tagToCatchForRethrow = chooseUniform(from: tags) - let catchBlockOutputTypes = b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef()] + let catchBlockOutputTypes = + b.type(of: tagToCatchForRethrow).wasmTagType!.parameters + [.wasmExnRef()] let module = b.buildWasmModule { wasmModule in // Wasm function that throws a tag, catches a tag (the same or a different one) to // rethrow it again (or another exnref if present). wasmModule.addWasmFunction(with: [] => []) { function, label, args in b.build(n: 10) - let caughtValues = function.wasmBuildBlockWithResults(with: [] => catchBlockOutputTypes, args: []) { catchRefLabel, _ in + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => catchBlockOutputTypes, args: [] + ) { catchRefLabel, _ in // TODO(mliedtke): We should probably allow mutations of try_tables to make // these cases more generic. This would probably require being able to wrap // things in a new block (so we can insert a target destination for a new catch // with a matching signature) or to at least create a new tag for an existing // block target. Either way, this is non-trivial. - function.wasmBuildTryTable(with: [] => [], args: [tagToCatchForRethrow, catchRefLabel], catches: [.Ref]) { _, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagToCatchForRethrow, catchRefLabel], catches: [.Ref] + ) { _, _ in b.build(n: 10) - function.WasmBuildThrow(tag: tagToThrow, inputs: throwParamTypes.map(function.findOrGenerateWasmVar)) + function.WasmBuildThrow( + tag: tagToThrow, + inputs: throwParamTypes.map(function.findOrGenerateWasmVar)) return [] } return catchBlockOutputTypes.map(function.findOrGenerateWasmVar) @@ -201,29 +215,37 @@ public let ProgramTemplates = [ let numCallees = Int.random(in: 1...5) let module = b.buildWasmModule { wasmModule in - let callees = (0.. 10) - return Int.random(in: (numIterations - 10).. 10) + return Int.random(in: (numIterations - 10).. [.wasmi32]) { f, _, args in // Interleave random Wasm instructions before growing b.build(n: 15) @@ -597,23 +637,33 @@ public let ProgramTemplates = [ // B. Create View (that will likely detach soon) let buffer = b.getProperty("buffer", of: memory) - let TypedArray = b.createNamedVariable(forBuiltin: chooseUniform(from: ["Int8Array", "Uint32Array", "Float64Array", "DataView"])) + let TypedArray = b.createNamedVariable( + forBuiltin: chooseUniform(from: [ + "Int8Array", "Uint32Array", "Float64Array", "DataView", + ])) let view = b.construct(TypedArray, withArgs: [buffer]) b.build(n: 3) // C. Growth/Resize Event (Mix of JS, Wasm, and RAB APIs) - withEqualProbability({ - _ = b.callMethod("grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...4))], guard: true) - }, { - _ = b.callFunction(wasmGrow, withArgs: [b.loadInt(Int64.random(in: 0...4))]) - }, { - let isResizable = b.getProperty("resizable", of: buffer) - b.buildIf(isResizable) { - let currentLen = b.getProperty("byteLength", of: buffer) - let newLen = b.binary(currentLen, b.loadInt(Int64(WasmConstants.specWasmMemPageSize)), with: .Add) - b.callMethod("resize", on: buffer, withArgs: [newLen]) - } - }) + withEqualProbability( + { + _ = b.callMethod( + "grow", on: memory, withArgs: [b.loadInt(Int64.random(in: 0...4))], + guard: true) + }, + { + _ = b.callFunction(wasmGrow, withArgs: [b.loadInt(Int64.random(in: 0...4))]) + }, + { + let isResizable = b.getProperty("resizable", of: buffer) + b.buildIf(isResizable) { + let currentLen = b.getProperty("byteLength", of: buffer) + let newLen = b.binary( + currentLen, b.loadInt(Int64(WasmConstants.specWasmMemPageSize)), + with: .Add) + b.callMethod("resize", on: buffer, withArgs: [newLen]) + } + }) } b.build(n: 15) } diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index b6050f5ea..eb5c1c514 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -27,7 +27,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ inContext: .single(.javascript), produces: [.object(ofGroup: "WasmGlobal")] ) { b in - b.createWasmGlobal(value: b.randomWasmGlobal(forContext: .javascript), isMutable: probability(0.5)) + b.createWasmGlobal( + value: b.randomWasmGlobal(forContext: .javascript), isMutable: probability(0.5)) }, CodeGenerator( @@ -77,55 +78,62 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ]), - CodeGenerator("WasmTypeGroupGenerator", [ - GeneratorStub( - "WasmTypeGroupBeginGenerator", - provides: [.wasmTypeGroup] - ) { b in - b.emit(WasmBeginTypeGroup()) - }, - GeneratorStub( - "WasmTypeGroupEndGenerator", - inContext: .single(.wasmTypeGroup) - ) { b in - b.wasmEndTypeGroup() - }, - ]), - - CodeGenerator("WasmTypeGroupWithAllTypesGenerator", [ - GeneratorStub( - "WasmTypeGroupBeginGenerator", - provides: [.wasmTypeGroup] - ) { b in - b.emit(WasmBeginTypeGroup()) - }, - wasmArrayTypeGenerator, - wasmStructTypeGenerator, - wasmSignatureTypeGenerator, - GeneratorStub( - "WasmTypeGroupEndGenerator", - inContext: .single(.wasmTypeGroup), - producesComplex: [ - .init(.wasmTypeDef(), .IsWasmArray), - .init(.wasmTypeDef(), .IsWasmStruct), - .init(.wasmTypeDef(), .IsWasmFunction) - ] - ) { b in - b.wasmEndTypeGroup() - }, - ]), + CodeGenerator( + "WasmTypeGroupGenerator", + [ + GeneratorStub( + "WasmTypeGroupBeginGenerator", + provides: [.wasmTypeGroup] + ) { b in + b.emit(WasmBeginTypeGroup()) + }, + GeneratorStub( + "WasmTypeGroupEndGenerator", + inContext: .single(.wasmTypeGroup) + ) { b in + b.wasmEndTypeGroup() + }, + ]), + + CodeGenerator( + "WasmTypeGroupWithAllTypesGenerator", + [ + GeneratorStub( + "WasmTypeGroupBeginGenerator", + provides: [.wasmTypeGroup] + ) { b in + b.emit(WasmBeginTypeGroup()) + }, + wasmArrayTypeGenerator, + wasmStructTypeGenerator, + wasmSignatureTypeGenerator, + GeneratorStub( + "WasmTypeGroupEndGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [ + .init(.wasmTypeDef(), .IsWasmArray), + .init(.wasmTypeDef(), .IsWasmStruct), + .init(.wasmTypeDef(), .IsWasmFunction), + ] + ) { b in + b.wasmEndTypeGroup() + }, + ]), CodeGenerator("WasmArrayTypeGenerator", [wasmArrayTypeGenerator]), CodeGenerator("WasmStructTypeGenerator", [wasmStructTypeGenerator]), CodeGenerator("WasmSignatureTypeGenerator", [wasmSignatureTypeGenerator]), - CodeGenerator("WasmSelfReferenceGenerator", inContext: .single(.wasmTypeGroup), produces: [.wasmSelfReference()]) { b in + CodeGenerator( + "WasmSelfReferenceGenerator", inContext: .single(.wasmTypeGroup), + produces: [.wasmSelfReference()] + ) { b in b.wasmDefineForwardOrSelfReference() }, CodeGenerator("WasmForwardReferenceGenerator", inContext: .single(.wasmTypeGroup)) { b in // TODO(cffsmith): think about this. - b.wasmDefineAndResolveForwardReference {b.buildRecursive(n: defaultCodeGenerationAmount)} + b.wasmDefineAndResolveForwardReference { b.buildRecursive(n: defaultCodeGenerationAmount) } }, CodeGenerator( @@ -138,10 +146,13 @@ public let WasmCodeGenerators: [CodeGenerator] = [ as? WasmArrayTypeDescription { let function = b.currentWasmModule.currentWasmFunction - let hasElement = b.findVariable{b.type(of: $0).Is(typeDesc.elementType.unpacked())} != nil + let hasElement = + b.findVariable { b.type(of: $0).Is(typeDesc.elementType.unpacked()) } != nil let isDefaultable = typeDesc.elementType.isWasmDefaultable - if hasElement && (!isDefaultable || probability(0.5)) { - let elements = (0.. outputTypes) b.runtimeData.push("blockSignature", signature) - b.emit(WasmBeginBlock(parameterCount: parameters.count), withInputs: [signature] + args) + b.emit( + WasmBeginBlock(parameterCount: parameters.count), withInputs: [signature] + args + ) }, GeneratorStub("WasmEndBlockGenerator", inContext: .single(.wasmFunction)) { b in let signature = b.runtimeData.pop("blockSignature") @@ -1397,7 +1503,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.emit(WasmBeginLoop(with: [] => []), withInputs: [signature]) // Increase loop counter. let result = function.wasmi32BinOp( - loopCtr, function.consti32(1), binOpKind: .Sub) + loopCtr, function.consti32(1), binOpKind: .Sub) function.wasmReassign(variable: loopCtr, to: result) }, GeneratorStub( @@ -1408,53 +1514,63 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let loopCtr = b.runtimeData.pop("loopCounter") // Backedge of loop, we continue if it is not equal to zero. let isNotZero = function.wasmi32CompareOp(loopCtr, function.consti32(0), using: .Ne) - b.emit(WasmEndLoop(outputCount: 0), withInputs: [b.runtimeData.pop("loopSignature")]) + b.emit( + WasmEndLoop(outputCount: 0), withInputs: [b.runtimeData.pop("loopSignature")]) }, ]), - CodeGenerator("WasmLoopWithSignatureGenerator", [ - GeneratorStub("WasmBeginLoopWithSignatureGenerator", inContext: .single(.wasmFunction), - provides: [.wasmFunction]) { b in - let function = b.currentWasmModule.currentWasmFunction - // Count upwards here to make it slightly more different from the other loop generator. - // Also, instead of using reassign, this generator uses the signature to pass and update the loop counter. - let randomArgs = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) - let randomArgTypes = randomArgs.map { b.type(of: $0) } - let args = [function.consti32(0)] + randomArgs - let parameters = args.map(b.type) - // TODO(mliedtke): Also allow index types in the output types. - let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) - let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) - let loopBegin = b.emit(WasmBeginLoop(parameterCount: parameters.count), - withInputs: [signature] + args) - let loopCounter = loopBegin.innerOutput(1) - assert(b.type(of: loopCounter).Is(.wasmi32)) - b.runtimeData.push("loopCounter", loopCounter) - b.runtimeData.push("loopSignature", signature) - b.runtimeData.push("loopLabel", loopBegin.innerOutput(0)) - }, - GeneratorStub("WasmEndLoopWithSignatureGenerator", inContext: .single(.wasmFunction), - provides: [.wasmFunction]) { b in - let signature = b.runtimeData.pop("loopSignature") - let function = b.currentWasmModule.currentWasmFunction + CodeGenerator( + "WasmLoopWithSignatureGenerator", + [ + GeneratorStub( + "WasmBeginLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction] + ) { b in + let function = b.currentWasmModule.currentWasmFunction + // Count upwards here to make it slightly more different from the other loop generator. + // Also, instead of using reassign, this generator uses the signature to pass and update the loop counter. + let randomArgs = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true) + let randomArgTypes = randomArgs.map { b.type(of: $0) } + let args = [function.consti32(0)] + randomArgs + let parameters = args.map(b.type) + // TODO(mliedtke): Also allow index types in the output types. + let outputTypes = b.randomWasmBlockOutputTypes(upTo: 5) + let signature = b.wasmDefineAdHocSignatureType(signature: parameters => outputTypes) + let loopBegin = b.emit( + WasmBeginLoop(parameterCount: parameters.count), + withInputs: [signature] + args) + let loopCounter = loopBegin.innerOutput(1) + assert(b.type(of: loopCounter).Is(.wasmi32)) + b.runtimeData.push("loopCounter", loopCounter) + b.runtimeData.push("loopSignature", signature) + b.runtimeData.push("loopLabel", loopBegin.innerOutput(0)) + }, + GeneratorStub( + "WasmEndLoopWithSignatureGenerator", inContext: .single(.wasmFunction), + provides: [.wasmFunction] + ) { b in + let signature = b.runtimeData.pop("loopSignature") + let function = b.currentWasmModule.currentWasmFunction - // Note that due to the do-while style implementation, the actual iteration count is at - // least 1. - let iterationCount = Int32.random(in: 0...16) - let loopCtr = function.wasmi32BinOp( - b.runtimeData.pop("loopCounter"), function.consti32(1), binOpKind: .Add) - let condition = function.wasmi32CompareOp( - loopCtr, function.consti32(iterationCount), using: .Lt_s) - let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature - let backedgeArgs = [loopCtr] + wasmSignature.parameterTypes.dropFirst() - .map {b.randomVariable(ofType: $0)!} - function.wasmBranchIf( - condition, to: b.runtimeData.pop("loopLabel"), args: backedgeArgs, - hint: b.randomWasmBranchHint()) - let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndLoop(outputCount: outputs.count), withInputs: [signature] + outputs) - }, - ]), + // Note that due to the do-while style implementation, the actual iteration count is at + // least 1. + let iterationCount = Int32.random(in: 0...16) + let loopCtr = function.wasmi32BinOp( + b.runtimeData.pop("loopCounter"), function.consti32(1), binOpKind: .Add) + let condition = function.wasmi32CompareOp( + loopCtr, function.consti32(iterationCount), using: .Lt_s) + let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature + let backedgeArgs = + [loopCtr] + + wasmSignature.parameterTypes.dropFirst() + .map { b.randomVariable(ofType: $0)! } + function.wasmBranchIf( + condition, to: b.runtimeData.pop("loopLabel"), args: backedgeArgs, + hint: b.randomWasmBranchHint()) + let outputs = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) + b.emit(WasmEndLoop(outputCount: outputs.count), withInputs: [signature] + outputs) + }, + ]), // TODO split this into a multi-part Generator. CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { b in @@ -1566,8 +1682,10 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let signature = b.runtimeData.peek("ifSignature") let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature let trueResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmBeginElse(parameterCount: wasmSignature.parameterTypes.count, - outputCount: wasmSignature.outputTypes.count), + b.emit( + WasmBeginElse( + parameterCount: wasmSignature.parameterTypes.count, + outputCount: wasmSignature.outputTypes.count), withInputs: [signature] + trueResults) }, GeneratorStub( @@ -1578,7 +1696,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let signature = b.runtimeData.pop("ifSignature") let wasmSignature = b.type(of: signature).wasmFunctionSignatureDefSignature let falseResults = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndIf(outputCount: wasmSignature.outputTypes.count), + b.emit( + WasmEndIf(outputCount: wasmSignature.outputTypes.count), withInputs: [signature] + falseResults) }, ]), @@ -1634,9 +1753,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [ } // Create a try-catch throwing and catching a tag producing an exnref as // a result. - function.wasmBuildBlockWithResults(with: [] => (tagType.parameters + [.wasmExnRef()]), args: []) { label, _ in + function.wasmBuildBlockWithResults( + with: [] => (tagType.parameters + [.wasmExnRef()]), args: [] + ) { label, _ in let args = tagType.parameters.map(function.findOrGenerateWasmVar) - function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { _, _ in + function.wasmBuildTryTable(with: [] => [], args: [tag, label], catches: [.Ref]) { + _, _ in function.WasmBuildThrow(tag: tag, inputs: args) return [] } @@ -1724,7 +1846,9 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBranchTable(on: value, labels: labels, args: args) (0.. WasmBeginTryTable.CatchKind in @@ -1793,8 +1922,9 @@ public let WasmCodeGenerators: [CodeGenerator] = [ signatureDefs.reversed().enumerated().forEach { n, signatureDef in let wasmSignature = b.type(of: signatureDef).wasmFunctionSignatureDefSignature let results = wasmSignature.outputTypes.map(function.findOrGenerateWasmVar) - b.emit(WasmEndBlock(outputCount: wasmSignature.outputTypes.count), - withInputs: [signatureDef] + results) + b.emit( + WasmEndBlock(outputCount: wasmSignature.outputTypes.count), + withInputs: [signatureDef] + results) b.buildRecursive(n: defaultCodeGenerationAmount) } } @@ -1843,13 +1973,17 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmSimd128IntegerBinOp(lhs, rhs, shape, binOpKind) }, - CodeGenerator("WasmSimd128IntegerTernaryOpGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128)) { b, left, mid, right in - let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter{ !$0.isFloat() } ) - let ternaryOpKind = chooseUniform(from: WasmSimd128IntegerTernaryOpKind.allCases.filter{ - $0.isValidForShape(shape: shape) - }) + CodeGenerator( + "WasmSimd128IntegerTernaryOpGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128) + ) { b, left, mid, right in + let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter { !$0.isFloat() }) + let ternaryOpKind = chooseUniform( + from: WasmSimd128IntegerTernaryOpKind.allCases.filter { + $0.isValidForShape(shape: shape) + }) - let function = b.currentWasmModule.currentWasmFunction; + let function = b.currentWasmModule.currentWasmFunction function.wasmSimd128IntegerTernaryOp(left, mid, right, shape, ternaryOpKind) }, @@ -1883,13 +2017,17 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmSimd128FloatBinOp(lhs, rhs, shape, binOpKind) }, - CodeGenerator("WasmSimd128FloatTernaryOpGenerator", inContext: .single(.wasmFunction), inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128)) { b, left, mid, right in - let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter{ $0.isFloat() } ) - let ternaryOpKind = chooseUniform(from: WasmSimd128FloatTernaryOpKind.allCases.filter{ - $0.isValidForShape(shape: shape) - }) + CodeGenerator( + "WasmSimd128FloatTernaryOpGenerator", inContext: .single(.wasmFunction), + inputs: .required(.wasmSimd128, .wasmSimd128, .wasmSimd128) + ) { b, left, mid, right in + let shape = chooseUniform(from: WasmSimd128Shape.allCases.filter { $0.isFloat() }) + let ternaryOpKind = chooseUniform( + from: WasmSimd128FloatTernaryOpKind.allCases.filter { + $0.isValidForShape(shape: shape) + }) - let function = b.currentWasmModule.currentWasmFunction; + let function = b.currentWasmModule.currentWasmFunction function.wasmSimd128FloatTernaryOp(left, mid, right, shape, ternaryOpKind) }, @@ -2014,7 +2152,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ }, ] -fileprivate let wasmArrayTypeGenerator = GeneratorStub( +private let wasmArrayTypeGenerator = GeneratorStub( "WasmArrayTypeGenerator", inContext: .single(.wasmTypeGroup), producesComplex: [.init(.wasmTypeDef(), .IsWasmArray)] @@ -2032,49 +2170,56 @@ fileprivate let wasmArrayTypeGenerator = GeneratorStub( mutability: mutability, indexType: elementType) } else { b.wasmDefineArrayType( - elementType: chooseUniform(from: [ - .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, - ] + WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: Bool.random())}), + elementType: chooseUniform( + from: [ + .wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, + .wasmSimd128, + ] + + WasmAbstractHeapType.allCases.map { + ILType.wasmRef($0, nullability: Bool.random()) + }), mutability: mutability) } } -fileprivate let wasmStructTypeGenerator = GeneratorStub( +private let wasmStructTypeGenerator = GeneratorStub( "WasmStructTypeGenerator", inContext: .single(.wasmTypeGroup), - producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)]) { b in + producesComplex: [.init(.wasmTypeDef(), .IsWasmStruct)] +) { b in let (fields, indexTypes) = b.generateRandomWasmStructFields() b.wasmDefineStructType(fields: fields, indexTypes: indexTypes) } -fileprivate let wasmSignatureTypeGenerator = GeneratorStub( - "WasmSignatureTypeGenerator", - inContext: .single(.wasmTypeGroup), - producesComplex: [.init(.wasmTypeDef(), .IsWasmFunction)] - ) { b in - let typeCount = Int.random(in: 0...10) - let returnCount = Int.random(in: 0...typeCount) - let parameterCount = typeCount - returnCount - - var indexTypes: [Variable] = [] - let chooseType = { - var type: ILType - if let elementType = b.randomVariable(ofType: .wasmTypeDef()), - probability(0.25) - { - let nullability = - b.type(of: elementType).wasmTypeDefinition!.description - == .selfReference || probability(0.5) - indexTypes.append(elementType) - return ILType.wasmRef(.Index(), nullability: nullability) - } else { - // TODO(mliedtke): Extend list with abstract heap types. - return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128]) - } +private let wasmSignatureTypeGenerator = GeneratorStub( + "WasmSignatureTypeGenerator", + inContext: .single(.wasmTypeGroup), + producesComplex: [.init(.wasmTypeDef(), .IsWasmFunction)] +) { b in + let typeCount = Int.random(in: 0...10) + let returnCount = Int.random(in: 0...typeCount) + let parameterCount = typeCount - returnCount + + var indexTypes: [Variable] = [] + let chooseType = { + var type: ILType + if let elementType = b.randomVariable(ofType: .wasmTypeDef()), + probability(0.25) + { + let nullability = + b.type(of: elementType).wasmTypeDefinition!.description + == .selfReference || probability(0.5) + indexTypes.append(elementType) + return ILType.wasmRef(.Index(), nullability: nullability) + } else { + // TODO(mliedtke): Extend list with abstract heap types. + return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128]) } - let signature = (0.. (0.. (0.. Variable { + private func compileClass( + _ name: String, superClass: ExpressionNode?, fields: [ClassFieldNode], isExpression: Bool + ) throws -> Variable { // The expressions for property values and computed properties need to be emitted before the class declaration is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() @@ -106,7 +108,9 @@ public class JavaScriptCompiler { let classDecl: Instruction if let superClass = superClass { let superClass = try compileExpression(superClass) - classDecl = emit(BeginClassDefinition(hasSuperclass: true, isExpression: isExpression), withInputs: [superClass]) + classDecl = emit( + BeginClassDefinition(hasSuperclass: true, isExpression: isExpression), + withInputs: [superClass]) } else { classDecl = emit(BeginClassDefinition(hasSuperclass: false, isExpression: isExpression)) } @@ -125,12 +129,16 @@ public class JavaScriptCompiler { var inputs = [Variable]() switch key { case .name(let name): - op = ClassAddProperty(propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddProperty( + propertyName: name, hasValue: property.hasValue, isStatic: property.isStatic + ) case .index(let index): - op = ClassAddElement(index: index, hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddElement( + index: index, hasValue: property.hasValue, isStatic: property.isStatic) case .expression: inputs.append(computedKeys.removeLast()) - op = ClassAddComputedProperty(hasValue: property.hasValue, isStatic: property.isStatic) + op = ClassAddComputedProperty( + hasValue: property.hasValue, isStatic: property.isStatic) } if property.hasValue { inputs.append(propertyValues.removeLast()) @@ -161,11 +169,18 @@ public class JavaScriptCompiler { } switch key { case .name(let name): - head = emit(BeginClassMethod(methodName: name, parameters: parameters, isStatic: method.isStatic)) + head = emit( + BeginClassMethod( + methodName: name, parameters: parameters, isStatic: method.isStatic)) case .index(let index): - head = emit(BeginClassMethod(methodName: String(index), parameters: parameters, isStatic: method.isStatic)) + head = emit( + BeginClassMethod( + methodName: String(index), parameters: parameters, + isStatic: method.isStatic)) case .expression: - head = emit(BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -195,9 +210,12 @@ public class JavaScriptCompiler { case .name(let name): head = emit(BeginClassGetter(propertyName: name, isStatic: getter.isStatic)) case .index(let index): - head = emit(BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) + head = emit( + BeginClassGetter(propertyName: String(index), isStatic: getter.isStatic)) case .expression: - head = emit(BeginClassComputedGetter(isStatic: getter.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedGetter(isStatic: getter.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -223,9 +241,12 @@ public class JavaScriptCompiler { case .name(let name): head = emit(BeginClassSetter(propertyName: name, isStatic: setter.isStatic)) case .index(let index): - head = emit(BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) + head = emit( + BeginClassSetter(propertyName: String(index), isStatic: setter.isStatic)) case .expression: - head = emit(BeginClassComputedSetter(isStatic: setter.isStatic), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginClassComputedSetter(isStatic: setter.isStatic), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -264,7 +285,9 @@ public class JavaScriptCompiler { return classDecl.output } - private func compileInitialDeclarationValue(_ decl: Compiler_Protobuf_VariableDeclarator) throws -> Variable { + private func compileInitialDeclarationValue(_ decl: Compiler_Protobuf_VariableDeclarator) throws + -> Variable + { if decl.hasValue { return try compileExpression(decl.value) } else { @@ -305,10 +328,14 @@ public class JavaScriptCompiler { case .const: declarationMode = .const case .UNRECOGNIZED(let type): - throw CompilerError.invalidNodeError("invalid variable declaration type \(type)") + throw CompilerError.invalidNodeError( + "invalid variable declaration type \(type)") } - let v = emit(CreateNamedVariable(decl.name, declarationMode: declarationMode), withInputs: [initialValue]).output + let v = emit( + CreateNamedVariable(decl.name, declarationMode: declarationMode), + withInputs: [initialValue] + ).output // Variables declared with .var are allowed to overwrite each other. assert(!currentScope.keys.contains(decl.name) || declarationMode == .var) mapOrRemap(decl.name, to: v) @@ -318,14 +345,21 @@ public class JavaScriptCompiler { for decl in variableDeclaration.declarations { let initialValue = try compileInitialDeclarationValue(decl) - let v: Variable; + let v: Variable switch variableDeclaration.kind { case .using: - v = emit(CreateNamedDisposableVariable(decl.name), withInputs: [initialValue]).output + v = + emit(CreateNamedDisposableVariable(decl.name), withInputs: [initialValue]) + .output case .awaitUsing: - v = emit(CreateNamedAsyncDisposableVariable(decl.name), withInputs: [initialValue]).output + v = + emit( + CreateNamedAsyncDisposableVariable(decl.name), + withInputs: [initialValue] + ).output case .UNRECOGNIZED(let type): - throw CompilerError.invalidNodeError("invalid disposable variable declaration type \(type)") + throw CompilerError.invalidNodeError( + "invalid disposable variable declaration type \(type)") } assert(!currentScope.keys.contains(decl.name)) mapOrRemap(decl.name, to: v) @@ -333,19 +367,24 @@ public class JavaScriptCompiler { case .functionDeclaration(let functionDeclaration): let parameters = convertParameters(functionDeclaration.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation switch functionDeclaration.type { case .plain: - functionBegin = BeginPlainFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginPlainFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndPlainFunction() case .generator: - functionBegin = BeginGeneratorFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginGeneratorFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndGeneratorFunction() case .async: - functionBegin = BeginAsyncFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginAsyncFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndAsyncFunction() case .asyncGenerator: - functionBegin = BeginAsyncGeneratorFunction(parameters: parameters, functionName: functionDeclaration.name) + functionBegin = BeginAsyncGeneratorFunction( + parameters: parameters, functionName: functionDeclaration.name) functionEnd = EndAsyncGeneratorFunction() case .UNRECOGNIZED(let type): throw CompilerError.invalidNodeError("invalid function declaration type \(type)") @@ -365,7 +404,9 @@ public class JavaScriptCompiler { case .classDeclaration(let classDeclaration): let superClass = classDeclaration.hasSuperClass ? classDeclaration.superClass : nil - try compileClass(classDeclaration.name, superClass: superClass, fields: classDeclaration.fields, isExpression: false) + try compileClass( + classDeclaration.name, superClass: superClass, fields: classDeclaration.fields, + isExpression: false) case .returnStatement(let returnStatement): if returnStatement.hasArgument { @@ -435,7 +476,8 @@ public class JavaScriptCompiler { case .declaration(let declaration): for declarator in declaration.declarations { loopVariables.append(declarator.name) - initialLoopVariableValues.append(try compileExpression(declarator.value)) + initialLoopVariableValues.append( + try compileExpression(declarator.value)) } case .expression(let expression): try compileExpression(expression) @@ -444,10 +486,13 @@ public class JavaScriptCompiler { } // Process condition. - var outputs = emit(BeginForLoopCondition(numLoopVariables: loopVariables.count), withInputs: initialLoopVariableValues).innerOutputs + var outputs = emit( + BeginForLoopCondition(numLoopVariables: loopVariables.count), + withInputs: initialLoopVariableValues + ).innerOutputs var cond: Variable? = nil try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) if forLoop.hasCondition { cond = try compileExpression(forLoop.condition) } else { @@ -456,9 +501,13 @@ public class JavaScriptCompiler { } // Process afterthought. - outputs = emit(BeginForLoopAfterthought(numLoopVariables: loopVariables.count), withInputs: [cond!]).innerOutputs + outputs = + emit( + BeginForLoopAfterthought(numLoopVariables: loopVariables.count), + withInputs: [cond!] + ).innerOutputs try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) if forLoop.hasAfterthought { try compileExpression(forLoop.afterthought) } @@ -467,16 +516,17 @@ public class JavaScriptCompiler { // Process body outputs = emit(BeginForLoopBody(numLoopVariables: loopVariables.count)).innerOutputs try enterNewScope { - zip(loopVariables, outputs).forEach({ map($0, to: $1 )}) + zip(loopVariables, outputs).forEach({ map($0, to: $1) }) try compileBody(forLoop.body) } emit(EndForLoop()) case .forInLoop(let forInLoop): - let initializer = forInLoop.left; + let initializer = forInLoop.left guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") + throw CompilerError.invalidNodeError( + "Expected no initial value for the variable declared in a for-in loop") } let obj = try compileExpression(forInLoop.right) @@ -490,9 +540,10 @@ public class JavaScriptCompiler { emit(EndForInLoop()) case .forOfLoop(let forOfLoop): - let initializer = forOfLoop.left; + let initializer = forOfLoop.left guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") + throw CompilerError.invalidNodeError( + "Expected no initial value for the variable declared in a for-of loop") } let obj = try compileExpression(forOfLoop.right) @@ -508,7 +559,7 @@ public class JavaScriptCompiler { case .breakStatement: // If we're in both .loop and .switch context, then the loop must be the most recent context // (switch blocks don't propagate an outer .loop context) so we just need to check for .loop here - if contextAnalyzer.context.contains(.loop){ + if contextAnalyzer.context.contains(.loop) { emit(LoopBreak()) } else if contextAnalyzer.context.contains(.switchCase) { emit(SwitchBreak()) @@ -615,7 +666,9 @@ public class JavaScriptCompiler { case .classExpression(let classExpression): let superClass = classExpression.hasSuperClass ? classExpression.superClass : nil - return try compileClass(classExpression.name, superClass: superClass, fields: classExpression.fields, isExpression: true) + return try compileClass( + classExpression.name, superClass: superClass, fields: classExpression.fields, + isExpression: true) case .ternaryExpression(let ternaryExpression): let condition = try compileExpression(ternaryExpression.condition) @@ -647,7 +700,7 @@ public class JavaScriptCompiler { } // Case 2 - assert(identifier.name != "this") // This is handled via ThisExpression + assert(identifier.name != "this") // This is handled via ThisExpression if identifier.name == "undefined" { return emit(LoadUndefined()).output } else if identifier.name == "arguments" { @@ -675,7 +728,10 @@ public class JavaScriptCompiler { // TODO should LoadBigInt support larger integer values (represented as string)? let stringValue = emit(LoadString(value: literal.value)).output let BigInt = emit(CreateNamedVariable("BigInt", declarationMode: .none)).output - return emit(CallFunction(numArguments: 1, isGuarded: false), withInputs: [BigInt, stringValue]).output + return emit( + CallFunction(numArguments: 1, isGuarded: false), + withInputs: [BigInt, stringValue] + ).output } case .stringLiteral(let literal): @@ -684,7 +740,8 @@ public class JavaScriptCompiler { case .templateLiteral(let templateLiteral): let interpolatedValues = try templateLiteral.expressions.map(compileExpression) - let parts = templateLiteral.parts.map({ $0.replacingOccurrences(of: "\n", with: "\\n") }) + let parts = templateLiteral.parts.map({ $0.replacingOccurrences(of: "\n", with: "\\n") } + ) return emit(CreateTemplateString(parts: parts), withInputs: interpolatedValues).output case .regExpLiteral(let literal): @@ -721,7 +778,8 @@ public class JavaScriptCompiler { // It's something like "+=", "-=", etc. let binaryOperator = String(assignmentExpression.operator.dropLast()) guard let op = BinaryOperator(rawValue: binaryOperator) else { - throw CompilerError.invalidNodeError("Unknown assignment operator \(assignmentExpression.operator)") + throw CompilerError.invalidNodeError( + "Unknown assignment operator \(assignmentExpression.operator)") } assignmentOperator = op } @@ -730,25 +788,37 @@ public class JavaScriptCompiler { case .memberExpression(let memberExpression): // Compile to a Set- or Update{Property/Element/ComputedProperty} operation let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError("missing property in member expression") + } switch property { case .name(let name): if let op = assignmentOperator { - emit(UpdateProperty(propertyName: name, operator: op), withInputs: [object, rhs]) + emit( + UpdateProperty(propertyName: name, operator: op), + withInputs: [object, rhs]) } else { - emit(SetProperty(propertyName: name, isGuarded: memberExpression.isOptional), withInputs: [object, rhs]) + emit( + SetProperty(propertyName: name, isGuarded: memberExpression.isOptional), + withInputs: [object, rhs]) } case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let index = Int64(exactly: literal.value) { + if case .numberLiteral(let literal) = expr.expression, + let index = Int64(exactly: literal.value) + { if let op = assignmentOperator { - emit(UpdateElement(index: index, operator: op), withInputs: [object, rhs]) + emit( + UpdateElement(index: index, operator: op), + withInputs: [object, rhs]) } else { emit(SetElement(index: index), withInputs: [object, rhs]) } } else { let property = try compileExpression(expr) if let op = assignmentOperator { - emit(UpdateComputedProperty(operator: op), withInputs: [object, property, rhs]) + emit( + UpdateComputedProperty(operator: op), + withInputs: [object, property, rhs]) } else { emit(SetComputedProperty(), withInputs: [object, property, rhs]) } @@ -757,18 +827,22 @@ public class JavaScriptCompiler { case .superMemberExpression(let superMemberExpression): guard superMemberExpression.isOptional == false else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super member expressions") } guard let property = superMemberExpression.property else { - throw CompilerError.invalidNodeError("Missing property in super member expression") + throw CompilerError.invalidNodeError( + "Missing property in super member expression") } switch property { case .name(let name): if let op = assignmentOperator { // Example: super.foo += 1 - emit(UpdateSuperProperty(propertyName: name, operator: op), withInputs: [rhs]) + emit( + UpdateSuperProperty(propertyName: name, operator: op), withInputs: [rhs] + ) } else { // Example: super.foo = 1 emit(SetSuperProperty(propertyName: name), withInputs: [rhs]) @@ -783,7 +857,9 @@ public class JavaScriptCompiler { case .identifier(let identifier): // Try to lookup the variable belonging to the identifier. If there is none, we're (probably) dealing with // an access to a global variable/builtin or a hoisted variable access. In the case, create a named variable. - let lhs = lookupIdentifier(identifier.name) ?? emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output + let lhs = + lookupIdentifier(identifier.name) + ?? emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output // Compile to a Reassign or Update operation switch assignmentExpression.operator { @@ -795,13 +871,15 @@ public class JavaScriptCompiler { // It's something like "+=", "-=", etc. let binaryOperator = String(assignmentExpression.operator.dropLast()) guard let op = BinaryOperator(rawValue: binaryOperator) else { - throw CompilerError.invalidNodeError("Unknown assignment operator \(assignmentExpression.operator)") + throw CompilerError.invalidNodeError( + "Unknown assignment operator \(assignmentExpression.operator)") } emit(Update(op), withInputs: [lhs, rhs]) } default: - throw CompilerError.unsupportedFeatureError("Compiler only supports assignments to object members or identifiers") + throw CompilerError.unsupportedFeatureError( + "Compiler only supports assignments to object members or identifiers") } return rhs @@ -812,20 +890,21 @@ public class JavaScriptCompiler { var computedKeys = [Variable]() for field in objectExpression.fields { guard let field = field.field else { - throw CompilerError.invalidNodeError("missing concrete field in object expression") + throw CompilerError.invalidNodeError( + "missing concrete field in object expression") } - let key : Compiler_Protobuf_PropertyKey + let key: Compiler_Protobuf_PropertyKey switch field { - case .property(let property): - propertyValues.append(try compileExpression(property.value)) - key = property.key - case .method(let method): - key = method.key - case .getter(let getter): - key = getter.key - case .setter(let setter): - key = setter.key + case .property(let property): + propertyValues.append(try compileExpression(property.value)) + key = property.key + case .method(let method): + key = method.key + case .getter(let getter): + key = getter.key + case .setter(let setter): + key = setter.key } if case .expression(let expression) = key.body { computedKeys.append(try compileExpression(expression)) @@ -842,7 +921,8 @@ public class JavaScriptCompiler { switch field.field! { case .property(let property): guard let key = property.key.body else { - throw CompilerError.invalidNodeError("missing key in object expression field") + throw CompilerError.invalidNodeError( + "missing key in object expression field") } let inputs = [propertyValues.removeLast()] switch key { @@ -851,22 +931,30 @@ public class JavaScriptCompiler { case .index(let index): emit(ObjectLiteralAddElement(index: index), withInputs: inputs) case .expression: - emit(ObjectLiteralAddComputedProperty(), withInputs: [computedKeys.removeLast()] + inputs) + emit( + ObjectLiteralAddComputedProperty(), + withInputs: [computedKeys.removeLast()] + inputs) } case .method(let method): let parameters = convertParameters(method.parameters) let head: Instruction guard let key = method.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression method") + throw CompilerError.invalidNodeError( + "Missing key in object expression method") } switch key { case .name(let name): - head = emit(BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + head = emit( + BeginObjectLiteralMethod(methodName: name, parameters: parameters)) case .index(let index): - head = emit(BeginObjectLiteralMethod(methodName: String(index), parameters: parameters)) + head = emit( + BeginObjectLiteralMethod( + methodName: String(index), parameters: parameters)) case .expression: - head = emit(BeginObjectLiteralComputedMethod(parameters: parameters), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedMethod(parameters: parameters), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { @@ -886,7 +974,8 @@ public class JavaScriptCompiler { } case .getter(let getter): guard let key = getter.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression getter") + throw CompilerError.invalidNodeError( + "Missing key in object expression getter") } let head: Instruction switch key { @@ -895,7 +984,9 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralGetter(propertyName: String(index))) case .expression: - head = emit(BeginObjectLiteralComputedGetter(), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedGetter(), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { map("this", to: head.innerOutput) @@ -911,7 +1002,8 @@ public class JavaScriptCompiler { } case .setter(let setter): guard let key = setter.key.body else { - throw CompilerError.invalidNodeError("Missing key in object expression setter") + throw CompilerError.invalidNodeError( + "Missing key in object expression setter") } let head: Instruction switch key { @@ -920,7 +1012,9 @@ public class JavaScriptCompiler { case .index(let index): head = emit(BeginObjectLiteralSetter(propertyName: String(index))) case .expression: - head = emit(BeginObjectLiteralComputedSetter(), withInputs: [computedKeys.removeLast()]) + head = emit( + BeginObjectLiteralComputedSetter(), + withInputs: [computedKeys.removeLast()]) } try enterNewScope { var parameters = head.innerOutputs @@ -965,12 +1059,14 @@ public class JavaScriptCompiler { if spreads.contains(true) { return emit(CreateArrayWithSpread(spreads: spreads), withInputs: elements).output } else { - return emit(CreateArray(numInitialValues: elements.count), withInputs: elements).output + return emit(CreateArray(numInitialValues: elements.count), withInputs: elements) + .output } case .functionExpression(let functionExpression): let parameters = convertParameters(functionExpression.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation let name = functionExpression.name.isEmpty ? nil : functionExpression.name switch functionExpression.type { case .plain: @@ -983,7 +1079,8 @@ public class JavaScriptCompiler { functionBegin = BeginAsyncFunction(parameters: parameters, functionName: name) functionEnd = EndAsyncFunction() case .asyncGenerator: - functionBegin = BeginAsyncGeneratorFunction(parameters: parameters, functionName: name) + functionBegin = BeginAsyncGeneratorFunction( + parameters: parameters, functionName: name) functionEnd = EndAsyncGeneratorFunction() case .UNRECOGNIZED(let type): throw CompilerError.invalidNodeError("invalid function declaration type \(type)") @@ -1002,7 +1099,8 @@ public class JavaScriptCompiler { case .arrowFunctionExpression(let arrowFunction): let parameters = convertParameters(arrowFunction.parameters) - let functionBegin, functionEnd: Operation + let functionBegin: Operation + let functionEnd: Operation switch arrowFunction.type { case .plain: functionBegin = BeginArrowFunction(parameters: parameters) @@ -1011,13 +1109,16 @@ public class JavaScriptCompiler { functionBegin = BeginAsyncArrowFunction(parameters: parameters) functionEnd = EndAsyncArrowFunction() default: - throw CompilerError.invalidNodeError("invalid arrow function type \(arrowFunction.type)") + throw CompilerError.invalidNodeError( + "invalid arrow function type \(arrowFunction.type)") } let instr = emit(functionBegin) try enterNewScope { mapParameters(arrowFunction.parameters, to: instr.innerOutputs) - guard let body = arrowFunction.body else { throw CompilerError.invalidNodeError("missing body in arrow function") } + guard let body = arrowFunction.body else { + throw CompilerError.invalidNodeError("missing body in arrow function") + } switch body { case .block(let block): try compileBody(block) @@ -1038,47 +1139,97 @@ public class JavaScriptCompiler { if case .memberExpression(let memberExpression) = callExpression.callee.expression { // obj.foo(...) or obj[expr](...) let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression in call expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError( + "missing property in member expression in call expression") + } switch property { case .name(let name): if isSpreading { - return emit(CallMethodWithSpread(methodName: name, numArguments: arguments.count, spreads: spreads, isGuarded: callExpression.isOptional), withInputs: [object] + arguments).output + return emit( + CallMethodWithSpread( + methodName: name, numArguments: arguments.count, spreads: spreads, + isGuarded: callExpression.isOptional), + withInputs: [object] + arguments + ).output } else { - return emit(CallMethod(methodName: name, numArguments: arguments.count, isGuarded: callExpression.isOptional), withInputs: [object] + arguments).output + return emit( + CallMethod( + methodName: name, numArguments: arguments.count, + isGuarded: callExpression.isOptional), + withInputs: [object] + arguments + ).output } case .expression(let expr): let method = try compileExpression(expr) if isSpreading { - return emit(CallComputedMethodWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: callExpression.isOptional), withInputs: [object, method] + arguments).output + return emit( + CallComputedMethodWithSpread( + numArguments: arguments.count, spreads: spreads, + isGuarded: callExpression.isOptional), + withInputs: [object, method] + arguments + ).output } else { - return emit(CallComputedMethod(numArguments: arguments.count, isGuarded: callExpression.isOptional), withInputs: [object, method] + arguments).output + return emit( + CallComputedMethod( + numArguments: arguments.count, isGuarded: callExpression.isOptional), + withInputs: [object, method] + arguments + ).output } } - } else if case .superMemberExpression(let superMemberExpression) = callExpression.callee.expression { + } else if case .superMemberExpression(let superMemberExpression) = callExpression.callee + .expression + { // super.foo(...) guard !isSpreading else { - throw CompilerError.unsupportedFeatureError("Spread calls with super are not supported") + throw CompilerError.unsupportedFeatureError( + "Spread calls with super are not supported") } guard case .name(let methodName) = superMemberExpression.property else { - throw CompilerError.invalidNodeError("Super method calls must use a property name") + throw CompilerError.invalidNodeError( + "Super method calls must use a property name") } guard !callExpression.isOptional else { - throw CompilerError.unsupportedFeatureError("Optional chaining with super method calls is not supported") + throw CompilerError.unsupportedFeatureError( + "Optional chaining with super method calls is not supported") + } + return emit( + CallSuperMethod(methodName: methodName, numArguments: arguments.count), + withInputs: arguments + ).output + // Now check if it is a V8 intrinsic function + } else if case .v8IntrinsicIdentifier(let v8Intrinsic) = callExpression.callee + .expression + { + guard !isSpreading else { + throw CompilerError.unsupportedFeatureError( + "Not currently supporting spread calls to V8 intrinsics") } - return emit(CallSuperMethod(methodName: methodName, numArguments: arguments.count), withInputs: arguments).output - // Now check if it is a V8 intrinsic function - } else if case .v8IntrinsicIdentifier(let v8Intrinsic) = callExpression.callee.expression { - guard !isSpreading else { throw CompilerError.unsupportedFeatureError("Not currently supporting spread calls to V8 intrinsics") } - let argsString = Array(repeating: "%@", count: arguments.count).joined(separator: ", ") - return emit(Eval("%\(v8Intrinsic.name)(\(argsString))", numArguments: arguments.count, hasOutput: true), withInputs: arguments).output - // Otherwise it's a regular function call + let argsString = Array(repeating: "%@", count: arguments.count).joined( + separator: ", ") + return emit( + Eval( + "%\(v8Intrinsic.name)(\(argsString))", numArguments: arguments.count, + hasOutput: true), withInputs: arguments + ).output + // Otherwise it's a regular function call } else { - guard !callExpression.isOptional else { throw CompilerError.unsupportedFeatureError("Not currently supporting optional chaining with function calls") } + guard !callExpression.isOptional else { + throw CompilerError.unsupportedFeatureError( + "Not currently supporting optional chaining with function calls") + } let callee = try compileExpression(callExpression.callee) if isSpreading { - return emit(CallFunctionWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + CallFunctionWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: false), + withInputs: [callee] + arguments + ).output } else { - return emit(CallFunction(numArguments: arguments.count, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + CallFunction(numArguments: arguments.count, isGuarded: false), + withInputs: [callee] + arguments + ).output } } @@ -1087,43 +1238,66 @@ public class JavaScriptCompiler { let isSpreading = spreads.contains(true) if isSpreading { - throw CompilerError.unsupportedFeatureError("Spread arguments are not supported in super constructor calls") + throw CompilerError.unsupportedFeatureError( + "Spread arguments are not supported in super constructor calls") } guard !callSuperConstructor.isOptional else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super constructor calls") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super constructor calls") } emit(CallSuperConstructor(numArguments: arguments.count), withInputs: arguments) // In JS, the result of calling the super constructor is just |this|, but in FuzzIL the operation doesn't have an output (because |this| is always available anyway) - return lookupIdentifier("this")! // we can force unwrap because |this| always exists in the context where |super| exists + return lookupIdentifier("this")! // we can force unwrap because |this| always exists in the context where |super| exists case .newExpression(let newExpression): let callee = try compileExpression(newExpression.callee) let (arguments, spreads) = try compileCallArguments(newExpression.arguments) let isSpreading = spreads.contains(true) if isSpreading { - return emit(ConstructWithSpread(numArguments: arguments.count, spreads: spreads, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + ConstructWithSpread( + numArguments: arguments.count, spreads: spreads, isGuarded: false), + withInputs: [callee] + arguments + ).output } else { - return emit(Construct(numArguments: arguments.count, isGuarded: false), withInputs: [callee] + arguments).output + return emit( + Construct(numArguments: arguments.count, isGuarded: false), + withInputs: [callee] + arguments + ).output } case .memberExpression(let memberExpression): let object = try compileExpression(memberExpression.object) - guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression") } + guard let property = memberExpression.property else { + throw CompilerError.invalidNodeError("missing property in member expression") + } switch property { case .name(let name): - return emit(GetProperty(propertyName: name, isGuarded: memberExpression.isOptional), withInputs: [object]).output + return emit( + GetProperty(propertyName: name, isGuarded: memberExpression.isOptional), + withInputs: [object] + ).output case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let index = Int64(exactly: literal.value) { - return emit(GetElement(index: index, isGuarded: memberExpression.isOptional), withInputs: [object]).output + if case .numberLiteral(let literal) = expr.expression, + let index = Int64(exactly: literal.value) + { + return emit( + GetElement(index: index, isGuarded: memberExpression.isOptional), + withInputs: [object] + ).output } else { let property = try compileExpression(expr) - return emit(GetComputedProperty(isGuarded: memberExpression.isOptional), withInputs: [object, property]).output + return emit( + GetComputedProperty(isGuarded: memberExpression.isOptional), + withInputs: [object, property] + ).output } } case .superMemberExpression(let superMemberExpression): guard superMemberExpression.isOptional == false else { - throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions") + throw CompilerError.unsupportedFeatureError( + "Optional chaining is not supported in super member expressions") } guard let property = superMemberExpression.property else { throw CompilerError.invalidNodeError("Missing property in super member expression") @@ -1134,8 +1308,11 @@ public class JavaScriptCompiler { return emit(GetSuperProperty(propertyName: name), withInputs: []).output case .expression(let expr): - if case .numberLiteral(let literal) = expr.expression, let _ = Int64(exactly: literal.value) { - throw CompilerError.unsupportedFeatureError("GetElement is not supported in super member expressions") + if case .numberLiteral(let literal) = expr.expression, + Int64(exactly: literal.value) != nil + { + throw CompilerError.unsupportedFeatureError( + "GetElement is not supported in super member expressions") } else { let compiledProperty = try compileExpression(expr) return emit(GetComputedSuperProperty(), withInputs: [compiledProperty]).output @@ -1150,8 +1327,12 @@ public class JavaScriptCompiler { let argument = try compileExpression(unaryExpression.argument) return emit(Void_(), withInputs: [argument]).output } else if unaryExpression.operator == "delete" { - guard case .memberExpression(let memberExpression) = unaryExpression.argument.expression else { - throw CompilerError.invalidNodeError("delete operator must be applied to a member expression") + guard + case .memberExpression(let memberExpression) = unaryExpression.argument + .expression + else { + throw CompilerError.invalidNodeError( + "delete operator must be applied to a member expression") } let obj = try compileExpression(memberExpression.object) @@ -1191,7 +1372,8 @@ public class JavaScriptCompiler { } } else { guard let op = UnaryOperator(rawValue: unaryExpression.operator) else { - throw CompilerError.invalidNodeError("invalid unary operator: \(unaryExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid unary operator: \(unaryExpression.operator)") } let argument = try compileExpression(unaryExpression.argument) return emit(UnaryOperation(op), withInputs: [argument]).output @@ -1209,7 +1391,8 @@ public class JavaScriptCompiler { } else if binaryExpression.operator == "instanceof" { return emit(TestInstanceOf(), withInputs: [lhs, rhs]).output } else { - throw CompilerError.invalidNodeError("invalid binary operator: \(binaryExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid binary operator: \(binaryExpression.operator)") } case .updateExpression(let updateExpression): @@ -1221,7 +1404,8 @@ public class JavaScriptCompiler { stringOp += " " } guard let op = UnaryOperator(rawValue: stringOp) else { - throw CompilerError.invalidNodeError("invalid unary operator: \(updateExpression.operator)") + throw CompilerError.invalidNodeError( + "invalid unary operator: \(updateExpression.operator)") } return emit(UnaryOperation(op), withInputs: [argument]).output @@ -1242,15 +1426,18 @@ public class JavaScriptCompiler { return try sequenceExpression.expressions.map({ try compileExpression($0) }).last! case .v8IntrinsicIdentifier: - fatalError("V8IntrinsicIdentifiers must be handled as part of their surrounding CallExpression") + fatalError( + "V8IntrinsicIdentifiers must be handled as part of their surrounding CallExpression" + ) case .awaitExpression(let awaitExpression): - // TODO await is also allowed at the top level of a module - if !contextAnalyzer.context.contains(.asyncFunction) { - throw CompilerError.invalidNodeError("`await` is currently only supported in async functions") - } - let argument = try compileExpression(awaitExpression.argument) - return emit(Await(), withInputs: [argument]).output + // TODO await is also allowed at the top level of a module + if !contextAnalyzer.context.contains(.asyncFunction) { + throw CompilerError.invalidNodeError( + "`await` is currently only supported in async functions") + } + let argument = try compileExpression(awaitExpression.argument) + return emit(Await(), withInputs: [argument]).output } } @@ -1266,7 +1453,7 @@ public class JavaScriptCompiler { return code.append(instr) } - private func enterNewScope(_ block: () throws -> ()) rethrows { + private func enterNewScope(_ block: () throws -> Void) rethrows { scopes.push([:]) try block() scopes.pop() @@ -1286,7 +1473,9 @@ public class JavaScriptCompiler { scopes.top[identifier] = v } - private func mapParameters(_ parameters: Compiler_Protobuf_Parameters, to variables: ArraySlice) { + private func mapParameters( + _ parameters: Compiler_Protobuf_Parameters, to variables: ArraySlice + ) { assert(parameters.parameters.count == variables.count) for (param, v) in zip(parameters.parameters, variables) { map(param.name, to: v) @@ -1294,7 +1483,8 @@ public class JavaScriptCompiler { } private func convertParameters(_ parameters: Compiler_Protobuf_Parameters) -> Parameters { - return Parameters(count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) + return Parameters( + count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) } /// Convenience accessor for the currently active scope. diff --git a/Sources/Fuzzilli/Compiler/JavaScriptParser.swift b/Sources/Fuzzilli/Compiler/JavaScriptParser.swift index f6a12f15d..a1dc29450 100644 --- a/Sources/Fuzzilli/Compiler/JavaScriptParser.swift +++ b/Sources/Fuzzilli/Compiler/JavaScriptParser.swift @@ -37,7 +37,8 @@ public class JavaScriptParser { // This will only work if the executor is node as we will need to use node modules. // The Parser/ subdirectory is copied verbatim into the module bundle, see Package.swift. - self.parserScriptPath = Bundle.module.path(forResource: "parser", ofType: "js", inDirectory: "Parser")! + self.parserScriptPath = Bundle.module.path( + forResource: "parser", ofType: "js", inDirectory: "Parser")! // Check if the parser works. If not, it's likely because its node.js dependencies have not been installed. do { @@ -49,7 +50,8 @@ public class JavaScriptParser { public func parse(_ path: String) throws -> AST { let astProtobufDefinitionPath = Bundle.module.path(forResource: "ast", ofType: "proto")! - let outputFilePath = FileManager.default.temporaryDirectory.path + "/" + UUID().uuidString + ".ast.proto" + let outputFilePath = + FileManager.default.temporaryDirectory.path + "/" + UUID().uuidString + ".ast.proto" try runParserScript(withArguments: [astProtobufDefinitionPath, path, outputFilePath]) let data = try Data(contentsOf: URL(fileURLWithPath: outputFilePath)) try FileManager.default.removeItem(atPath: outputFilePath) diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 28c7eaad4..d6fa2d311 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -106,23 +106,25 @@ public struct Configuration { // be imported due to disabled wasm capabilities in the fuzzer. public static let excludedWasmDirectory = "excluded_wasm_programs" - public init(arguments: [String] = [], - timeout: UInt32 = 250, - skipStartupTests: Bool = false, - logLevel: LogLevel = .info, - startupTests: [(String, ExpectedStartupTestResult)] = [], - minimizationLimit: Double = 0.0, - dropoutRate: Double = 0, - collectRuntimeTypes: Bool = false, - enableDiagnostics: Bool = false, - enableInspection: Bool = false, - staticCorpus: Bool = false, - tag: String? = nil, - isWasmEnabled: Bool = false, - storagePath: String? = nil, - forDifferentialFuzzing: Bool = false, - instanceId: Int = -1, - dumplingEnabled: Bool = false) { + public init( + arguments: [String] = [], + timeout: UInt32 = 250, + skipStartupTests: Bool = false, + logLevel: LogLevel = .info, + startupTests: [(String, ExpectedStartupTestResult)] = [], + minimizationLimit: Double = 0.0, + dropoutRate: Double = 0, + collectRuntimeTypes: Bool = false, + enableDiagnostics: Bool = false, + enableInspection: Bool = false, + staticCorpus: Bool = false, + tag: String? = nil, + isWasmEnabled: Bool = false, + storagePath: String? = nil, + forDifferentialFuzzing: Bool = false, + instanceId: Int = -1, + dumplingEnabled: Bool = false + ) { self.arguments = arguments self.timeout = timeout self.logLevel = logLevel @@ -137,11 +139,14 @@ public struct Configuration { self.isWasmEnabled = isWasmEnabled self.storagePath = storagePath self.forDifferentialFuzzing = forDifferentialFuzzing - self.diffConfig = dumplingEnabled ? DifferentialConfig.create(for: instanceId, storagePath: storagePath!) : nil + self.diffConfig = + dumplingEnabled + ? DifferentialConfig.create(for: instanceId, storagePath: storagePath!) : nil } public func getInstanceSpecificArguments(forReferenceRunner: Bool) -> [String] { - return diffConfig.map { [$0.getDumpFilenameParameter(isOptimized: !forReferenceRunner)] } ?? [] + return diffConfig.map { [$0.getDumpFilenameParameter(isOptimized: !forReferenceRunner)] } + ?? [] } } diff --git a/Sources/Fuzzilli/Corpus/BasicCorpus.swift b/Sources/Fuzzilli/Corpus/BasicCorpus.swift index 2c4c6041f..eaa03d526 100644 --- a/Sources/Fuzzilli/Corpus/BasicCorpus.swift +++ b/Sources/Fuzzilli/Corpus/BasicCorpus.swift @@ -75,7 +75,7 @@ public class BasicCorpus: ComponentBase, Collection, Corpus { return true } - public func add(_ program: Program, _ : ProgramAspects) { + public func add(_ program: Program, _: ProgramAspects) { addInternal(program) } diff --git a/Sources/Fuzzilli/Corpus/Corpus.swift b/Sources/Fuzzilli/Corpus/Corpus.swift index 366b2dccd..0d72afbd6 100644 --- a/Sources/Fuzzilli/Corpus/Corpus.swift +++ b/Sources/Fuzzilli/Corpus/Corpus.swift @@ -18,7 +18,7 @@ import Foundation /// It manages discovered programs, determines the next seed to target, /// and provides programs to be used in the splice mutators -public protocol Corpus : ComponentBase { +public protocol Corpus: ComponentBase { var size: Int { get } var isEmpty: Bool { get } @@ -54,7 +54,9 @@ extension Corpus { if fuzzer.config.enableInspection { // Except for one identifying them as part of the corpus - program.comments.add("Corpus entry #\(index) on instance \(fuzzer.id) with Corpus type \(name)", at: .header) + program.comments.add( + "Corpus entry #\(index) on instance \(fuzzer.id) with Corpus type \(name)", + at: .header) } } } diff --git a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift index 8bec46d77..bbc069983 100644 --- a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift +++ b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift @@ -22,7 +22,7 @@ public class MarkovCorpus: ComponentBase, Corpus { private var programExecutionQueue: [Program] = [] // For each edge encountered thus far, track which program initially discovered it - private var edgeMap: [UInt32:Program] = [:] + private var edgeMap: [UInt32: Program] = [:] // This scheduler tracks the total number of samples it has returned // This allows it to build an initial baseline by randomly selecting a program to mutate @@ -137,7 +137,9 @@ public class MarkovCorpus: ComponentBase, Corpus { // Applies dropout on otherwise valid samples, to ensure variety between instances // This will likely select some samples multiple times, which is acceptable as // it is proportional to how many infrquently hit edges the sample has - if val != 0 && val <= maxEdgeCountToFind && (probability(1 - dropoutRate) || programExecutionQueue.isEmpty) { + if val != 0 && val <= maxEdgeCountToFind + && (probability(1 - dropoutRate) || programExecutionQueue.isEmpty) + { if let prog = edgeMap[UInt32(i)] { programExecutionQueue.append(prog) } diff --git a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift index 677256f53..430169bb2 100644 --- a/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift +++ b/Sources/Fuzzilli/DumplingDiffOracle/Oracle.swift @@ -68,7 +68,6 @@ // b:35 // a1:1 - import Foundation // This class is implementing one public function relate(optimizedOutput, unoptimizedOutput). @@ -129,13 +128,15 @@ public final class DiffOracle { guard self.bytecodeOffset == reference.bytecodeOffset, self.functionId == reference.functionId, self.arguments.count == reference.arguments.count, - self.registers.count == reference.registers.count else { + self.registers.count == reference.registers.count + else { return false } // Logic: 'self' is the Optimized frame. It is allowed to have "" or "". func isMatch(_ optValue: String, unoptValue: String) -> Bool { - return optValue == "" || optValue == "" || optValue == unoptValue + return optValue == "" || optValue == "" + || optValue == unoptValue } if !isMatch(self.accumulator, unoptValue: reference.accumulator) { @@ -161,7 +162,9 @@ public final class DiffOracle { _ runningRegs: inout [String] ) -> Frame { - func parseValue(prefix: String, defaultValue: T, index: inout Int, conversion: (Substring) -> T) -> T { + func parseValue( + prefix: String, defaultValue: T, index: inout Int, conversion: (Substring) -> T + ) -> T { if index < frameArr.endIndex && frameArr[index].starts(with: prefix) { let value = conversion(frameArr[index].dropFirst(prefix.count)) index += 1 @@ -172,13 +175,13 @@ public final class DiffOracle { var i = frameArr.startIndex func parseFrameType(_ type: Substring) -> FrameType { switch type { - case "---I": .interpreter - case "---S": .sparkplug - case "---M": .maglev - case "---T": .turbofan - case "---D": .deoptTurbofan - default: - fatalError("Unknown frame type") + case "---I": .interpreter + case "---S": .sparkplug + case "---M": .maglev + case "---T": .turbofan + case "---D": .deoptTurbofan + default: + fatalError("Unknown frame type") } } @@ -186,11 +189,21 @@ public final class DiffOracle { i += 1 - let bytecodeOffset = parseValue(prefix: "b:", defaultValue: prevFrame?.bytecodeOffset ?? -1, index: &i){ Int($0)! } - let functionId = parseValue(prefix: "f:", defaultValue: prevFrame?.functionId ?? -1, index: &i){ Int($0)! } - let accumulator = parseValue(prefix: "x:", defaultValue: prevFrame?.accumulator ?? "", index: &i){ String($0) } - let argCount = parseValue(prefix: "n:", defaultValue: prevFrame?.arguments.count ?? -1, index: &i){ Int($0)! } - let regCount = parseValue(prefix: "m:", defaultValue: prevFrame?.registers.count ?? -1, index: &i){ Int($0)! } + let bytecodeOffset = parseValue( + prefix: "b:", defaultValue: prevFrame?.bytecodeOffset ?? -1, index: &i + ) { Int($0)! } + let functionId = parseValue( + prefix: "f:", defaultValue: prevFrame?.functionId ?? -1, index: &i + ) { Int($0)! } + let accumulator = parseValue( + prefix: "x:", defaultValue: prevFrame?.accumulator ?? "", index: &i + ) { String($0) } + let argCount = parseValue( + prefix: "n:", defaultValue: prevFrame?.arguments.count ?? -1, index: &i + ) { Int($0)! } + let regCount = parseValue( + prefix: "m:", defaultValue: prevFrame?.registers.count ?? -1, index: &i + ) { Int($0)! } func updateValues(prefix: String, requiredCount: Int, buffer: inout [String]) -> [String] { @@ -201,7 +214,8 @@ public final class DiffOracle { } while i < frameArr.endIndex && frameArr[i].starts(with: prefix) { - let data = frameArr[i].dropFirst(1).split(separator: ":", maxSplits: 1, omittingEmptySubsequences: false) + let data = frameArr[i].dropFirst(1).split( + separator: ":", maxSplits: 1, omittingEmptySubsequences: false) let number = Int(data[0])! let value = String(data[1]) @@ -215,12 +229,13 @@ public final class DiffOracle { let arguments = updateValues(prefix: "a", requiredCount: argCount, buffer: &runningArgs) let registers = updateValues(prefix: "r", requiredCount: regCount, buffer: &runningRegs) - let frame = Frame(bytecodeOffset: bytecodeOffset, - accumulator: accumulator, - arguments: arguments, - registers: registers, - functionId: functionId, - frameType: frameType) + let frame = Frame( + bytecodeOffset: bytecodeOffset, + accumulator: accumulator, + arguments: arguments, + registers: registers, + functionId: functionId, + frameType: frameType) return frame } @@ -235,7 +250,9 @@ public final class DiffOracle { let frames = split.split(separator: "") for frame in frames { - assert(frame.first?.starts(with: "---") == true, "Invalid frame header found: \(frame.first ?? "nil")") + assert( + frame.first?.starts(with: "---") == true, + "Invalid frame header found: \(frame.first ?? "nil")") prevFrame = parseDiffFrame(frame, prevFrame, &runningArgs, &runningRegs) frameArray.append(prevFrame!) @@ -254,7 +271,9 @@ public final class DiffOracle { print("--------------------------") print("[") for unoptFrame in unoptFrames { - if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset && unoptFrame.functionId == optFrame.functionId { + if unoptFrame.bytecodeOffset == optFrame.bytecodeOffset + && unoptFrame.functionId == optFrame.functionId + { print(unoptFrame) } } diff --git a/Sources/Fuzzilli/Engines/FuzzEngine.swift b/Sources/Fuzzilli/Engines/FuzzEngine.swift index ce13aab1e..191c613cf 100644 --- a/Sources/Fuzzilli/Engines/FuzzEngine.swift +++ b/Sources/Fuzzilli/Engines/FuzzEngine.swift @@ -32,8 +32,10 @@ public class FuzzEngine: ComponentBase { fatalError("Must be implemented by child classes") } - final func execute(_ rawProgram: Program, withTimeout timeout: UInt32? = nil) -> ExecutionOutcome { - let program : Program + final func execute(_ rawProgram: Program, withTimeout timeout: UInt32? = nil) + -> ExecutionOutcome + { + let program: Program do { // An optional post processor can reject a sample right away with // the postProcessRejectionError. @@ -49,41 +51,48 @@ public class FuzzEngine: ComponentBase { let execution = fuzzer.execute(program, withTimeout: timeout, purpose: .fuzzing) switch execution.outcome { - case .crashed(let termsig): - fuzzer.processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local, withExectime: execution.execTime) - program.contributors.generatedCrashingSample() - - case .differential: - fuzzer.processDifferential(program, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local) - program.contributors.generatedDifferentialSample() - - case .succeeded: - fuzzer.dispatchEvent(fuzzer.events.ValidProgramFound, data: program) - var isInteresting = false - if let aspects = fuzzer.evaluator.evaluate(execution) { - if fuzzer.config.enableInspection { - program.comments.add("Program may be interesting due to \(aspects)", at: .footer) - program.comments.add("RUNNER ARGS: \(fuzzer.runner.processArguments.joined(separator: " "))", at: .header) - } - isInteresting = fuzzer.processMaybeInteresting(program, havingAspects: aspects, origin: .local) + case .crashed(let termsig): + fuzzer.processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: .local, withExectime: execution.execTime) + program.contributors.generatedCrashingSample() + + case .differential: + fuzzer.processDifferential( + program, withStderr: execution.stderr, withStdout: execution.stdout, origin: .local) + program.contributors.generatedDifferentialSample() + + case .succeeded: + fuzzer.dispatchEvent(fuzzer.events.ValidProgramFound, data: program) + var isInteresting = false + if let aspects = fuzzer.evaluator.evaluate(execution) { + if fuzzer.config.enableInspection { + program.comments.add( + "Program may be interesting due to \(aspects)", at: .footer) + program.comments.add( + "RUNNER ARGS: \(fuzzer.runner.processArguments.joined(separator: " "))", + at: .header) } - - if isInteresting { - program.contributors.generatedInterestingSample() - } else { - program.contributors.generatedValidSample() - } - - case .failed(_): - if fuzzer.config.enableDiagnostics { - program.comments.add("Stdout:\n" + execution.stdout, at: .footer) - } - fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: program) - program.contributors.generatedInvalidSample() - - case .timedOut: - fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: program) - program.contributors.generatedTimeOutSample() + isInteresting = fuzzer.processMaybeInteresting( + program, havingAspects: aspects, origin: .local) + } + + if isInteresting { + program.contributors.generatedInterestingSample() + } else { + program.contributors.generatedValidSample() + } + + case .failed(_): + if fuzzer.config.enableDiagnostics { + program.comments.add("Stdout:\n" + execution.stdout, at: .footer) + } + fuzzer.dispatchEvent(fuzzer.events.InvalidProgramFound, data: program) + program.contributors.generatedInvalidSample() + + case .timedOut: + fuzzer.dispatchEvent(fuzzer.events.TimeOutFound, data: program) + program.contributors.generatedTimeOutSample() } if fuzzer.config.enableDiagnostics { @@ -96,13 +105,16 @@ public class FuzzEngine: ComponentBase { private final func ensureDeterministicExecutionOutcomeForDiagnostic(of program: Program) { let execution1 = fuzzer.execute(program, purpose: .other) - let stdout1 = execution1.stdout, stderr1 = execution1.stderr + let stdout1 = execution1.stdout + let stderr1 = execution1.stderr let execution2 = fuzzer.execute(program, purpose: .other) switch (execution1.outcome, execution2.outcome) { case (.succeeded, .failed(_)), - (.failed(_), .succeeded): - let stdout2 = execution2.stdout, stderr2 = execution2.stderr - logger.warning(""" + (.failed(_), .succeeded): + let stdout2 = execution2.stdout + let stderr2 = execution2.stderr + logger.warning( + """ Non-deterministic execution detected for program \(fuzzer.lifter.lift(program)) // Stdout of first execution diff --git a/Sources/Fuzzilli/Engines/HybridEngine.swift b/Sources/Fuzzilli/Engines/HybridEngine.swift index 214ff67cb..3c57b68f4 100644 --- a/Sources/Fuzzilli/Engines/HybridEngine.swift +++ b/Sources/Fuzzilli/Engines/HybridEngine.swift @@ -57,11 +57,16 @@ public class HybridEngine: FuzzEngine { for template in self.fuzzer.programTemplates { let name = template.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Statistics.percentageOrNa(template.correctnessRate, 7) - let interestingSamplesRate = Statistics.percentageOrNa(template.interestingSamplesRate, 7) + let interestingSamplesRate = Statistics.percentageOrNa( + template.interestingSamplesRate, 7) let timeoutRate = Statistics.percentageOrNa(template.timeoutRate, 6) - let avgInstructionsAdded = String(format: "%.2f", template.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) + let avgInstructionsAdded = String( + format: "%.2f", template.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) let samplesGenerated = template.totalSamples - self.logger.verbose(" \(name) : Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions generated: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)") + self.logger.verbose( + " \(name) : Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions generated: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)" + ) } let totalOutcomes = self.outcomeCounts.values.reduce(0, +) @@ -69,13 +74,21 @@ public class HybridEngine: FuzzEngine { for outcome in CodeGenerationOutcome.allCases { let count = self.outcomeCounts[outcome]! let frequency = (Double(count) / Double(totalOutcomes)) * 100.0 - self.logger.verbose(" \(outcome.rawValue.rightPadded(toLength: 25)): \(String(format: "%.2f%%", frequency))") + self.logger.verbose( + " \(outcome.rawValue.rightPadded(toLength: 25)): \(String(format: "%.2f%%", frequency))" + ) } self.logger.verbose("Number of generated programs: \(self.programsGenerated)") - self.logger.verbose("Average programs size: \(self.totalInstructionsGenerated / self.programsGenerated)") - self.logger.verbose("Average percentage of guarded operations after code generation: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeGeneration.currentValue))%") - self.logger.verbose("Average percentage of guarded operations after code refining: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeRefining.currentValue))%") + self.logger.verbose( + "Average programs size: \(self.totalInstructionsGenerated / self.programsGenerated)" + ) + self.logger.verbose( + "Average percentage of guarded operations after code generation: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeGeneration.currentValue))%" + ) + self.logger.verbose( + "Average percentage of guarded operations after code refining: \(String(format: "%.2f%", self.percentageOfGuardedOperationsAfterCodeRefining.currentValue))%" + ) } } } @@ -99,7 +112,8 @@ public class HybridEngine: FuzzEngine { // Update basic codegen statistics. totalInstructionsGenerated += generatedProgram.size programsGenerated += 1 - percentageOfGuardedOperationsAfterCodeGeneration.add(computePercentageOfGuardedOperations(in: generatedProgram)) + percentageOfGuardedOperationsAfterCodeGeneration.add( + computePercentageOfGuardedOperations(in: generatedProgram)) // We use a higher timeout for the initial execution as pure code generation should only rarely lead to infinite loops/recursion. // On the other hand, the generated program may contain slow operations (e.g. try-catch guards) that the subsequent fixup may remove. @@ -125,7 +139,8 @@ public class HybridEngine: FuzzEngine { let refinedProgram: Program if let result = fixupMutator.mutate(generatedProgram, for: fuzzer) { refinedProgram = result - percentageOfGuardedOperationsAfterCodeRefining.add(computePercentageOfGuardedOperations(in: refinedProgram)) + percentageOfGuardedOperationsAfterCodeRefining.add( + computePercentageOfGuardedOperations(in: refinedProgram)) } else { // Fixup is expected to fail sometimes, for example if there is nothing to fix. refinedProgram = generatedProgram @@ -155,7 +170,8 @@ public class HybridEngine: FuzzEngine { } guard let program = mutatedProgram else { - logger.warning("Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") + logger.warning( + "Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") continue } diff --git a/Sources/Fuzzilli/Engines/MultiEngine.swift b/Sources/Fuzzilli/Engines/MultiEngine.swift index 2eab72945..625776291 100644 --- a/Sources/Fuzzilli/Engines/MultiEngine.swift +++ b/Sources/Fuzzilli/Engines/MultiEngine.swift @@ -29,7 +29,10 @@ public class MultiEngine: FuzzEngine { /// The number of fuzzing iterations. private var currentIteration = 0 - public init(engines: WeightedList, initialActive: FuzzEngine? = nil, iterationsPerEngine: Int) { + public init( + engines: WeightedList, initialActive: FuzzEngine? = nil, + iterationsPerEngine: Int + ) { assert(iterationsPerEngine > 0) self.iterationsPerEngine = iterationsPerEngine self.engines = engines @@ -49,7 +52,8 @@ public class MultiEngine: FuzzEngine { if currentIteration % iterationsPerEngine == 0 { let nextEngine = engines.randomElement() if nextEngine !== activeEngine { - logger.info("Switching active engine from \(activeEngine.name) to \(nextEngine.name)") + logger.info( + "Switching active engine from \(activeEngine.name) to \(nextEngine.name)") activeEngine = nextEngine } } diff --git a/Sources/Fuzzilli/Engines/MutationEngine.swift b/Sources/Fuzzilli/Engines/MutationEngine.swift index a02176bee..6975f8c77 100644 --- a/Sources/Fuzzilli/Engines/MutationEngine.swift +++ b/Sources/Fuzzilli/Engines/MutationEngine.swift @@ -67,7 +67,8 @@ public class MutationEngine: FuzzEngine { } guard let program = mutatedProgram else { - logger.warning("Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") + logger.warning( + "Could not mutate sample, giving up. Sample:\n\(FuzzILLifter().lift(parent))") continue } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index cb052d76f..05a1c753b 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -16,7 +16,9 @@ import Foundation public class JavaScriptEnvironment: ComponentBase { // Possible return values of the 'typeof' operator. - public static let jsTypeNames = ["undefined", "boolean", "number", "string", "symbol", "function", "object", "bigint"] + public static let jsTypeNames = [ + "undefined", "boolean", "number", "string", "symbol", "function", "object", "bigint", + ] // TODO: use it in all places where it can be used. public static let typedArrayConstructors = [ @@ -27,36 +29,45 @@ public class JavaScriptEnvironment: ComponentBase { // Integer values that are more likely to trigger edge-cases. public static let InterestingIntegers: [Int64] = [ - -9223372036854775808, -9223372036854775807, // Int64 min, mostly for BigInts - -9007199254740992, -9007199254740991, -9007199254740990, // Smallest integer value that is still precisely representable by a double - -4294967297, -4294967296, -4294967295, // Negative Uint32 max - -2147483649, -2147483648, -2147483647, // Int32 min - -1073741824, -536870912, -268435456, // -2**32 / {4, 8, 16} - -65537, -65536, -65535, // -2**16 - -4096, -1024, -256, -128, // Other powers of two - -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 - 127, 128, 129, // 2**7 - 255, 256, 257, // 2**8 - 512, 1000, 1024, 4096, 10000, // Misc numbers - 65535, 65536, 65537, // 2**16 - 268435439, 268435440, 268435441, // V8 String kMaxLength (32-bit) - 536870887, 536870888, 536870889, // V8 String kMaxLength (64-bit) - 268435456, 536870912, 1073741824, // 2**32 / {4, 8, 16} - 1073741823, 1073741824, 1073741825, // 2**30 - 2147483647, 2147483648, 2147483649, // Int32 max - 4294967295, 4294967296, 4294967297, // Uint32 max - 9007199254740990, 9007199254740991, 9007199254740992, // Biggest integer value that is still precisely representable by a double - 9223372036854775807, // Int64 max, mostly for BigInts - 0x3ffffffc, 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000002, // Numbers around smi max (2^30 - 1) - 0xbffffffd, 0xbfffffff, 0xc0000000, 0xc0000001, 0xc0000003 // Numbers around Smi min (-2^30) + -9_223_372_036_854_775_808, -9_223_372_036_854_775_807, // Int64 min, mostly for BigInts + -9_007_199_254_740_992, -9_007_199_254_740_991, -9_007_199_254_740_990, // Smallest integer value that is still precisely representable by a double + -4_294_967_297, -4_294_967_296, -4_294_967_295, // Negative Uint32 max + -2_147_483_649, -2_147_483_648, -2_147_483_647, // Int32 min + -1_073_741_824, -536_870_912, -268_435_456, // -2**32 / {4, 8, 16} + -65537, -65536, -65535, // -2**16 + -4096, -1024, -256, -128, // Other powers of two + -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 64, // Numbers around 0 + 127, 128, 129, // 2**7 + 255, 256, 257, // 2**8 + 512, 1000, 1024, 4096, 10000, // Misc numbers + 65535, 65536, 65537, // 2**16 + 268_435_439, 268_435_440, 268_435_441, // V8 String kMaxLength (32-bit) + 536_870_887, 536_870_888, 536_870_889, // V8 String kMaxLength (64-bit) + 268_435_456, 536_870_912, 1_073_741_824, // 2**32 / {4, 8, 16} + 1_073_741_823, 1_073_741_824, 1_073_741_825, // 2**30 + 2_147_483_647, 2_147_483_648, 2_147_483_649, // Int32 max + 4_294_967_295, 4_294_967_296, 4_294_967_297, // Uint32 max + 9_007_199_254_740_990, 9_007_199_254_740_991, 9_007_199_254_740_992, // Biggest integer value that is still precisely representable by a double + 9_223_372_036_854_775_807, // Int64 max, mostly for BigInts + 0x3fff_fffc, 0x3fff_fffe, 0x3fff_ffff, 0x4000_0000, 0x4000_0002, // Numbers around smi max (2^30 - 1) + 0xbfff_fffd, 0xbfff_ffff, 0xc000_0000, 0xc000_0001, 0xc000_0003, // Numbers around Smi min (-2^30) ] - static let wellKnownSymbols = ["iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", "hasInstance", "isConcatSpreadable", "unscopables", "species", "toPrimitive", "toStringTag", "dispose", "asyncDispose"] + static let wellKnownSymbols = [ + "iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", + "hasInstance", "isConcatSpreadable", "unscopables", "species", "toPrimitive", "toStringTag", + "dispose", "asyncDispose", + ] public let interestingIntegers = InterestingIntegers // Double values that are more likely to trigger edge-cases. - public let interestingFloats = [-Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan] + public let interestingFloats = [ + -Double.infinity, -Double.greatestFiniteMagnitude, -1e-15, -1e12, -1e9, -1e6, -1e3, -5.0, + -4.0, -3.0, -2.0, -1.0, -Double.ulpOfOne, -Double.leastNormalMagnitude, -0.0, 0.0, + Double.leastNormalMagnitude, Double.ulpOfOne, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6, 1e9, 1e12, + 1e-15, Double.greatestFiniteMagnitude, Double.infinity, Double.nan, + ] // TODO more? public let interestingStrings = jsTypeNames + [""] @@ -65,227 +76,230 @@ public class JavaScriptEnvironment: ComponentBase { // https://cs.chromium.org/chromium/src/testing/libfuzzer/fuzzers/dicts/regexp.dict public let interestingRegExps = [ // These do *not* work with unicode or unicodeSets - (pattern: #"a\q"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[z-\d]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\11"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\111]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c!"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\11a]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c!]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c~]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\[\]\{\}\(\)\%\^\#\ "#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\[\]\{\}\(\)\%\^\#\ ]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\118"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\00011]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c~"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{,}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[-123]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[-\xf0\x9f\x92\xa9]+"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{,}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{12,"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?!a)?a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\111"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?!a)?a\1"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\1111]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c1]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){0,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\q"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\011"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\d-z]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\011]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\8"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\11a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\118]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\1112"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{12,"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\d-\d]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\11"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)\4*"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?:(?=a))a\1"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c_"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"a{"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(x)(x)(x)\4"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\c"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\x3z"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\c_]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{1z}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){1,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\1111"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\u003z"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[\11]"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"\9"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"{}"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"(?=a){9,10}a"#, incompatibleFlags: .unicode | .unicodeSets), - (pattern: #"[a-b-c]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a\q"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[z-\d]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{"#, incompatibleFlags: .unicode | .unicodeSets), + ( + pattern: #"(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\11"#, + incompatibleFlags: .unicode | .unicodeSets + ), + (pattern: #"[\111]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c!"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\11a]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c!]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c~]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\[\]\{\}\(\)\%\^\#\ "#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\[\]\{\}\(\)\%\^\#\ ]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\118"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\00011]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c~"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{,}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[-123]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[-\xf0\x9f\x92\xa9]+"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{,}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{12,"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?!a)?a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\111"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?!a)?a\1"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\1111]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12,3b"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c1]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){0,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\q"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\011"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\d-z]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\011]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\8"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\11a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\118]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\1112"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{12,"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\d-\d]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\11"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(x)(x)(x)\4*"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?:(?=a))a\1"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c_"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"a{"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(x)(x)(x)\4"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\c"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\x3z"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\c_]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{1z}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){1,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\1111"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\u003z"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[\11]"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"\9"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"{}"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"(?=a){9,10}a"#, incompatibleFlags: .unicode | .unicodeSets), + (pattern: #"[a-b-c]"#, incompatibleFlags: .unicode | .unicodeSets), // These work with all flags - (pattern: #"(x)(x)(x)\1*"#, incompatibleFlags: .empty), - (pattern: #"\x01"#, incompatibleFlags: .empty), - (pattern: #"(?: foo )"#, incompatibleFlags: .empty), - (pattern: #"(ab|cde)"#, incompatibleFlags: .empty), - (pattern: #"foo|(bar|baz)|quux"#, incompatibleFlags: .empty), - (pattern: #"(?:a*)*"#, incompatibleFlags: .empty), - (pattern: #"a{0,1}?"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)?"#, incompatibleFlags: .empty), - (pattern: #"a$"#, incompatibleFlags: .empty), - (pattern: #"a(?=b)"#, incompatibleFlags: .empty), - (pattern: #"foo[z]*"#, incompatibleFlags: .empty), - (pattern: #"\u{12345}\u{23456}"#, incompatibleFlags: .empty), - (pattern: #"(?!(a))\1"#, incompatibleFlags: .empty), - (pattern: #"abc+?"#, incompatibleFlags: .empty), - (pattern: #"a*b"#, incompatibleFlags: .empty), - (pattern: #"(?:a?)*"#, incompatibleFlags: .empty), - (pattern: #"\xf0\x9f\x92\xa9"#, incompatibleFlags: .empty), - (pattern: #"a{1,2}?"#, incompatibleFlags: .empty), - (pattern: #"a\n"#, incompatibleFlags: .empty), - (pattern: #"\P{Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"(?=)"#, incompatibleFlags: .empty), - (pattern: #"\1(a)"#, incompatibleFlags: .empty), - (pattern: #"."#, incompatibleFlags: .empty), - (pattern: #"()"#, incompatibleFlags: .empty), - (pattern: #"(a)"#, incompatibleFlags: .empty), - (pattern: #"(?:a{5,1000000}){3,1000000}"#, incompatibleFlags: .empty), - (pattern: #"a\Sc"#, incompatibleFlags: .empty), - (pattern: #"a(?=b)c"#, incompatibleFlags: .empty), - (pattern: #"a{0}"#, incompatibleFlags: .empty), - (pattern: #"(?:a*)+"#, incompatibleFlags: .empty), - (pattern: #"\ud808\udf45*"#, incompatibleFlags: .empty), - (pattern: #"a\w"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)*"#, incompatibleFlags: .empty), - (pattern: #"a(?:b)"#, incompatibleFlags: .empty), - (pattern: #"(?<=a)"#, incompatibleFlags: .empty), - (pattern: #"(x)(x)(x)\3"#, incompatibleFlags: .empty), - (pattern: #"foo(?<=bar)baz"#, incompatibleFlags: .empty), - (pattern: #"\xe2\x81\xa3"#, incompatibleFlags: .empty), - (pattern: #"ab\b\d\bcd"#, incompatibleFlags: .empty), - (pattern: #"[\ca]"#, incompatibleFlags: .empty), - (pattern: #"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\xbf]"#, incompatibleFlags: .empty), - (pattern: #"\p{Script_Extensions=Greek}"#, incompatibleFlags: .empty), - (pattern: #"\cj\cJ\ci\cI\ck\cK"#, incompatibleFlags: .empty), - (pattern: #"a\fb\nc\rd\te\vf"#, incompatibleFlags: .empty), - (pattern: #"\p{General_Category=Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"\u{12345}"#, incompatibleFlags: .empty), - (pattern: #"a\b!"#, incompatibleFlags: .empty), - (pattern: #"a[^a]"#, incompatibleFlags: .empty), - (pattern: #"\1\2(a(?:\1(b\1\2))\2)\1"#, incompatibleFlags: .empty), - (pattern: #"(?:ab)+"#, incompatibleFlags: .empty), - (pattern: #"[^123]"#, incompatibleFlags: .empty), - (pattern: #"a(?!b)"#, incompatibleFlags: .empty), - (pattern: #"a\Bb"#, incompatibleFlags: .empty), - (pattern: #"(?:ab)?"#, incompatibleFlags: .empty), - (pattern: #"(?)"#, incompatibleFlags: .empty), - (pattern: #"(?.)"#, incompatibleFlags: .empty), - (pattern: #"[\cz]"#, incompatibleFlags: .empty), - (pattern: #"(x)(x)(x)\3*"#, incompatibleFlags: .empty), - (pattern: #"foo(?.)\k"#, incompatibleFlags: .empty), - (pattern: #"(?:a+)+"#, incompatibleFlags: .empty), - (pattern: #"(?=.)"#, incompatibleFlags: .empty), - (pattern: #"\p{Changes_When_NFKC_Casefolded}"#, incompatibleFlags: .empty), - (pattern: #"a\sc"#, incompatibleFlags: .empty), - (pattern: #"a||bc"#, incompatibleFlags: .empty), - (pattern: #"a+b"#, incompatibleFlags: .empty), - (pattern: #"[\cZ]"#, incompatibleFlags: .empty), - (pattern: #"a|b"#, incompatibleFlags: .empty), - (pattern: #"\u0034"#, incompatibleFlags: .empty), - (pattern: #"\cA"#, incompatibleFlags: .empty), - (pattern: #"ab|c"#, incompatibleFlags: .empty), - (pattern: #"abc|def|ghi"#, incompatibleFlags: .empty), - (pattern: #"(?:ab|cde)"#, incompatibleFlags: .empty), - (pattern: #"xyz?"#, incompatibleFlags: .empty), - (pattern: #"[a-zA-Z0-9]"#, incompatibleFlags: .empty), - (pattern: #"(?:a?)?"#, incompatibleFlags: .empty), - (pattern: #"xyz{0,1}"#, incompatibleFlags: .empty), - (pattern: #"a\D"#, incompatibleFlags: .empty), - (pattern: #"(?!\1(a\1)\1)\1"#, incompatibleFlags: .empty), - (pattern: #"a\bc"#, incompatibleFlags: .empty), - (pattern: #"\P{gc=Decimal_Number}"#, incompatibleFlags: .empty), - (pattern: #"\b"#, incompatibleFlags: .empty), - (pattern: #"[x]"#, incompatibleFlags: .empty), - (pattern: #"(?:ab){4,7}"#, incompatibleFlags: .empty), - (pattern: #"a??"#, incompatibleFlags: .empty), - (pattern: #"(?(?(?(?.).).).)"#, incompatibleFlags: .empty), - (pattern: #"[\xe2\x81\xa3]"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\1*"#, incompatibleFlags: .empty), + (pattern: #"\x01"#, incompatibleFlags: .empty), + (pattern: #"(?: foo )"#, incompatibleFlags: .empty), + (pattern: #"(ab|cde)"#, incompatibleFlags: .empty), + (pattern: #"foo|(bar|baz)|quux"#, incompatibleFlags: .empty), + (pattern: #"(?:a*)*"#, incompatibleFlags: .empty), + (pattern: #"a{0,1}?"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)?"#, incompatibleFlags: .empty), + (pattern: #"a$"#, incompatibleFlags: .empty), + (pattern: #"a(?=b)"#, incompatibleFlags: .empty), + (pattern: #"foo[z]*"#, incompatibleFlags: .empty), + (pattern: #"\u{12345}\u{23456}"#, incompatibleFlags: .empty), + (pattern: #"(?!(a))\1"#, incompatibleFlags: .empty), + (pattern: #"abc+?"#, incompatibleFlags: .empty), + (pattern: #"a*b"#, incompatibleFlags: .empty), + (pattern: #"(?:a?)*"#, incompatibleFlags: .empty), + (pattern: #"\xf0\x9f\x92\xa9"#, incompatibleFlags: .empty), + (pattern: #"a{1,2}?"#, incompatibleFlags: .empty), + (pattern: #"a\n"#, incompatibleFlags: .empty), + (pattern: #"\P{Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"(?=)"#, incompatibleFlags: .empty), + (pattern: #"\1(a)"#, incompatibleFlags: .empty), + (pattern: #"."#, incompatibleFlags: .empty), + (pattern: #"()"#, incompatibleFlags: .empty), + (pattern: #"(a)"#, incompatibleFlags: .empty), + (pattern: #"(?:a{5,1000000}){3,1000000}"#, incompatibleFlags: .empty), + (pattern: #"a\Sc"#, incompatibleFlags: .empty), + (pattern: #"a(?=b)c"#, incompatibleFlags: .empty), + (pattern: #"a{0}"#, incompatibleFlags: .empty), + (pattern: #"(?:a*)+"#, incompatibleFlags: .empty), + (pattern: #"\ud808\udf45*"#, incompatibleFlags: .empty), + (pattern: #"a\w"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)*"#, incompatibleFlags: .empty), + (pattern: #"a(?:b)"#, incompatibleFlags: .empty), + (pattern: #"(?<=a)"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\3"#, incompatibleFlags: .empty), + (pattern: #"foo(?<=bar)baz"#, incompatibleFlags: .empty), + (pattern: #"\xe2\x81\xa3"#, incompatibleFlags: .empty), + (pattern: #"ab\b\d\bcd"#, incompatibleFlags: .empty), + (pattern: #"[\ca]"#, incompatibleFlags: .empty), + (pattern: #"[\xf0\x9f\x92\xa9-\xf4\x8f\xbf\xbf]"#, incompatibleFlags: .empty), + (pattern: #"\p{Script_Extensions=Greek}"#, incompatibleFlags: .empty), + (pattern: #"\cj\cJ\ci\cI\ck\cK"#, incompatibleFlags: .empty), + (pattern: #"a\fb\nc\rd\te\vf"#, incompatibleFlags: .empty), + (pattern: #"\p{General_Category=Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"\u{12345}"#, incompatibleFlags: .empty), + (pattern: #"a\b!"#, incompatibleFlags: .empty), + (pattern: #"a[^a]"#, incompatibleFlags: .empty), + (pattern: #"\1\2(a(?:\1(b\1\2))\2)\1"#, incompatibleFlags: .empty), + (pattern: #"(?:ab)+"#, incompatibleFlags: .empty), + (pattern: #"[^123]"#, incompatibleFlags: .empty), + (pattern: #"a(?!b)"#, incompatibleFlags: .empty), + (pattern: #"a\Bb"#, incompatibleFlags: .empty), + (pattern: #"(?:ab)?"#, incompatibleFlags: .empty), + (pattern: #"(?)"#, incompatibleFlags: .empty), + (pattern: #"(?.)"#, incompatibleFlags: .empty), + (pattern: #"[\cz]"#, incompatibleFlags: .empty), + (pattern: #"(x)(x)(x)\3*"#, incompatibleFlags: .empty), + (pattern: #"foo(?.)\k"#, incompatibleFlags: .empty), + (pattern: #"(?:a+)+"#, incompatibleFlags: .empty), + (pattern: #"(?=.)"#, incompatibleFlags: .empty), + (pattern: #"\p{Changes_When_NFKC_Casefolded}"#, incompatibleFlags: .empty), + (pattern: #"a\sc"#, incompatibleFlags: .empty), + (pattern: #"a||bc"#, incompatibleFlags: .empty), + (pattern: #"a+b"#, incompatibleFlags: .empty), + (pattern: #"[\cZ]"#, incompatibleFlags: .empty), + (pattern: #"a|b"#, incompatibleFlags: .empty), + (pattern: #"\u0034"#, incompatibleFlags: .empty), + (pattern: #"\cA"#, incompatibleFlags: .empty), + (pattern: #"ab|c"#, incompatibleFlags: .empty), + (pattern: #"abc|def|ghi"#, incompatibleFlags: .empty), + (pattern: #"(?:ab|cde)"#, incompatibleFlags: .empty), + (pattern: #"xyz?"#, incompatibleFlags: .empty), + (pattern: #"[a-zA-Z0-9]"#, incompatibleFlags: .empty), + (pattern: #"(?:a?)?"#, incompatibleFlags: .empty), + (pattern: #"xyz{0,1}"#, incompatibleFlags: .empty), + (pattern: #"a\D"#, incompatibleFlags: .empty), + (pattern: #"(?!\1(a\1)\1)\1"#, incompatibleFlags: .empty), + (pattern: #"a\bc"#, incompatibleFlags: .empty), + (pattern: #"\P{gc=Decimal_Number}"#, incompatibleFlags: .empty), + (pattern: #"\b"#, incompatibleFlags: .empty), + (pattern: #"[x]"#, incompatibleFlags: .empty), + (pattern: #"(?:ab){4,7}"#, incompatibleFlags: .empty), + (pattern: #"a??"#, incompatibleFlags: .empty), + (pattern: #"(?(?(?(?.).).).)"#, incompatibleFlags: .empty), + (pattern: #"[\xe2\x81\xa3]"#, incompatibleFlags: .empty), ] public let interestingRegExpQuantifiers = ["*", "+", "?"] @@ -302,7 +316,6 @@ public class JavaScriptEnvironment: ComponentBase { public private(set) var builtinProperties = Set() public private(set) var builtinMethods = Set() - // Something that can generate a variable public typealias EnvironmentValueGenerator = (ProgramBuilder) -> Variable @@ -311,7 +324,8 @@ public class JavaScriptEnvironment: ComponentBase { private var enums: [String: ILType] = [:] // Producing generators, keyed on `type.group` - private var producingGenerators: [String: (generator: EnvironmentValueGenerator, probability: Double)] = [:] + private var producingGenerators: + [String: (generator: EnvironmentValueGenerator, probability: Double)] = [:] // Named string generators, keyed on `type.group` private var namedStringGenerators: [String: () -> String] = [:] private var producingMethods: [ILType: [(group: String, method: String)]] = [:] @@ -341,7 +355,10 @@ public class JavaScriptEnvironment: ComponentBase { static let propertyIndex = try! Regex("^(\(index))$") } - public init(additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], additionalEnumerations: [ILType] = []) { + public init( + additionalBuiltins: [String: ILType] = [:], additionalObjectGroups: [ObjectGroup] = [], + additionalEnumerations: [ILType] = [] + ) { super.init(name: "JavaScriptEnvironment") @@ -393,7 +410,11 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsAsyncDisposableStackConstructor) registerObjectGroup(.jsArrayBuffers) registerObjectGroup(.jsSharedArrayBuffers) - for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { + for variant in [ + "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", + "BigUint64Array", + ] { registerObjectGroup(.jsTypedArrays(variant)) registerObjectGroup(.jsTypedArrayPrototype(variant)) registerObjectGroup(.jsTypedArrayConstructor(variant)) @@ -426,7 +447,10 @@ public class JavaScriptEnvironment: ComponentBase { registerObjectGroup(.jsArrayBufferPrototype) registerObjectGroup(.jsSharedArrayBufferConstructor) registerObjectGroup(.jsSharedArrayBufferPrototype) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "AggregateError", "URIError", "SuppressedError"] { + for variant in [ + "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", + "AggregateError", "URIError", "SuppressedError", + ] { registerObjectGroup(.jsError(variant)) registerObjectGroup(.jsErrorPrototype(variant)) registerObjectGroup(.jsErrorConstructor(variant)) @@ -595,44 +619,80 @@ public class JavaScriptEnvironment: ComponentBase { registerOptionsBag(.jsIntlLocaleMatcherSettings) registerOptionsBag(.jsIteratorZipSettings) - registerTemporalFieldsObject(.jsTemporalPlainTimeLikeObject, forWith: false, dateFields: false, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateLikeObject, forWith: false, dateFields: true, timeFields: false, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateLikeObjectForWith, forWith: true, dateFields: true, timeFields: false, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalPlainDateTimeLikeObjectForWith, forWith: true, dateFields: true, timeFields: true, zonedFields: false) - registerTemporalFieldsObject(.jsTemporalZonedDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, zonedFields: true) - registerTemporalFieldsObject(.jsTemporalZonedDateTimeLikeObjectForWith, forWith: true, dateFields: true, timeFields: true, zonedFields: true) + registerTemporalFieldsObject( + .jsTemporalPlainTimeLikeObject, forWith: false, dateFields: false, timeFields: true, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateLikeObject, forWith: false, dateFields: true, timeFields: false, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateLikeObjectForWith, forWith: true, dateFields: true, + timeFields: false, zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, + zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalPlainDateTimeLikeObjectForWith, forWith: true, dateFields: true, + timeFields: true, zonedFields: false) + registerTemporalFieldsObject( + .jsTemporalZonedDateTimeLikeObject, forWith: false, dateFields: true, timeFields: true, + zonedFields: true) + registerTemporalFieldsObject( + .jsTemporalZonedDateTimeLikeObjectForWith, forWith: true, dateFields: true, + timeFields: true, zonedFields: true) // This isn't a normal "temporal fields object" but is similar, and needs a similar producing generator registerObjectGroup(.jsTemporalDurationLikeObject) - addProducingGenerator(forType: ObjectGroup.jsTemporalDurationLikeObject.instanceType, with: { b in b.createTemporalDurationFieldsObject() }) - addNamedStringGenerator(forType: ObjectGroup.jsTemporalTimeZoneLike, - with: { - if Bool.random() { - return ProgramBuilder.randomTimeZoneString() - } else { - return ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: true) - } - }) - addNamedStringGenerator(forType: .jsIntlLocaleString, with: { ProgramBuilder.constructIntlLocaleString() }) - addNamedStringGenerator(forType: .jsIntlLanguageString, with: { ProgramBuilder.constructIntlLanguageString() }) - addNamedStringGenerator(forType: .jsIntlScriptString, with: { ProgramBuilder.constructIntlScriptString() }) - addNamedStringGenerator(forType: .jsIntlRegionString, with: { ProgramBuilder.constructIntlRegionString() }) - addNamedStringGenerator(forType: .jsIntlVariantString, with: { ProgramBuilder.constructIntlVariantString() }) - addNamedStringGenerator(forType: .jsIntlUnitString, with: { ProgramBuilder.constructIntlUnit() }) + addProducingGenerator( + forType: ObjectGroup.jsTemporalDurationLikeObject.instanceType, + with: { b in b.createTemporalDurationFieldsObject() }) + addNamedStringGenerator( + forType: ObjectGroup.jsTemporalTimeZoneLike, + with: { + if Bool.random() { + return ProgramBuilder.randomTimeZoneString() + } else { + return ProgramBuilder.randomUTCOffsetString(mayHaveSeconds: true) + } + }) + addNamedStringGenerator( + forType: .jsIntlLocaleString, with: { ProgramBuilder.constructIntlLocaleString() }) + addNamedStringGenerator( + forType: .jsIntlLanguageString, with: { ProgramBuilder.constructIntlLanguageString() }) + addNamedStringGenerator( + forType: .jsIntlScriptString, with: { ProgramBuilder.constructIntlScriptString() }) + addNamedStringGenerator( + forType: .jsIntlRegionString, with: { ProgramBuilder.constructIntlRegionString() }) + addNamedStringGenerator( + forType: .jsIntlVariantString, with: { ProgramBuilder.constructIntlVariantString() }) + addNamedStringGenerator( + forType: .jsIntlUnitString, with: { ProgramBuilder.constructIntlUnit() }) // Temporal types are produced by a large number of methods; which means findOrGenerateType(), when asked to produce // a Temporal type, will tend towards trying to call a method on another Temporal type, which needs more Temporal types, // leading to a large amount of code generated. We do wish to test these codepaths as well, but by and large we // just want a freshly generated type. - addProducingGenerator(forType: .jsTemporalInstant, with: { $0.constructTemporalInstant() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalDuration, with: { $0.constructTemporalDuration() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainTime, with: { $0.constructTemporalTime() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainYearMonth, with: { $0.constructTemporalYearMonth() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainMonthDay, with: { $0.constructTemporalMonthDay() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainDate, with: { $0.constructTemporalDate() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalPlainDateTime, with: { $0.constructTemporalDateTime() }, probability: 0.9) - addProducingGenerator(forType: .jsTemporalZonedDateTime, with: { $0.constructTemporalZonedDateTime() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalInstant, with: { $0.constructTemporalInstant() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalDuration, with: { $0.constructTemporalDuration() }, probability: 0.9 + ) + addProducingGenerator( + forType: .jsTemporalPlainTime, with: { $0.constructTemporalTime() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainYearMonth, with: { $0.constructTemporalYearMonth() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainMonthDay, with: { $0.constructTemporalMonthDay() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainDate, with: { $0.constructTemporalDate() }, probability: 0.9) + addProducingGenerator( + forType: .jsTemporalPlainDateTime, with: { $0.constructTemporalDateTime() }, + probability: 0.9) + addProducingGenerator( + forType: .jsTemporalZonedDateTime, with: { $0.constructTemporalZonedDateTime() }, + probability: 0.9) // Register builtins that should be available for fuzzing. // Here it is easy to selectively disable/enable some APIs for fuzzing by @@ -647,12 +707,19 @@ public class JavaScriptEnvironment: ComponentBase { registerBuiltin("Iterator", ofType: .jsIteratorConstructor) registerBuiltin("BigInt", ofType: .jsBigIntConstructor) registerBuiltin("RegExp", ofType: .jsRegExpConstructor) - for variant in ["Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "SuppressedError", "AggregateError"] { + for variant in [ + "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", + "URIError", "SuppressedError", "AggregateError", + ] { registerBuiltin(variant, ofType: .jsErrorConstructor(variant)) } registerBuiltin("ArrayBuffer", ofType: .jsArrayBufferConstructor) registerBuiltin("SharedArrayBuffer", ofType: .jsSharedArrayBufferConstructor) - for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array"] { + for variant in [ + "Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", + "Float16Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "BigInt64Array", + "BigUint64Array", + ] { registerBuiltin(variant, ofType: .jsTypedArrayConstructor(variant)) } registerBuiltin("DataView", ofType: .jsDataViewConstructor) @@ -713,25 +780,31 @@ public class JavaScriptEnvironment: ComponentBase { logger.info("Initialized static JS environment model") logger.info("Have \(builtins.count) available builtins: \(builtins.sorted())") logger.info("Have \(groups.count) different object groups: \(groups.keys.sorted())") - logger.info("Have \(builtinProperties.count) builtin property names: \(builtinProperties.sorted())") + logger.info( + "Have \(builtinProperties.count) builtin property names: \(builtinProperties.sorted())") logger.info("Have \(builtinMethods.count) builtin method names: \(builtinMethods.sorted())") - logger.info("Have \(customProperties.count) custom property names: \(customProperties.sorted())") + logger.info( + "Have \(customProperties.count) custom property names: \(customProperties.sorted())") logger.info("Have \(customMethods.count) custom method names: \(customMethods.sorted())") - logger.info("Have \(customPrivateMethods.count) custom private method names: \(customPrivateMethods.sorted())") + logger.info( + "Have \(customPrivateMethods.count) custom private method names: \(customPrivateMethods.sorted())" + ) } func checkConstructorAvailability() { logger.info("Checking constructor availability...") // These constructors return types that are well-known instead of .object types. let knownExceptions = [ - "Boolean", // returns .boolean - "Number", // returns .number - "Object", // returns plain .object - "Proxy", // returns .jsAnything + "Boolean", // returns .boolean + "Number", // returns .number + "Object", // returns plain .object + "Proxy", // returns .jsAnything ] for builtin in builtins where type(ofBuiltin: builtin).Is(.constructor()) { if knownExceptions.contains(builtin) { continue } - if !hasGroup(builtin) { logger.warning("Missing group info for constructable \(builtin)")} + if !hasGroup(builtin) { + logger.warning("Missing group info for constructable \(builtin)") + } if type(ofBuiltin: builtin).signature == nil { logger.warning("Missing signature for builtin \(builtin)") } else { @@ -764,25 +837,36 @@ public class JavaScriptEnvironment: ComponentBase { // - Temporal objects: These can be obtained from the result of other API calls, however a // a lot of these API calls need more Temporal objects, leading to runaway recursion attempting // to generate a large number of Temporal objects. Instead, we bias heavily towards the producing generator. - public func addProducingGenerator(forType type: ILType, with generator: @escaping EnvironmentValueGenerator, probability: Double = 1.0) { - assert(type.Is(.object()), "Producing generators can only be registered for objects, found \(type)") + public func addProducingGenerator( + forType type: ILType, with generator: @escaping EnvironmentValueGenerator, + probability: Double = 1.0 + ) { + assert( + type.Is(.object()), + "Producing generators can only be registered for objects, found \(type)") producingGenerators[type.group!] = (generator, probability) } // Register a generator for a custom named string. - public func addNamedStringGenerator(forType type: ILType, with generator: @escaping () -> String) { - assert(type.Is(.string), "Named string generators can only be registered for strings, found \(type)") + public func addNamedStringGenerator( + forType type: ILType, with generator: @escaping () -> String + ) { + assert( + type.Is(.string), + "Named string generators can only be registered for strings, found \(type)") namedStringGenerators[type.group!] = generator } private func addProducingMethod(forType type: ILType, by method: String, on group: String) { if producingMethods[type] == nil { - producingMethods[type] = [] + producingMethods[type] = [] } producingMethods[type]! += [(group: group, method: method)] } - @discardableResult private func addProducingProperty(forType type: ILType, by property: String, on group: String) -> ILType { + @discardableResult private func addProducingProperty( + forType type: ILType, by property: String, on group: String + ) -> ILType { let actualType: ILType if type.Is(.constructor()) { actualType = type.signature!.outputType @@ -825,8 +909,9 @@ public class JavaScriptEnvironment: ComponentBase { // for overloads in group.methods { for method in overloads.value { - assert(method.outputType != .nothing, - "Method \(overloads.key) in group \(group.name) has .nothing as outputType") + assert( + method.outputType != .nothing, + "Method \(overloads.key) in group \(group.name) has .nothing as outputType") if method.outputType == .undefined { continue } @@ -836,7 +921,8 @@ public class JavaScriptEnvironment: ComponentBase { if var current = groups[groupName] { while let parent = current.parent { current = groups[parent]! - addProducingMethod(forType: current.instanceType, by: overloads.key, on: group.name) + addProducingMethod( + forType: current.instanceType, by: overloads.key, on: group.name) } } } @@ -847,12 +933,14 @@ public class JavaScriptEnvironment: ComponentBase { // Step 3: Initialize `producingProperties` // for property in group.properties { - let producedType = addProducingProperty(forType: property.value, by: property.key, on: group.name) + let producedType = addProducingProperty( + forType: property.value, by: property.key, on: group.name) if let groupName = producedType.group { if var current = groups[groupName] { while let parent = current.parent { current = groups[parent]! - addProducingProperty(forType: current.instanceType, by: property.key, on: group.name) + addProducingProperty( + forType: current.instanceType, by: property.key, on: group.name) } } } @@ -862,11 +950,17 @@ public class JavaScriptEnvironment: ComponentBase { // Temporal has a large number of "fields" object (aka "partial temporal objects" or "temporal-like objects") // which have a number of datetime-like fields. These are never produced as a result from any JS APIs, so we cannot // expect instances of them to already exist in scope. Instead, we generate them ourselves when requested. - public func registerTemporalFieldsObject(_ group: ObjectGroup, forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool) { + public func registerTemporalFieldsObject( + _ group: ObjectGroup, forWith: Bool, dateFields: Bool, timeFields: Bool, zonedFields: Bool + ) { registerObjectGroup(group) - addProducingGenerator(forType: group.instanceType, with: { b in - b.createTemporalFieldsObject(forWith: forWith, dateFields: dateFields, timeFields: timeFields, zonedFields: zonedFields) - }) + addProducingGenerator( + forType: group.instanceType, + with: { b in + b.createTemporalFieldsObject( + forWith: forWith, dateFields: dateFields, timeFields: timeFields, + zonedFields: zonedFields) + }) } public func registerBuiltin(_ name: String, ofType type: ILType) { @@ -875,14 +969,14 @@ public class JavaScriptEnvironment: ComponentBase { builtins.insert(name) let producedType = addProducingProperty(forType: type, by: name, on: "") - if let groupName = producedType.group { - if var current = groups[groupName] { - while let parent = current.parent { - current = groups[parent]! - addProducingProperty(forType: current.instanceType, by: name, on: "") - } + if let groupName = producedType.group { + if var current = groups[groupName] { + while let parent = current.parent { + current = groups[parent]! + addProducingProperty(forType: current.instanceType, by: name, on: "") } } + } } public func registerOptionsBag(_ bag: OptionsBag) { @@ -890,11 +984,15 @@ public class JavaScriptEnvironment: ComponentBase { for property in bag.properties.values { if property.isEnumeration { - assert(enums[property.group!] != nil, "Enum \(property.group!) used in options bag but not registered on the JavaScriptEnvironment") + assert( + enums[property.group!] != nil, + "Enum \(property.group!) used in options bag but not registered on the JavaScriptEnvironment" + ) } } - addProducingGenerator(forType: bag.group.instanceType, with: { b in b.createOptionsBag(bag) }) + addProducingGenerator( + forType: bag.group.instanceType, with: { b in b.createOptionsBag(bag) }) } public func type(ofBuiltin builtinName: String) -> ILType { @@ -906,7 +1004,7 @@ public class JavaScriptEnvironment: ComponentBase { } } - public func type (ofGroup groupName: String) -> ILType { + public func type(ofGroup groupName: String) -> ILType { if let type = groups[groupName]?.instanceType { return type } else { @@ -961,8 +1059,10 @@ public class JavaScriptEnvironment: ComponentBase { // For ObjectGroups, get a generator that is registered as being able to produce this // ObjectGroup. - public func getProducingGenerator(ofType type: ILType) -> (generator: EnvironmentValueGenerator, probability: Double)? { - type.group.flatMap {producingGenerators[$0]} + public func getProducingGenerator(ofType type: ILType) -> ( + generator: EnvironmentValueGenerator, probability: Double + )? { + type.group.flatMap { producingGenerators[$0] } } // For named strings, get a generator that is registered as being able to produce this @@ -971,7 +1071,6 @@ public class JavaScriptEnvironment: ComponentBase { namedStringGenerators[name] } - // If the object group refers to a constructor, get its path. public func getPathIfConstructor(ofGroup groupName: String) -> [String]? { guard let group = groups[groupName] else { @@ -1026,7 +1125,10 @@ public struct ObjectGroup { /// The type of instances of this group. public var instanceType: ILType - public init(name: String, constructorPath: String? = nil, instanceType: ILType?, properties: [String: ILType], overloads: [String: [Signature]], parent: String? = nil) { + public init( + name: String, constructorPath: String? = nil, instanceType: ILType?, + properties: [String: ILType], overloads: [String: [Signature]], parent: String? = nil + ) { self.name = name self.properties = properties self.methods = overloads @@ -1037,24 +1139,39 @@ public struct ObjectGroup { // (which would then need some kind of fallback ObjectGroup that is consulted by the // type lookup routines if the real group doesn't have the requested information). assert(instanceType.group == name, "group name mismatch for group \(name)") - assert(instanceType.properties == Set(properties.keys), "inconsistent property information for object group \(name): \(Set(properties.keys).symmetricDifference(instanceType.properties))") - assert(instanceType.methods == Set(methods.keys), "inconsistent method information for object group \(name): \(Set(methods.keys).symmetricDifference(instanceType.methods))") + assert( + instanceType.properties == Set(properties.keys), + "inconsistent property information for object group \(name): \(Set(properties.keys).symmetricDifference(instanceType.properties))" + ) + assert( + instanceType.methods == Set(methods.keys), + "inconsistent method information for object group \(name): \(Set(methods.keys).symmetricDifference(instanceType.methods))" + ) self.instanceType = instanceType } else { // Simply calculate the instance type based on the ObjectGroup information. - self.instanceType = .object(ofGroup: name, withProperties: Array(properties.keys), withMethods: Array(methods.keys)) + self.instanceType = .object( + ofGroup: name, withProperties: Array(properties.keys), + withMethods: Array(methods.keys)) } if let constructorPath { - assert(self.instanceType.Is(.constructor()) || self.instanceType.Is(.function()), "\(name) has a constructor path set but does not wrap a constructor") + assert( + self.instanceType.Is(.constructor()) || self.instanceType.Is(.function()), + "\(name) has a constructor path set but does not wrap a constructor") self.constructorPath = constructorPath.split(separator: ".").map({ String($0) }) } else { self.constructorPath = nil } } - public init(name: String, constructorPath: String? = nil, instanceType: ILType?, properties: [String: ILType], methods: [String: Signature], parent: String? = nil) { - self.init(name: name, constructorPath: constructorPath, instanceType: instanceType, properties: properties, overloads: methods.mapValues({[$0]}), parent: parent) + public init( + name: String, constructorPath: String? = nil, instanceType: ILType?, + properties: [String: ILType], methods: [String: Signature], parent: String? = nil + ) { + self.init( + name: name, constructorPath: constructorPath, instanceType: instanceType, + properties: properties, overloads: methods.mapValues({ [$0] }), parent: parent) } } @@ -1072,15 +1189,17 @@ public struct OptionsBag { self.properties = properties let properties = properties.mapValues { // This list can be expanded over time as long as createOptionsBag() supports this - assert($0.isEnumeration || $0.Is(.number | .integer | .boolean | .iterable) || + assert( + $0.isEnumeration || $0.Is(.number | .integer | .boolean | .iterable) // Has a producing generator registered - $0.Is(.jsTemporalPlainTime) || + || $0.Is(.jsTemporalPlainTime) // Has explicit support in createOptionsBag - $0.Is(OptionsBag.jsTemporalRelativeTo), - "Found unsupported option type \($0) in options bag \(name)") - return $0 | .undefined; + || $0.Is(OptionsBag.jsTemporalRelativeTo), + "Found unsupported option type \($0) in options bag \(name)") + return $0 | .undefined } - self.group = ObjectGroup(name: name, instanceType: nil, properties: properties, overloads: [:]) + self.group = ObjectGroup( + name: name, instanceType: nil, properties: properties, overloads: [:]) } } @@ -1100,77 +1219,170 @@ public struct OptionsBag { // // Note, these must be kept in sync with the ObjectGroups below (in particular the properties and methods). To help with that, the ObjectGroup // constructor asserts that the type information is consistent between instance type and the ObjectGroup. -public extension ILType { +extension ILType { /// Type of a string in JavaScript. /// A JS string is both a string and an object on which methods can be called. - static let jsString = ILType.string + ILType.iterable + ILType.object(ofGroup: "String", withProperties: ["length"], withMethods: ["charAt", "charCodeAt", "codePointAt", "concat", "includes", "endsWith", "indexOf", "lastIndexOf", "match", "matchAll", "padEnd", "padStart", "normalize", "repeat", "replace", "replaceAll", "search", "slice", "split", "startsWith", "substring", "trim", "trimStart", "trimLeft", "trimEnd", "trimRight" ,"toUpperCase", "toLowerCase", "localeCompare", "anchor", "at", "big", "blink", "bold", "fixed", "fontcolor", "fontsize", "isWellFormed", "italics", "link", "small", "strike", "sub", "substr", "sup", "toLocaleLowerCase", "toLocaleUpperCase", "toWellFormed"]) + public static let jsString = + ILType.string + ILType.iterable + + ILType.object( + ofGroup: "String", withProperties: ["length"], + withMethods: [ + "charAt", "charCodeAt", "codePointAt", "concat", "includes", "endsWith", "indexOf", + "lastIndexOf", "match", "matchAll", "padEnd", "padStart", "normalize", "repeat", + "replace", "replaceAll", "search", "slice", "split", "startsWith", "substring", + "trim", "trimStart", "trimLeft", "trimEnd", "trimRight", "toUpperCase", + "toLowerCase", "localeCompare", "anchor", "at", "big", "blink", "bold", "fixed", + "fontcolor", "fontsize", "isWellFormed", "italics", "link", "small", "strike", + "sub", "substr", "sup", "toLocaleLowerCase", "toLocaleUpperCase", "toWellFormed", + ]) /// Type of a regular expression in JavaScript. /// A JS RegExp is both a RegExp and an object on which methods can be called. - static let jsRegExp = ILType.regexp + ILType.object(ofGroup: "RegExp", withProperties: ["flags", "dotAll", "global", "ignoreCase", "multiline", "source", "sticky", "unicode"], withMethods: ["compile", "exec", "test"]) + public static let jsRegExp = + ILType.regexp + + ILType.object( + ofGroup: "RegExp", + withProperties: [ + "flags", "dotAll", "global", "ignoreCase", "multiline", "source", "sticky", + "unicode", + ], withMethods: ["compile", "exec", "test"]) /// Type of a JavaScript Symbol. - static let jsSymbol = ILType.object(ofGroup: "Symbol", withProperties: ["description"]) + public static let jsSymbol = ILType.object(ofGroup: "Symbol", withProperties: ["description"]) /// Type of a JavaScript array. - static let jsArray = ILType.iterable + ILType.object(ofGroup: "Array", withProperties: ["length"], withMethods: ["at", "concat", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", "toReversed", "toSorted", "toSpliced", "with", "join", "lastIndexOf", "values", "flat", "flatMap"]) + public static let jsArray = + ILType.iterable + + ILType.object( + ofGroup: "Array", withProperties: ["length"], + withMethods: [ + "at", "concat", "copyWithin", "fill", "find", "findIndex", "findLast", + "findLastIndex", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", + "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", + "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", + "toReversed", "toSorted", "toSpliced", "with", "join", "lastIndexOf", "values", + "flat", "flatMap", + ]) /// Type of a JavaScript function's arguments object. - static let jsArguments = ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) + public static let jsArguments = + ILType.iterable + ILType.object(ofGroup: "Arguments", withProperties: ["length", "callee"]) /// Type of a JavaScript Iterator object. - static let jsIterator = ILType.iterable + ILType.object(ofGroup: "Iterator", withProperties: ["value", "done"], withMethods: ["next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", "toArray", "forEach", "some", "every", "find"]) + public static let jsIterator = + ILType.iterable + + ILType.object( + ofGroup: "Iterator", withProperties: ["value", "done"], + withMethods: [ + "next", "return", "throw", "map", "filter", "take", "drop", "flatMap", "reduce", + "toArray", "forEach", "some", "every", "find", + ]) /// Type of the JavaScript Iterator constructor builtin. - static let jsIteratorConstructor = ILType.object(ofGroup: "IteratorConstructor", withProperties: ["prototype"], withMethods: ["from", "concat", "zip"]) + public static let jsIteratorConstructor = ILType.object( + ofGroup: "IteratorConstructor", withProperties: ["prototype"], + withMethods: ["from", "concat", "zip"]) /// Type of a JavaScript generator object. - static let jsGenerator = ILType.iterable + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) + public static let jsGenerator = + ILType.iterable + + ILType.object(ofGroup: "Generator", withMethods: ["next", "return", "throw"]) /// Type of a JavaScript Promise object. - static let jsPromise = ILType.object(ofGroup: "Promise", withMethods: ["catch", "finally", "then"]) + public static let jsPromise = ILType.object( + ofGroup: "Promise", withMethods: ["catch", "finally", "then"]) /// Type of a JavaScript Map object. - static let jsMap = ILType.iterable + ILType.object(ofGroup: "Map", withProperties: ["size"], withMethods: ["clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values", "getOrInsert", "getOrInsertComputed"]) + public static let jsMap = + ILType.iterable + + ILType.object( + ofGroup: "Map", withProperties: ["size"], + withMethods: [ + "clear", "delete", "entries", "forEach", "get", "has", "keys", "set", "values", + "getOrInsert", "getOrInsertComputed", + ]) /// Type of a JavaScript WeakMap object. - static let jsWeakMap = ILType.object(ofGroup: "WeakMap", withMethods: ["delete", "get", "has", "set", "getOrInsert", "getOrInsertComputed"]) + public static let jsWeakMap = ILType.object( + ofGroup: "WeakMap", + withMethods: ["delete", "get", "has", "set", "getOrInsert", "getOrInsertComputed"]) /// Type of a JavaScript Set object. - static let jsSet = ILType.iterable + ILType.object(ofGroup: "Set", withProperties: ["size"], withMethods: ["add", "clear", "delete", "entries", "forEach", "has", "keys", "values", "difference", "intersection", "isDisjointFrom", "isSubsetOf", "isSupersetOf", "symmetricDifference", "union"]) + public static let jsSet = + ILType.iterable + + ILType.object( + ofGroup: "Set", withProperties: ["size"], + withMethods: [ + "add", "clear", "delete", "entries", "forEach", "has", "keys", "values", + "difference", "intersection", "isDisjointFrom", "isSubsetOf", "isSupersetOf", + "symmetricDifference", "union", + ]) /// Type of a JavaScript WeakSet object. - static let jsWeakSet = ILType.object(ofGroup: "WeakSet", withMethods: ["add", "delete", "has"]) + public static let jsWeakSet = ILType.object( + ofGroup: "WeakSet", withMethods: ["add", "delete", "has"]) /// Type of a JavaScript WeakRef object. - static let jsWeakRef = ILType.object(ofGroup: "WeakRef", withMethods: ["deref"]) + public static let jsWeakRef = ILType.object(ofGroup: "WeakRef", withMethods: ["deref"]) /// Type of a JavaScript FinalizationRegistry object. - static let jsFinalizationRegistry = ILType.object(ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) + public static let jsFinalizationRegistry = ILType.object( + ofGroup: "FinalizationRegistry", withMethods: ["register", "unregister"]) /// Type of a JavaScript DisposableStack object. - static let jsDisposableStack = ILType.object(ofGroup: "DisposableStack", withProperties: ["disposed"], withMethods: ["dispose", "use", "adopt", "defer", "move"]) + public static let jsDisposableStack = ILType.object( + ofGroup: "DisposableStack", withProperties: ["disposed"], + withMethods: ["dispose", "use", "adopt", "defer", "move"]) /// Type of a JavaScript AsyncDisposableStack object. - static let jsAsyncDisposableStack = ILType.object(ofGroup: "AsyncDisposableStack", withProperties: ["disposed"], withMethods: ["disposeAsync", "use", "adopt", "defer", "move"]) + public static let jsAsyncDisposableStack = ILType.object( + ofGroup: "AsyncDisposableStack", withProperties: ["disposed"], + withMethods: ["disposeAsync", "use", "adopt", "defer", "move"]) /// Type of a JavaScript ArrayBuffer object. - static let jsArrayBuffer = ILType.object(ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], withMethods: ["resize", "slice", "sliceToImmutable", "transfer", "transferToFixedLength", "transferToImmutable"]) + public static let jsArrayBuffer = ILType.object( + ofGroup: "ArrayBuffer", withProperties: ["byteLength", "maxByteLength", "resizable"], + withMethods: [ + "resize", "slice", "sliceToImmutable", "transfer", "transferToFixedLength", + "transferToImmutable", + ]) /// Type of a JavaScript SharedArrayBuffer object. - static let jsSharedArrayBuffer = ILType.object(ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], withMethods: ["grow", "slice"]) + public static let jsSharedArrayBuffer = ILType.object( + ofGroup: "SharedArrayBuffer", withProperties: ["byteLength", "maxByteLength", "growable"], + withMethods: ["grow", "slice"]) /// Type of a JavaScript DataView object. - static let jsDataView = ILType.object(ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], withMethods: ["getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", "getFloat32", "getFloat64", "getBigInt64", "getBigUint64", "setInt8", "setUint8", "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", "setFloat64", "setBigInt64", "setBigUint64"]) + public static let jsDataView = ILType.object( + ofGroup: "DataView", withProperties: ["buffer", "byteLength", "byteOffset"], + withMethods: [ + "getInt8", "getUint8", "getInt16", "getUint16", "getInt32", "getUint32", "getFloat16", + "getFloat32", "getFloat64", "getBigInt64", "getBigUint64", "setInt8", "setUint8", + "setInt16", "setUint16", "setInt32", "setUint32", "setFloat16", "setFloat32", + "setFloat64", "setBigInt64", "setBigUint64", + ]) /// Type of a JavaScript TypedArray object of the given variant. - static func jsTypedArray(_ variant: String) -> ILType { - let extraMethods = variant == "Uint8Array" ? ["setFromBase64", "setFromHex", "toBase64", "toHex"] : [] - return .iterable + .object(ofGroup: variant, withProperties: ["BYTES_PER_ELEMENT", "buffer", "byteOffset", "byteLength", "length"], withMethods: ["at", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", "reverse", "slice", "sort", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "set", "some", "subarray", "reduce", "reduceRight", "join", "lastIndexOf", "values", "toLocaleString", "toString", "toReversed", "toSorted", "with"] - + extraMethods) + public static func jsTypedArray(_ variant: String) -> ILType { + let extraMethods = + variant == "Uint8Array" ? ["setFromBase64", "setFromHex", "toBase64", "toHex"] : [] + return .iterable + + .object( + ofGroup: variant, + withProperties: [ + "BYTES_PER_ELEMENT", "buffer", "byteOffset", "byteLength", "length", + ], + withMethods: [ + "at", "copyWithin", "fill", "find", "findIndex", "findLast", "findLastIndex", + "reverse", "slice", "sort", "includes", "indexOf", "keys", "entries", "forEach", + "filter", "map", "every", "set", "some", "subarray", "reduce", "reduceRight", + "join", "lastIndexOf", "values", "toLocaleString", "toString", "toReversed", + "toSorted", "with", + ] + + extraMethods) } - static let jsUint8Array = jsTypedArray("Uint8Array") + public static let jsUint8Array = jsTypedArray("Uint8Array") // TODO(mliedtke): Saying "any typed array" isn't really easily possible right now, so we type // the expected parameter type as any object. @@ -1178,49 +1390,103 @@ public extension ILType { /// Type of a JavaScript function. /// A JavaScript function is also constructors. Moreover, it is also an object as it has a number of properties and methods. - static func jsFunction(_ signature: Signature = Signature.forUnknownFunction) -> ILType { - return .constructor(signature) + .function(signature) + .object(ofGroup: "Function", withProperties: ["prototype", "length", "arguments", "caller", "name"], withMethods: ["apply", "bind", "call"]) + public static func jsFunction(_ signature: Signature = Signature.forUnknownFunction) -> ILType { + return .constructor(signature) + .function(signature) + + .object( + ofGroup: "Function", + withProperties: ["prototype", "length", "arguments", "caller", "name"], + withMethods: ["apply", "bind", "call"]) } /// Type of the JavaScript Object constructor builtin. - static let jsObjectConstructor = .functionAndConstructor([.jsAnything...] => .object()) + .object(ofGroup: "ObjectConstructor", withProperties: ["prototype"], withMethods: ["assign", "fromEntries", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "values", "groupBy", "hasOwn"]) + public static let jsObjectConstructor = + .functionAndConstructor([.jsAnything...] => .object()) + + .object( + ofGroup: "ObjectConstructor", withProperties: ["prototype"], + withMethods: [ + "assign", "fromEntries", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", + "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", + "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", + "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", + "values", "groupBy", "hasOwn", + ]) /// Type of the JavaScript Array constructor builtin. - static let jsArrayConstructor = .functionAndConstructor([.integer] => .jsArray) + .object(ofGroup: "ArrayConstructor", withProperties: ["prototype"], withMethods: ["from", "fromAsync", "of", "isArray"]) + public static let jsArrayConstructor = + .functionAndConstructor([.integer] => .jsArray) + + .object( + ofGroup: "ArrayConstructor", withProperties: ["prototype"], + withMethods: ["from", "fromAsync", "of", "isArray"]) /// Type of the JavaScript Function constructor builtin. - static let jsFunctionConstructor = ILType.constructor([.string] => .jsFunction(Signature.forUnknownFunction)) + .object(ofGroup: "FunctionConstructor", withProperties: ["prototype"]) + public static let jsFunctionConstructor = + ILType.constructor([.string] => .jsFunction(Signature.forUnknownFunction)) + + .object(ofGroup: "FunctionConstructor", withProperties: ["prototype"]) /// Type of the JavaScript String constructor builtin. - static let jsStringConstructor = ILType.functionAndConstructor([.jsAnything] => .jsString) + .object(ofGroup: "StringConstructor", withProperties: ["prototype"], withMethods: ["fromCharCode", "fromCodePoint", "raw"]) + public static let jsStringConstructor = + ILType.functionAndConstructor([.jsAnything] => .jsString) + + .object( + ofGroup: "StringConstructor", withProperties: ["prototype"], + withMethods: ["fromCharCode", "fromCodePoint", "raw"]) /// Type of the JavaScript Boolean constructor builtin. - static let jsBooleanConstructor = ILType.functionAndConstructor([.jsAnything] => .boolean) + .object(ofGroup: "BooleanConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsBooleanConstructor = + ILType.functionAndConstructor([.jsAnything] => .boolean) + + .object(ofGroup: "BooleanConstructor", withProperties: ["prototype"], withMethods: []) /// Type of the JavaScript Number constructor builtin. - static let jsNumberConstructor = ILType.functionAndConstructor([.jsAnything] => .number) + .object(ofGroup: "NumberConstructor", withProperties: ["prototype", "EPSILON", "MAX_SAFE_INTEGER", "MAX_VALUE", "MIN_SAFE_INTEGER", "MIN_VALUE", "NaN", "NEGATIVE_INFINITY", "POSITIVE_INFINITY"], withMethods: ["isNaN", "isFinite", "isInteger", "isSafeInteger", "parseFloat", "parseInt"]) + public static let jsNumberConstructor = + ILType.functionAndConstructor([.jsAnything] => .number) + + .object( + ofGroup: "NumberConstructor", + withProperties: [ + "prototype", "EPSILON", "MAX_SAFE_INTEGER", "MAX_VALUE", "MIN_SAFE_INTEGER", + "MIN_VALUE", "NaN", "NEGATIVE_INFINITY", "POSITIVE_INFINITY", + ], + withMethods: [ + "isNaN", "isFinite", "isInteger", "isSafeInteger", "parseFloat", "parseInt", + ]) /// Type of the JavaScript Symbol constructor builtin. - static let jsSymbolConstructor = ILType.function([.string] => .jsSymbol) + .object(ofGroup: "SymbolConstructor", withProperties: JavaScriptEnvironment.wellKnownSymbols, withMethods: ["for", "keyFor"]) + public static let jsSymbolConstructor = + ILType.function([.string] => .jsSymbol) + + .object( + ofGroup: "SymbolConstructor", withProperties: JavaScriptEnvironment.wellKnownSymbols, + withMethods: ["for", "keyFor"]) /// Type of the JavaScript BigInt constructor builtin. - static let jsBigIntConstructor = ILType.function([.number] => .bigint) + .object(ofGroup: "BigIntConstructor", withProperties: ["prototype"], withMethods: ["asIntN", "asUintN"]) + public static let jsBigIntConstructor = + ILType.function([.number] => .bigint) + + .object( + ofGroup: "BigIntConstructor", withProperties: ["prototype"], + withMethods: ["asIntN", "asUintN"]) /// Type of the JavaScript RegExp constructor builtin. - static let jsRegExpConstructor = ILType.functionAndConstructor([.string] => .jsRegExp) + .object(ofGroup: "RegExpConstructor", withProperties: ["prototype", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$_", "input", "lastMatch", "lastParen", "leftContext"], withMethods: ["escape"]) + public static let jsRegExpConstructor = + ILType.functionAndConstructor([.string] => .jsRegExp) + + .object( + ofGroup: "RegExpConstructor", + withProperties: [ + "prototype", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$_", "input", + "lastMatch", "lastParen", "leftContext", + ], withMethods: ["escape"]) /// Type of a JavaScript Error object of the given variant. - static func jsError(_ variant: String) -> ILType { - return .object(ofGroup: variant, withProperties: ["message", "name", "cause", "stack"], withMethods: ["toString"]) + public static func jsError(_ variant: String) -> ILType { + return .object( + ofGroup: variant, withProperties: ["message", "name", "cause", "stack"], + withMethods: ["toString"]) } /// Type of the JavaScript Error constructor builtin - static func jsErrorConstructor(_ variant: String) -> ILType { - let signature = if variant == "AggregateError" { - [.plain(.iterable), .opt(.string), .opt(.object())] => .jsError("AggregateError") - } else { - [.opt(.string)] => .jsError(variant) - } + public static func jsErrorConstructor(_ variant: String) -> ILType { + let signature = + if variant == "AggregateError" { + [.plain(.iterable), .opt(.string), .opt(.object())] => .jsError("AggregateError") + } else { + [.opt(.string)] => .jsError(variant) + } return .functionAndConstructor(signature) + .object( ofGroup: "\(variant)Constructor", @@ -1229,16 +1495,25 @@ public extension ILType { } /// Type of the JavaScript ArrayBuffer constructor builtin. - static let jsArrayBufferConstructor = ILType.constructor([.integer, .opt(.object())] => .jsArrayBuffer) + .object(ofGroup: "ArrayBufferConstructor", withProperties: ["prototype"], withMethods: ["isView"]) + public static let jsArrayBufferConstructor = + ILType.constructor([.integer, .opt(.object())] => .jsArrayBuffer) + + .object( + ofGroup: "ArrayBufferConstructor", withProperties: ["prototype"], + withMethods: ["isView"]) /// Type of the JavaScript SharedArrayBuffer constructor builtin. - static let jsSharedArrayBufferConstructor = ILType.constructor([.integer, .opt(.object())] => .jsSharedArrayBuffer) + .object(ofGroup: "SharedArrayBufferConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsSharedArrayBufferConstructor = + ILType.constructor([.integer, .opt(.object())] => .jsSharedArrayBuffer) + + .object( + ofGroup: "SharedArrayBufferConstructor", withProperties: ["prototype"], withMethods: []) /// Type of a JavaScript TypedArray constructor builtin. - static func jsTypedArrayConstructor(_ variant: String) -> ILType { + public static func jsTypedArrayConstructor(_ variant: String) -> ILType { let methods = variant == "Uint8Array" ? ["fromBase64", "fromHex"] : [] // TODO Also allow SharedArrayBuffers for first argument - return .constructor([.opt(.integer | .jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsTypedArray(variant)) + return .constructor( + [.opt(.integer | .jsArrayBuffer), .opt(.integer), .opt(.integer)] + => .jsTypedArray(variant)) + .object( ofGroup: "\(variant)Constructor", withProperties: ["prototype", "BYTES_PER_ELEMENT"], @@ -1246,141 +1521,233 @@ public extension ILType { } /// Type of the JavaScript DataView constructor builtin. (TODO Also allow SharedArrayBuffers for first argument) - static let jsDataViewConstructor = ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) + public static let jsDataViewConstructor = + ILType.constructor([.plain(.jsArrayBuffer), .opt(.integer), .opt(.integer)] => .jsDataView) + + .object(ofGroup: "DataViewConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Promise constructor builtin. - static let jsPromiseConstructor = ILType.constructor([.function()] => .jsPromise) + .object(ofGroup: "PromiseConstructor", withProperties: ["prototype"], withMethods: ["resolve", "reject", "all", "any", "race", "allSettled", "try", "withResolvers"]) + public static let jsPromiseConstructor = + ILType.constructor([.function()] => .jsPromise) + + .object( + ofGroup: "PromiseConstructor", withProperties: ["prototype"], + withMethods: [ + "resolve", "reject", "all", "any", "race", "allSettled", "try", "withResolvers", + ]) /// Type of the JavaScript Proxy constructor builtin. - static let jsProxyConstructor = ILType.constructor([.object(), .object()] => .jsAnything) + .object(ofGroup: "ProxyConstructor", withProperties: [], withMethods: ["revocable"]) + public static let jsProxyConstructor = + ILType.constructor([.object(), .object()] => .jsAnything) + + .object(ofGroup: "ProxyConstructor", withProperties: [], withMethods: ["revocable"]) /// Type of the JavaScript Map constructor builtin. - static let jsMapConstructor = ILType.constructor([.object()] => .jsMap) + .object(ofGroup: "MapConstructor", withProperties: ["prototype"], withMethods: ["groupBy"]) + public static let jsMapConstructor = + ILType.constructor([.object()] => .jsMap) + + .object( + ofGroup: "MapConstructor", withProperties: ["prototype"], withMethods: ["groupBy"]) /// Type of the JavaScript WeakMap constructor builtin. - static let jsWeakMapConstructor = ILType.constructor([.object()] => .jsWeakMap) + .object(ofGroup: "WeakMapConstructor", withProperties: ["prototype"]) + public static let jsWeakMapConstructor = + ILType.constructor([.object()] => .jsWeakMap) + + .object(ofGroup: "WeakMapConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Set constructor builtin. - static let jsSetConstructor = ILType.constructor([.object()] => .jsSet) + .object(ofGroup: "SetConstructor", withProperties: ["prototype"]) + public static let jsSetConstructor = + ILType.constructor([.object()] => .jsSet) + + .object(ofGroup: "SetConstructor", withProperties: ["prototype"]) /// Type of the JavaScript WeakSet constructor builtin. - static let jsWeakSetConstructor = ILType.constructor([.object()] => .jsWeakSet) + .object(ofGroup: "WeakSetConstructor", withProperties: ["prototype"]) + public static let jsWeakSetConstructor = + ILType.constructor([.object()] => .jsWeakSet) + + .object(ofGroup: "WeakSetConstructor", withProperties: ["prototype"]) /// Type of the JavaScript WeakRef constructor builtin. - static let jsWeakRefConstructor = ILType.constructor([.object()] => .jsWeakRef) + .object(ofGroup: "WeakRefConstructor", withProperties: ["prototype"]) + public static let jsWeakRefConstructor = + ILType.constructor([.object()] => .jsWeakRef) + + .object(ofGroup: "WeakRefConstructor", withProperties: ["prototype"]) /// Type of the JavaScript FinalizationRegistry constructor builtin. - static let jsFinalizationRegistryConstructor = ILType.constructor([.function()] => .jsFinalizationRegistry) + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) + public static let jsFinalizationRegistryConstructor = + ILType.constructor([.function()] => .jsFinalizationRegistry) + + .object(ofGroup: "FinalizationRegistryConstructor", withProperties: ["prototype"]) /// Type of the JavaScript DisposableStack constructor builtin. - static let jsDisposableStackConstructor = ILType.constructor([] => .jsDisposableStack) + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) + public static let jsDisposableStackConstructor = + ILType.constructor([] => .jsDisposableStack) + + .object(ofGroup: "DisposableStackConstructor", withProperties: ["prototype"]) /// Type of the JavaScript AsyncDisposableStack constructor builtin. - static let jsAsyncDisposableStackConstructor = ILType.constructor([] => .jsAsyncDisposableStack) + .object(ofGroup: "AsyncDisposableStackConstructor", withProperties: ["prototype"]) + public static let jsAsyncDisposableStackConstructor = + ILType.constructor([] => .jsAsyncDisposableStack) + + .object(ofGroup: "AsyncDisposableStackConstructor", withProperties: ["prototype"]) /// Type of the JavaScript Math constructor builtin. - static let jsMathObject = ILType.object(ofGroup: "Math", withProperties: ["E", "PI", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"], withMethods: ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "f16round", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc"]) + public static let jsMathObject = ILType.object( + ofGroup: "Math", + withProperties: ["E", "PI", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"], + withMethods: [ + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", + "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "f16round", "hypot", "imul", + "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", + "sinh", "sqrt", "sumPrecise", "tan", "tanh", "trunc", + ]) /// Type of the JavaScript Atomics builtin. - static let jsAtomicsObject = ILType.object(ofGroup: "Atomics", withProperties: [], withMethods: ["add", "and", "compareExchange", "exchange", "isLockFree", "load", "notify", "or", "pause", "store", "sub", "wait", "waitAsync", "xor"]) + public static let jsAtomicsObject = ILType.object( + ofGroup: "Atomics", withProperties: [], + withMethods: [ + "add", "and", "compareExchange", "exchange", "isLockFree", "load", "notify", "or", + "pause", "store", "sub", "wait", "waitAsync", "xor", + ]) /// Type of the JavaScript Date object - static let jsDate = ILType.object(ofGroup: "Date", withMethods: ["toISOString", "toDateString", "toTimeString", "toLocaleString", "toLocaleDateString", "toLocaleTimeString", "getTime", "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "getTimezoneOffset", "getYear", "setTime", "setMilliseconds", "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "setYear", "toJSON", "toUTCString", "toGMTString", "toTemporalInstant"]) + public static let jsDate = ILType.object( + ofGroup: "Date", + withMethods: [ + "toISOString", "toDateString", "toTimeString", "toLocaleString", "toLocaleDateString", + "toLocaleTimeString", "getTime", "getFullYear", "getUTCFullYear", "getMonth", + "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", + "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", + "getMilliseconds", "getUTCMilliseconds", "getTimezoneOffset", "getYear", "setTime", + "setMilliseconds", "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", + "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", "setMonth", + "setUTCMonth", "setFullYear", "setUTCFullYear", "setYear", "toJSON", "toUTCString", + "toGMTString", "toTemporalInstant", + ]) /// Type of the JavaScript Date constructor builtin - static let jsDateConstructor = ILType.functionAndConstructor([.opt(.string | .number)] => .jsDate) + .object(ofGroup: "DateConstructor", withProperties: ["prototype"], withMethods: ["UTC", "now", "parse"]) + public static let jsDateConstructor = + ILType.functionAndConstructor([.opt(.string | .number)] => .jsDate) + + .object( + ofGroup: "DateConstructor", withProperties: ["prototype"], + withMethods: ["UTC", "now", "parse"]) /// Type of the JavaScript JSON object builtin. - static let jsJSONObject = ILType.object(ofGroup: "JSON", withMethods: ["parse", "stringify", "rawJSON", "isRawJSON"]) + public static let jsJSONObject = ILType.object( + ofGroup: "JSON", withMethods: ["parse", "stringify", "rawJSON", "isRawJSON"]) /// Type of the JavaScript Reflect object builtin. - static let jsReflectObject = ILType.object(ofGroup: "Reflect", withMethods: ["apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"]) + public static let jsReflectObject = ILType.object( + ofGroup: "Reflect", + withMethods: [ + "apply", "construct", "defineProperty", "deleteProperty", "get", + "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", + "preventExtensions", "set", "setPrototypeOf", + ]) /// Type of the JavaScript isNaN builtin function. - static let jsIsNaNFunction = ILType.function([.jsAnything] => .boolean) + public static let jsIsNaNFunction = ILType.function([.jsAnything] => .boolean) /// Type of the JavaScript isFinite builtin function. - static let jsIsFiniteFunction = ILType.function([.jsAnything] => .boolean) + public static let jsIsFiniteFunction = ILType.function([.jsAnything] => .boolean) /// Type of the JavaScript escape builtin function. - static let jsEscapeFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEscapeFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript unescape builtin function. - static let jsUnescapeFunction = ILType.function([.jsAnything] => .jsString) + public static let jsUnescapeFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript decodeURI builtin function. - static let jsDecodeURIFunction = ILType.function([.jsAnything] => .jsString) + public static let jsDecodeURIFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript decodeURIComponent builtin function. - static let jsDecodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) + public static let jsDecodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript encodeURI builtin function. - static let jsEncodeURIFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEncodeURIFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript encodeURIComponent builtin function. - static let jsEncodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) + public static let jsEncodeURIComponentFunction = ILType.function([.jsAnything] => .jsString) /// Type of the JavaScript eval builtin function. - static let jsEvalFunction = ILType.function([.string] => .jsAnything) + public static let jsEvalFunction = ILType.function([.string] => .jsAnything) /// Type of the JavaScript parseInt builtin function. - static let jsParseIntFunction = ILType.function([.string] => .integer) + public static let jsParseIntFunction = ILType.function([.string] => .integer) /// Type of the JavaScript parseFloat builtin function. - static let jsParseFloatFunction = ILType.function([.string] => .float) + public static let jsParseFloatFunction = ILType.function([.string] => .float) /// Type of the JavaScript undefined value. - static let jsUndefined = ILType.undefined + public static let jsUndefined = ILType.undefined /// Type of the JavaScript NaN value. - static let jsNaN = ILType.float + public static let jsNaN = ILType.float /// Type of the JavaScript Infinity value. - static let jsInfinity = ILType.float + public static let jsInfinity = ILType.float - static let jsWebAssemblyModule = ILType.object(ofGroup: "WebAssembly.Module") + public static let jsWebAssemblyModule = ILType.object(ofGroup: "WebAssembly.Module") /// Type of the WebAssembly.Module() constructor. // TODO: The first constructor argument can also be any typed array and .jsSharedArrayBuffer. - static let jsWebAssemblyModuleConstructor = + public static let jsWebAssemblyModuleConstructor = ILType.constructor([.plain(.jsArrayBuffer)] => .jsWebAssemblyModule) - + .object(ofGroup: "WebAssemblyModuleConstructor", withProperties: ["prototype"], + + .object( + ofGroup: "WebAssemblyModuleConstructor", withProperties: ["prototype"], withMethods: ["customSections", "imports", "exports"]) - static let jsWebAssemblyGlobalConstructor = + public static let jsWebAssemblyGlobalConstructor = // We do not type the result as being part of the ObjectGroup "WasmGlobal" as that would // require to also add a WasmTypeExtension to its type. This is fine as the proper // construction of globals is done via the high-level Wasm operations and these builtins // only serve the purpose of fuzzing the API. - ILType.constructor([.plain(.object()), .jsAnything] => .object(withProperties: ["value"], withMethods: ["valueOf"])) - + .object(ofGroup: "WebAssemblyGlobalConstructor", withProperties: ["prototype"], withMethods: []) - - static let jsWebAssemblyInstance = ILType.object(ofGroup: "WebAssembly.Instance", + ILType.constructor( + [.plain(.object()), .jsAnything] + => .object(withProperties: ["value"], withMethods: ["valueOf"])) + + .object( + ofGroup: "WebAssemblyGlobalConstructor", withProperties: ["prototype"], withMethods: []) + + public static let jsWebAssemblyInstance = ILType.object( + ofGroup: "WebAssembly.Instance", withProperties: ["exports"]) - static let jsWebAssemblyInstanceConstructor = - ILType.constructor([.plain(.jsWebAssemblyModule), .plain(.object())] => .jsWebAssemblyInstance) - + .object(ofGroup: "WebAssemblyInstanceConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsWebAssemblyInstanceConstructor = + ILType.constructor( + [.plain(.jsWebAssemblyModule), .plain(.object())] => .jsWebAssemblyInstance) + + .object( + ofGroup: "WebAssemblyInstanceConstructor", withProperties: ["prototype"], + withMethods: []) // Similarly to Wasm globals, we do not type the results as being part of an object group as the // result type doesn't have a valid WasmTypeExtension. - static let jsWebAssemblyMemoryConstructor = ILType.constructor([.plain(.object(withProperties: ["initial"]))] => .object(withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"])) + public static let jsWebAssemblyMemoryConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["initial"]))] + => .object( + withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"])) + .object(ofGroup: "WebAssemblyMemoryConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyTableConstructor = ILType.constructor([.plain(.object(withProperties: ["initial"]))] => object(withProperties: ["length"], withMethods: ["get", "grow", "set"])) + public static let jsWebAssemblyTableConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["initial"]))] + => object(withProperties: ["length"], withMethods: ["get", "grow", "set"])) + .object(ofGroup: "WebAssemblyTableConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyTagConstructor = ILType.constructor([.plain(.object(withProperties: ["parameters"]))] => object(withMethods: [])) + public static let jsWebAssemblyTagConstructor = + ILType.constructor( + [.plain(.object(withProperties: ["parameters"]))] => object(withMethods: [])) + .object(ofGroup: "WebAssemblyTagConstructor", withProperties: ["prototype"]) - static let jsWebAssemblyExceptionConstructor = ILType.constructor([.plain(ObjectGroup.jsWasmTag.instanceType), .plain(.jsArray), .opt(.object(withProperties: ["traceStack"]))] => ObjectGroup.jsWebAssemblyException.instanceType) + public static let jsWebAssemblyExceptionConstructor = + ILType.constructor( + [ + .plain(ObjectGroup.jsWasmTag.instanceType), .plain(.jsArray), + .opt(.object(withProperties: ["traceStack"])), + ] => ObjectGroup.jsWebAssemblyException.instanceType) + .object(ofGroup: "WebAssemblyExceptionConstructor", withProperties: ["prototype"]) // The JavaScript WebAssembly.Table object of the given variant, i.e. FuncRef or ExternRef - static let wasmTable = ILType.object(ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"]) + public static let wasmTable = ILType.object( + ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"]) // Temporal types - static let jsTemporalObject = ILType.object(ofGroup: "Temporal", withProperties: ["Instant", "Duration", "PlainTime", "PlainYearMonth", "PlainMonthDay", "PlainDate", "PlainDateTime", "ZonedDateTime", "Now"]) + public static let jsTemporalObject = ILType.object( + ofGroup: "Temporal", + withProperties: [ + "Instant", "Duration", "PlainTime", "PlainYearMonth", "PlainMonthDay", "PlainDate", + "PlainDateTime", "ZonedDateTime", "Now", + ]) // TODO(mliedtke): Can we stop documenting Object.prototype methods? It doesn't make much sense that half of the ObjectGroups register a toString method, // the other half doesn't and not a single one registers e.g. propertyIsEnumerable or isPrototypeOf.`? @@ -1388,50 +1755,155 @@ public extension ILType { // Note that Temporal toString accepts additional parameters private static let commonStringifierMethods = ["toString", "toJSON", "toLocaleString"] - static let jsTemporalInstant = ILType.object(ofGroup: "Temporal.Instant", withProperties: ["epochMilliseconds", "epochNanoseconds"], withMethods: ["add", "subtract", "until", "since", "round", "equals", "toZonedDateTimeISO"] + commonStringifierMethods) - - static let jsTemporalInstantConstructor = ILType.functionAndConstructor([.bigint] => .jsTemporalInstant) + .object(ofGroup: "TemporalInstantConstructor", withProperties: ["prototype"], withMethods: ["from", "fromEpochMilliseconds", "fromEpochNanoseconds", "compare"]) - - static let jsTemporalDuration = ILType.object(ofGroup: "Temporal.Duration", withProperties: ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "sign", "blank"], withMethods: ["with", "negated", "abs", "add", "subtract", "round", "total"] + commonStringifierMethods) - - static let jsTemporalDurationConstructor = ILType.functionAndConstructor([.opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .jsTemporalDuration) + .object(ofGroup: "TemporalDurationConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - fileprivate static let timeProperties = ["hour", "minute", "second", "millisecond", "microsecond", "nanosecond"] - static let jsTemporalPlainTime = ILType.object(ofGroup: "Temporal.PlainTime", withProperties: timeProperties, withMethods: ["add", "subtract", "with", "until", "since", "round", "equals"] + commonStringifierMethods) - - static let jsTemporalPlainTimeConstructor = ILType.functionAndConstructor([.opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .jsTemporalPlainTime) + .object(ofGroup: "TemporalPlainTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - static let jsTemporalCalendarEnum = ILType.enumeration(ofName: "temporalCalendar", withValues: ["buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", "islamicc", "iso8601", "japanese", "persian", "roc"]) - - fileprivate static let yearMonthProperties = ["calendarId", "era", "eraYear", "year", "month", "monthCode", "daysInMonth", "daysInYear", "monthsInYear", "inLeapYear"] - - static let jsTemporalPlainYearMonth = ILType.object(ofGroup: "Temporal.PlainYearMonth", withProperties: yearMonthProperties, withMethods: ["with", "add", "subtract", "until", "since", "equals", "toPlainDate"] + commonStringifierMethods) - - static let jsTemporalPlainYearMonthConstructor = ILType.functionAndConstructor([.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] => .jsTemporalPlainYearMonth) + .object(ofGroup: "TemporalPlainYearMonthConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - static let jsTemporalPlainMonthDay = ILType.object(ofGroup: "Temporal.PlainMonthDay", withProperties: ["calendarId", "monthCode", "day"], withMethods: ["with", "equals", "toPlainDate"] + commonStringifierMethods) - - static let jsTemporalPlainMonthDayConstructor = ILType.functionAndConstructor([.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] => .jsTemporalPlainMonthDay) + .object(ofGroup: "TemporalPlainMonthDayConstructor", withProperties: ["prototype"], withMethods: ["from"]) - - fileprivate static let dateProperties = yearMonthProperties + ["day", "dayOfYear", "dayOfWeek", "weekOfYear", "yearOfWeek", "daysInWeek"] - - static let jsTemporalPlainDate = ILType.object(ofGroup: "Temporal.PlainDate", withProperties: dateProperties, withMethods: ["toPlainYearMonth", "toPlainMonthDay", "add", "subtract", "with", "withCalendar", "until", "since", "equals", "toPlainDateTime", "toZonedDateTime"] + commonStringifierMethods) - - static let jsTemporalPlainDateConstructor = ILType.functionAndConstructor([.number, .number, .number, .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate) + .object(ofGroup: "TemporalPlainDateConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) - - - static let jsTemporalPlainDateTime = ILType.object(ofGroup: "Temporal.PlainDateTime", withProperties: dateProperties + timeProperties, withMethods: ["with", "withPlainTime", "withCalendar", "add", "subtract", "until", "since", "round", "equals", "toZonedDateTime", "toPlainDate", "toPlainTime"] + commonStringifierMethods) - - static let jsTemporalPlainDateTimeConstructor = ILType.functionAndConstructor([.number, .number, .number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDateTime) + .object(ofGroup: "TemporalPlainDateTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) + public static let jsTemporalInstant = ILType.object( + ofGroup: "Temporal.Instant", withProperties: ["epochMilliseconds", "epochNanoseconds"], + withMethods: ["add", "subtract", "until", "since", "round", "equals", "toZonedDateTimeISO"] + + commonStringifierMethods) + + public static let jsTemporalInstantConstructor = + ILType.functionAndConstructor([.bigint] => .jsTemporalInstant) + + .object( + ofGroup: "TemporalInstantConstructor", withProperties: ["prototype"], + withMethods: ["from", "fromEpochMilliseconds", "fromEpochNanoseconds", "compare"]) + + public static let jsTemporalDuration = ILType.object( + ofGroup: "Temporal.Duration", + withProperties: [ + "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", + "microseconds", "nanoseconds", "sign", "blank", + ], + withMethods: ["with", "negated", "abs", "add", "subtract", "round", "total"] + + commonStringifierMethods) + + public static let jsTemporalDurationConstructor = + ILType.functionAndConstructor( + [ + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + ] => .jsTemporalDuration) + + .object( + ofGroup: "TemporalDurationConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + fileprivate static let timeProperties = [ + "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", + ] + public static let jsTemporalPlainTime = ILType.object( + ofGroup: "Temporal.PlainTime", withProperties: timeProperties, + withMethods: ["add", "subtract", "with", "until", "since", "round", "equals"] + + commonStringifierMethods) + + public static let jsTemporalPlainTimeConstructor = + ILType.functionAndConstructor( + [ + .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), + ] => .jsTemporalPlainTime) + + .object( + ofGroup: "TemporalPlainTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalCalendarEnum = ILType.enumeration( + ofName: "temporalCalendar", + withValues: [ + "buddhist", "chinese", "coptic", "dangi", "ethioaa", "ethiopic", "ethiopic-amete-alem", + "gregory", "hebrew", "indian", "islamic-civil", "islamic-tbla", "islamic-umalqura", + "islamicc", "iso8601", "japanese", "persian", "roc", + ]) - static let jsTemporalZonedDateTime = ILType.object(ofGroup: "Temporal.ZonedDateTime", withProperties: dateProperties + timeProperties + ["timeZoneId", "epochMilliseconds", "epochNanoseconds", "offsetNanoseconds", "offset"], withMethods: ["with", "withPlainTime", "withTimeZone", "withCalendar", "add", "subtract", "until", "since", "round", "equals", "startOfDay", "getTimeZoneTransition", "toInstant", "toPlainDate", "toPlainTime", "toPlainDateTime"] + commonStringifierMethods) + fileprivate static let yearMonthProperties = [ + "calendarId", "era", "eraYear", "year", "month", "monthCode", "daysInMonth", "daysInYear", + "monthsInYear", "inLeapYear", + ] - static let jsTemporalZonedDateTimeConstructor = ILType.functionAndConstructor([.bigint, .string, .opt(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime) + .object(ofGroup: "TemporalZonedDateTimeConstructor", withProperties: ["prototype"], withMethods: ["from", "compare"]) + public static let jsTemporalPlainYearMonth = ILType.object( + ofGroup: "Temporal.PlainYearMonth", withProperties: yearMonthProperties, + withMethods: ["with", "add", "subtract", "until", "since", "equals", "toPlainDate"] + + commonStringifierMethods) + + public static let jsTemporalPlainYearMonthConstructor = + ILType.functionAndConstructor( + [.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] + => .jsTemporalPlainYearMonth) + + .object( + ofGroup: "TemporalPlainYearMonthConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalPlainMonthDay = ILType.object( + ofGroup: "Temporal.PlainMonthDay", withProperties: ["calendarId", "monthCode", "day"], + withMethods: ["with", "equals", "toPlainDate"] + commonStringifierMethods) + + public static let jsTemporalPlainMonthDayConstructor = + ILType.functionAndConstructor( + [.integer, .integer, .opt(.jsTemporalCalendarEnum), .opt(.integer)] + => .jsTemporalPlainMonthDay) + + .object( + ofGroup: "TemporalPlainMonthDayConstructor", withProperties: ["prototype"], + withMethods: ["from"]) + + fileprivate static let dateProperties = + yearMonthProperties + [ + "day", "dayOfYear", "dayOfWeek", "weekOfYear", "yearOfWeek", "daysInWeek", + ] - static let jsTemporalNow = ILType.object(ofGroup: "Temporal.Now", withProperties: [], withMethods: ["timeZoneId", "instant", "plainDateTimeISO", "zonedDateTimeISO", "plainDateISO", "plainTimeISO"]) + public static let jsTemporalPlainDate = ILType.object( + ofGroup: "Temporal.PlainDate", withProperties: dateProperties, + withMethods: [ + "toPlainYearMonth", "toPlainMonthDay", "add", "subtract", "with", "withCalendar", + "until", "since", "equals", "toPlainDateTime", "toZonedDateTime", + ] + commonStringifierMethods) + + public static let jsTemporalPlainDateConstructor = + ILType.functionAndConstructor( + [.number, .number, .number, .opt(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate) + + .object( + ofGroup: "TemporalPlainDateConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalPlainDateTime = ILType.object( + ofGroup: "Temporal.PlainDateTime", withProperties: dateProperties + timeProperties, + withMethods: [ + "with", "withPlainTime", "withCalendar", "add", "subtract", "until", "since", "round", + "equals", "toZonedDateTime", "toPlainDate", "toPlainTime", + ] + commonStringifierMethods) + + public static let jsTemporalPlainDateTimeConstructor = + ILType.functionAndConstructor( + [ + .number, .number, .number, .opt(.number), .opt(.number), .opt(.number), + .opt(.number), .opt(.number), .opt(.number), .opt(.jsTemporalCalendarEnum), + ] => .jsTemporalPlainDateTime) + + .object( + ofGroup: "TemporalPlainDateTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalZonedDateTime = ILType.object( + ofGroup: "Temporal.ZonedDateTime", + withProperties: dateProperties + timeProperties + [ + "timeZoneId", "epochMilliseconds", "epochNanoseconds", "offsetNanoseconds", "offset", + ], + withMethods: [ + "with", "withPlainTime", "withTimeZone", "withCalendar", "add", "subtract", "until", + "since", "round", "equals", "startOfDay", "getTimeZoneTransition", "toInstant", + "toPlainDate", "toPlainTime", "toPlainDateTime", + ] + commonStringifierMethods) + + public static let jsTemporalZonedDateTimeConstructor = + ILType.functionAndConstructor( + [.bigint, .string, .opt(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime) + + .object( + ofGroup: "TemporalZonedDateTimeConstructor", withProperties: ["prototype"], + withMethods: ["from", "compare"]) + + public static let jsTemporalNow = ILType.object( + ofGroup: "Temporal.Now", withProperties: [], + withMethods: [ + "timeZoneId", "instant", "plainDateTimeISO", "zonedDateTimeISO", "plainDateISO", + "plainTimeISO", + ]) } -public extension ObjectGroup { +extension ObjectGroup { // Creates an object group representing a "prototype" object on a built-in, like Date.prototype. // These objects are somewhat special in JavaScript as they describe an object which has // methods on them for which you shall not call them with the bound this as a receiver, e.g. @@ -1440,14 +1912,17 @@ public extension ObjectGroup { // them. Instead Fuzzilli generates GetProperty operations for them which will then be typed as // an `ILType.unboundFunction` which knows the required receiver type (in the example `Date`), // so Fuzzilli can generate sequences like `Date.prototype.getTime.call(new Date())`. - static func createPrototypeObjectGroup( - _ receiver: ObjectGroup, - constructor: ILType = .object(), - excludeProperties: [String] = [], - additionalProperties: [String: ILType] = [:]) -> ObjectGroup { + public static func createPrototypeObjectGroup( + _ receiver: ObjectGroup, + constructor: ILType = .object(), + excludeProperties: [String] = [], + additionalProperties: [String: ILType] = [:] + ) -> ObjectGroup { let name = receiver.name + ".prototype" - var properties = Dictionary(uniqueKeysWithValues: receiver.methods.map { - ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) }) + var properties = Dictionary( + uniqueKeysWithValues: receiver.methods.map { + ($0.0, ILType.unboundFunction($0.1.first, receiver: receiver.instanceType)) + }) properties.merge(additionalProperties) { _, _ in fatalError("duplicate property") @@ -1467,7 +1942,8 @@ public extension ObjectGroup { } return ObjectGroup( name: name, - instanceType: .object(ofGroup: name, withProperties: properties.map {$0.0}, withMethods: []), + instanceType: .object( + ofGroup: name, withProperties: properties.map { $0.0 }, withMethods: []), properties: properties, methods: [:] ) @@ -1478,179 +1954,180 @@ public extension ObjectGroup { // The general rules here are: // * "output" type information (properties and return values) should be as precise as possible // * "input" type information (function parameters) should be as broad as possible -public extension ObjectGroup { +extension ObjectGroup { /// Object group modelling JavaScript strings - static let jsStrings = ObjectGroup( + public static let jsStrings = ObjectGroup( name: "String", instanceType: .jsString, properties: [ - "length" : .integer, + "length": .integer ], methods: [ - "charAt" : [.integer] => .jsString, - "charCodeAt" : [.integer] => .integer, - "codePointAt" : [.integer] => .integer, - "concat" : [.jsAnything...] => .jsString, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "endsWith" : [.string, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "match" : [.regexp] => .jsArray, - "matchAll" : [.regexp] => .jsIterator, - "normalize" : [] => .jsString, // the first parameter must be a specific string value, so we have a CodeGenerator for that instead - "padEnd" : [.integer, .opt(.string)] => .jsString, - "padStart" : [.integer, .opt(.string)] => .jsString, - "repeat" : [.integer] => .jsString, - "replace" : [.oneof(.string, .regexp), .string] => .jsString, - "replaceAll" : [.string, .string] => .jsString, - "search" : [.regexp] => .integer, - "slice" : [.integer, .opt(.integer)] => .jsString, - "split" : [.opt(.string), .opt(.integer)] => .jsArray, - "startsWith" : [.string, .opt(.integer)] => .boolean, - "substring" : [.integer, .opt(.integer)] => .jsString, - "trim" : [] => .undefined, - "trimStart" : [] => .jsString, - "trimLeft" : [] => .jsString, - "trimEnd" : [] => .jsString, - "trimRight" : [] => .jsString, - "toLowerCase" : [] => .jsString, - "toUpperCase" : [] => .jsString, - "localeCompare" : [.string, .opt(.string), .opt(.object())] => .integer, - "anchor" : [.string] => .jsString, - "at" : [.integer] => .jsString, - "big" : [] => .jsString, - "blink" : [] => .jsString, - "bold" : [] => .jsString, - "fixed" : [] => .jsString, - "fontcolor" : [.string] => .jsString, - "fontsize" : [.integer] => .jsString, + "charAt": [.integer] => .jsString, + "charCodeAt": [.integer] => .integer, + "codePointAt": [.integer] => .integer, + "concat": [.jsAnything...] => .jsString, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "endsWith": [.string, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "match": [.regexp] => .jsArray, + "matchAll": [.regexp] => .jsIterator, + "normalize": [] => .jsString, // the first parameter must be a specific string value, so we have a CodeGenerator for that instead + "padEnd": [.integer, .opt(.string)] => .jsString, + "padStart": [.integer, .opt(.string)] => .jsString, + "repeat": [.integer] => .jsString, + "replace": [.oneof(.string, .regexp), .string] => .jsString, + "replaceAll": [.string, .string] => .jsString, + "search": [.regexp] => .integer, + "slice": [.integer, .opt(.integer)] => .jsString, + "split": [.opt(.string), .opt(.integer)] => .jsArray, + "startsWith": [.string, .opt(.integer)] => .boolean, + "substring": [.integer, .opt(.integer)] => .jsString, + "trim": [] => .undefined, + "trimStart": [] => .jsString, + "trimLeft": [] => .jsString, + "trimEnd": [] => .jsString, + "trimRight": [] => .jsString, + "toLowerCase": [] => .jsString, + "toUpperCase": [] => .jsString, + "localeCompare": [.string, .opt(.string), .opt(.object())] => .integer, + "anchor": [.string] => .jsString, + "at": [.integer] => .jsString, + "big": [] => .jsString, + "blink": [] => .jsString, + "bold": [] => .jsString, + "fixed": [] => .jsString, + "fontcolor": [.string] => .jsString, + "fontsize": [.integer] => .jsString, "isWellFormed": [] => .boolean, - "italics" : [] => .jsString, - "link" : [.string] => .jsString, - "small" : [] => .jsString, - "strike" : [] => .jsString, - "sub" : [] => .jsString, - "substr" : [.integer, .opt(.integer)] => .jsString, - "sup" : [] => .jsString, - "toLocaleLowerCase" : [.opt(.jsIntlLocaleLike)] => .jsString, - "toLocaleUpperCase" : [.opt(.jsIntlLocaleLike)] => .jsString, + "italics": [] => .jsString, + "link": [.string] => .jsString, + "small": [] => .jsString, + "strike": [] => .jsString, + "sub": [] => .jsString, + "substr": [.integer, .opt(.integer)] => .jsString, + "sup": [] => .jsString, + "toLocaleLowerCase": [.opt(.jsIntlLocaleLike)] => .jsString, + "toLocaleUpperCase": [.opt(.jsIntlLocaleLike)] => .jsString, "toWellFormed": [] => .jsString, ] ) /// Object group modelling JavaScript regular expressions. - static let jsRegExps = ObjectGroup( + public static let jsRegExps = ObjectGroup( name: "RegExp", instanceType: .jsRegExp, properties: [ - "flags" : .string, - "dotAll" : .boolean, - "global" : .boolean, - "ignoreCase" : .boolean, - "multiline" : .boolean, - "source" : .string, - "sticky" : .boolean, - "unicode" : .boolean, + "flags": .string, + "dotAll": .boolean, + "global": .boolean, + "ignoreCase": .boolean, + "multiline": .boolean, + "source": .string, + "sticky": .boolean, + "unicode": .boolean, ], methods: [ - "compile" : [.string] => .jsRegExp, - "exec" : [.string] => .jsArray, - "test" : [.string] => .boolean, + "compile": [.string] => .jsRegExp, + "exec": [.string] => .jsArray, + "test": [.string] => .boolean, ] ) /// Object group modelling JavaScript arrays - static let jsArrays = ObjectGroup( + public static let jsArrays = ObjectGroup( name: "Array", instanceType: .jsArray, properties: [ - "length" : .integer, + "length": .integer ], methods: [ - "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsArray, - "entries" : [] => .jsIterator, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsArray, - "find" : [.function(), .opt(.object())] => .jsAnything, - "findIndex" : [.function(), .opt(.object())] => .integer, - "findLast" : [.function(), .opt(.object())] => .jsAnything, - "findLastIndex" : [.function(), .opt(.object())] => .integer, - "forEach" : [.function(), .opt(.object())] => .undefined, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "join" : [.string] => .jsString, - "keys" : [] => .jsIterator, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .jsArray, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .jsArray, - "values" : [] => .jsIterator, - "pop" : [] => .jsAnything, - "push" : [.jsAnything...] => .integer, - "shift" : [] => .jsAnything, - "splice" : [.integer, .opt(.integer), .jsAnything...] => .jsArray, - "unshift" : [.jsAnything...] => .integer, - "concat" : [.jsAnything...] => .jsArray, - "filter" : [.function(), .opt(.object())] => .jsArray, - "map" : [.function(), .opt(.object())] => .jsArray, - "slice" : [.opt(.integer), .opt(.integer)] => .jsArray, - "flat" : [.opt(.integer)] => .jsArray, - "flatMap" : [.function(), .opt(.jsAnything)] => .jsArray, - "toString" : [] => .jsString, - "toLocaleString" : [.opt(.string), .opt(.object())] => .jsString, - "toReversed" : [] => .jsArray, - "toSorted" : [.opt(.function())] => .jsArray, - "toSpliced" : [.integer, .opt(.integer), .jsAnything...] => .jsArray, - "with" : [.integer, .jsAnything] => .jsArray, + "at": [.integer] => .jsAnything, + "copyWithin": [.integer, .integer, .opt(.integer)] => .jsArray, + "entries": [] => .jsIterator, + "every": [.function(), .opt(.object())] => .boolean, + "fill": [.jsAnything, .opt(.integer), .opt(.integer)] => .jsArray, + "find": [.function(), .opt(.object())] => .jsAnything, + "findIndex": [.function(), .opt(.object())] => .integer, + "findLast": [.function(), .opt(.object())] => .jsAnything, + "findLastIndex": [.function(), .opt(.object())] => .integer, + "forEach": [.function(), .opt(.object())] => .undefined, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "join": [.string] => .jsString, + "keys": [] => .jsIterator, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "reduceRight": [.function(), .opt(.jsAnything)] => .jsAnything, + "reverse": [] => .jsArray, + "some": [.function(), .opt(.jsAnything)] => .boolean, + "sort": [.function()] => .jsArray, + "values": [] => .jsIterator, + "pop": [] => .jsAnything, + "push": [.jsAnything...] => .integer, + "shift": [] => .jsAnything, + "splice": [.integer, .opt(.integer), .jsAnything...] => .jsArray, + "unshift": [.jsAnything...] => .integer, + "concat": [.jsAnything...] => .jsArray, + "filter": [.function(), .opt(.object())] => .jsArray, + "map": [.function(), .opt(.object())] => .jsArray, + "slice": [.opt(.integer), .opt(.integer)] => .jsArray, + "flat": [.opt(.integer)] => .jsArray, + "flatMap": [.function(), .opt(.jsAnything)] => .jsArray, + "toString": [] => .jsString, + "toLocaleString": [.opt(.string), .opt(.object())] => .jsString, + "toReversed": [] => .jsArray, + "toSorted": [.opt(.function())] => .jsArray, + "toSpliced": [.integer, .opt(.integer), .jsAnything...] => .jsArray, + "with": [.integer, .jsAnything] => .jsArray, ] ) /// ObjectGroup modelling JavaScript functions - static let jsFunctions = ObjectGroup( + public static let jsFunctions = ObjectGroup( name: "Function", instanceType: .jsFunction(), properties: [ - "prototype" : .object(), - "length" : .integer, - "arguments" : .jsArray, - "caller" : .jsFunction(), - "name" : .jsString, + "prototype": .object(), + "length": .integer, + "arguments": .jsArray, + "caller": .jsFunction(), + "name": .jsString, ], methods: [ - "apply" : [.object(), .object()] => .jsAnything, - "call" : [.object(), .jsAnything...] => .jsAnything, - "bind" : [.object(), .jsAnything...] => .jsAnything, + "apply": [.object(), .object()] => .jsAnything, + "call": [.object(), .jsAnything...] => .jsAnything, + "bind": [.object(), .jsAnything...] => .jsAnything, ] ) - static let jsFunctionPrototype = createPrototypeObjectGroup(jsFunctions, + public static let jsFunctionPrototype = createPrototypeObjectGroup( + jsFunctions, constructor: .jsFunctionConstructor) - static let jsFunctionConstructor = ObjectGroup( + public static let jsFunctionConstructor = ObjectGroup( name: "FunctionConstructor", constructorPath: "Function", instanceType: .jsFunctionConstructor, properties: [ - "prototype" : jsFunctionPrototype.instanceType, + "prototype": jsFunctionPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript Symbols - static let jsSymbols = ObjectGroup( + public static let jsSymbols = ObjectGroup( name: "Symbol", instanceType: .jsSymbol, properties: [ - "description" : .jsString, + "description": .jsString ], methods: [:] ) /// Object group modelling JavaScript arguments objects. - static let jsArguments = ObjectGroup( + public static let jsArguments = ObjectGroup( name: "Arguments", instanceType: .jsArguments, properties: [ @@ -1660,95 +2137,97 @@ public extension ObjectGroup { methods: [:] ) - static let jsIterator = ObjectGroup( + public static let jsIterator = ObjectGroup( name: "Iterator", instanceType: .jsIterator, properties: [ "done": .boolean, - "value": .jsAnything + "value": .jsAnything, ], methods: [ - "next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "return" : [.jsAnything] => .object(withProperties: ["done", "value"]), - "throw" : [.jsAnything] => .object(withProperties: ["done", "value"]), - "map" : [.function()] => .jsIterator, - "filter" : [.function()] => .jsIterator, - "take" : [.integer] => .jsIterator, - "drop" : [.integer] => .jsIterator, - "flatMap" : [.function()] => .jsIterator, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "toArray" : [] => .jsArray, - "forEach" : [.function()] => .undefined, - "some" : [.function()] => .boolean, - "every" : [.function()] => .boolean, - "find" : [.function()] => .jsAnything, + "next": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "return": [.jsAnything] => .object(withProperties: ["done", "value"]), + "throw": [.jsAnything] => .object(withProperties: ["done", "value"]), + "map": [.function()] => .jsIterator, + "filter": [.function()] => .jsIterator, + "take": [.integer] => .jsIterator, + "drop": [.integer] => .jsIterator, + "flatMap": [.function()] => .jsIterator, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "toArray": [] => .jsArray, + "forEach": [.function()] => .undefined, + "some": [.function()] => .boolean, + "every": [.function()] => .boolean, + "find": [.function()] => .jsAnything, ] ) // next, return and throw are part of the Iterator protocol, not Iterator.prototype. - static let jsIteratorPrototype = createPrototypeObjectGroup(jsIterator, + public static let jsIteratorPrototype = createPrototypeObjectGroup( + jsIterator, constructor: .jsIteratorConstructor, excludeProperties: ["next", "return", "throw"]) - static let jsIteratorConstructor = ObjectGroup( + public static let jsIteratorConstructor = ObjectGroup( name: "IteratorConstructor", instanceType: .jsIteratorConstructor, properties: [ - "prototype" : jsIteratorPrototype.instanceType + "prototype": jsIteratorPrototype.instanceType ], methods: [ - "from" : [.jsAnything] => .jsIterator, - "concat" : [.jsAnything...] => .jsIterator, - "zip" : [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] => .jsIterator, + "from": [.jsAnything] => .jsIterator, + "concat": [.jsAnything...] => .jsIterator, + "zip": [.iterable, .opt(OptionsBag.jsIteratorZipSettings.group.instanceType)] + => .jsIterator, ] ) - static let jsGenerators = ObjectGroup( + public static let jsGenerators = ObjectGroup( name: "Generator", instanceType: .jsGenerator, properties: [:], methods: [ - "next" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "return" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), - "throw" : [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "next": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "return": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), + "throw": [.opt(.jsAnything)] => .object(withProperties: ["done", "value"]), ] ) /// Object group modelling JavaScript promises. - static let jsPromises = ObjectGroup( + public static let jsPromises = ObjectGroup( name: "Promise", instanceType: .jsPromise, properties: [:], methods: [ - "catch" : [.function()] => .jsPromise, - "then" : [.function()] => .jsPromise, - "finally" : [.function()] => .jsPromise, + "catch": [.function()] => .jsPromise, + "then": [.function()] => .jsPromise, + "finally": [.function()] => .jsPromise, ] ) /// ObjectGroup modelling JavaScript Map objects - static let jsMaps = ObjectGroup( + public static let jsMaps = ObjectGroup( name: "Map", instanceType: .jsMap, properties: [ - "size" : .integer + "size": .integer ], methods: [ - "clear" : [] => .undefined, - "delete" : [.jsAnything] => .boolean, - "entries" : [] => .jsIterator, - "forEach" : [.function(), .opt(.object())] => .undefined, - "get" : [.jsAnything] => .jsAnything, - "has" : [.jsAnything] => .boolean, - "keys" : [] => .jsIterator, - "set" : [.jsAnything, .jsAnything] => .jsMap, - "values" : [] => .jsIterator, - "getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything, + "clear": [] => .undefined, + "delete": [.jsAnything] => .boolean, + "entries": [] => .jsIterator, + "forEach": [.function(), .opt(.object())] => .undefined, + "get": [.jsAnything] => .jsAnything, + "has": [.jsAnything] => .boolean, + "keys": [] => .jsIterator, + "set": [.jsAnything, .jsAnything] => .jsMap, + "values": [] => .jsIterator, + "getOrInsert": [.jsAnything, .jsAnything] => .jsAnything, "getOrInsertComputed": [.jsAnything, .function()] => .jsAnything, ] ) - static let jsProxyConstructor = ObjectGroup( + public static let jsProxyConstructor = ObjectGroup( name: "ProxyConstructor", constructorPath: "Proxy", instanceType: .jsProxyConstructor, @@ -1758,15 +2237,16 @@ public extension ObjectGroup { ] ) - static let jsMapPrototype = createPrototypeObjectGroup(jsMaps, + public static let jsMapPrototype = createPrototypeObjectGroup( + jsMaps, constructor: .jsMapConstructor) - static let jsMapConstructor = ObjectGroup( + public static let jsMapConstructor = ObjectGroup( name: "MapConstructor", constructorPath: "Map", instanceType: .jsMapConstructor, properties: [ - "prototype" : jsMapPrototype.instanceType + "prototype": jsMapPrototype.instanceType ], methods: [ "groupBy": [.iterable, .function()] => .jsMap @@ -1774,305 +2254,318 @@ public extension ObjectGroup { ) /// ObjectGroup modelling JavaScript WeakMap objects - static let jsWeakMaps = ObjectGroup( + public static let jsWeakMaps = ObjectGroup( name: "WeakMap", instanceType: .jsWeakMap, properties: [:], methods: [ - "delete" : [.jsAnything] => .boolean, - "get" : [.jsAnything] => .jsAnything, - "has" : [.jsAnything] => .boolean, - "set" : [.jsAnything, .jsAnything] => .jsWeakMap, - "getOrInsert" : [.jsAnything, .jsAnything] => .jsAnything, + "delete": [.jsAnything] => .boolean, + "get": [.jsAnything] => .jsAnything, + "has": [.jsAnything] => .boolean, + "set": [.jsAnything, .jsAnything] => .jsWeakMap, + "getOrInsert": [.jsAnything, .jsAnything] => .jsAnything, "getOrInsertComputed": [.jsAnything, .function()] => .jsAnything, ] ) - static let jsWeakMapPrototype = createPrototypeObjectGroup(jsWeakMaps, + public static let jsWeakMapPrototype = createPrototypeObjectGroup( + jsWeakMaps, constructor: .jsWeakMapConstructor) - static let jsWeakMapConstructor = ObjectGroup( + public static let jsWeakMapConstructor = ObjectGroup( name: "WeakMapConstructor", constructorPath: "WeakMap", instanceType: .jsWeakMapConstructor, properties: [ - "prototype" : jsWeakMapPrototype.instanceType + "prototype": jsWeakMapPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript Set objects - static let jsSets = ObjectGroup( + public static let jsSets = ObjectGroup( name: "Set", instanceType: .jsSet, properties: [ - "size" : .integer + "size": .integer ], methods: [ - "add" : [.jsAnything] => .jsSet, - "clear" : [] => .undefined, - "delete" : [.jsAnything] => .boolean, - "difference" : [.plain(.jsSet)] => .jsSet, - "entries" : [] => .jsIterator, - "forEach" : [.function(), .opt(.object())] => .undefined, - "has" : [.jsAnything] => .boolean, - "intersection" : [.plain(.jsSet)] => .jsSet, - "isDisjointFrom" : [.plain(.jsSet)] => .boolean, - "isSubsetOf" : [.plain(.jsSet)] => .boolean, - "isSupersetOf" : [.plain(.jsSet)] => .boolean, - "keys" : [] => .jsIterator, - "symmetricDifference" : [.plain(.jsSet)] => .jsSet, - "union" : [.plain(.jsSet)] => .jsSet, - "values" : [] => .jsIterator, + "add": [.jsAnything] => .jsSet, + "clear": [] => .undefined, + "delete": [.jsAnything] => .boolean, + "difference": [.plain(.jsSet)] => .jsSet, + "entries": [] => .jsIterator, + "forEach": [.function(), .opt(.object())] => .undefined, + "has": [.jsAnything] => .boolean, + "intersection": [.plain(.jsSet)] => .jsSet, + "isDisjointFrom": [.plain(.jsSet)] => .boolean, + "isSubsetOf": [.plain(.jsSet)] => .boolean, + "isSupersetOf": [.plain(.jsSet)] => .boolean, + "keys": [] => .jsIterator, + "symmetricDifference": [.plain(.jsSet)] => .jsSet, + "union": [.plain(.jsSet)] => .jsSet, + "values": [] => .jsIterator, ] ) - static let jsSetPrototype = createPrototypeObjectGroup(jsSets, + public static let jsSetPrototype = createPrototypeObjectGroup( + jsSets, constructor: .jsSetConstructor) - static let jsSetConstructor = ObjectGroup( + public static let jsSetConstructor = ObjectGroup( name: "SetConstructor", constructorPath: "Set", instanceType: .jsSetConstructor, properties: [ - "prototype" : jsSetPrototype.instanceType + "prototype": jsSetPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript WeakSet objects - static let jsWeakSets = ObjectGroup( + public static let jsWeakSets = ObjectGroup( name: "WeakSet", instanceType: .jsWeakSet, properties: [:], methods: [ - "add" : [.jsAnything] => .jsWeakSet, - "delete" : [.jsAnything] => .boolean, - "has" : [.jsAnything] => .boolean, + "add": [.jsAnything] => .jsWeakSet, + "delete": [.jsAnything] => .boolean, + "has": [.jsAnything] => .boolean, ] ) - static let jsWeakSetPrototype = createPrototypeObjectGroup(jsWeakSets, + public static let jsWeakSetPrototype = createPrototypeObjectGroup( + jsWeakSets, constructor: .jsWeakSetConstructor) - static let jsWeakSetConstructor = ObjectGroup( + public static let jsWeakSetConstructor = ObjectGroup( name: "WeakSetConstructor", constructorPath: "WeakSet", instanceType: .jsWeakSetConstructor, properties: [ - "prototype" : jsWeakSetPrototype.instanceType + "prototype": jsWeakSetPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript WeakRef objects - static let jsWeakRefs = ObjectGroup( + public static let jsWeakRefs = ObjectGroup( name: "WeakRef", instanceType: .jsWeakRef, properties: [:], methods: [ - "deref" : [] => .object(), + "deref": [] => .object() ] ) - static let jsWeakRefPrototype = createPrototypeObjectGroup(jsWeakRefs, + public static let jsWeakRefPrototype = createPrototypeObjectGroup( + jsWeakRefs, constructor: .jsWeakRefConstructor) - static let jsWeakRefConstructor = ObjectGroup( + public static let jsWeakRefConstructor = ObjectGroup( name: "WeakRefConstructor", constructorPath: "WeakRef", instanceType: .jsWeakRefConstructor, properties: [ - "prototype" : jsWeakRefPrototype.instanceType + "prototype": jsWeakRefPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript FinalizationRegistry objects - static let jsFinalizationRegistrys = ObjectGroup( + public static let jsFinalizationRegistrys = ObjectGroup( name: "FinalizationRegistry", instanceType: .jsFinalizationRegistry, properties: [:], methods: [ - "register" : [.object(), .jsAnything, .opt(.object())] => .undefined, - "unregister" : [.jsAnything] => .boolean, + "register": [.object(), .jsAnything, .opt(.object())] => .undefined, + "unregister": [.jsAnything] => .boolean, ] ) - static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup(jsFinalizationRegistrys, + public static let jsFinalizationRegistryPrototype = createPrototypeObjectGroup( + jsFinalizationRegistrys, constructor: .jsFinalizationRegistryConstructor) - static let jsFinalizationRegistryConstructor = ObjectGroup( + public static let jsFinalizationRegistryConstructor = ObjectGroup( name: "FinalizationRegistryConstructor", constructorPath: "FinalizationRegistry", instanceType: .jsFinalizationRegistryConstructor, properties: [ - "prototype" : jsFinalizationRegistryPrototype.instanceType + "prototype": jsFinalizationRegistryPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript DisposableStack objects - static let jsDisposableStacks = ObjectGroup( + public static let jsDisposableStacks = ObjectGroup( name: "DisposableStack", instanceType: .jsDisposableStack, properties: [ - "disposed" : .boolean + "disposed": .boolean ], methods: [ - "dispose" : [] => .undefined, - "use" : [.jsAnything] => .jsAnything, - "adopt" : [.jsAnything, .function()] => .jsAnything, - "defer" : [.function()] => .undefined, - "move" : [] => .jsDisposableStack, + "dispose": [] => .undefined, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsDisposableStack, ] ) - static let jsDisposableStackPrototype = createPrototypeObjectGroup(jsDisposableStacks, + public static let jsDisposableStackPrototype = createPrototypeObjectGroup( + jsDisposableStacks, constructor: .jsDisposableStackConstructor) - static let jsDisposableStackConstructor = ObjectGroup( + public static let jsDisposableStackConstructor = ObjectGroup( name: "DisposableStackConstructor", constructorPath: "DisposableStack", instanceType: .jsDisposableStackConstructor, properties: [ - "prototype" : jsDisposableStackPrototype.instanceType + "prototype": jsDisposableStackPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript AsyncDisposableStack objects - static let jsAsyncDisposableStacks = ObjectGroup( + public static let jsAsyncDisposableStacks = ObjectGroup( name: "AsyncDisposableStack", instanceType: .jsAsyncDisposableStack, properties: [ - "disposed" : .boolean + "disposed": .boolean ], methods: [ - "disposeAsync" : [] => .jsPromise, - "use" : [.jsAnything] => .jsAnything, - "adopt" : [.jsAnything, .function()] => .jsAnything, - "defer" : [.function()] => .undefined, - "move" : [] => .jsAsyncDisposableStack, + "disposeAsync": [] => .jsPromise, + "use": [.jsAnything] => .jsAnything, + "adopt": [.jsAnything, .function()] => .jsAnything, + "defer": [.function()] => .undefined, + "move": [] => .jsAsyncDisposableStack, ] ) - static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup(jsAsyncDisposableStacks, + public static let jsAsyncDisposableStackPrototype = createPrototypeObjectGroup( + jsAsyncDisposableStacks, constructor: .jsAsyncDisposableStackConstructor) - static let jsAsyncDisposableStackConstructor = ObjectGroup( + public static let jsAsyncDisposableStackConstructor = ObjectGroup( name: "AsyncDisposableStackConstructor", constructorPath: "AsyncDisposableStack", instanceType: .jsAsyncDisposableStackConstructor, properties: [ - "prototype" : jsAsyncDisposableStackPrototype.instanceType + "prototype": jsAsyncDisposableStackPrototype.instanceType ], methods: [:] ) /// ObjectGroup modelling JavaScript ArrayBuffer objects - static let jsArrayBuffers = ObjectGroup( + public static let jsArrayBuffers = ObjectGroup( name: "ArrayBuffer", instanceType: .jsArrayBuffer, properties: [ - "byteLength" : .integer, - "maxByteLength" : .integer, - "resizable" : .boolean, + "byteLength": .integer, + "maxByteLength": .integer, + "resizable": .boolean, ], methods: [ - "resize" : [.integer] => .undefined, - "slice" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, - "sliceToImmutable" : [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, - "transfer" : [.opt(.integer)] => .jsArrayBuffer, - "transferToFixedLength" : [.opt(.integer)] => .jsArrayBuffer, - "transferToImmutable" : [.opt(.integer)] => .jsArrayBuffer, + "resize": [.integer] => .undefined, + "slice": [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, + "sliceToImmutable": [.opt(.integer), .opt(.integer)] => .jsArrayBuffer, + "transfer": [.opt(.integer)] => .jsArrayBuffer, + "transferToFixedLength": [.opt(.integer)] => .jsArrayBuffer, + "transferToImmutable": [.opt(.integer)] => .jsArrayBuffer, ] ) /// ObjectGroup modelling JavaScript SharedArrayBuffer objects - static let jsSharedArrayBuffers = ObjectGroup( + public static let jsSharedArrayBuffers = ObjectGroup( name: "SharedArrayBuffer", instanceType: .jsSharedArrayBuffer, properties: [ - "byteLength" : .integer, - "maxByteLength" : .integer, - "growable" : .boolean, + "byteLength": .integer, + "maxByteLength": .integer, + "growable": .boolean, ], methods: [ - "grow" : [.number] => .undefined, - "slice" : [.integer, .opt(.integer)] => .jsSharedArrayBuffer, + "grow": [.number] => .undefined, + "slice": [.integer, .opt(.integer)] => .jsSharedArrayBuffer, ] ) /// ObjectGroup modelling JavaScript TypedArray objects - static func jsTypedArrays(_ variant: String) -> ObjectGroup { + public static func jsTypedArrays(_ variant: String) -> ObjectGroup { // Extra methods from the base64 proposal: https://tc39.es/proposal-arraybuffer-base64/ - let extraMethods: [String: Signature] = variant != "Uint8Array" ? [:] : [ - "toBase64": [.opt(OptionsBag.toBase64Settings.group.instanceType)] => .string, - "toHex": [] => .string, - "setFromBase64": [.string, .opt(OptionsBag.fromBase64Settings.group.instanceType)] - => .object(withProperties: ["read", "written"]), - "setFromHex": [.string] => .object(withProperties: ["read", "written"]), - ] + let extraMethods: [String: Signature] = + variant != "Uint8Array" + ? [:] + : [ + "toBase64": [.opt(OptionsBag.toBase64Settings.group.instanceType)] => .string, + "toHex": [] => .string, + "setFromBase64": [.string, .opt(OptionsBag.fromBase64Settings.group.instanceType)] + => .object(withProperties: ["read", "written"]), + "setFromHex": [.string] => .object(withProperties: ["read", "written"]), + ] return ObjectGroup( name: variant, instanceType: .jsTypedArray(variant), properties: [ "BYTES_PER_ELEMENT": .integer, - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer, - "length" : .integer + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, + "length": .integer, ], methods: [ - "at" : [.integer] => .jsAnything, - "copyWithin" : [.integer, .integer, .opt(.integer)] => .jsTypedArray(variant), - "entries" : [] => .jsIterator, - "every" : [.function(), .opt(.object())] => .boolean, - "fill" : [.jsAnything, .opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "find" : [.function(), .opt(.object())] => .jsAnything, - "findIndex" : [.function(), .opt(.object())] => .integer, - "findLast" : [.function(), .opt(.object())] => .jsAnything, - "findLastIndex" : [.function(), .opt(.object())] => .integer, - "forEach" : [.function(), .opt(.object())] => .undefined, - "includes" : [.jsAnything, .opt(.integer)] => .boolean, - "indexOf" : [.jsAnything, .opt(.integer)] => .integer, - "join" : [.string] => .jsString, - "keys" : [] => .jsIterator, - "lastIndexOf" : [.jsAnything, .opt(.integer)] => .integer, - "reduce" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reduceRight" : [.function(), .opt(.jsAnything)] => .jsAnything, - "reverse" : [] => .jsTypedArray(variant), - "set" : [.object(), .opt(.integer)] => .undefined, - "some" : [.function(), .opt(.jsAnything)] => .boolean, - "sort" : [.function()] => .jsTypedArray(variant), - "values" : [] => .jsIterator, - "filter" : [.function(), .opt(.object())] => .jsTypedArray(variant), - "map" : [.function(), .opt(.object())] => .jsTypedArray(variant), - "slice" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "subarray" : [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), - "toString" : [] => .jsString, - "toLocaleString" : [.opt(.string), .opt(.object())] => .jsString, - "toReversed" : [] => .jsTypedArray(variant), - "toSorted" : [.opt(.function())] => .jsTypedArray(variant), - "with" : [.integer, .jsAnything] => .jsTypedArray(variant), + "at": [.integer] => .jsAnything, + "copyWithin": [.integer, .integer, .opt(.integer)] => .jsTypedArray(variant), + "entries": [] => .jsIterator, + "every": [.function(), .opt(.object())] => .boolean, + "fill": [.jsAnything, .opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "find": [.function(), .opt(.object())] => .jsAnything, + "findIndex": [.function(), .opt(.object())] => .integer, + "findLast": [.function(), .opt(.object())] => .jsAnything, + "findLastIndex": [.function(), .opt(.object())] => .integer, + "forEach": [.function(), .opt(.object())] => .undefined, + "includes": [.jsAnything, .opt(.integer)] => .boolean, + "indexOf": [.jsAnything, .opt(.integer)] => .integer, + "join": [.string] => .jsString, + "keys": [] => .jsIterator, + "lastIndexOf": [.jsAnything, .opt(.integer)] => .integer, + "reduce": [.function(), .opt(.jsAnything)] => .jsAnything, + "reduceRight": [.function(), .opt(.jsAnything)] => .jsAnything, + "reverse": [] => .jsTypedArray(variant), + "set": [.object(), .opt(.integer)] => .undefined, + "some": [.function(), .opt(.jsAnything)] => .boolean, + "sort": [.function()] => .jsTypedArray(variant), + "values": [] => .jsIterator, + "filter": [.function(), .opt(.object())] => .jsTypedArray(variant), + "map": [.function(), .opt(.object())] => .jsTypedArray(variant), + "slice": [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "subarray": [.opt(.integer), .opt(.integer)] => .jsTypedArray(variant), + "toString": [] => .jsString, + "toLocaleString": [.opt(.string), .opt(.object())] => .jsString, + "toReversed": [] => .jsTypedArray(variant), + "toSorted": [.opt(.function())] => .jsTypedArray(variant), + "with": [.integer, .jsAnything] => .jsTypedArray(variant), ].merging(extraMethods) { _, _ in fatalError("duplicate method") } ) } - static func jsTypedArrayPrototype(_ variant: String) -> ObjectGroup { + public static func jsTypedArrayPrototype(_ variant: String) -> ObjectGroup { return createPrototypeObjectGroup( jsTypedArrays(variant), constructor: .jsTypedArrayConstructor(variant), additionalProperties: [ - "BYTES_PER_ELEMENT": .integer, + "BYTES_PER_ELEMENT": .integer ]) } - static func jsTypedArrayConstructor(_ variant: String) -> ObjectGroup { - let methods : [String : Signature] = variant == "Uint8Array" + public static func jsTypedArrayConstructor(_ variant: String) -> ObjectGroup { + let methods: [String: Signature] = + variant == "Uint8Array" ? [ - "fromBase64": [.plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType)] => .jsUint8Array, + "fromBase64": [ + .plain(.string), .opt(OptionsBag.fromBase64Settings.group.instanceType), + ] => .jsUint8Array, "fromHex": [.plain(.string)] => .jsUint8Array, ] : [:] @@ -2089,296 +2582,318 @@ public extension ObjectGroup { } /// ObjectGroup modelling JavaScript DataView objects - static let jsDataViews = ObjectGroup( + public static let jsDataViews = ObjectGroup( name: "DataView", instanceType: .jsDataView, properties: [ - "buffer" : .jsArrayBuffer, - "byteLength" : .integer, - "byteOffset" : .integer + "buffer": .jsArrayBuffer, + "byteLength": .integer, + "byteOffset": .integer, ], methods: [ - "getInt8" : [.integer] => .integer, - "getUint8" : [.integer] => .integer, - "getInt16" : [.integer, .opt(.boolean)] => .integer, - "getUint16" : [.integer, .opt(.boolean)] => .integer, - "getInt32" : [.integer, .opt(.boolean)] => .integer, - "getUint32" : [.integer, .opt(.boolean)] => .integer, - "getFloat16" : [.integer, .opt(.boolean)] => .float, - "getFloat32" : [.integer, .opt(.boolean)] => .float, - "getFloat64" : [.integer, .opt(.boolean)] => .float, - "getBigInt64" : [.integer, .opt(.boolean)] => .bigint, + "getInt8": [.integer] => .integer, + "getUint8": [.integer] => .integer, + "getInt16": [.integer, .opt(.boolean)] => .integer, + "getUint16": [.integer, .opt(.boolean)] => .integer, + "getInt32": [.integer, .opt(.boolean)] => .integer, + "getUint32": [.integer, .opt(.boolean)] => .integer, + "getFloat16": [.integer, .opt(.boolean)] => .float, + "getFloat32": [.integer, .opt(.boolean)] => .float, + "getFloat64": [.integer, .opt(.boolean)] => .float, + "getBigInt64": [.integer, .opt(.boolean)] => .bigint, "getBigUint64": [.integer, .opt(.boolean)] => .bigint, - "setInt8" : [.integer, .integer] => .undefined, - "setUint8" : [.integer, .integer] => .undefined, - "setInt16" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setUint16" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setInt32" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setUint32" : [.integer, .integer, .opt(.boolean)] => .undefined, - "setFloat16" : [.integer, .float, .opt(.boolean)] => .undefined, - "setFloat32" : [.integer, .float, .opt(.boolean)] => .undefined, - "setFloat64" : [.integer, .float, .opt(.boolean)] => .undefined, - "setBigInt64" : [.integer, .bigint, .opt(.boolean)] => .undefined, - "setBigUint64" : [.integer, .bigint, .opt(.boolean)] => .undefined, + "setInt8": [.integer, .integer] => .undefined, + "setUint8": [.integer, .integer] => .undefined, + "setInt16": [.integer, .integer, .opt(.boolean)] => .undefined, + "setUint16": [.integer, .integer, .opt(.boolean)] => .undefined, + "setInt32": [.integer, .integer, .opt(.boolean)] => .undefined, + "setUint32": [.integer, .integer, .opt(.boolean)] => .undefined, + "setFloat16": [.integer, .float, .opt(.boolean)] => .undefined, + "setFloat32": [.integer, .float, .opt(.boolean)] => .undefined, + "setFloat64": [.integer, .float, .opt(.boolean)] => .undefined, + "setBigInt64": [.integer, .bigint, .opt(.boolean)] => .undefined, + "setBigUint64": [.integer, .bigint, .opt(.boolean)] => .undefined, ] ) - static let jsDataViewPrototype = createPrototypeObjectGroup(jsDataViews, + public static let jsDataViewPrototype = createPrototypeObjectGroup( + jsDataViews, constructor: .jsDataViewConstructor) - static let jsDataViewConstructor = ObjectGroup( + public static let jsDataViewConstructor = ObjectGroup( name: "DataViewConstructor", constructorPath: "DataView", instanceType: .jsDataViewConstructor, properties: [ - "prototype": jsDataViewPrototype.instanceType, + "prototype": jsDataViewPrototype.instanceType ], methods: [:] ) - static let jsPromisePrototype = + public static let jsPromisePrototype = createPrototypeObjectGroup(jsPromises, constructor: .jsPromiseConstructor) /// ObjectGroup modelling the JavaScript Promise constructor builtin - static let jsPromiseConstructor = ObjectGroup( + public static let jsPromiseConstructor = ObjectGroup( name: "PromiseConstructor", constructorPath: "Promise", instanceType: .jsPromiseConstructor, properties: [ - "prototype" : jsPromisePrototype.instanceType + "prototype": jsPromisePrototype.instanceType ], methods: [ - "resolve" : [.jsAnything] => .jsPromise, - "reject" : [.jsAnything] => .jsPromise, - "all" : [.iterable] => .jsPromise, - "any" : [.iterable] => .jsPromise, - "race" : [.iterable] => .jsPromise, - "allSettled" : [.iterable] => .jsPromise, - "try" : [.function(), .jsAnything...] => .jsPromise, + "resolve": [.jsAnything] => .jsPromise, + "reject": [.jsAnything] => .jsPromise, + "all": [.iterable] => .jsPromise, + "any": [.iterable] => .jsPromise, + "race": [.iterable] => .jsPromise, + "allSettled": [.iterable] => .jsPromise, + "try": [.function(), .jsAnything...] => .jsPromise, "withResolvers": [] => .object(withProperties: ["promise", "resolve", "reject"]), ] ) /// ObjectGroup modelling JavaScript Date objects - static let jsDate = ObjectGroup( + public static let jsDate = ObjectGroup( name: "Date", instanceType: .jsDate, properties: [:], methods: [ - "toISOString" : [] => .jsString, - "toDateString" : [] => .jsString, - "toTimeString" : [] => .jsString, - "toLocaleString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "toLocaleDateString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "toLocaleTimeString" : [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsString, - "getTime" : [] => .number, - "getFullYear" : [] => .number, - "getUTCFullYear" : [] => .number, - "getMonth" : [] => .number, - "getUTCMonth" : [] => .number, - "getDate" : [] => .number, - "getUTCDate" : [] => .number, - "getDay" : [] => .number, - "getUTCDay" : [] => .number, - "getHours" : [] => .number, - "getUTCHours" : [] => .number, - "getMinutes" : [] => .number, - "getUTCMinutes" : [] => .number, - "getSeconds" : [] => .number, - "getUTCSeconds" : [] => .number, - "getMilliseconds" : [] => .number, - "getUTCMilliseconds" : [] => .number, - "getTimezoneOffset" : [] => .number, - "getYear" : [] => .number, - "setTime" : [.number] => .number, - "setMilliseconds" : [.number] => .number, - "setUTCMilliseconds" : [.number] => .number, - "setSeconds" : [.number] => .number, - "setUTCSeconds" : [.number, .opt(.number)] => .number, - "setMinutes" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCMinutes" : [.number, .opt(.number), .opt(.number)] => .number, - "setHours" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCHours" : [.number, .opt(.number), .opt(.number)] => .number, - "setDate" : [.number] => .number, - "setUTCDate" : [.number] => .number, - "setMonth" : [.number] => .number, - "setUTCMonth" : [.number] => .number, - "setFullYear" : [.number, .opt(.number), .opt(.number)] => .number, - "setUTCFullYear" : [.number, .opt(.number), .opt(.number)] => .number, - "setYear" : [.number] => .number, - "toJSON" : [] => .jsString, - "toUTCString" : [] => .jsString, - "toGMTString" : [] => .jsString, - "toTemporalInstant" : [] => .jsTemporalInstant, + "toISOString": [] => .jsString, + "toDateString": [] => .jsString, + "toTimeString": [] => .jsString, + "toLocaleString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "toLocaleDateString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "toLocaleTimeString": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsString, + "getTime": [] => .number, + "getFullYear": [] => .number, + "getUTCFullYear": [] => .number, + "getMonth": [] => .number, + "getUTCMonth": [] => .number, + "getDate": [] => .number, + "getUTCDate": [] => .number, + "getDay": [] => .number, + "getUTCDay": [] => .number, + "getHours": [] => .number, + "getUTCHours": [] => .number, + "getMinutes": [] => .number, + "getUTCMinutes": [] => .number, + "getSeconds": [] => .number, + "getUTCSeconds": [] => .number, + "getMilliseconds": [] => .number, + "getUTCMilliseconds": [] => .number, + "getTimezoneOffset": [] => .number, + "getYear": [] => .number, + "setTime": [.number] => .number, + "setMilliseconds": [.number] => .number, + "setUTCMilliseconds": [.number] => .number, + "setSeconds": [.number] => .number, + "setUTCSeconds": [.number, .opt(.number)] => .number, + "setMinutes": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCMinutes": [.number, .opt(.number), .opt(.number)] => .number, + "setHours": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCHours": [.number, .opt(.number), .opt(.number)] => .number, + "setDate": [.number] => .number, + "setUTCDate": [.number] => .number, + "setMonth": [.number] => .number, + "setUTCMonth": [.number] => .number, + "setFullYear": [.number, .opt(.number), .opt(.number)] => .number, + "setUTCFullYear": [.number, .opt(.number), .opt(.number)] => .number, + "setYear": [.number] => .number, + "toJSON": [] => .jsString, + "toUTCString": [] => .jsString, + "toGMTString": [] => .jsString, + "toTemporalInstant": [] => .jsTemporalInstant, ] ) - static let jsDatePrototype = createPrototypeObjectGroup(jsDate, constructor: .jsDateConstructor) + public static let jsDatePrototype = createPrototypeObjectGroup( + jsDate, constructor: .jsDateConstructor) /// ObjectGroup modelling the JavaScript Date constructor - static let jsDateConstructor = ObjectGroup( + public static let jsDateConstructor = ObjectGroup( name: "DateConstructor", constructorPath: "Date", instanceType: .jsDateConstructor, properties: [ - "prototype" : jsDatePrototype.instanceType + "prototype": jsDatePrototype.instanceType ], methods: [ - "UTC" : [.number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number)] => .number, - "now" : [] => .number, - "parse" : [.string] => .number, + "UTC": [ + .number, .opt(.number), .opt(.number), .opt(.number), .opt(.number), .opt(.number), + .opt(.number), + ] => .number, + "now": [] => .number, + "parse": [.string] => .number, ] ) /// ObjectGroup modelling the JavaScript Object constructor builtin - static let jsObjectConstructor = ObjectGroup( + public static let jsObjectConstructor = ObjectGroup( name: "ObjectConstructor", constructorPath: "Object", instanceType: .jsObjectConstructor, properties: [ - "prototype" : .object(), // TODO + "prototype": .object() // TODO ], methods: [ - "assign" : [.object(), .object()] => .object(), - "create" : [.object(), .object()] => .object(), - "defineProperty" : [.object(), .string, .oneof(.object(withProperties: ["configurable", "writable", "enumerable", "value"]), .object(withMethods: ["get", "set"]))] => .object(), - "defineProperties" : [.object(), .object()] => .object(), - "entries" : [.object()] => .object(), - "freeze" : [.object()] => .object(), - "fromEntries" : [.object()] => .object(), - "getOwnPropertyDescriptor" : [.object(), .string] => .object(withProperties: ["configurable", "writable", "enumerable", "value"]), - "getOwnPropertyDescriptors" : [.object()] => .object(), - "getOwnPropertyNames" : [.object()] => .jsArray, - "getOwnPropertySymbols" : [.object()] => .jsArray, - "getPrototypeOf" : [.object()] => .object(), - "is" : [.object(), .object()] => .boolean, - "isExtensible" : [.object()] => .boolean, - "isFrozen" : [.object()] => .boolean, - "isSealed" : [.object()] => .boolean, - "keys" : [.object()] => .jsArray, - "preventExtensions" : [.object()] => .object(), - "seal" : [.object()] => .object(), - "setPrototypeOf" : [.object(), .object()] => .object(), - "values" : [.object()] => .jsArray, - "groupBy" : [.iterable, .function()] => .object(), - "hasOwn" : [.object(), .oneof(.jsString, .jsSymbol)] => .boolean, + "assign": [.object(), .object()] => .object(), + "create": [.object(), .object()] => .object(), + "defineProperty": [ + .object(), .string, + .oneof( + .object(withProperties: ["configurable", "writable", "enumerable", "value"]), + .object(withMethods: ["get", "set"])), + ] => .object(), + "defineProperties": [.object(), .object()] => .object(), + "entries": [.object()] => .object(), + "freeze": [.object()] => .object(), + "fromEntries": [.object()] => .object(), + "getOwnPropertyDescriptor": [.object(), .string] + => .object(withProperties: ["configurable", "writable", "enumerable", "value"]), + "getOwnPropertyDescriptors": [.object()] => .object(), + "getOwnPropertyNames": [.object()] => .jsArray, + "getOwnPropertySymbols": [.object()] => .jsArray, + "getPrototypeOf": [.object()] => .object(), + "is": [.object(), .object()] => .boolean, + "isExtensible": [.object()] => .boolean, + "isFrozen": [.object()] => .boolean, + "isSealed": [.object()] => .boolean, + "keys": [.object()] => .jsArray, + "preventExtensions": [.object()] => .object(), + "seal": [.object()] => .object(), + "setPrototypeOf": [.object(), .object()] => .object(), + "values": [.object()] => .jsArray, + "groupBy": [.iterable, .function()] => .object(), + "hasOwn": [.object(), .oneof(.jsString, .jsSymbol)] => .boolean, ] ) /// ObjectGroup modelling the JavaScript Array constructor builtin - static let jsArrayConstructor = ObjectGroup( + public static let jsArrayConstructor = ObjectGroup( name: "ArrayConstructor", constructorPath: "Array", instanceType: .jsArrayConstructor, properties: [ // This might seem wrong, note however that `Array.isArray(Array.prototype)` is true. - "prototype" : .jsArray, + "prototype": .jsArray ], methods: [ - "from" : [.jsAnything, .opt(.function()), .opt(.object())] => .jsArray, - "fromAsync" : [.jsAnything, .opt(.function()), .opt(.object())] => .jsPromise, - "isArray" : [.jsAnything] => .boolean, - "of" : [.jsAnything...] => .jsArray, + "from": [.jsAnything, .opt(.function()), .opt(.object())] => .jsArray, + "fromAsync": [.jsAnything, .opt(.function()), .opt(.object())] => .jsPromise, + "isArray": [.jsAnything] => .boolean, + "of": [.jsAnything...] => .jsArray, ] ) - static let jsArrayBufferPrototype = + public static let jsArrayBufferPrototype = createPrototypeObjectGroup(jsArrayBuffers, constructor: .jsArrayBufferConstructor) - static let jsArrayBufferConstructor = ObjectGroup( + public static let jsArrayBufferConstructor = ObjectGroup( name: "ArrayBufferConstructor", constructorPath: "ArrayBuffer", instanceType: .jsArrayBufferConstructor, properties: [ - "prototype" : jsArrayBufferPrototype.instanceType + "prototype": jsArrayBufferPrototype.instanceType ], methods: [ - "isView" : [.jsAnything] => .boolean + "isView": [.jsAnything] => .boolean ] ) - static let jsSharedArrayBufferPrototype = - createPrototypeObjectGroup(jsSharedArrayBuffers, constructor: .jsSharedArrayBufferConstructor) + public static let jsSharedArrayBufferPrototype = + createPrototypeObjectGroup( + jsSharedArrayBuffers, constructor: .jsSharedArrayBufferConstructor) - static let jsSharedArrayBufferConstructor = ObjectGroup( + public static let jsSharedArrayBufferConstructor = ObjectGroup( name: "SharedArrayBufferConstructor", constructorPath: "SharedArrayBuffer", instanceType: .jsSharedArrayBufferConstructor, properties: [ - "prototype" : jsSharedArrayBufferPrototype.instanceType + "prototype": jsSharedArrayBufferPrototype.instanceType ], methods: [:] ) - static let jsStringPrototype = + public static let jsStringPrototype = createPrototypeObjectGroup(jsStrings, constructor: .jsStringConstructor) /// Object group modelling the JavaScript String constructor builtin - static let jsStringConstructor = ObjectGroup( + public static let jsStringConstructor = ObjectGroup( name: "StringConstructor", constructorPath: "String", instanceType: .jsStringConstructor, properties: [ - "prototype" : jsStringPrototype.instanceType + "prototype": jsStringPrototype.instanceType ], methods: [ - "fromCharCode" : [.jsAnything...] => .jsString, - "fromCodePoint" : [.jsAnything...] => .jsString, - "raw" : [.jsAnything...] => .jsString + "fromCharCode": [.jsAnything...] => .jsString, + "fromCodePoint": [.jsAnything...] => .jsString, + "raw": [.jsAnything...] => .jsString, ] ) /// Object group modelling the JavaScript Symbol constructor builtin - static let jsSymbolConstructor = ObjectGroup( + public static let jsSymbolConstructor = ObjectGroup( name: "SymbolConstructor", constructorPath: "Symbol", instanceType: .jsSymbolConstructor, properties: [ - "iterator" : .jsSymbol, - "asyncIterator" : .jsSymbol, - "match" : .jsSymbol, - "matchAll" : .jsSymbol, - "replace" : .jsSymbol, - "search" : .jsSymbol, - "split" : .jsSymbol, - "hasInstance" : .jsSymbol, - "isConcatSpreadable" : .jsSymbol, - "unscopables" : .jsSymbol, - "species" : .jsSymbol, - "toPrimitive" : .jsSymbol, - "toStringTag" : .jsSymbol, - "dispose" : .jsSymbol, - "asyncDispose" : .jsSymbol + "iterator": .jsSymbol, + "asyncIterator": .jsSymbol, + "match": .jsSymbol, + "matchAll": .jsSymbol, + "replace": .jsSymbol, + "search": .jsSymbol, + "split": .jsSymbol, + "hasInstance": .jsSymbol, + "isConcatSpreadable": .jsSymbol, + "unscopables": .jsSymbol, + "species": .jsSymbol, + "toPrimitive": .jsSymbol, + "toStringTag": .jsSymbol, + "dispose": .jsSymbol, + "asyncDispose": .jsSymbol, ], methods: [ - "for" : [.string] => .jsSymbol, - "keyFor" : [.object(ofGroup: "Symbol")] => .jsString, + "for": [.string] => .jsSymbol, + "keyFor": [.object(ofGroup: "Symbol")] => .jsString, ] ) /// Object group modelling the JavaScript BigInt constructor builtin - static let jsBigIntConstructor = ObjectGroup( + public static let jsBigIntConstructor = ObjectGroup( name: "BigIntConstructor", constructorPath: "BigInt", instanceType: .jsBigIntConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [ - "asIntN" : [.number, .bigint] => .bigint, - "asUintN" : [.number, .bigint] => .bigint, + "asIntN": [.number, .bigint] => .bigint, + "asUintN": [.number, .bigint] => .bigint, ] ) - static let jsRegExpPrototype = createPrototypeObjectGroup(jsRegExps, constructor: .jsRegExpConstructor) + public static let jsRegExpPrototype = createPrototypeObjectGroup( + jsRegExps, constructor: .jsRegExpConstructor) /// Object group modelling the JavaScript RegExp constructor builtin - static let jsRegExpConstructor = ObjectGroup( + public static let jsRegExpConstructor = ObjectGroup( name: "RegExpConstructor", constructorPath: "RegExp", instanceType: .jsRegExpConstructor, properties: [ - "prototype" : jsRegExpPrototype.instanceType, + "prototype": jsRegExpPrototype.instanceType, "$1": .jsString, "$2": .jsString, "$3": .jsString, @@ -2395,100 +2910,100 @@ public extension ObjectGroup { "leftContext": .jsString, ], methods: [ - "escape" : [.string] => .jsString, + "escape": [.string] => .jsString ] ) /// Object group modelling the JavaScript Boolean constructor builtin - static let jsBooleanConstructor = ObjectGroup( + public static let jsBooleanConstructor = ObjectGroup( name: "BooleanConstructor", constructorPath: "Boolean", instanceType: .jsBooleanConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) /// Object group modelling the JavaScript Number constructor builtin - static let jsNumberConstructor = ObjectGroup( + public static let jsNumberConstructor = ObjectGroup( name: "NumberConstructor", constructorPath: "Number", instanceType: .jsNumberConstructor, properties: [ - "prototype" : .object(), + "prototype": .object(), // TODO: should there be a .jsNumber type? - "EPSILON" : .number, - "MAX_SAFE_INTEGER" : .number, - "MAX_VALUE" : .number, - "MIN_SAFE_INTEGER" : .number, - "MIN_VALUE" : .number, - "NaN" : .number, - "NEGATIVE_INFINITY" : .number, - "POSITIVE_INFINITY" : .number, + "EPSILON": .number, + "MAX_SAFE_INTEGER": .number, + "MAX_VALUE": .number, + "MIN_SAFE_INTEGER": .number, + "MIN_VALUE": .number, + "NaN": .number, + "NEGATIVE_INFINITY": .number, + "POSITIVE_INFINITY": .number, ], methods: [ - "isNaN" : [.jsAnything] => .boolean, - "isFinite" : [.jsAnything] => .boolean, - "isInteger" : [.jsAnything] => .boolean, - "isSafeInteger" : [.jsAnything] => .boolean, - "parseFloat" : [.string] => .float, - "parseInt" : [.string] => .integer, + "isNaN": [.jsAnything] => .boolean, + "isFinite": [.jsAnything] => .boolean, + "isInteger": [.jsAnything] => .boolean, + "isSafeInteger": [.jsAnything] => .boolean, + "parseFloat": [.string] => .float, + "parseInt": [.string] => .integer, ] ) /// Object group modelling the JavaScript Math builtin - static let jsMathObject = ObjectGroup( + public static let jsMathObject = ObjectGroup( name: "Math", instanceType: .jsMathObject, properties: [ - "E" : .number, - "PI" : .number, - "LN10" : .number, - "LN2" : .number, - "LOG10E" : .number, - "LOG2E" : .number, - "SQRT1_2" : .number, - "SQRT2" : .number, + "E": .number, + "PI": .number, + "LN10": .number, + "LN2": .number, + "LOG10E": .number, + "LOG2E": .number, + "SQRT1_2": .number, + "SQRT2": .number, ], methods: [ - "abs" : [.jsAnything] => .number, - "acos" : [.jsAnything] => .number, - "acosh" : [.jsAnything] => .number, - "asin" : [.jsAnything] => .number, - "asinh" : [.jsAnything] => .number, - "atan" : [.jsAnything] => .number, - "atanh" : [.jsAnything] => .number, - "atan2" : [.jsAnything, .jsAnything] => .number, - "cbrt" : [.jsAnything] => .number, - "ceil" : [.jsAnything] => .number, - "clz32" : [.jsAnything] => .number, - "cos" : [.jsAnything] => .number, - "cosh" : [.jsAnything] => .number, - "exp" : [.jsAnything] => .number, - "expm1" : [.jsAnything] => .number, - "floor" : [.jsAnything] => .number, - "fround" : [.jsAnything] => .number, - "f16round" : [.jsAnything] => .number, - "hypot" : [.jsAnything...] => .number, - "imul" : [.jsAnything, .jsAnything] => .integer, - "log" : [.jsAnything] => .number, - "log1p" : [.jsAnything] => .number, - "log10" : [.jsAnything] => .number, - "log2" : [.jsAnything] => .number, - "max" : [.jsAnything...] => .number, - "min" : [.jsAnything...] => .number, - "pow" : [.jsAnything, .jsAnything] => .number, - "random" : [] => .number, - "round" : [.jsAnything] => .number, - "sign" : [.jsAnything] => .number, - "sin" : [.jsAnything] => .number, - "sinh" : [.jsAnything] => .number, - "sqrt" : [.jsAnything] => .number, - "sumPrecise" : [.iterable] => .number, - "tan" : [.jsAnything] => .number, - "tanh" : [.jsAnything] => .number, - "trunc" : [.jsAnything] => .number, + "abs": [.jsAnything] => .number, + "acos": [.jsAnything] => .number, + "acosh": [.jsAnything] => .number, + "asin": [.jsAnything] => .number, + "asinh": [.jsAnything] => .number, + "atan": [.jsAnything] => .number, + "atanh": [.jsAnything] => .number, + "atan2": [.jsAnything, .jsAnything] => .number, + "cbrt": [.jsAnything] => .number, + "ceil": [.jsAnything] => .number, + "clz32": [.jsAnything] => .number, + "cos": [.jsAnything] => .number, + "cosh": [.jsAnything] => .number, + "exp": [.jsAnything] => .number, + "expm1": [.jsAnything] => .number, + "floor": [.jsAnything] => .number, + "fround": [.jsAnything] => .number, + "f16round": [.jsAnything] => .number, + "hypot": [.jsAnything...] => .number, + "imul": [.jsAnything, .jsAnything] => .integer, + "log": [.jsAnything] => .number, + "log1p": [.jsAnything] => .number, + "log10": [.jsAnything] => .number, + "log2": [.jsAnything] => .number, + "max": [.jsAnything...] => .number, + "min": [.jsAnything...] => .number, + "pow": [.jsAnything, .jsAnything] => .number, + "random": [] => .number, + "round": [.jsAnything] => .number, + "sign": [.jsAnything] => .number, + "sin": [.jsAnything] => .number, + "sinh": [.jsAnything] => .number, + "sqrt": [.jsAnything] => .number, + "sumPrecise": [.iterable] => .number, + "tan": [.jsAnything] => .number, + "tanh": [.jsAnything] => .number, + "trunc": [.jsAnything] => .number, ] ) @@ -2496,83 +3011,91 @@ public extension ObjectGroup { /// Note that the typing here is not perfect: .someTypedArray doesn't have precise type /// information. The parameters and results typed as .jsAnything are either .number or .bigint /// depending on the type of the TypedArray that is passed as the first argument. - static let jsAtomicsObject = ObjectGroup( + public static let jsAtomicsObject = ObjectGroup( name: "Atomics", instanceType: .jsAtomicsObject, properties: [:], methods: [ - "add" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "and" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "compareExchange" : [.plain(.someTypedArray), .integer, .jsAnything, .jsAnything] => .jsAnything, - "exchange" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "isLockFree" : [.integer] => .boolean, - "load" : [.plain(.someTypedArray), .integer] => .jsAnything, - "notify" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), .integer, .opt(.integer)] => .integer, - "or" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "pause" : [.opt(.integer)] => .undefined, - "store" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "sub" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, - "wait" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), - .integer, .jsAnything, .opt(.number)] => .string, - "waitAsync" : [.oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), - .integer, .jsAnything, .opt(.number)] => .object(withProperties: ["async", "value"]), - "xor" : [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "add": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "and": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "compareExchange": [.plain(.someTypedArray), .integer, .jsAnything, .jsAnything] + => .jsAnything, + "exchange": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "isLockFree": [.integer] => .boolean, + "load": [.plain(.someTypedArray), .integer] => .jsAnything, + "notify": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), .integer, + .opt(.integer), + ] => .integer, + "or": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "pause": [.opt(.integer)] => .undefined, + "store": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "sub": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, + "wait": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), + .integer, .jsAnything, .opt(.number), + ] => .string, + "waitAsync": [ + .oneof(.jsTypedArray("Int32Array"), .jsTypedArray("BigInt64Array")), + .integer, .jsAnything, .opt(.number), + ] => .object(withProperties: ["async", "value"]), + "xor": [.plain(.someTypedArray), .integer, .jsAnything] => .jsAnything, ] ) /// ObjectGroup modelling the JavaScript JSON builtin - static let jsJSONObject = ObjectGroup( + public static let jsJSONObject = ObjectGroup( name: "JSON", instanceType: .jsJSONObject, properties: [:], methods: [ - "parse" : [.string, .opt(.function())] => .jsAnything, - "stringify" : [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString, - "rawJSON" : [.plain(.string | .number | .boolean)] => .jsAnything, - "isRawJSON" : [.jsAnything] => .boolean, + "parse": [.string, .opt(.function())] => .jsAnything, + "stringify": [.jsAnything, .opt(.function()), .opt(.number | .string)] => .jsString, + "rawJSON": [.plain(.string | .number | .boolean)] => .jsAnything, + "isRawJSON": [.jsAnything] => .boolean, ] ) /// ObjectGroup modelling the JavaScript Reflect builtin - static let jsReflectObject = ObjectGroup( + public static let jsReflectObject = ObjectGroup( name: "Reflect", instanceType: .jsReflectObject, properties: [:], methods: [ - "apply" : [.function(), .jsAnything, .object()] => .jsAnything, - "construct" : [.constructor(), .object(), .opt(.object())] => .jsAnything, - "defineProperty" : [.object(), .string, .object()] => .boolean, - "deleteProperty" : [.object(), .string] => .boolean, - "get" : [.object(), .string, .opt(.object())] => .jsAnything, - "getOwnPropertyDescriptor" : [.object(), .string] => .jsAnything, - "getPrototypeOf" : [.object()] => .jsAnything, - "has" : [.object(), .string] => .boolean, - "isExtensible" : [.object()] => .boolean, - "ownKeys" : [.object()] => .jsArray, - "preventExtensions" : [.object()] => .boolean, - "set" : [.object(), .string, .jsAnything, .opt(.object())] => .boolean, - "setPrototypeOf" : [.object(), .object()] => .boolean, + "apply": [.function(), .jsAnything, .object()] => .jsAnything, + "construct": [.constructor(), .object(), .opt(.object())] => .jsAnything, + "defineProperty": [.object(), .string, .object()] => .boolean, + "deleteProperty": [.object(), .string] => .boolean, + "get": [.object(), .string, .opt(.object())] => .jsAnything, + "getOwnPropertyDescriptor": [.object(), .string] => .jsAnything, + "getPrototypeOf": [.object()] => .jsAnything, + "has": [.object(), .string] => .boolean, + "isExtensible": [.object()] => .boolean, + "ownKeys": [.object()] => .jsArray, + "preventExtensions": [.object()] => .boolean, + "set": [.object(), .string, .jsAnything, .opt(.object())] => .boolean, + "setPrototypeOf": [.object(), .object()] => .boolean, ] ) /// ObjectGroup modelling JavaScript Error objects - static func jsError(_ variant: String) -> ObjectGroup { + public static func jsError(_ variant: String) -> ObjectGroup { return ObjectGroup( name: variant, instanceType: .jsError(variant), properties: [ - "message" : .jsString, - "name" : .jsString, - "cause" : .jsAnything, - "stack" : .jsString, + "message": .jsString, + "name": .jsString, + "cause": .jsAnything, + "stack": .jsString, ], methods: [ - "toString" : [] => .jsString, + "toString": [] => .jsString ] ) } - static func jsErrorPrototype(_ variant: String) -> ObjectGroup { + public static func jsErrorPrototype(_ variant: String) -> ObjectGroup { return createPrototypeObjectGroup( jsError(variant), constructor: .jsErrorConstructor(variant), @@ -2582,7 +3105,7 @@ public extension ObjectGroup { ]) } - static func jsErrorConstructor(_ variant: String) -> ObjectGroup { + public static func jsErrorConstructor(_ variant: String) -> ObjectGroup { return ObjectGroup( name: "\(variant)Constructor", constructorPath: variant, @@ -2601,7 +3124,7 @@ public extension ObjectGroup { // TODO(mliedtke): We need to construct these to make code generators be able to provide // somewhat reasonable compile options. - static let jsWebAssemblyCompileOptions = ObjectGroup( + public static let jsWebAssemblyCompileOptions = ObjectGroup( name: "WebAssemblyCompileOptions", instanceType: nil, properties: [ @@ -2613,18 +3136,19 @@ public extension ObjectGroup { // Note: This supports all typed arrays, however, that would add a huge amount of overloads, so // we only add a few selected typed arrays here. - static let wasmBufferTypes = [ + public static let wasmBufferTypes = [ ILType.jsArrayBuffer, .jsSharedArrayBuffer, .jsTypedArray("Int8Array"), - .jsTypedArray("Float32Array"), .jsTypedArray("BigUint64Array")] + .jsTypedArray("Float32Array"), .jsTypedArray("BigUint64Array"), + ] - static let jsWebAssemblyModule = ObjectGroup( + public static let jsWebAssemblyModule = ObjectGroup( name: "WebAssembly.Module", instanceType: .jsWebAssemblyModule, properties: [:], methods: [:] ) - static let jsWebAssemblyModuleConstructor = ObjectGroup( + public static let jsWebAssemblyModuleConstructor = ObjectGroup( name: "WebAssemblyModuleConstructor", constructorPath: "WebAssembly.Module", instanceType: .jsWebAssemblyModuleConstructor, @@ -2632,88 +3156,89 @@ public extension ObjectGroup { "prototype": .object() ], methods: [ - "customSections": [.plain(jsWebAssemblyModule.instanceType), .plain(.jsString)] => .jsArray, + "customSections": [.plain(jsWebAssemblyModule.instanceType), .plain(.jsString)] + => .jsArray, "exports": [.plain(jsWebAssemblyModule.instanceType)] => .jsArray, "imports": [.plain(jsWebAssemblyModule.instanceType)] => .jsArray, ] ) - static let jsWebAssemblyGlobalPrototype = + public static let jsWebAssemblyGlobalPrototype = createPrototypeObjectGroup(jsWasmGlobal, constructor: .jsWebAssemblyGlobalConstructor) - static let jsWebAssemblyGlobalConstructor = ObjectGroup( + public static let jsWebAssemblyGlobalConstructor = ObjectGroup( name: "WebAssemblyGlobalConstructor", constructorPath: "WebAssembly.Global", instanceType: .jsWebAssemblyGlobalConstructor, properties: [ - "prototype": jsWebAssemblyGlobalPrototype.instanceType, + "prototype": jsWebAssemblyGlobalPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyInstanceConstructor = ObjectGroup( + public static let jsWebAssemblyInstanceConstructor = ObjectGroup( name: "WebAssemblyInstanceConstructor", constructorPath: "WebAssembly.Instance", instanceType: .jsWebAssemblyInstanceConstructor, properties: [ - "prototype": .object(), + "prototype": .object() ], methods: [:] ) - static let jsWebAssemblyInstance = ObjectGroup( + public static let jsWebAssemblyInstance = ObjectGroup( name: "WebAssembly.Instance", instanceType: .jsWebAssemblyInstance, properties: [ - "exports": .object(), + "exports": .object() ], methods: [:] ) - static let jsWebAssemblyMemoryPrototype = + public static let jsWebAssemblyMemoryPrototype = createPrototypeObjectGroup(jsWasmMemory, constructor: .jsWebAssemblyMemoryConstructor) - static let jsWebAssemblyMemoryConstructor = ObjectGroup( + public static let jsWebAssemblyMemoryConstructor = ObjectGroup( name: "WebAssemblyMemoryConstructor", constructorPath: "WebAssembly.Memory", instanceType: .jsWebAssemblyMemoryConstructor, properties: [ - "prototype": jsWebAssemblyMemoryPrototype.instanceType, + "prototype": jsWebAssemblyMemoryPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyTablePrototype = + public static let jsWebAssemblyTablePrototype = createPrototypeObjectGroup(wasmTable, constructor: .jsWebAssemblyTableConstructor) - static let jsWebAssemblyTableConstructor = ObjectGroup( + public static let jsWebAssemblyTableConstructor = ObjectGroup( name: "WebAssemblyTableConstructor", constructorPath: "WebAssembly.Table", instanceType: .jsWebAssemblyTableConstructor, properties: [ - "prototype": jsWebAssemblyTablePrototype.instanceType, + "prototype": jsWebAssemblyTablePrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyTagPrototype = + public static let jsWebAssemblyTagPrototype = createPrototypeObjectGroup(jsWasmTag, constructor: .jsWebAssemblyTagConstructor) - static let jsWebAssemblyTagConstructor = ObjectGroup( + public static let jsWebAssemblyTagConstructor = ObjectGroup( name: "WebAssemblyTagConstructor", constructorPath: "WebAssembly.Tag", instanceType: .jsWebAssemblyTagConstructor, properties: [ - "prototype": jsWebAssemblyTagPrototype.instanceType, + "prototype": jsWebAssemblyTagPrototype.instanceType ], methods: [:] ) - static let jsWebAssemblyException = ObjectGroup( + public static let jsWebAssemblyException = ObjectGroup( name: "WebAssembly.Exception", instanceType: nil, properties: [ - "stack": .string | .undefined, + "stack": .string | .undefined ], methods: [ "getArg": [.plain(jsWasmTag.instanceType), .plain(.integer)] => .jsAnything, @@ -2721,16 +3246,16 @@ public extension ObjectGroup { ] ) - static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup( + public static let jsWebAssemblyExceptionPrototype = createPrototypeObjectGroup( jsWebAssemblyException, constructor: .jsWebAssemblyExceptionConstructor) - static let jsWebAssemblyExceptionConstructor = ObjectGroup( + public static let jsWebAssemblyExceptionConstructor = ObjectGroup( name: "WebAssemblyExceptionConstructor", constructorPath: "WebAssembly.Exception", instanceType: .jsWebAssemblyExceptionConstructor, properties: [ - "prototype": jsWebAssemblyExceptionPrototype.instanceType, + "prototype": jsWebAssemblyExceptionPrototype.instanceType ], methods: [:] ) @@ -2748,7 +3273,9 @@ public extension ObjectGroup { ) fileprivate static let webAssemblyErrorConstructorType = - ILType.constructor([.opt(.string), .opt(.object() | .string), .opt(.string)] => jsWebAssemblyError.instanceType) + ILType.constructor( + [.opt(.string), .opt(.object() | .string), .opt(.string)] + => jsWebAssemblyError.instanceType) + .object(ofGroup: "WebAssemblyErrorConstructor", withProperties: ["prototype"]) fileprivate static let jsWebAssemblyErrorPrototype = createPrototypeObjectGroup( @@ -2764,18 +3291,20 @@ public extension ObjectGroup { name: "WebAssemblyErrorConstructor", instanceType: webAssemblyErrorConstructorType, properties: [ - "prototype": jsWebAssemblyErrorPrototype.instanceType, + "prototype": jsWebAssemblyErrorPrototype.instanceType ], methods: [:] ) - fileprivate static let webAssemblySuspendingConstructorType = ILType.constructor([.plain(.function())] => .object()) + fileprivate static let webAssemblySuspendingConstructorType = ILType.constructor( + [.plain(.function())] => .object()) - static let jsWebAssembly = ObjectGroup( + public static let jsWebAssembly = ObjectGroup( name: "WebAssembly", instanceType: nil, properties: [ - "JSTag": .object(ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true)), + "JSTag": .object( + ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true)), "Module": .jsWebAssemblyModuleConstructor, "Global": .jsWebAssemblyGlobalConstructor, "Instance": .jsWebAssemblyInstanceConstructor, @@ -2791,62 +3320,73 @@ public extension ObjectGroup { ], overloads: [ "compile": wasmBufferTypes.map { - [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + }, // TODO: The first parameter should be a Response which Fuzzilli doesn't know as it is // mostly used by WebAPIs like fetch(). "compileStreaming": [ - [.object(), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise], + [.object(), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + ], "instantiate": wasmBufferTypes.map { - [.plain($0), /*imports*/ .opt(.object()), - .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [ + .plain($0), /*imports*/ .opt(.object()), + .opt(jsWebAssemblyCompileOptions.instanceType), + ] => .jsPromise + }, // TODO: Same as compileStreaming(), the first parameter has to be a Response. "instantiateStreaming": [ - [.object(), /*imports*/ .opt(.object()), - .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise], + [ + .object(), /*imports*/ .opt(.object()), + .opt(jsWebAssemblyCompileOptions.instanceType), + ] => .jsPromise + ], "validate": wasmBufferTypes.map { - [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise}, + [.plain($0), .opt(jsWebAssemblyCompileOptions.instanceType)] => .jsPromise + }, // The argument needs to be an exported Wasm function. Fuzzilli's type system does not // distinguish between Wasm and JS functions, so we can't express this precisely. - "promising": [[.function()] => .function()] + "promising": [[.function()] => .function()], ] ) /// ObjectGroup modelling JavaScript WebAssembly Global objects. - static let jsWasmGlobal = ObjectGroup( + public static let jsWasmGlobal = ObjectGroup( name: "WasmGlobal", instanceType: nil, properties: [ // TODO: Try using precise JS types based on the global's underlying valuetype (e.g. float for f32 and f64). - "value" : .jsAnything + "value": .jsAnything ], methods: ["valueOf": [] => .jsAnything] ) /// ObjectGroup modelling JavaScript WebAssembly Memory objects. - static let jsWasmMemory = ObjectGroup( + public static let jsWasmMemory = ObjectGroup( name: "WasmMemory", - instanceType: .object(ofGroup: "WasmMemory", withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"]), + instanceType: .object( + ofGroup: "WasmMemory", withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"]), properties: [ - "buffer" : .jsArrayBuffer | .jsSharedArrayBuffer + "buffer": .jsArrayBuffer | .jsSharedArrayBuffer ], methods: [ - "grow" : [.number] => .number, - "toResizableBuffer" : [] => (.jsArrayBuffer | .jsSharedArrayBuffer), - "toFixedLengthBuffer" : [] => (.jsArrayBuffer | .jsSharedArrayBuffer), + "grow": [.number] => .number, + "toResizableBuffer": [] => (.jsArrayBuffer | .jsSharedArrayBuffer), + "toFixedLengthBuffer": [] => (.jsArrayBuffer | .jsSharedArrayBuffer), ] ) // TOOD(mliedtke): Reconsider whether WebAssembly.Tag and WebAssembly.JSTag should share the // same object group. When split, we can register the type() prototype method. - static let jsWasmTag = ObjectGroup( + public static let jsWasmTag = ObjectGroup( name: "WasmTag", - instanceType: nil, // inferred + instanceType: nil, // inferred properties: [:], methods: [:] ) /// ObjectGroup modelling JavaScript WebAssembly Table objects - static let wasmTable = ObjectGroup( + public static let wasmTable = ObjectGroup( name: "WasmTable", instanceType: .wasmTable, properties: [ @@ -2859,7 +3399,7 @@ public extension ObjectGroup { ] ) - static let jsWasmSuspendingObject = ObjectGroup( + public static let jsWasmSuspendingObject = ObjectGroup( name: "WasmSuspendingObject", instanceType: .object(ofGroup: "WasmSuspendingObject"), properties: [:], @@ -2869,24 +3409,36 @@ public extension ObjectGroup { // Temporal types // Helpers for constructing common signatures - private static func temporalAddSubtractSignature(forType: ILType, needsOverflow: Bool) -> [Signature] { + private static func temporalAddSubtractSignature(forType: ILType, needsOverflow: Bool) + -> [Signature] + { if needsOverflow { - return jsTemporalDurationLikeParameters.map { [.plain($0), .opt(jsTemporalOverflowSettings)] => forType } + return jsTemporalDurationLikeParameters.map { + [.plain($0), .opt(jsTemporalOverflowSettings)] => forType + } } else { return jsTemporalDurationLikeParameters.map { [.plain($0)] => forType } } } private static func temporalUntilSinceSignature(possibleParams: [ILType]) -> [Signature] { - return possibleParams.map { [.plain($0), .opt(jsTemporalDifferenceSettings)] => .jsTemporalDuration } + return possibleParams.map { + [.plain($0), .opt(jsTemporalDifferenceSettings)] => .jsTemporalDuration + } } - private static func temporalFromSignature(forType: ILType, possibleParams: [ILType], settingsArg: ILType? = nil) -> [Signature] { + private static func temporalFromSignature( + forType: ILType, possibleParams: [ILType], settingsArg: ILType? = nil + ) -> [Signature] { if let settingsArg { return possibleParams.map { [.plain($0), .opt(settingsArg)] => forType } } else { - return possibleParams.map { [.plain($0), .opt(jsTemporalDifferenceSettings)] => forType } + return possibleParams.map { + [.plain($0), .opt(jsTemporalDifferenceSettings)] => forType + } } } - private static func temporalCompareSignature(possibleParams: [ILType], settingsArg: ILType? = nil) -> [Signature] { + private static func temporalCompareSignature( + possibleParams: [ILType], settingsArg: ILType? = nil + ) -> [Signature] { possibleParams.flatMap { param1 in return possibleParams.map { param2 in if let settingsArg { @@ -2902,7 +3454,9 @@ public extension ObjectGroup { return possibleParams.map { [.plain($0)] => .boolean } } - private static func temporalTimeZoneLikeSignature(signature: (ILType) -> Signature) -> [Signature] { + private static func temporalTimeZoneLikeSignature(signature: (ILType) -> Signature) + -> [Signature] + { return [ signature(jsTemporalTimeZoneLike), signature(.jsTemporalZonedDateTime), @@ -2910,39 +3464,43 @@ public extension ObjectGroup { } /// Object group modelling the JavaScript Temporal builtin - static let jsTemporalObject = ObjectGroup( + public static let jsTemporalObject = ObjectGroup( name: "Temporal", instanceType: .jsTemporalObject, properties: [ - "Instant" : .jsTemporalInstantConstructor, - "Duration" : .jsTemporalDurationConstructor, - "PlainTime" : .jsTemporalPlainTimeConstructor, - "PlainYearMonth" : .jsTemporalPlainYearMonthConstructor, - "PlainMonthDay" : .jsTemporalPlainMonthDayConstructor, - "PlainDate" : .jsTemporalPlainDateConstructor, - "PlainDateTime" : .jsTemporalPlainDateTimeConstructor, - "ZonedDateTime" : .jsTemporalZonedDateTimeConstructor, + "Instant": .jsTemporalInstantConstructor, + "Duration": .jsTemporalDurationConstructor, + "PlainTime": .jsTemporalPlainTimeConstructor, + "PlainYearMonth": .jsTemporalPlainYearMonthConstructor, + "PlainMonthDay": .jsTemporalPlainMonthDayConstructor, + "PlainDate": .jsTemporalPlainDateConstructor, + "PlainDateTime": .jsTemporalPlainDateTimeConstructor, + "ZonedDateTime": .jsTemporalZonedDateTimeConstructor, "Now": .jsTemporalNow, ], methods: [:] ) - static let jsTemporalNow = ObjectGroup( + public static let jsTemporalNow = ObjectGroup( name: "Temporal.Now", instanceType: .jsTemporalNow, properties: [:], overloads: [ "timeZoneId": [[] => .string], "instant": [[] => .jsTemporalInstant], - "plainDateTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainDateTime }, - "zonedDateTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalZonedDateTime }, + "plainDateTimeISO": temporalTimeZoneLikeSignature { + [.opt($0)] => .jsTemporalPlainDateTime + }, + "zonedDateTimeISO": temporalTimeZoneLikeSignature { + [.opt($0)] => .jsTemporalZonedDateTime + }, "plainDateISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainDate }, "plainTimeISO": temporalTimeZoneLikeSignature { [.opt($0)] => .jsTemporalPlainTime }, ] ) /// ObjectGroup modelling JavaScript Temporal.Instant objects - static let jsTemporalInstant = ObjectGroup( + public static let jsTemporalInstant = ObjectGroup( name: "Temporal.Instant", instanceType: .jsTemporalInstant, properties: [ @@ -2951,7 +3509,8 @@ public extension ObjectGroup { ], overloads: [ "add": temporalAddSubtractSignature(forType: .jsTemporalInstant, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalInstant, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalInstant, needsOverflow: false), "until": temporalUntilSinceSignature(possibleParams: jsTemporalInstantLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalInstantLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalInstant], @@ -2959,30 +3518,33 @@ public extension ObjectGroup { "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toZonedDateTimeISO": temporalTimeZoneLikeSignature { [.plain($0)] => .jsTemporalZonedDateTime }, + "toZonedDateTimeISO": temporalTimeZoneLikeSignature { + [.plain($0)] => .jsTemporalZonedDateTime + }, ] ) - static let jsTemporalInstantPrototype = + public static let jsTemporalInstantPrototype = createPrototypeObjectGroup(jsTemporalInstant, constructor: .jsTemporalInstantConstructor) /// ObjectGroup modelling the JavaScript Temporal.Instant constructor - static let jsTemporalInstantConstructor = ObjectGroup( + public static let jsTemporalInstantConstructor = ObjectGroup( name: "TemporalInstantConstructor", constructorPath: "Temporal.Instant", instanceType: .jsTemporalInstantConstructor, properties: [ - "prototype" : jsTemporalInstantPrototype.instanceType + "prototype": jsTemporalInstantPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalInstant, possibleParams: jsTemporalInstantLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalInstant, possibleParams: jsTemporalInstantLikeParameters), "fromEpochMilliseconds": [[.number] => .jsTemporalInstant], "fromEpochNanoseconds": [[.bigint] => .jsTemporalInstant], "compare": temporalCompareSignature(possibleParams: jsTemporalInstantLikeParameters), ] ) /// ObjectGroup modelling JavaScript Temporal.Duration objects - static let jsTemporalDuration = ObjectGroup( + public static let jsTemporalDuration = ObjectGroup( name: "Temporal.Duration", instanceType: .jsTemporalDuration, properties: [ @@ -3004,7 +3566,8 @@ public extension ObjectGroup { "negated": [[] => .jsTemporalDuration], "abs": [[] => .jsTemporalDuration], "add": temporalAddSubtractSignature(forType: .jsTemporalDuration, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalDuration, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalDuration, needsOverflow: false), "round": [[.plain(jsTemporalDurationRoundToSettings)] => .jsTemporalDuration], "total": [[.plain(jsTemporalDurationTotalOfSettings)] => .jsTemporalDuration], "toString": [[.opt(jsTemporalToStringSettings)] => .string], @@ -3013,24 +3576,27 @@ public extension ObjectGroup { ] ) - static let jsTemporalDurationPrototype = + public static let jsTemporalDurationPrototype = createPrototypeObjectGroup(jsTemporalDuration, constructor: .jsTemporalDurationConstructor) /// ObjectGroup modelling the JavaScript Temporal.Duration constructor - static let jsTemporalDurationConstructor = ObjectGroup( + public static let jsTemporalDurationConstructor = ObjectGroup( name: "TemporalDurationConstructor", constructorPath: "Temporal.Duration", instanceType: .jsTemporalDurationConstructor, properties: [ - "prototype" : jsTemporalDurationPrototype.instanceType + "prototype": jsTemporalDurationPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalDuration, possibleParams: jsTemporalDurationLikeParameters), - "compare": temporalCompareSignature(possibleParams: jsTemporalDurationLikeParameters, settingsArg: jsTemporalDurationCompareSettings), + "from": temporalFromSignature( + forType: .jsTemporalDuration, possibleParams: jsTemporalDurationLikeParameters), + "compare": temporalCompareSignature( + possibleParams: jsTemporalDurationLikeParameters, + settingsArg: jsTemporalDurationCompareSettings), ] ) - static let jsTemporalPlainTime = ObjectGroup( + public static let jsTemporalPlainTime = ObjectGroup( name: "Temporal.PlainTime", instanceType: .jsTemporalPlainTime, properties: [ @@ -3042,9 +3608,16 @@ public extension ObjectGroup { "nanosecond": .number, ], overloads: [ - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainTime, needsOverflow: false), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainTime, needsOverflow: false), - "with": [[.plain(jsTemporalPlainTimeLikeObject.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainTime], + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainTime, needsOverflow: false), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainTime, needsOverflow: false), + "with": [ + [ + .plain(jsTemporalPlainTimeLikeObject.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainTime + ], "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainTimeLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalPlainTime], @@ -3055,19 +3628,21 @@ public extension ObjectGroup { ] ) - static let jsTemporalPlainTimePrototype = - createPrototypeObjectGroup(jsTemporalPlainTime, constructor: .jsTemporalPlainTimeConstructor) + public static let jsTemporalPlainTimePrototype = + createPrototypeObjectGroup( + jsTemporalPlainTime, constructor: .jsTemporalPlainTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainTime constructor - static let jsTemporalPlainTimeConstructor = ObjectGroup( + public static let jsTemporalPlainTimeConstructor = ObjectGroup( name: "TemporalPlainTimeConstructor", constructorPath: "Temporal.PlainTime", instanceType: .jsTemporalPlainTimeConstructor, properties: [ - "prototype" : jsTemporalPlainTimePrototype.instanceType + "prototype": jsTemporalPlainTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainTime, possibleParams: jsTemporalPlainTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainTime, possibleParams: jsTemporalPlainTimeLikeParameters), "compare": temporalCompareSignature(possibleParams: jsTemporalPlainTimeLikeParameters), ] ) @@ -3083,45 +3658,60 @@ public extension ObjectGroup { "daysInYear": .integer, "monthsInYear": .integer, "inLeapYear": .boolean, - ]; + ] - static let jsTemporalPlainYearMonth = ObjectGroup( + public static let jsTemporalPlainYearMonth = ObjectGroup( name: "Temporal.PlainYearMonth", instanceType: .jsTemporalPlainYearMonth, properties: jsTemporalPlainYearMonthProperties, overloads: [ - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainYearMonth], - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainYearMonth, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainYearMonth, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainYearMonth + ], + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainYearMonth, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainYearMonth, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toPlainDate": [[.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate], + "toPlainDate": [ + [.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate + ], ] ) - static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainYearMonthPrototype = createPrototypeObjectGroup( jsTemporalPlainYearMonth, constructor: .jsTemporalPlainYearMonthConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainYearMonth constructor - static let jsTemporalPlainYearMonthConstructor = ObjectGroup( + public static let jsTemporalPlainYearMonthConstructor = ObjectGroup( name: "TemporalPlainYearMonthConstructor", constructorPath: "Temporal.PlainYearMonth", instanceType: .jsTemporalPlainYearMonthConstructor, properties: [ - "prototype" : jsTemporalPlainYearMonthPrototype.instanceType + "prototype": jsTemporalPlainYearMonthPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainYearMonth, possibleParams: jsTemporalPlainYearMonthLikeParameters), - "compare": temporalCompareSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainYearMonth, + possibleParams: jsTemporalPlainYearMonthLikeParameters), + "compare": temporalCompareSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), ] ) - static let jsTemporalPlainMonthDay = ObjectGroup( + public static let jsTemporalPlainMonthDay = ObjectGroup( name: "Temporal.PlainMonthDay", instanceType: .jsTemporalPlainMonthDay, properties: [ @@ -3130,149 +3720,211 @@ public extension ObjectGroup { "day": .integer, ], overloads: [ - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainYearMonth], - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainYearMonthLikeParameters), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainYearMonth + ], + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainYearMonthLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toPlainDate": [[.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate], + "toPlainDate": [ + [.plain(jsTemporalPlainDateLikeObject.instanceType)] => .jsTemporalPlainDate + ], ] ) - static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainMonthDayPrototype = createPrototypeObjectGroup( jsTemporalPlainMonthDay, constructor: .jsTemporalPlainMonthDayConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainMonthDay constructor. - static let jsTemporalPlainMonthDayConstructor = ObjectGroup( + public static let jsTemporalPlainMonthDayConstructor = ObjectGroup( name: "TemporalPlainMonthDayConstructor", constructorPath: "Temporal.PlainMonthDay", instanceType: .jsTemporalPlainMonthDayConstructor, properties: [ - "prototype" : jsTemporalPlainMonthDayPrototype.instanceType + "prototype": jsTemporalPlainMonthDayPrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainMonthDay, possibleParams: jsTemporalPlainMonthDayLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainMonthDay, + possibleParams: jsTemporalPlainMonthDayLikeParameters) ] ) - static let jsTemporalPlainDate = ObjectGroup( + public static let jsTemporalPlainDate = ObjectGroup( name: "Temporal.PlainDate", instanceType: .jsTemporalPlainDate, - properties: mergeFields(jsTemporalPlainYearMonthProperties, [ - "day": .integer, - "dayOfWeek": .integer, - "dayOfYear": .integer, - "weekOfYear": .integer, - "yearOfWeek": .integer, - "daysInWeek": .integer, - ]), + properties: mergeFields( + jsTemporalPlainYearMonthProperties, + [ + "day": .integer, + "dayOfWeek": .integer, + "dayOfYear": .integer, + "weekOfYear": .integer, + "yearOfWeek": .integer, + "daysInWeek": .integer, + ]), overloads: [ "toPlainYearMonth": [[] => .jsTemporalPlainYearMonth], "toPlainMonthDay": [[] => .jsTemporalPlainMonthDay], "add": temporalAddSubtractSignature(forType: .jsTemporalPlainDate, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainDate, needsOverflow: true), - "with": [[.plain(jsTemporalPlainDateLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainDate], + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainDate, needsOverflow: true), + "with": [ + [ + .plain(jsTemporalPlainDateLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainDate + ], "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalPlainDate], "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateLikeParameters), "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateLikeParameters), "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainDateLikeParameters), - "toPlainDateTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalPlainDateTime}, - "toZonedDateTime": temporalTimeZoneLikeSignature { [.plain($0)] => .jsTemporalZonedDateTime } + "toPlainDateTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalPlainDateTime + }, + "toZonedDateTime": temporalTimeZoneLikeSignature { + [.plain($0)] => .jsTemporalZonedDateTime + } // Can also accept an object with timezone/time fields - + [[.plain(OptionsBag.jsTemporalPlainDateToZDTSettings.group.instanceType)] => .jsTemporalZonedDateTime], + + [ + [.plain(OptionsBag.jsTemporalPlainDateToZDTSettings.group.instanceType)] + => .jsTemporalZonedDateTime + ], "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], ] ) - static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainDatePrototype = createPrototypeObjectGroup( jsTemporalPlainDate, constructor: .jsTemporalPlainDateConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDate constructor - static let jsTemporalPlainDateConstructor = ObjectGroup( + public static let jsTemporalPlainDateConstructor = ObjectGroup( name: "TemporalPlainDateConstructor", constructorPath: "Temporal.PlainDate", instanceType: .jsTemporalPlainDateConstructor, properties: [ - "prototype" : jsTemporalPlainDatePrototype.instanceType + "prototype": jsTemporalPlainDatePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainDate, possibleParams: jsTemporalPlainDateLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainDate, possibleParams: jsTemporalPlainDateLikeParameters), "compare": temporalCompareSignature(possibleParams: jsTemporalPlainDateLikeParameters), ] ) - static let jsTemporalPlainDateTime = ObjectGroup( + public static let jsTemporalPlainDateTime = ObjectGroup( name: "Temporal.PlainDateTime", instanceType: .jsTemporalPlainDateTime, properties: mergeFields(jsTemporalPlainDate.properties, jsTemporalPlainTime.properties), overloads: [ - "with": [[.plain(jsTemporalPlainDateTimeLikeObjectForWith.instanceType), .opt(jsTemporalOverflowSettings)] => .jsTemporalPlainDateTime], - "withPlainTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalPlainDateTime}, + "with": [ + [ + .plain(jsTemporalPlainDateTimeLikeObjectForWith.instanceType), + .opt(jsTemporalOverflowSettings), + ] => .jsTemporalPlainDateTime + ], + "withPlainTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalPlainDateTime + }, "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalPlainDateTime], - "add": temporalAddSubtractSignature(forType: .jsTemporalPlainDateTime, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalPlainDateTime, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "add": temporalAddSubtractSignature( + forType: .jsTemporalPlainDateTime, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalPlainDateTime, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalPlainDateTime], - "equals": temporalEqualsSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], - "toZonedDateTime": temporalTimeZoneLikeSignature { [.plain($0), .opt(OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType)] => .jsTemporalZonedDateTime }, + "toZonedDateTime": temporalTimeZoneLikeSignature { + [ + .plain($0), + .opt(OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType), + ] => .jsTemporalZonedDateTime + }, "toPlainDate": [[] => .jsTemporalPlainDate], "toPlainTime": [[] => .jsTemporalPlainTime], ] ) - static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup( + public static let jsTemporalPlainDateTimePrototype = createPrototypeObjectGroup( jsTemporalPlainDateTime, constructor: .jsTemporalPlainDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.PlainDateTime constructor - static let jsTemporalPlainDateTimeConstructor = ObjectGroup( + public static let jsTemporalPlainDateTimeConstructor = ObjectGroup( name: "TemporalPlainDateTimeConstructor", constructorPath: "Temporal.PlainDateTime", instanceType: .jsTemporalPlainDateTimeConstructor, properties: [ - "prototype" : jsTemporalPlainDateTimePrototype.instanceType + "prototype": jsTemporalPlainDateTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalPlainDateTime, possibleParams: jsTemporalPlainDateTimeLikeParameters, settingsArg: jsTemporalOverflowSettings), - "compare": temporalCompareSignature(possibleParams: jsTemporalPlainDateTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalPlainDateTime, + possibleParams: jsTemporalPlainDateTimeLikeParameters, + settingsArg: jsTemporalOverflowSettings), + "compare": temporalCompareSignature( + possibleParams: jsTemporalPlainDateTimeLikeParameters), ] ) - - static let jsTemporalZonedDateTime = ObjectGroup( + public static let jsTemporalZonedDateTime = ObjectGroup( name: "Temporal.ZonedDateTime", instanceType: .jsTemporalZonedDateTime, - properties: mergeFields(jsTemporalPlainDate.properties, jsTemporalPlainTime.properties, [ - "timeZoneId": .string, - "epochMilliseconds": .integer, - "epochNanoseconds": .bigint, - "offsetNanoseconds": .integer, - "offset": .string, - ]), + properties: mergeFields( + jsTemporalPlainDate.properties, jsTemporalPlainTime.properties, + [ + "timeZoneId": .string, + "epochMilliseconds": .integer, + "epochNanoseconds": .bigint, + "offsetNanoseconds": .integer, + "offset": .string, + ]), overloads: [ - "with": [[.plain(jsTemporalZonedDateTimeLikeObjectForWith.instanceType), .opt(jsTemporalZonedInterpretationSettings)] => .jsTemporalZonedDateTime], - "withPlainTime": jsTemporalPlainTimeLikeParameters.map {[.opt($0)] => .jsTemporalZonedDateTime}, + "with": [ + [ + .plain(jsTemporalZonedDateTimeLikeObjectForWith.instanceType), + .opt(jsTemporalZonedInterpretationSettings), + ] => .jsTemporalZonedDateTime + ], + "withPlainTime": jsTemporalPlainTimeLikeParameters.map { + [.opt($0)] => .jsTemporalZonedDateTime + }, "withCalendar": [[.plain(.jsTemporalCalendarEnum)] => .jsTemporalZonedDateTime], "withTimeZone": [[.string] => .jsTemporalZonedDateTime], - "add": temporalAddSubtractSignature(forType: .jsTemporalZonedDateTime, needsOverflow: true), - "subtract": temporalAddSubtractSignature(forType: .jsTemporalZonedDateTime, needsOverflow: true), - "until": temporalUntilSinceSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), - "since": temporalUntilSinceSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "add": temporalAddSubtractSignature( + forType: .jsTemporalZonedDateTime, needsOverflow: true), + "subtract": temporalAddSubtractSignature( + forType: .jsTemporalZonedDateTime, needsOverflow: true), + "until": temporalUntilSinceSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), + "since": temporalUntilSinceSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), "round": [[.plain(jsTemporalRoundTo)] => .jsTemporalZonedDateTime], - "equals": temporalEqualsSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "equals": temporalEqualsSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), "toString": [[.opt(jsTemporalToStringSettings)] => .string], "toJSON": [[] => .string], "toLocaleString": [[.opt(.string), .opt(jsTemporalToLocaleStringSettings)] => .string], "startOfDay": [[] => .jsTemporalZonedDateTime], - "getTimeZoneTransition": [[.plain(jsTemporalDirectionParam)] => .jsTemporalZonedDateTime], + "getTimeZoneTransition": [ + [.plain(jsTemporalDirectionParam)] => .jsTemporalZonedDateTime + ], "toInstant": [[] => .jsTemporalInstant], "toPlainDate": [[] => .jsTemporalPlainDate], "toPlainTime": [[] => .jsTemporalPlainTime], @@ -3280,21 +3932,25 @@ public extension ObjectGroup { ] ) - static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup( + public static let jsTemporalZonedDateTimePrototype = createPrototypeObjectGroup( jsTemporalZonedDateTime, constructor: .jsTemporalZonedDateTimeConstructor) /// ObjectGroup modelling the JavaScript Temporal.ZonedDateTime constructor - static let jsTemporalZonedDateTimeConstructor = ObjectGroup( + public static let jsTemporalZonedDateTimeConstructor = ObjectGroup( name: "TemporalZonedDateTimeConstructor", constructorPath: "Temporal.ZonedDateTime", instanceType: .jsTemporalZonedDateTimeConstructor, properties: [ - "prototype" : jsTemporalZonedDateTimePrototype.instanceType + "prototype": jsTemporalZonedDateTimePrototype.instanceType ], overloads: [ - "from": temporalFromSignature(forType: .jsTemporalZonedDateTime, possibleParams: jsTemporalZonedDateTimeLikeParameters, settingsArg: jsTemporalZonedInterpretationSettings), - "compare": temporalCompareSignature(possibleParams: jsTemporalZonedDateTimeLikeParameters), + "from": temporalFromSignature( + forType: .jsTemporalZonedDateTime, + possibleParams: jsTemporalZonedDateTimeLikeParameters, + settingsArg: jsTemporalZonedInterpretationSettings), + "compare": temporalCompareSignature( + possibleParams: jsTemporalZonedDateTimeLikeParameters), ] ) @@ -3321,33 +3977,33 @@ public extension ObjectGroup { ], methods: [:]) - private static let jsTemporalTimeLikeFields : [String: ILType] = [ - "hour": .number | .undefined, - "minute": .number | .undefined, - "second": .number | .undefined, - "millisecond": .number | .undefined, - "microsecond": .number | .undefined, - "nanosecond": .number | .undefined, + private static let jsTemporalTimeLikeFields: [String: ILType] = [ + "hour": .number | .undefined, + "minute": .number | .undefined, + "second": .number | .undefined, + "millisecond": .number | .undefined, + "microsecond": .number | .undefined, + "nanosecond": .number | .undefined, ] - private static let jsTemporalCalendarField : [String: ILType] = [ - "calendar": .jsTemporalCalendarEnum | .undefined, + private static let jsTemporalCalendarField: [String: ILType] = [ + "calendar": .jsTemporalCalendarEnum | .undefined ] - private static let jsTemporalDateLikeFields : [String: ILType] = [ - "era": .string | .undefined, - "eraYear": .number | .undefined, - "month": .number | .undefined, - "monthCode": .string | .undefined, - "day": .number | .undefined, + private static let jsTemporalDateLikeFields: [String: ILType] = [ + "era": .string | .undefined, + "eraYear": .number | .undefined, + "month": .number | .undefined, + "monthCode": .string | .undefined, + "day": .number | .undefined, ] private static func mergeFields(_ fields: [String: ILType]...) -> [String: ILType] { - fields.reduce([:]) { - $0.merging($1) { _, _ in - fatalError("Duplicate field in \(fields)") + fields.reduce([:]) { + $0.merging($1) { _, _ in + fatalError("Duplicate field in \(fields)") + } } - } } fileprivate static let jsTemporalPlainTimeLikeObject = ObjectGroup( @@ -3365,15 +4021,17 @@ public extension ObjectGroup { fileprivate static let jsTemporalPlainDateTimeLikeObject = ObjectGroup( name: "TemporalPlainDateTimeLikeObject", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, jsTemporalCalendarField), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, jsTemporalCalendarField), methods: [:]) fileprivate static let jsTemporalZonedDateTimeLikeObject = ObjectGroup( name: "TemporalZonedDateTimeLikeObject", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, - ["timeZone": .string | .undefined, "offset": .string | .undefined], - jsTemporalCalendarField), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, + ["timeZone": .string | .undefined, "offset": .string | .undefined], + jsTemporalCalendarField), methods: [:]) // with() takes a reduced set of fields: it cannot have a calendar or timeZone, @@ -3393,38 +4051,68 @@ public extension ObjectGroup { fileprivate static let jsTemporalZonedDateTimeLikeObjectForWith = ObjectGroup( name: "TemporalZonedDateTimeLikeObjectForWith", instanceType: nil, - properties: mergeFields(jsTemporalDateLikeFields, jsTemporalTimeLikeFields, ["offset": .string | .undefined]), + properties: mergeFields( + jsTemporalDateLikeFields, jsTemporalTimeLikeFields, ["offset": .string | .undefined]), methods: [:]) // Temporal-object-like parameters (accepted by ToTemporalFoo) // ToTemporalFoo, and APIs based on it (from, compare, until, since, equals, occasionally withFoo/toFoo) accept // a Temporal-like object, a Temporal object that is a superset of the type, or a string representation. // TODO(manishearth, 439921647) Most of the stringy types here are with a specific format, we should consider generating them - private static let jsTemporalDurationLikeParameters: [ILType] = [jsTemporalDurationLikeObject.instanceType, .jsTemporalDuration, .string] - private static let jsTemporalInstantLikeParameters: [ILType] = [.jsTemporalInstant, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainTimeLikeParameters: [ILType] = [jsTemporalPlainTimeLikeObject.instanceType, .jsTemporalPlainTime, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainYearMonthLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainYearMonth, .string] - private static let jsTemporalPlainMonthDayLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainMonthDay, .string] - private static let jsTemporalPlainDateLikeParameters: [ILType] = [jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalPlainDateTimeLikeParameters: [ILType] = [jsTemporalPlainDateTimeLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string] - private static let jsTemporalZonedDateTimeLikeParameters: [ILType] = [jsTemporalZonedDateTimeLikeObject.instanceType, .string] + private static let jsTemporalDurationLikeParameters: [ILType] = [ + jsTemporalDurationLikeObject.instanceType, .jsTemporalDuration, .string, + ] + private static let jsTemporalInstantLikeParameters: [ILType] = [ + .jsTemporalInstant, .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainTimeLikeParameters: [ILType] = [ + jsTemporalPlainTimeLikeObject.instanceType, .jsTemporalPlainTime, .jsTemporalPlainDateTime, + .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainYearMonthLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainYearMonth, .string, + ] + private static let jsTemporalPlainMonthDayLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainMonthDay, .string, + ] + private static let jsTemporalPlainDateLikeParameters: [ILType] = [ + jsTemporalPlainDateLikeObject.instanceType, .jsTemporalPlainDate, .jsTemporalPlainDateTime, + .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalPlainDateTimeLikeParameters: [ILType] = [ + jsTemporalPlainDateTimeLikeObject.instanceType, .jsTemporalPlainDate, + .jsTemporalPlainDateTime, .jsTemporalZonedDateTime, .string, + ] + private static let jsTemporalZonedDateTimeLikeParameters: [ILType] = [ + jsTemporalZonedDateTimeLikeObject.instanceType, .string, + ] // Stringy objects // TODO(manishearth, 439921647) support stringy objects - fileprivate static let jsTemporalTimeZoneLike = ILType.namedString(ofName: "TemporalTimeZoneString") + fileprivate static let jsTemporalTimeZoneLike = ILType.namedString( + ofName: "TemporalTimeZoneString") // Options objects - fileprivate static let jsTemporalDifferenceSettings = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType + fileprivate static let jsTemporalDifferenceSettings = OptionsBag + .jsTemporalDifferenceSettingOrRoundTo.group.instanceType // roundTo accepts a subset of fields compared to differenceSettings; we merge the two bag types but retain separate // variables for clarity in the signatures above. - fileprivate static let jsTemporalRoundTo = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType - fileprivate static let jsTemporalToStringSettings = OptionsBag.jsTemporalToStringSettings.group.instanceType - fileprivate static let jsTemporalOverflowSettings = OptionsBag.jsTemporalOverflowSettings.group.instanceType - fileprivate static let jsTemporalZonedInterpretationSettings = OptionsBag.jsTemporalZonedInterpretationSettings.group.instanceType - fileprivate static let jsTemporalDirectionParam = ILType.enumeration(ofName: "directionParam", withValues: ["previous", "next"]) - fileprivate static let jsTemporalDurationRoundToSettings = OptionsBag.jsTemporalDurationRoundToSettings.group.instanceType - fileprivate static let jsTemporalDurationTotalOfSettings = OptionsBag.jsTemporalDurationTotalOfSettings.group.instanceType - fileprivate static let jsTemporalDurationCompareSettings = OptionsBag.jsTemporalDurationCompareSettings.group.instanceType + fileprivate static let jsTemporalRoundTo = OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group + .instanceType + fileprivate static let jsTemporalToStringSettings = OptionsBag.jsTemporalToStringSettings.group + .instanceType + fileprivate static let jsTemporalOverflowSettings = OptionsBag.jsTemporalOverflowSettings.group + .instanceType + fileprivate static let jsTemporalZonedInterpretationSettings = OptionsBag + .jsTemporalZonedInterpretationSettings.group.instanceType + fileprivate static let jsTemporalDirectionParam = ILType.enumeration( + ofName: "directionParam", withValues: ["previous", "next"]) + fileprivate static let jsTemporalDurationRoundToSettings = OptionsBag + .jsTemporalDurationRoundToSettings.group.instanceType + fileprivate static let jsTemporalDurationTotalOfSettings = OptionsBag + .jsTemporalDurationTotalOfSettings.group.instanceType + fileprivate static let jsTemporalDurationCompareSettings = OptionsBag + .jsTemporalDurationCompareSettings.group.instanceType // This is huge and comes from Intl, not Temporal // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters fileprivate static let jsTemporalToLocaleStringSettings = ILType.jsAnything @@ -3433,16 +4121,35 @@ public extension ObjectGroup { extension OptionsBag { // Individual enums - fileprivate static let jsTemporalUnitEnum = ILType.enumeration(ofName: "temporalUnit", withValues: ["auto", "year", "month", "week", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "auto", "years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"]) - fileprivate static let jsTemporalRoundingModeEnum = ILType.enumeration(ofName: "temporalRoundingMode", withValues: ["ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"]) - fileprivate static let jsTemporalShowCalendarEnum = ILType.enumeration(ofName: "temporalShowCalendar", withValues: ["auto", "always", "never", "critical"]) - fileprivate static let jsTemporalShowOffsetEnum = ILType.enumeration(ofName: "temporalShowOffset", withValues: ["auto", "never"]) - fileprivate static let jsTemporalShowTimeZoneEnum = ILType.enumeration(ofName: "temporalShowOfTimeZone", withValues: ["auto", "never", "critical"]) - fileprivate static let jsTemporalOverflowEnum = ILType.enumeration(ofName: "temporalOverflow", withValues: ["constrain", "reject"]) - fileprivate static let jsTemporalDisambiguationEnum = ILType.enumeration(ofName: "temporalDisambiguation", withValues: ["compatible", "earlier", "later", "reject"]) - fileprivate static let jsTemporalOffsetEnum = ILType.enumeration(ofName: "temporalOffset", withValues: ["prefer", "use", "ignore", "reject"]) - - static let jsTemporalRelativeTo = ILType.jsTemporalZonedDateTime | ILType.jsTemporalPlainDateTime | ILType.jsTemporalPlainDate | .string + fileprivate static let jsTemporalUnitEnum = ILType.enumeration( + ofName: "temporalUnit", + withValues: [ + "auto", "year", "month", "week", "day", "hour", "minute", "second", "millisecond", + "microsecond", "nanosecond", "auto", "years", "months", "weeks", "days", "hours", + "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", + ]) + fileprivate static let jsTemporalRoundingModeEnum = ILType.enumeration( + ofName: "temporalRoundingMode", + withValues: [ + "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", + "halfEven", + ]) + fileprivate static let jsTemporalShowCalendarEnum = ILType.enumeration( + ofName: "temporalShowCalendar", withValues: ["auto", "always", "never", "critical"]) + fileprivate static let jsTemporalShowOffsetEnum = ILType.enumeration( + ofName: "temporalShowOffset", withValues: ["auto", "never"]) + fileprivate static let jsTemporalShowTimeZoneEnum = ILType.enumeration( + ofName: "temporalShowOfTimeZone", withValues: ["auto", "never", "critical"]) + fileprivate static let jsTemporalOverflowEnum = ILType.enumeration( + ofName: "temporalOverflow", withValues: ["constrain", "reject"]) + fileprivate static let jsTemporalDisambiguationEnum = ILType.enumeration( + ofName: "temporalDisambiguation", withValues: ["compatible", "earlier", "later", "reject"]) + fileprivate static let jsTemporalOffsetEnum = ILType.enumeration( + ofName: "temporalOffset", withValues: ["prefer", "use", "ignore", "reject"]) + + static let jsTemporalRelativeTo = + ILType.jsTemporalZonedDateTime | ILType.jsTemporalPlainDateTime | ILType.jsTemporalPlainDate + | .string // differenceSettings and roundTo are mostly the same, with differenceSettings accepting an additional largestUnit // note that the Duration roundTo option is different @@ -3471,7 +4178,7 @@ extension OptionsBag { static let jsTemporalOverflowSettings = OptionsBag( name: "jsTemporalOverflowSettingsObject", properties: [ - "overflow": jsTemporalOverflowEnum, + "overflow": jsTemporalOverflowEnum ]) static let jsTemporalZonedInterpretationSettings = OptionsBag( @@ -3482,7 +4189,7 @@ extension OptionsBag { "offset": jsTemporalOffsetEnum, ]) - static let jsTemporalDurationRoundToSettings = OptionsBag( + static let jsTemporalDurationRoundToSettings = OptionsBag( name: "TemporalDurationRoundToSettingsObject", properties: [ "largestUnit": OptionsBag.jsTemporalUnitEnum, @@ -3492,17 +4199,17 @@ extension OptionsBag { "smallestUnit": OptionsBag.jsTemporalUnitEnum, ] ) - static let jsTemporalDurationTotalOfSettings = OptionsBag( + static let jsTemporalDurationTotalOfSettings = OptionsBag( name: "TemporalDurationTotalOfSettingsObject", properties: [ "relativeTo": jsTemporalRelativeTo, "unit": OptionsBag.jsTemporalUnitEnum, ] ) - static let jsTemporalDurationCompareSettings = OptionsBag( + static let jsTemporalDurationCompareSettings = OptionsBag( name: "TemporalDurationCompareSettingsObject", properties: [ - "relativeTo": jsTemporalRelativeTo, + "relativeTo": jsTemporalRelativeTo ] ) @@ -3518,39 +4225,143 @@ extension OptionsBag { // Intl extension ILType { // Intl types - static let jsIntlObject = ILType.object(ofGroup: "Intl", withProperties: ["DateTimeFormat", "Collator", "DisplayNames", "DurationFormat", "ListFormat", "Locale", "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter"], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) - - static let jsIntlLocale = ILType.object(ofGroup: "Intl.Locale", withProperties: ["baseName", "calendar", "caseFirst", "collation", "hourCycle", "language", "numberingSystem", "numeric", "region", "script", "variants"], withMethods: ["getCalendars", "getCollations", "getHourCycles", "getNumberingSystems", "getTextInfo", "getTimeZones", "getWeekInfo", "maximize", "minimize", "toString"]) - static let jsIntlLocaleConstructor = ILType.functionAndConstructor([.plain(.jsIntlLocaleString), .opt(OptionsBag.jsIntlLocaleSettings.group.instanceType)] => .jsIntlLocale) + .object(ofGroup: "IntlLocaleConstructor", withProperties: ["prototype"], withMethods: []) - - static let jsIntlCollator = ILType.object(ofGroup: "Intl.Collator", withProperties: [], withMethods: ["compare", "resolvedOptions"]) - static let jsIntlCollatorConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlCollatorSettings.group.instanceType)] => .jsIntlCollator) + .object(ofGroup: "IntlCollatorConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDisplayNames = ILType.object(ofGroup: "Intl.DisplayNames", withProperties: [], withMethods: ["of", "resolvedOptions"]) - static let jsIntlDisplayNamesConstructor = ILType.functionAndConstructor([.plain(.jsIntlLocaleLike), .plain(OptionsBag.jsIntlDisplayNamesSettings.group.instanceType)] => .jsIntlDisplayNames) + .object(ofGroup: "IntlDisplayNamesConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDurationFormat = ILType.object(ofGroup: "Intl.DurationFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlDurationFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDurationFormatSettings.group.instanceType)] => .jsIntlDurationFormat) + .object(ofGroup: "IntlDurationFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlDateTimeFormat = ILType.object(ofGroup: "Intl.DateTimeFormat", withProperties: [], withMethods: ["format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions"]) - static let jsIntlDateTimeFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType)] => .jsIntlDateTimeFormat) + .object(ofGroup: "IntlDateTimeFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlListFormat = ILType.object(ofGroup: "Intl.ListFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlListFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlListFormatSettings.group.instanceType)] => .jsIntlListFormat) + .object(ofGroup: "IntlListFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlNumberFormat = ILType.object(ofGroup: "Intl.NumberFormat", withProperties: [], withMethods: ["format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions"]) - static let jsIntlNumberFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlNumberFormatSettings.group.instanceType)] => .jsIntlNumberFormat) + .object(ofGroup: "IntlNumberFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlPluralRules = ILType.object(ofGroup: "Intl.PluralRules", withProperties: [], withMethods: ["select", "selectRange", "resolvedOptions"]) - static let jsIntlPluralRulesConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlPluralRulesSettings.group.instanceType)] => .jsIntlPluralRules) + .object(ofGroup: "IntlPluralRulesConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlRelativeTimeFormat = ILType.object(ofGroup: "Intl.RelativeTimeFormat", withProperties: [], withMethods: ["format", "formatToParts", "resolvedOptions"]) - static let jsIntlRelativeTimeFormatConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlRelativeTimeFormatSettings.group.instanceType)] => .jsIntlRelativeTimeFormat) + .object(ofGroup: "IntlRelativeTimeFormatConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlSegmenter = ILType.object(ofGroup: "Intl.Segmenter", withProperties: [], withMethods: ["segment", "resolvedOptions"]) - static let jsIntlSegmenterConstructor = ILType.functionAndConstructor([.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlSegmenterSettings.group.instanceType)] => .jsIntlSegmenter) + .object(ofGroup: "IntlSegmenterConstructor", withProperties: ["prototype"], withMethods: ["supportedLocalesOf"]) - - static let jsIntlSegmenterSegments = ILType.object(ofGroup: "IntlSegmenterSegments", withProperties: [], withMethods: ["containing"]) + static let jsIntlObject = ILType.object( + ofGroup: "Intl", + withProperties: [ + "DateTimeFormat", "Collator", "DisplayNames", "DurationFormat", "ListFormat", "Locale", + "NumberFormat", "PluralRules", "RelativeTimeFormat", "Segmenter", + ], withMethods: ["getCanonicalLocales", "supportedValuesOf"]) + + static let jsIntlLocale = ILType.object( + ofGroup: "Intl.Locale", + withProperties: [ + "baseName", "calendar", "caseFirst", "collation", "hourCycle", "language", + "numberingSystem", "numeric", "region", "script", "variants", + ], + withMethods: [ + "getCalendars", "getCollations", "getHourCycles", "getNumberingSystems", "getTextInfo", + "getTimeZones", "getWeekInfo", "maximize", "minimize", "toString", + ]) + static let jsIntlLocaleConstructor = + ILType.functionAndConstructor( + [.plain(.jsIntlLocaleString), .opt(OptionsBag.jsIntlLocaleSettings.group.instanceType)] + => .jsIntlLocale) + + .object(ofGroup: "IntlLocaleConstructor", withProperties: ["prototype"], withMethods: []) + + static let jsIntlCollator = ILType.object( + ofGroup: "Intl.Collator", withProperties: [], withMethods: ["compare", "resolvedOptions"]) + static let jsIntlCollatorConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlCollatorSettings.group.instanceType)] + => .jsIntlCollator) + + .object( + ofGroup: "IntlCollatorConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDisplayNames = ILType.object( + ofGroup: "Intl.DisplayNames", withProperties: [], withMethods: ["of", "resolvedOptions"]) + static let jsIntlDisplayNamesConstructor = + ILType.functionAndConstructor( + [ + .plain(.jsIntlLocaleLike), + .plain(OptionsBag.jsIntlDisplayNamesSettings.group.instanceType), + ] => .jsIntlDisplayNames) + + .object( + ofGroup: "IntlDisplayNamesConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDurationFormat = ILType.object( + ofGroup: "Intl.DurationFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlDurationFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDurationFormatSettings.group.instanceType), + ] => .jsIntlDurationFormat) + + .object( + ofGroup: "IntlDurationFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlDateTimeFormat = ILType.object( + ofGroup: "Intl.DateTimeFormat", withProperties: [], + withMethods: [ + "format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions", + ]) + static let jsIntlDateTimeFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlDateTimeFormatSettings.group.instanceType), + ] => .jsIntlDateTimeFormat) + + .object( + ofGroup: "IntlDateTimeFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlListFormat = ILType.object( + ofGroup: "Intl.ListFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlListFormatConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlListFormatSettings.group.instanceType)] + => .jsIntlListFormat) + + .object( + ofGroup: "IntlListFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlNumberFormat = ILType.object( + ofGroup: "Intl.NumberFormat", withProperties: [], + withMethods: [ + "format", "formatRange", "formatRangeToParts", "formatToParts", "resolvedOptions", + ]) + static let jsIntlNumberFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlNumberFormatSettings.group.instanceType), + ] => .jsIntlNumberFormat) + + .object( + ofGroup: "IntlNumberFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlPluralRules = ILType.object( + ofGroup: "Intl.PluralRules", withProperties: [], + withMethods: ["select", "selectRange", "resolvedOptions"]) + static let jsIntlPluralRulesConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlPluralRulesSettings.group.instanceType), + ] => .jsIntlPluralRules) + + .object( + ofGroup: "IntlPluralRulesConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlRelativeTimeFormat = ILType.object( + ofGroup: "Intl.RelativeTimeFormat", withProperties: [], + withMethods: ["format", "formatToParts", "resolvedOptions"]) + static let jsIntlRelativeTimeFormatConstructor = + ILType.functionAndConstructor( + [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlRelativeTimeFormatSettings.group.instanceType), + ] => .jsIntlRelativeTimeFormat) + + .object( + ofGroup: "IntlRelativeTimeFormatConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlSegmenter = ILType.object( + ofGroup: "Intl.Segmenter", withProperties: [], withMethods: ["segment", "resolvedOptions"]) + static let jsIntlSegmenterConstructor = + ILType.functionAndConstructor( + [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlSegmenterSettings.group.instanceType)] + => .jsIntlSegmenter) + + .object( + ofGroup: "IntlSegmenterConstructor", withProperties: ["prototype"], + withMethods: ["supportedLocalesOf"]) + + static let jsIntlSegmenterSegments = ILType.object( + ofGroup: "IntlSegmenterSegments", withProperties: [], withMethods: ["containing"]) static let jsIntlLocaleString = ILType.namedString(ofName: "IntlLocaleString") static let jsIntlLanguageString = ILType.namedString(ofName: "IntlLanguageString") @@ -3563,22 +4374,24 @@ extension ILType { } extension ObjectGroup { - static let jsIntlSupportedValuesEnum = ILType.enumeration(ofName: "IntlSupportedValues", withValues: ["calendar", "collation", "currency", "numberingSystem", "timeZone"]) + static let jsIntlSupportedValuesEnum = ILType.enumeration( + ofName: "IntlSupportedValues", + withValues: ["calendar", "collation", "currency", "numberingSystem", "timeZone"]) static let jsIntlObject = ObjectGroup( name: "Intl", instanceType: .jsIntlObject, properties: [ - "Collator" : .jsIntlCollatorConstructor, - "DateTimeFormat" : .jsIntlDateTimeFormatConstructor, - "DisplayNames" : .jsIntlDisplayNamesConstructor, - "DurationFormat" : .jsIntlDurationFormatConstructor, - "ListFormat" : .jsIntlListFormatConstructor, - "Locale" : .jsIntlLocaleConstructor, - "NumberFormat" : .jsIntlNumberFormatConstructor, - "PluralRules" : .jsIntlPluralRulesConstructor, - "RelativeTimeFormat" : .jsIntlRelativeTimeFormatConstructor, - "Segmenter" : .jsIntlSegmenterConstructor, + "Collator": .jsIntlCollatorConstructor, + "DateTimeFormat": .jsIntlDateTimeFormatConstructor, + "DisplayNames": .jsIntlDisplayNamesConstructor, + "DurationFormat": .jsIntlDurationFormatConstructor, + "ListFormat": .jsIntlListFormatConstructor, + "Locale": .jsIntlLocaleConstructor, + "NumberFormat": .jsIntlNumberFormatConstructor, + "PluralRules": .jsIntlPluralRulesConstructor, + "RelativeTimeFormat": .jsIntlRelativeTimeFormatConstructor, + "Segmenter": .jsIntlSegmenterConstructor, ], methods: [ "getCanonicalLocales": [] => .jsArray, @@ -3608,11 +4421,14 @@ extension ObjectGroup { constructorPath: "Intl.Collator", instanceType: .jsIntlCollatorConstructor, properties: [ - "prototype" : jsIntlCollatorPrototype.instanceType + "prototype": jsIntlCollatorPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3622,7 +4438,10 @@ extension ObjectGroup { properties: [:], methods: [ "of": [.string] => .string, // TODO(mliedtke): The parameter should be typed more precise than string. - "resolvedOptions": [] => .object(withProperties: ["locale", "style", "type", "fallback", "languageDisplay"]), + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "style", "type", "fallback", "languageDisplay", + ]), ] ) @@ -3635,11 +4454,14 @@ extension ObjectGroup { constructorPath: "Intl.DisplayNames", instanceType: .jsIntlDisplayNamesConstructor, properties: [ - "prototype" : jsIntlDisplayNamesPrototype.instanceType + "prototype": jsIntlDisplayNamesPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3649,8 +4471,12 @@ extension ObjectGroup { properties: [:], methods: [ "format": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] => .string, - "formatToParts": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] => .jsArray, - "resolvedOptions": [] => .object(withProperties: ["locale", "numberingSystem", "style", "fractionalDigits"]), + "formatToParts": [.plain(ObjectGroup.jsTemporalDurationLikeObject.instanceType)] + => .jsArray, + "resolvedOptions": [] + => .object(withProperties: [ + "locale", "numberingSystem", "style", "fractionalDigits", + ]), ] ) @@ -3663,18 +4489,24 @@ extension ObjectGroup { constructorPath: "Intl.DurationFormat", instanceType: .jsIntlDurationFormatConstructor, properties: [ - "prototype" : jsIntlDurationFormatPrototype.instanceType + "prototype": jsIntlDurationFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) fileprivate static func dateTimeFormatSignature(_ returnType: ILType) -> [Signature] { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format#date // No ZonedDateTime as stated in the docs. - [ILType.jsDate, .jsTemporalPlainDate, .jsTemporalPlainTime, .jsTemporalPlainMonthDay, .jsTemporalPlainYearMonth, .jsTemporalPlainDateTime].map { + [ + ILType.jsDate, .jsTemporalPlainDate, .jsTemporalPlainTime, .jsTemporalPlainMonthDay, + .jsTemporalPlainYearMonth, .jsTemporalPlainDateTime, + ].map { [.opt($0)] => returnType } } @@ -3712,11 +4544,14 @@ extension ObjectGroup { constructorPath: "Intl.DateTimeFormat", instanceType: .jsIntlDateTimeFormatConstructor, properties: [ - "prototype" : jsIntlDateTimeFormatPrototype.instanceType + "prototype": jsIntlDateTimeFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3740,11 +4575,14 @@ extension ObjectGroup { constructorPath: "Intl.ListFormat", instanceType: .jsIntlListFormatConstructor, properties: [ - "prototype" : jsIntlListFormatPrototype.instanceType + "prototype": jsIntlListFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3786,7 +4624,7 @@ extension ObjectGroup { constructorPath: "Intl.Locale", instanceType: .jsIntlLocaleConstructor, properties: [ - "prototype" : jsIntlLocalePrototype.instanceType, + "prototype": jsIntlLocalePrototype.instanceType ], methods: [:] ) @@ -3830,11 +4668,14 @@ extension ObjectGroup { constructorPath: "Intl.NumberFormat", instanceType: .jsIntlNumberFormatConstructor, properties: [ - "prototype" : jsIntlNumberFormatPrototype.instanceType + "prototype": jsIntlNumberFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3857,15 +4698,20 @@ extension ObjectGroup { constructorPath: "Intl.PluralRules", instanceType: .jsIntlPluralRulesConstructor, properties: [ - "prototype" : jsIntlPluralRulesPrototype.instanceType + "prototype": jsIntlPluralRulesPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) - static let jsIntlRelativeTimeFormatUnitEnum = ILType.enumeration(ofName: "IntlRelativeTimeFormatUnit", withValues: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"]) + static let jsIntlRelativeTimeFormatUnitEnum = ILType.enumeration( + ofName: "IntlRelativeTimeFormatUnit", + withValues: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"]) static let jsIntlRelativeTimeFormat = ObjectGroup( name: "Intl.RelativeTimeFormat", @@ -3887,11 +4733,14 @@ extension ObjectGroup { constructorPath: "Intl.RelativeTimeFormat", instanceType: .jsIntlRelativeTimeFormatConstructor, properties: [ - "prototype" : jsIntlRelativeTimeFormatPrototype.instanceType + "prototype": jsIntlRelativeTimeFormatPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) @@ -3913,11 +4762,14 @@ extension ObjectGroup { constructorPath: "Intl.Segmenter", instanceType: .jsIntlSegmenterConstructor, properties: [ - "prototype" : jsIntlSegmenterPrototype.instanceType + "prototype": jsIntlSegmenterPrototype.instanceType ], methods: [ // TODO(manishearth) this also accepts arrays of locale-likes - "supportedLocalesOf": [.opt(.jsIntlLocaleLike), .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType)] => .jsArray, + "supportedLocalesOf": [ + .opt(.jsIntlLocaleLike), + .opt(OptionsBag.jsIntlLocaleMatcherSettings.group.instanceType), + ] => .jsArray ] ) static let jsIntlSegmenterSegments = ObjectGroup( @@ -3925,45 +4777,91 @@ extension ObjectGroup { instanceType: .jsIntlSegmenterSegments, properties: [:], methods: [ - "containing": [.number] => .object(), + "containing": [.number] => .object() ] ) } extension OptionsBag { - fileprivate static let jsIntlLocaleMatcherEnum = ILType.enumeration(ofName: "IntlLocaleMatcher", withValues: ["lookup", "best fit"]) - fileprivate static let jsIntlNumberingSystemEnum = ILType.enumeration(ofName: "IntlNumberingSystem", withValues: Locale.NumberingSystem.availableNumberingSystems.map { $0.identifier }) - fileprivate static let jsIntlHourCycleEnum = ILType.enumeration(ofName: "IntlHourCycle", withValues: ["h11", "h12", "h23", "h24"]) - fileprivate static let jsIntlLongShortNarrowEnum = ILType.enumeration(ofName: "IntlLongShortNarrow", withValues: ["long", "short", "narrow"]) - fileprivate static let jsIntlLongShortEnum = ILType.enumeration(ofName: "IntlLongShort", withValues: ["long", "short"]) - fileprivate static let jsIntlAutoAlwaysEnum = ILType.enumeration(ofName: "IntlAutoAlways", withValues: ["auto", "always"]) - fileprivate static let jsIntlNumeric2DigitEnum = ILType.enumeration(ofName: "IntlNumeric2Digit", withValues: ["numeric", "2-digit"]) - fileprivate static let jsIntlMonthEnum = ILType.enumeration(ofName: "IntlMonth", withValues: ["numeric", "2-digit", "long", "short", "narrow"]) - fileprivate static let jsIntlTimeZoneNameEnum = ILType.enumeration(ofName: "IntlTimeZoneName", withValues: ["long", "short", "shortOffset", "longOffset", "shortGeneric", "longGeneric"]) - fileprivate static let jsIntlFormatMatcherEnum = ILType.enumeration(ofName: "IntlFormatMatcher", withValues: ["basic", "best fit"]) - fileprivate static let jsIntlFullLongMediumShort = ILType.enumeration(ofName: "IntlFullLongMediumShort", withValues: ["full", "long", "medium", "short"]) - fileprivate static let jsIntlCollatorUsageEnum = ILType.enumeration(ofName: "IntlCollatorUsage", withValues: ["sort", "search"]) - fileprivate static let jsIntlCollationEnum = ILType.enumeration(ofName: "IntlCollation", withValues: ["emoji", "pinyin", "stroke"]) - fileprivate static let jsIntlCollationTypeEnum = ILType.enumeration(ofName: "IntlCollationType", withValues: ["compat", "emoji", "eor", "phonebk", "pinyin", "searchjl", "stroke", "trad", "unihan", "zhuyin"]) - fileprivate static let jsIntlCaseFirstEnum = ILType.enumeration(ofName: "IntlCaseFirst", withValues: ["upper", "lower", "false"]) - fileprivate static let jsIntlCollatorSensitivityEnum = ILType.enumeration(ofName: "IntlCollatorSensitivity", withValues: ["base", "accent", "case", "variant"]) - fileprivate static let jsIntlDisplayNamesTypeEnum = ILType.enumeration(ofName: "IntlDisplayNamesTypeEnum", withValues: ["language", "region", "script", "currency", "calendar", "dateTimeField"]) - fileprivate static let jsIntlDisplayNamesFallbackEnum = ILType.enumeration(ofName: "IntlDisplayNamesFallbackEnum", withValues: ["code", "none"]) - fileprivate static let jsIntlDisplayNamesLanguageDisplayEnum = ILType.enumeration(ofName: "IntlDisplayNamesLanguageDisplayEnum", withValues: ["dialect", "standard"]) - fileprivate static let jsIntlDurationFormatStyleEnum = ILType.enumeration(ofName: "IntlDurationFormatStyleEnum", withValues: ["long", "short", "narrow", "digital"]) - fileprivate static let jsIntlListFormatTypeEnum = ILType.enumeration(ofName: "IntlListFormatTypeEnum", withValues: ["conjunction", "disjunction", "unit"]) - fileprivate static let jsIntlNumberFormatStyleEnum = ILType.enumeration(ofName: "IntlNumberFormatStyleEnum", withValues: ["decimal", "currency", "percent", "unit"]) - fileprivate static let jsIntlCurrencySystemEnum = ILType.enumeration(ofName: "IntlCurrency", withValues: Locale.Currency.isoCurrencies.map { $0.identifier }) - fileprivate static let jsIntlCurrencyDisplayEnum = ILType.enumeration(ofName: "IntlCurrencyDisplayEnum", withValues: ["code", "symbol", "narrowSymbol", "name"]) - fileprivate static let jsIntlCurrencySignEnum = ILType.enumeration(ofName: "IntlCurrencySignEnum", withValues: ["standard", "accounting"]) - fileprivate static let jsIntlRoundingPriorityEnum = ILType.enumeration(ofName: "IntlRoundingPriority", withValues: ["auto", "morePrecision", "lessPrecision"]) - fileprivate static let jsIntlRoundingModeEnum = ILType.enumeration(ofName: "IntlRoundingMode", withValues: ["ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven"]) - fileprivate static let jsIntlTrailingZeroDisplayEnum = ILType.enumeration(ofName: "IntlTrailingZeroDisplay", withValues: ["auto", "stripIfInteger"]) - fileprivate static let jsIntlNumberFormatNotationEnum = ILType.enumeration(ofName: "IntlNumberFormatNotation", withValues: ["standard", "scientific", "engineering", "compact"]) - fileprivate static let jsIntlNumberFormatGroupingEnum = ILType.enumeration(ofName: "IntlNumberFormatGrouping", withValues: ["always", "auto", "min2", "true", "false"]) - fileprivate static let jsIntlSignDisplayEnum = ILType.enumeration(ofName: "IntlSignDisplay", withValues: ["auto", "always", "exceptZero", "negative", "never"]) - fileprivate static let jsIntlPluralRulesTypeEnum = ILType.enumeration(ofName: "IntlPluralRulesTypeEnum", withValues: ["cardinal", "ordinal"]) - fileprivate static let jsIntlSegmenterGranularityEnum = ILType.enumeration(ofName: "IntlSegmenterGranularityEnum", withValues: ["grapheme", "word", "sentence"]) + fileprivate static let jsIntlLocaleMatcherEnum = ILType.enumeration( + ofName: "IntlLocaleMatcher", withValues: ["lookup", "best fit"]) + fileprivate static let jsIntlNumberingSystemEnum = ILType.enumeration( + ofName: "IntlNumberingSystem", + withValues: Locale.NumberingSystem.availableNumberingSystems.map { $0.identifier }) + fileprivate static let jsIntlHourCycleEnum = ILType.enumeration( + ofName: "IntlHourCycle", withValues: ["h11", "h12", "h23", "h24"]) + fileprivate static let jsIntlLongShortNarrowEnum = ILType.enumeration( + ofName: "IntlLongShortNarrow", withValues: ["long", "short", "narrow"]) + fileprivate static let jsIntlLongShortEnum = ILType.enumeration( + ofName: "IntlLongShort", withValues: ["long", "short"]) + fileprivate static let jsIntlAutoAlwaysEnum = ILType.enumeration( + ofName: "IntlAutoAlways", withValues: ["auto", "always"]) + fileprivate static let jsIntlNumeric2DigitEnum = ILType.enumeration( + ofName: "IntlNumeric2Digit", withValues: ["numeric", "2-digit"]) + fileprivate static let jsIntlMonthEnum = ILType.enumeration( + ofName: "IntlMonth", withValues: ["numeric", "2-digit", "long", "short", "narrow"]) + fileprivate static let jsIntlTimeZoneNameEnum = ILType.enumeration( + ofName: "IntlTimeZoneName", + withValues: ["long", "short", "shortOffset", "longOffset", "shortGeneric", "longGeneric"]) + fileprivate static let jsIntlFormatMatcherEnum = ILType.enumeration( + ofName: "IntlFormatMatcher", withValues: ["basic", "best fit"]) + fileprivate static let jsIntlFullLongMediumShort = ILType.enumeration( + ofName: "IntlFullLongMediumShort", withValues: ["full", "long", "medium", "short"]) + fileprivate static let jsIntlCollatorUsageEnum = ILType.enumeration( + ofName: "IntlCollatorUsage", withValues: ["sort", "search"]) + fileprivate static let jsIntlCollationEnum = ILType.enumeration( + ofName: "IntlCollation", withValues: ["emoji", "pinyin", "stroke"]) + fileprivate static let jsIntlCollationTypeEnum = ILType.enumeration( + ofName: "IntlCollationType", + withValues: [ + "compat", "emoji", "eor", "phonebk", "pinyin", "searchjl", "stroke", "trad", "unihan", + "zhuyin", + ]) + fileprivate static let jsIntlCaseFirstEnum = ILType.enumeration( + ofName: "IntlCaseFirst", withValues: ["upper", "lower", "false"]) + fileprivate static let jsIntlCollatorSensitivityEnum = ILType.enumeration( + ofName: "IntlCollatorSensitivity", withValues: ["base", "accent", "case", "variant"]) + fileprivate static let jsIntlDisplayNamesTypeEnum = ILType.enumeration( + ofName: "IntlDisplayNamesTypeEnum", + withValues: ["language", "region", "script", "currency", "calendar", "dateTimeField"]) + fileprivate static let jsIntlDisplayNamesFallbackEnum = ILType.enumeration( + ofName: "IntlDisplayNamesFallbackEnum", withValues: ["code", "none"]) + fileprivate static let jsIntlDisplayNamesLanguageDisplayEnum = ILType.enumeration( + ofName: "IntlDisplayNamesLanguageDisplayEnum", withValues: ["dialect", "standard"]) + fileprivate static let jsIntlDurationFormatStyleEnum = ILType.enumeration( + ofName: "IntlDurationFormatStyleEnum", withValues: ["long", "short", "narrow", "digital"]) + fileprivate static let jsIntlListFormatTypeEnum = ILType.enumeration( + ofName: "IntlListFormatTypeEnum", withValues: ["conjunction", "disjunction", "unit"]) + fileprivate static let jsIntlNumberFormatStyleEnum = ILType.enumeration( + ofName: "IntlNumberFormatStyleEnum", withValues: ["decimal", "currency", "percent", "unit"]) + fileprivate static let jsIntlCurrencySystemEnum = ILType.enumeration( + ofName: "IntlCurrency", withValues: Locale.Currency.isoCurrencies.map { $0.identifier }) + fileprivate static let jsIntlCurrencyDisplayEnum = ILType.enumeration( + ofName: "IntlCurrencyDisplayEnum", withValues: ["code", "symbol", "narrowSymbol", "name"]) + fileprivate static let jsIntlCurrencySignEnum = ILType.enumeration( + ofName: "IntlCurrencySignEnum", withValues: ["standard", "accounting"]) + fileprivate static let jsIntlRoundingPriorityEnum = ILType.enumeration( + ofName: "IntlRoundingPriority", withValues: ["auto", "morePrecision", "lessPrecision"]) + fileprivate static let jsIntlRoundingModeEnum = ILType.enumeration( + ofName: "IntlRoundingMode", + withValues: [ + "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", + "halfEven", + ]) + fileprivate static let jsIntlTrailingZeroDisplayEnum = ILType.enumeration( + ofName: "IntlTrailingZeroDisplay", withValues: ["auto", "stripIfInteger"]) + fileprivate static let jsIntlNumberFormatNotationEnum = ILType.enumeration( + ofName: "IntlNumberFormatNotation", + withValues: ["standard", "scientific", "engineering", "compact"]) + fileprivate static let jsIntlNumberFormatGroupingEnum = ILType.enumeration( + ofName: "IntlNumberFormatGrouping", withValues: ["always", "auto", "min2", "true", "false"]) + fileprivate static let jsIntlSignDisplayEnum = ILType.enumeration( + ofName: "IntlSignDisplay", + withValues: ["auto", "always", "exceptZero", "negative", "never"]) + fileprivate static let jsIntlPluralRulesTypeEnum = ILType.enumeration( + ofName: "IntlPluralRulesTypeEnum", withValues: ["cardinal", "ordinal"]) + fileprivate static let jsIntlSegmenterGranularityEnum = ILType.enumeration( + ofName: "IntlSegmenterGranularityEnum", withValues: ["grapheme", "word", "sentence"]) // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters static let jsIntlDateTimeFormatSettings = OptionsBag( @@ -3986,7 +4884,7 @@ extension OptionsBag { "hour": jsIntlNumeric2DigitEnum, "minute": jsIntlNumeric2DigitEnum, "second": jsIntlNumeric2DigitEnum, - "fractionalSecondDigits": .integer, // Technically only 1-3 + "fractionalSecondDigits": .integer, // Technically only 1-3 "timeZoneName": jsIntlTimeZoneNameEnum, "formatMatcher": jsIntlFormatMatcherEnum, // style options @@ -4154,14 +5052,15 @@ extension OptionsBag { static let jsIntlLocaleMatcherSettings = OptionsBag( name: "IntlLocaleMatcherSettings", properties: [ - "localeMatcher": jsIntlLocaleMatcherEnum, + "localeMatcher": jsIntlLocaleMatcherEnum ] ) } // Iterator extension OptionsBag { - fileprivate static let jsIteratorZipModeEnum = ILType.enumeration(ofName: "IteratorZipMode", withValues: ["strict", "longest", "shortest"]) + fileprivate static let jsIteratorZipModeEnum = ILType.enumeration( + ofName: "IteratorZipMode", withValues: ["strict", "longest", "shortest"]) static let jsIteratorZipSettings = OptionsBag( name: "IteratorZipSettings", @@ -4177,7 +5076,9 @@ extension OptionsBag { fileprivate static let base64Alphabet = ILType.enumeration(ofName: "base64Alphabet", withValues: ["base64", "base64url"]) fileprivate static let base64LastChunkHandling = - ILType.enumeration(ofName: "base64LastChunkHandling", withValues: ["loose", "strict", "stop-before-partial"]) + ILType.enumeration( + ofName: "base64LastChunkHandling", + withValues: ["loose", "strict", "stop-before-partial"]) static let toBase64Settings = OptionsBag( name: "ToBase64Settings", @@ -4190,7 +5091,7 @@ extension OptionsBag { name: "FromBase64Settings", properties: [ "alphabet": base64Alphabet, - "lastChunkHandling": base64LastChunkHandling + "lastChunkHandling": base64LastChunkHandling, ] ) } diff --git a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift index ed17d6d43..4decc2812 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift @@ -36,7 +36,8 @@ public class CovEdgeSet: ProgramAspects { } public override var description: String { - return "new coverage: \(count) newly discovered edge\(count > 1 ? "s" : "") in the CFG of the target" + return + "new coverage: \(count) newly discovered edge\(count > 1 ? "s" : "") in the CFG of the target" } /// Returns an array of all the newly discovered edges of this CovEdgeSet. @@ -74,14 +75,14 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { /// Whether per-edge hit counts should be tracked as well. /// These are expensive to compute, so this need to be enabled explicitly. - private var shouldTrackEdgeCounts : Bool + private var shouldTrackEdgeCounts: Bool /// Keep track of how often an edge has been reset. Frequently set/cleared edges will be ignored - private var resetCounts : [UInt32:UInt64] = [:] + private var resetCounts: [UInt32: UInt64] = [:] /// How often an edge may be reset at most before it is considered non-deterministic. /// In that case, the edge is marked as found, but will not be considered an aspect of any program. - private let maxResetCount : UInt64 = 1000 + private let maxResetCount: UInt64 = 1000 /// The current edge coverage percentage. public var currentScore: Double { @@ -105,20 +106,19 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { guard libcoverage.cov_initialize(&context) == 0 else { fatalError("Could not initialize libcoverage") } -#if os(Windows) - runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(GetCurrentProcessId())_\(id)") -#else - runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(getpid())_\(id)") -#endif + #if os(Windows) + runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(GetCurrentProcessId())_\(id)") + #else + runner.setEnvironmentVariable("SHM_ID", to: "shm_id_\(getpid())_\(id)") + #endif } public func enableEdgeTracking() { - assert(!isInitialized) // This should only be called prior to initialization + assert(!isInitialized) // This should only be called prior to initialization shouldTrackEdgeCounts = true } - public func getEdgeHitCounts() -> [UInt32] { var edgeCounts = libcoverage.edge_counts() let result = libcoverage.cov_get_edge_counts(&context, &edgeCounts) @@ -126,7 +126,8 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { logger.error("Error retrifying smallest hit count edges") return [] } - var edgeArray = Array(UnsafeBufferPointer(start: edgeCounts.edge_hit_count, count: Int(edgeCounts.count))) + var edgeArray = Array( + UnsafeBufferPointer(start: edgeCounts.edge_hit_count, count: Int(edgeCounts.count))) // Clear all edges that have hit their reset limits for (edge, count) in resetCounts { @@ -208,7 +209,9 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { return result == 1 } - public func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + public func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { guard let firstCovEdgeSet = aspects as? CovEdgeSet else { logger.fatal("Coverage Evaluator received non coverage aspects") } @@ -221,8 +224,10 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { guard execution.outcome == .succeeded else { return nil } guard let secondCovEdgeSet = evaluate(execution) as? CovEdgeSet else { return nil } - let firstEdgeSet = Set(UnsafeBufferPointer(start: firstCovEdgeSet.edges, count: Int(firstCovEdgeSet.count))) - let secondEdgeSet = Set(UnsafeBufferPointer(start: secondCovEdgeSet.edges, count: Int(secondCovEdgeSet.count))) + let firstEdgeSet = Set( + UnsafeBufferPointer(start: firstCovEdgeSet.edges, count: Int(firstCovEdgeSet.count))) + let secondEdgeSet = Set( + UnsafeBufferPointer(start: secondCovEdgeSet.edges, count: Int(secondCovEdgeSet.count))) // Reset all edges that were only triggered by the 2nd execution (those only triggered by the 1st execution were already reset earlier). for edge in secondEdgeSet.subtracting(firstEdgeSet) { @@ -252,10 +257,12 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { public func importState(_ state: Data) throws { assert(isInitialized) - let headerSize = 12 // 3 x 4 bytes: num_edges, bitmap_size, found_edges. See exportState() above + let headerSize = 12 // 3 x 4 bytes: num_edges, bitmap_size, found_edges. See exportState() above guard state.count == headerSize + Int(context.bitmap_size) * 2 else { - throw FuzzilliError.evaluatorStateImportError("Cannot import coverage state as it has an unexpected size. Ensure all instances use the same build of the target") + throw FuzzilliError.evaluatorStateImportError( + "Cannot import coverage state as it has an unexpected size. Ensure all instances use the same build of the target" + ) } let numEdges = state.withUnsafeBytes { $0.load(fromByteOffset: 0, as: UInt32.self) } @@ -263,7 +270,9 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { let foundEdges = state.withUnsafeBytes { $0.load(fromByteOffset: 8, as: UInt32.self) } guard bitmapSize == context.bitmap_size && numEdges == context.num_edges else { - throw FuzzilliError.evaluatorStateImportError("Cannot import coverage state due to different bitmap sizes. Ensure all instances use the same build of the target") + throw FuzzilliError.evaluatorStateImportError( + "Cannot import coverage state due to different bitmap sizes. Ensure all instances use the same build of the target" + ) } context.found_edges = foundEdges @@ -281,7 +290,6 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { libcoverage.cov_reset_state(&context) } - // TODO See if we want to count the number of non-deterministic edges and expose them through the fuzzer statistics (if deterministic mode is enabled) private func resetEdge(_ edge: UInt32) { resetCounts[edge] = (resetCounts[edge] ?? 0) + 1 diff --git a/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift index 815f809ef..0d19ccba2 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift @@ -41,7 +41,8 @@ public protocol ProgramEvaluator: Component { /// Executes the program, evaluates the execution, and computes the intersection with the given aspects from a previous execution. /// This will also reset the internal state of the evaluator so that only the aspects common to both program executions are considered already discovered afterwards. - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? /// Resets the internal state func resetState() diff --git a/Sources/Fuzzilli/Execution/Execution.swift b/Sources/Fuzzilli/Execution/Execution.swift index 9297ef296..09a32b7c0 100644 --- a/Sources/Fuzzilli/Execution/Execution.swift +++ b/Sources/Fuzzilli/Execution/Execution.swift @@ -100,19 +100,21 @@ struct DiffExecution: Execution { // TODO(mdanylo): we shouldn't pass dump outputs as a separate parameter, // instead we should rather make them a part of a REPRL protocol between Fuzzilli and V8. - static func diff(optExec: Execution, unoptExec: Execution, - optDumpOut: String, unoptDumpOut: String) -> Execution { + static func diff( + optExec: Execution, unoptExec: Execution, + optDumpOut: String, unoptDumpOut: String + ) -> Execution { assert(optExec.outcome == .succeeded && unoptExec.outcome == .succeeded) func formatDiff(label: String, optData: String, unoptData: String) -> String { return """ - === OPT \(label) === - \(optData) + === OPT \(label) === + \(optData) - === UNOPT \(label) === - \(unoptData) - """ + === UNOPT \(label) === + \(unoptData) + """ } let relateOutcome = DiffOracle.relate(optDumpOut, with: unoptDumpOut) @@ -120,9 +122,12 @@ struct DiffExecution: Execution { return DiffExecution( outcome: relateOutcome ? .succeeded : .differential, execTime: optExec.execTime, - stdout: formatDiff(label: "STDOUT", optData: optExec.stdout, unoptData: unoptExec.stdout), - stderr: formatDiff(label: "STDERR", optData: optExec.stderr, unoptData: unoptExec.stderr), - fuzzout: formatDiff(label: "FUZZOUT", optData: optExec.fuzzout, unoptData: unoptExec.fuzzout) + stdout: formatDiff( + label: "STDOUT", optData: optExec.stdout, unoptData: unoptExec.stdout), + stderr: formatDiff( + label: "STDERR", optData: optExec.stderr, unoptData: unoptExec.stderr), + fuzzout: formatDiff( + label: "FUZZOUT", optData: optExec.fuzzout, unoptData: unoptExec.fuzzout) ) } } diff --git a/Sources/Fuzzilli/Execution/REPRL.swift b/Sources/Fuzzilli/Execution/REPRL.swift index 40555fbd2..44fba010a 100644 --- a/Sources/Fuzzilli/Execution/REPRL.swift +++ b/Sources/Fuzzilli/Execution/REPRL.swift @@ -44,7 +44,10 @@ public class REPRL: ComponentBase, ScriptRunner { /// future executions. This is only used if diagnostics mode is enabled. private var scriptBuffer = String() - public init(executable: String, processArguments: [String], processEnvironment: [String: String], maxExecsBeforeRespawn: Int) { + public init( + executable: String, processArguments: [String], processEnvironment: [String: String], + maxExecsBeforeRespawn: Int + ) { self.processArguments = [executable] + processArguments self.maxExecsBeforeRespawn = maxExecsBeforeRespawn super.init(name: "REPRL") @@ -63,8 +66,12 @@ public class REPRL: ComponentBase, ScriptRunner { let argv = convertToCArray(processArguments) let envp = convertToCArray(env.map({ $0 + "=" + $1 })) - if reprl_initialize_context(reprlContext, argv, envp, /* capture stdout */ 1, /* capture stderr: */ 1) != 0 { - logger.fatal("Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(reprlContext)))") + if reprl_initialize_context( + reprlContext, argv, envp, /* capture stdout */ 1, /* capture stderr: */ 1) != 0 + { + logger.fatal( + "Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(reprlContext)))" + ) } freeCArray(argv, numElems: processArguments.count) @@ -105,28 +112,35 @@ public class REPRL: ComponentBase, ScriptRunner { } } - var execTime: UInt64 = 0 // In microseconds - let timeout = UInt64(timeout) * 1000 // In microseconds + var execTime: UInt64 = 0 // In microseconds + let timeout = UInt64(timeout) * 1000 // In microseconds var status: Int32 = 0 script.withCString { ptr in - status = reprl_execute(reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, freshInstance) + status = reprl_execute( + reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, + freshInstance) // If we fail, we retry after a short timeout and with a fresh instance. If we still fail, we give up trying // to execute this program. If we repeatedly fail to execute any program, we abort. if status < 0 { let errorMsg = String(cString: reprl_get_last_error(reprlContext)) logger.warning("Script execution failed: \(errorMsg). Retrying in 1 second...") if fuzzer.config.enableDiagnostics { - fuzzer.dispatchEvent(fuzzer.events.DiagnosticsEvent, data: (name: "REPRLFail", content: scriptBuffer.data(using: .utf8)!)) + fuzzer.dispatchEvent( + fuzzer.events.DiagnosticsEvent, + data: (name: "REPRLFail", content: scriptBuffer.data(using: .utf8)!)) } Thread.sleep(forTimeInterval: 1) - status = reprl_execute(reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, 1) + status = reprl_execute( + reprlContext, ptr, UInt64(script.utf8.count), UInt64(timeout), &execTime, 1) } } if status < 0 { let errorMsg = String(cString: reprl_get_last_error(reprlContext)) - let stderr = String(cString: reprl_fetch_stderr(reprlContext)).trimmingCharacters(in: .whitespacesAndNewlines) - let stdout = String(cString: reprl_fetch_stdout(reprlContext)).trimmingCharacters(in: .whitespacesAndNewlines) + let stderr = String(cString: reprl_fetch_stderr(reprlContext)).trimmingCharacters( + in: .whitespacesAndNewlines) + let stdout = String(cString: reprl_fetch_stdout(reprlContext)).trimmingCharacters( + in: .whitespacesAndNewlines) let childOutput = """ stderr: \(stderr.isEmpty ? "" : stderr) diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index 782f27e11..aabce9662 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -62,7 +62,7 @@ struct DefUseAnalyzer: Analyzer { if isRunning { code.append(instr) } - assert(code[instr.index].op === instr.op) // Must be operating on the program passed in during construction + assert(code[instr.index].op === instr.op) // Must be operating on the program passed in during construction assert(!analysisDone) for v in instr.allOutputs { assignments[v] = [instr.index] @@ -184,16 +184,20 @@ struct ContextAnalyzer: Analyzer { assert(contextStack.count >= 2) // Currently we only support context "skipping" for switch blocks. This logic may need to be refined if it is ever used for other constructs as well. - assert((contextStack.top.contains(.switchBlock) && contextStack.top.subtracting(.switchBlock) == .empty)) + assert( + (contextStack.top.contains(.switchBlock) + && contextStack.top.subtracting(.switchBlock) == .empty)) newContext.formUnion(contextStack.secondToTop) } // If we are in a loop, we don't want to propagate the switch context and vice versa. Otherwise we couldn't determine which break operation to emit. // TODO Make this generic for similar logic cases as well. E.g. by using a instr.op.contextClosed list. - if (instr.op.contextOpened.contains(.switchBlock) || instr.op.contextOpened.contains(.switchCase)) { + if instr.op.contextOpened.contains(.switchBlock) + || instr.op.contextOpened.contains(.switchCase) + { newContext.remove(.loop) - } else if (instr.op.contextOpened.contains(.loop)) { + } else if instr.op.contextOpened.contains(.loop) { newContext.remove(.switchBlock) newContext.remove(.switchCase) } diff --git a/Sources/Fuzzilli/FuzzIL/Blocks.swift b/Sources/Fuzzilli/FuzzIL/Blocks.swift index 7527e440b..4b6d9a518 100644 --- a/Sources/Fuzzilli/FuzzIL/Blocks.swift +++ b/Sources/Fuzzilli/FuzzIL/Blocks.swift @@ -56,7 +56,6 @@ public struct Block { self.tail = tail } - } /// A block group is a sequence of blocks (and thus instructions) that is started by an opening instruction diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index 1e63b0ff9..b0229396c 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -59,7 +59,9 @@ public struct Code: Collection { return instructions[i] } set { - return instructions[i] = Instruction(newValue.op, inouts: newValue.inouts, index: i, flags: newValue.flags) + instructions[i] = Instruction( + newValue.op, inouts: newValue.inouts, index: i, flags: newValue.flags) + return } } @@ -93,12 +95,12 @@ public struct Code: Collection { } /// Returns the instructions in this code in reversed order. - public func reversed() -> ReversedCollection> { + public func reversed() -> ReversedCollection<[Instruction]> { return instructions.reversed() } /// Enumerates the instructions in this code. - public func enumerated() -> EnumeratedSequence> { + public func enumerated() -> EnumeratedSequence<[Instruction]> { return instructions.enumerated() } @@ -182,7 +184,9 @@ public struct Code: Collection { for v in instr.allOutputs { guard !definedVariables.contains(v) else { return false } if v.number > 0 { - guard definedVariables.contains(Variable(number: v.number - 1)) else { return false } + guard definedVariables.contains(Variable(number: v.number - 1)) else { + return false + } } definedVariables.insert(v) } @@ -219,7 +223,8 @@ public struct Code: Collection { if v.number != 0 { let prev = Variable(number: v.number - 1) guard definedVariables.contains(prev) else { - throw FuzzilliError.codeVerificationError("variable definitions are not contiguous: \(v) is defined before \(prev)") + throw FuzzilliError.codeVerificationError( + "variable definitions are not contiguous: \(v) is defined before \(prev)") } } definedVariables[v] = scope @@ -227,7 +232,8 @@ public struct Code: Collection { for (idx, instr) in instructions.enumerated() { guard idx == instr.index else { - throw FuzzilliError.codeVerificationError("instruction \(idx) has wrong index \(String(describing: instr.index))") + throw FuzzilliError.codeVerificationError( + "instruction \(idx) has wrong index \(String(describing: instr.index))") } // Ensure all input variables are valid and have been defined @@ -236,12 +242,14 @@ public struct Code: Collection { throw FuzzilliError.codeVerificationError("variable \(input) was never defined") } guard activeBlocks.contains(where: { $0.scopeId == definingScope }) else { - throw FuzzilliError.codeVerificationError("variable \(input) is not visible anymore") + throw FuzzilliError.codeVerificationError( + "variable \(input) is not visible anymore") } } guard instr.op.requiredContext.isSubset(of: contextAnalyzer.context) else { - throw FuzzilliError.codeVerificationError("operation \(instr.op.name) inside an invalid context") + throw FuzzilliError.codeVerificationError( + "operation \(instr.op.name) inside an invalid context") } // Ensure that the instruction exists in the right context @@ -254,7 +262,8 @@ public struct Code: Collection { } let block = activeBlocks.pop() guard block.head?.isMatchingStart(for: instr.op) ?? false else { - throw FuzzilliError.codeVerificationError("block end does not match block start") + throw FuzzilliError.codeVerificationError( + "block end does not match block start") } } @@ -485,6 +494,8 @@ public struct Code: Collection { /// Check that the given block object describes a block in this code. private func isValidBlock(_ block: Block) -> Bool { - return block.tail <= endIndex && self[block.head].isBlockStart && self[block.tail].isBlockEnd && self[block.tail].op.isMatchingEnd(for: self[block.head].op) + return block.tail <= endIndex && self[block.head].isBlockStart + && self[block.tail].isBlockEnd + && self[block.tail].op.isMatchingEnd(for: self[block.head].op) } } diff --git a/Sources/Fuzzilli/FuzzIL/Context.swift b/Sources/Fuzzilli/FuzzIL/Context.swift index 550610934..080c3d5e8 100644 --- a/Sources/Fuzzilli/FuzzIL/Context.swift +++ b/Sources/Fuzzilli/FuzzIL/Context.swift @@ -39,41 +39,41 @@ public struct Context: OptionSet, Hashable, CaseIterable { } // Default javascript context. - public static let javascript = Context(rawValue: 1 << 0) + public static let javascript = Context(rawValue: 1 << 0) // Inside a subroutine (function, constructor, method, ...) definition. // This for example means that doing `return` or accessing `arguments` is allowed. - public static let subroutine = Context(rawValue: 1 << 1) + public static let subroutine = Context(rawValue: 1 << 1) // Inside a generator function definition. // This for example means that `yield` and `yield*` are allowed. public static let generatorFunction = Context(rawValue: 1 << 2) // Inside an async function definition. // This for example means that `await` is allowed. - public static let asyncFunction = Context(rawValue: 1 << 3) + public static let asyncFunction = Context(rawValue: 1 << 3) // Inside a method. // This for example means that access to `super` is allowed. - public static let method = Context(rawValue: 1 << 4) + public static let method = Context(rawValue: 1 << 4) // Inside a class method. // This for example means that access to private properties is allowed. - public static let classMethod = Context(rawValue: 1 << 5) + public static let classMethod = Context(rawValue: 1 << 5) // Inside a loop. - public static let loop = Context(rawValue: 1 << 6) + public static let loop = Context(rawValue: 1 << 6) // Inside an object literal. - public static let objectLiteral = Context(rawValue: 1 << 7) + public static let objectLiteral = Context(rawValue: 1 << 7) // Inside a class definition. - public static let classDefinition = Context(rawValue: 1 << 8) + public static let classDefinition = Context(rawValue: 1 << 8) // Inside a switch block. - public static let switchBlock = Context(rawValue: 1 << 9) + public static let switchBlock = Context(rawValue: 1 << 9) // Inside a switch case. - public static let switchCase = Context(rawValue: 1 << 10) + public static let switchCase = Context(rawValue: 1 << 10) // Inside a wasm module - public static let wasm = Context(rawValue: 1 << 11) + public static let wasm = Context(rawValue: 1 << 11) // Inside a function in a wasm module - public static let wasmFunction = Context(rawValue: 1 << 12) + public static let wasmFunction = Context(rawValue: 1 << 12) // Inside a wasm recursive type group definition. - public static let wasmTypeGroup = Context(rawValue: 1 << 13) + public static let wasmTypeGroup = Context(rawValue: 1 << 13) + + public static let empty = Context([]) - public static let empty = Context([]) - public var inWasm: Bool { self.contains(.wasm) || self.contains(.wasmFunction) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 35c78eae3..e40947e3b 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -112,12 +112,12 @@ public struct Instruction { /// The output variables of this instruction in the surrounding scope. public var outputs: ArraySlice { - return inouts_[numInputs ..< numInputs + numOutputs] + return inouts_[numInputs.. { - return inouts_[numInputs + numOutputs ..< numInouts] + return inouts_[numInputs + numOutputs.. Variable { @@ -125,12 +125,12 @@ public struct Instruction { } public func innerOutputs(_ r: PartialRangeFrom) -> ArraySlice { - return inouts_[numInputs + numOutputs + r.lowerBound ..< numInouts] + return inouts_[numInputs + numOutputs + r.lowerBound.. { - return inouts_[numInputs ..< numInouts] + return inouts_[numInputs..(_ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags) where Variables.Element == Variable { + public init( + _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags + ) where Variables.Element == Variable { assert(op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count) self.op = op self.inouts_ = Array(inouts) @@ -319,7 +320,8 @@ extension Instruction: ProtobufConvertible { typealias ProtobufType = Fuzzilli_Protobuf_Instruction func asProtobuf(with opCache: OperationCache?) -> ProtobufType { - func convertEnum(_ s: S, _ allValues: [S]) -> P where P.RawValue == Int { + func convertEnum(_ s: S, _ allValues: [S]) -> P + where P.RawValue == Int { return P(rawValue: allValues.firstIndex(of: s)!)! } @@ -338,7 +340,7 @@ extension Instruction: ProtobufConvertible { $0.valueType = Fuzzilli_Protobuf_WasmValueType.nothing } } - if (underlyingWasmType.Is(.wasmFunctionDef())) { + if underlyingWasmType.Is(.wasmFunctionDef()) { return Fuzzilli_Protobuf_WasmILType.with { $0.valueType = Fuzzilli_Protobuf_WasmValueType.functiondef } @@ -381,112 +383,121 @@ extension Instruction: ProtobufConvertible { default: if underlyingWasmType <= .wasmGenericRef { switch underlyingWasmType.wasmReferenceType!.kind { - case .Index(_): - return Fuzzilli_Protobuf_WasmILType.with { - $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { - $0.kind = Fuzzilli_Protobuf_WasmReferenceTypeKind.index - $0.nullability = underlyingWasmType.wasmReferenceType!.nullability - } + case .Index(_): + return Fuzzilli_Protobuf_WasmILType.with { + $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { + $0.kind = Fuzzilli_Protobuf_WasmReferenceTypeKind.index + $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } - case .Abstract(let heapTypeInfo): - let kind = switch heapTypeInfo.heapType { - case .WasmExn: - Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref - case .WasmI31: - Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref - case .WasmFunc: - Fuzzilli_Protobuf_WasmReferenceTypeKind.funcref - case .WasmExtern: - Fuzzilli_Protobuf_WasmReferenceTypeKind.externref - case .WasmAny: - Fuzzilli_Protobuf_WasmReferenceTypeKind.anyref - case .WasmEq: - Fuzzilli_Protobuf_WasmReferenceTypeKind.eqref - case .WasmStruct: - Fuzzilli_Protobuf_WasmReferenceTypeKind.structref - case .WasmArray: - Fuzzilli_Protobuf_WasmReferenceTypeKind.arrayref - case .WasmNone: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noneref - case .WasmNoExtern: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noexternref - case .WasmNoFunc: - Fuzzilli_Protobuf_WasmReferenceTypeKind.nofuncref - case .WasmNoExn: - Fuzzilli_Protobuf_WasmReferenceTypeKind.noexnref + } + case .Abstract(let heapTypeInfo): + let kind = + switch heapTypeInfo.heapType { + case .WasmExn: + Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref + case .WasmI31: + Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref + case .WasmFunc: + Fuzzilli_Protobuf_WasmReferenceTypeKind.funcref + case .WasmExtern: + Fuzzilli_Protobuf_WasmReferenceTypeKind.externref + case .WasmAny: + Fuzzilli_Protobuf_WasmReferenceTypeKind.anyref + case .WasmEq: + Fuzzilli_Protobuf_WasmReferenceTypeKind.eqref + case .WasmStruct: + Fuzzilli_Protobuf_WasmReferenceTypeKind.structref + case .WasmArray: + Fuzzilli_Protobuf_WasmReferenceTypeKind.arrayref + case .WasmNone: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noneref + case .WasmNoExtern: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noexternref + case .WasmNoFunc: + Fuzzilli_Protobuf_WasmReferenceTypeKind.nofuncref + case .WasmNoExn: + Fuzzilli_Protobuf_WasmReferenceTypeKind.noexnref } - return Fuzzilli_Protobuf_WasmILType.with { - $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { - $0.kind = kind - $0.nullability = underlyingWasmType.wasmReferenceType!.nullability - } + return Fuzzilli_Protobuf_WasmILType.with { + $0.refType = Fuzzilli_Protobuf_WasmReferenceType.with { + $0.kind = kind + $0.nullability = underlyingWasmType.wasmReferenceType!.nullability } + } } } - fatalError("Can not serialize a non-wasm type \(underlyingWasmType) into a Protobuf_WasmILType! for instruction \(self)") + fatalError( + "Can not serialize a non-wasm type \(underlyingWasmType) into a Protobuf_WasmILType! for instruction \(self)" + ) } } - func convertWasmMemoryLoadType(_ loadType: WasmMemoryLoadType) -> Fuzzilli_Protobuf_WasmMemoryLoadType { + func convertWasmMemoryLoadType(_ loadType: WasmMemoryLoadType) + -> Fuzzilli_Protobuf_WasmMemoryLoadType + { switch loadType { - case .I32LoadMem: - return .i32Loadmem - case .I64LoadMem: - return .i64Loadmem - case .F32LoadMem: - return .f32Loadmem - case .F64LoadMem: - return .f64Loadmem - case .I32LoadMem8S: - return .i32Loadmem8S - case .I32LoadMem8U: - return .i32Loadmem8U - case .I32LoadMem16S: - return .i32Loadmem16S - case .I32LoadMem16U: - return .i32Loadmem16U - case .I64LoadMem8S: - return .i64Loadmem8S - case .I64LoadMem8U: - return .i64Loadmem8U - case .I64LoadMem16S: - return .i64Loadmem16S - case .I64LoadMem16U: - return .i64Loadmem16U - case .I64LoadMem32S: - return .i64Loadmem32S - case .I64LoadMem32U: - return .i64Loadmem32U + case .I32LoadMem: + return .i32Loadmem + case .I64LoadMem: + return .i64Loadmem + case .F32LoadMem: + return .f32Loadmem + case .F64LoadMem: + return .f64Loadmem + case .I32LoadMem8S: + return .i32Loadmem8S + case .I32LoadMem8U: + return .i32Loadmem8U + case .I32LoadMem16S: + return .i32Loadmem16S + case .I32LoadMem16U: + return .i32Loadmem16U + case .I64LoadMem8S: + return .i64Loadmem8S + case .I64LoadMem8U: + return .i64Loadmem8U + case .I64LoadMem16S: + return .i64Loadmem16S + case .I64LoadMem16U: + return .i64Loadmem16U + case .I64LoadMem32S: + return .i64Loadmem32S + case .I64LoadMem32U: + return .i64Loadmem32U } } - func convertWasmMemoryStoreType(_ loadType: WasmMemoryStoreType) -> Fuzzilli_Protobuf_WasmMemoryStoreType { + func convertWasmMemoryStoreType(_ loadType: WasmMemoryStoreType) + -> Fuzzilli_Protobuf_WasmMemoryStoreType + { switch loadType { - case .I32StoreMem: - return .i32Storemem - case .I64StoreMem: - return .i64Storemem - case .F32StoreMem: - return .f32Storemem - case .F64StoreMem: - return .f64Storemem - case .I32StoreMem8: - return .i32Storemem8 - case .I32StoreMem16: - return .i32Storemem16 - case .I64StoreMem8: - return .i64Storemem8 - case .I64StoreMem16: - return .i64Storemem16 - case .I64StoreMem32: - return .i64Storemem32 - case .S128StoreMem: - return .s128Storemem + case .I32StoreMem: + return .i32Storemem + case .I64StoreMem: + return .i64Storemem + case .F32StoreMem: + return .f32Storemem + case .F64StoreMem: + return .f64Storemem + case .I32StoreMem8: + return .i32Storemem8 + case .I32StoreMem16: + return .i32Storemem16 + case .I64StoreMem8: + return .i64Storemem8 + case .I64StoreMem16: + return .i64Storemem16 + case .I64StoreMem32: + return .i64Storemem32 + case .S128StoreMem: + return .s128Storemem } } - func convertWasmGlobal(wasmGlobal: WasmGlobal) -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal { + func convertWasmGlobal(wasmGlobal: WasmGlobal) + -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal + { switch wasmGlobal { case .wasmi32(let val): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.valuei32(val) @@ -499,17 +510,23 @@ extension Instruction: ProtobufConvertible { case .refFunc(let val): return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.funcref(Int64(val)) case .externref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.externref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.externref) case .exnref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.exnref) case .i31ref: - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref(Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.nullref( + Fuzzilli_Protobuf_WasmReferenceTypeKind.i31Ref) case .imported(let ilType): - return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.imported(ILTypeToWasmTypeEnum(ilType)) + return Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal.imported( + ILTypeToWasmTypeEnum(ilType)) } } - func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) -> Fuzzilli_Protobuf_WasmCatchKind { + func convertWasmCatch(catchKind: WasmBeginTryTable.CatchKind) + -> Fuzzilli_Protobuf_WasmCatchKind + { switch catchKind { case .NoRef: return .noRef @@ -550,7 +567,7 @@ extension Instruction: ProtobufConvertible { $0.loadFloat = Fuzzilli_Protobuf_LoadFloat.with { $0.value = op.value } case .loadString(let op): $0.loadString = Fuzzilli_Protobuf_LoadString.with { - $0.value = op.value; + $0.value = op.value if let customName = op.customName { $0.customName = customName } @@ -570,15 +587,23 @@ extension Instruction: ProtobufConvertible { case .loadAsyncDisposableVariable: $0.loadAsyncDisposableVariable = Fuzzilli_Protobuf_LoadAsyncDisposableVariable() case .loadRegExp(let op): - $0.loadRegExp = Fuzzilli_Protobuf_LoadRegExp.with { $0.pattern = op.pattern; $0.flags = op.flags.rawValue } + $0.loadRegExp = Fuzzilli_Protobuf_LoadRegExp.with { + $0.pattern = op.pattern + $0.flags = op.flags.rawValue + } case .beginObjectLiteral: $0.beginObjectLiteral = Fuzzilli_Protobuf_BeginObjectLiteral() case .objectLiteralAddProperty(let op): - $0.objectLiteralAddProperty = Fuzzilli_Protobuf_ObjectLiteralAddProperty.with { $0.propertyName = op.propertyName } + $0.objectLiteralAddProperty = Fuzzilli_Protobuf_ObjectLiteralAddProperty.with { + $0.propertyName = op.propertyName + } case .objectLiteralAddElement(let op): - $0.objectLiteralAddElement = Fuzzilli_Protobuf_ObjectLiteralAddElement.with { $0.index = op.index } + $0.objectLiteralAddElement = Fuzzilli_Protobuf_ObjectLiteralAddElement.with { + $0.index = op.index + } case .objectLiteralAddComputedProperty: - $0.objectLiteralAddComputedProperty = Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty() + $0.objectLiteralAddComputedProperty = + Fuzzilli_Protobuf_ObjectLiteralAddComputedProperty() case .objectLiteralCopyProperties: $0.objectLiteralCopyProperties = Fuzzilli_Protobuf_ObjectLiteralCopyProperties() case .objectLiteralSetPrototype: @@ -591,25 +616,37 @@ extension Instruction: ProtobufConvertible { case .endObjectLiteralMethod: $0.endObjectLiteralMethod = Fuzzilli_Protobuf_EndObjectLiteralMethod() case .beginObjectLiteralComputedMethod(let op): - $0.beginObjectLiteralComputedMethod = Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod.with { $0.parameters = convertParameters(op.parameters) } + $0.beginObjectLiteralComputedMethod = + Fuzzilli_Protobuf_BeginObjectLiteralComputedMethod.with { + $0.parameters = convertParameters(op.parameters) + } case .endObjectLiteralComputedMethod: - $0.endObjectLiteralComputedMethod = Fuzzilli_Protobuf_EndObjectLiteralComputedMethod() + $0.endObjectLiteralComputedMethod = + Fuzzilli_Protobuf_EndObjectLiteralComputedMethod() case .beginObjectLiteralGetter(let op): - $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { $0.propertyName = op.propertyName } + $0.beginObjectLiteralGetter = Fuzzilli_Protobuf_BeginObjectLiteralGetter.with { + $0.propertyName = op.propertyName + } case .endObjectLiteralGetter: $0.endObjectLiteralGetter = Fuzzilli_Protobuf_EndObjectLiteralGetter() case .beginObjectLiteralComputedGetter: - $0.beginObjectLiteralComputedGetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() + $0.beginObjectLiteralComputedGetter = + Fuzzilli_Protobuf_BeginObjectLiteralComputedGetter() case .endObjectLiteralComputedGetter: - $0.endObjectLiteralComputedGetter = Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() + $0.endObjectLiteralComputedGetter = + Fuzzilli_Protobuf_EndObjectLiteralComputedGetter() case .beginObjectLiteralSetter(let op): - $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { $0.propertyName = op.propertyName } + $0.beginObjectLiteralSetter = Fuzzilli_Protobuf_BeginObjectLiteralSetter.with { + $0.propertyName = op.propertyName + } case .endObjectLiteralSetter: $0.endObjectLiteralSetter = Fuzzilli_Protobuf_EndObjectLiteralSetter() case .beginObjectLiteralComputedSetter: - $0.beginObjectLiteralComputedSetter = Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() + $0.beginObjectLiteralComputedSetter = + Fuzzilli_Protobuf_BeginObjectLiteralComputedSetter() case .endObjectLiteralComputedSetter: - $0.endObjectLiteralComputedSetter = Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() + $0.endObjectLiteralComputedSetter = + Fuzzilli_Protobuf_EndObjectLiteralComputedSetter() case .endObjectLiteral: $0.endObjectLiteral = Fuzzilli_Protobuf_EndObjectLiteral() case .beginClassDefinition(let op): @@ -618,7 +655,9 @@ extension Instruction: ProtobufConvertible { $0.isExpression = op.isExpression } case .beginClassConstructor(let op): - $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { $0.parameters = convertParameters(op.parameters) } + $0.beginClassConstructor = Fuzzilli_Protobuf_BeginClassConstructor.with { + $0.parameters = convertParameters(op.parameters) + } case .endClassConstructor: $0.endClassConstructor = Fuzzilli_Protobuf_EndClassConstructor() case .classAddProperty(let op): @@ -669,7 +708,9 @@ extension Instruction: ProtobufConvertible { case .endClassGetter: $0.endClassGetter = Fuzzilli_Protobuf_EndClassGetter() case .beginClassComputedGetter(let op): - $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { $0.isStatic = op.isStatic } + $0.beginClassComputedGetter = Fuzzilli_Protobuf_BeginClassComputedGetter.with { + $0.isStatic = op.isStatic + } case .endClassComputedGetter: $0.endClassComputedGetter = Fuzzilli_Protobuf_EndClassComputedGetter() case .beginClassSetter(let op): @@ -680,7 +721,9 @@ extension Instruction: ProtobufConvertible { case .endClassSetter: $0.endClassSetter = Fuzzilli_Protobuf_EndClassSetter() case .beginClassComputedSetter(let op): - $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { $0.isStatic = op.isStatic } + $0.beginClassComputedSetter = Fuzzilli_Protobuf_BeginClassComputedSetter.with { + $0.isStatic = op.isStatic + } case .endClassComputedSetter: $0.endClassComputedSetter = Fuzzilli_Protobuf_EndClassComputedSetter() case .beginClassStaticInitializer: @@ -700,11 +743,17 @@ extension Instruction: ProtobufConvertible { case .createIntArray(let op): $0.createIntArray = Fuzzilli_Protobuf_CreateIntArray.with { $0.values = op.values } case .createFloatArray(let op): - $0.createFloatArray = Fuzzilli_Protobuf_CreateFloatArray.with { $0.values = op.values } + $0.createFloatArray = Fuzzilli_Protobuf_CreateFloatArray.with { + $0.values = op.values + } case .createArrayWithSpread(let op): - $0.createArrayWithSpread = Fuzzilli_Protobuf_CreateArrayWithSpread.with { $0.spreads = op.spreads } + $0.createArrayWithSpread = Fuzzilli_Protobuf_CreateArrayWithSpread.with { + $0.spreads = op.spreads + } case .createTemplateString(let op): - $0.createTemplateString = Fuzzilli_Protobuf_CreateTemplateString.with { $0.parts = op.parts } + $0.createTemplateString = Fuzzilli_Protobuf_CreateTemplateString.with { + $0.parts = op.parts + } case .getProperty(let op): $0.getProperty = Fuzzilli_Protobuf_GetProperty.with { $0.propertyName = op.propertyName @@ -759,13 +808,19 @@ extension Instruction: ProtobufConvertible { $0.type = convertEnum(op.type, PropertyType.allCases) } case .getComputedProperty(let op): - $0.getComputedProperty = Fuzzilli_Protobuf_GetComputedProperty.with { $0.isGuarded = op.isGuarded } + $0.getComputedProperty = Fuzzilli_Protobuf_GetComputedProperty.with { + $0.isGuarded = op.isGuarded + } case .setComputedProperty: $0.setComputedProperty = Fuzzilli_Protobuf_SetComputedProperty() case .updateComputedProperty(let op): - $0.updateComputedProperty = Fuzzilli_Protobuf_UpdateComputedProperty.with{ $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.updateComputedProperty = Fuzzilli_Protobuf_UpdateComputedProperty.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .deleteComputedProperty(let op): - $0.deleteComputedProperty = Fuzzilli_Protobuf_DeleteComputedProperty.with { $0.isGuarded = op.isGuarded } + $0.deleteComputedProperty = Fuzzilli_Protobuf_DeleteComputedProperty.with { + $0.isGuarded = op.isGuarded + } case .configureComputedProperty(let op): $0.configureComputedProperty = Fuzzilli_Protobuf_ConfigureComputedProperty.with { $0.isWritable = op.flags.contains(.writable) @@ -812,7 +867,7 @@ extension Instruction: ProtobufConvertible { $0.name = name } } - case.endAsyncFunction: + case .endAsyncFunction: $0.endAsyncFunction = Fuzzilli_Protobuf_EndAsyncFunction() case .beginAsyncArrowFunction(let op): $0.beginAsyncArrowFunction = Fuzzilli_Protobuf_BeginAsyncArrowFunction.with { @@ -821,7 +876,8 @@ extension Instruction: ProtobufConvertible { case .endAsyncArrowFunction: $0.endAsyncArrowFunction = Fuzzilli_Protobuf_EndAsyncArrowFunction() case .beginAsyncGeneratorFunction(let op): - $0.beginAsyncGeneratorFunction = Fuzzilli_Protobuf_BeginAsyncGeneratorFunction.with { + $0.beginAsyncGeneratorFunction = Fuzzilli_Protobuf_BeginAsyncGeneratorFunction.with + { $0.parameters = convertParameters(op.parameters) if let name = op.functionName { $0.name = name @@ -846,7 +902,9 @@ extension Instruction: ProtobufConvertible { case .await: $0.await = Fuzzilli_Protobuf_Await() case .callFunction(let op): - $0.callFunction = Fuzzilli_Protobuf_CallFunction.with { $0.isGuarded = op.isGuarded } + $0.callFunction = Fuzzilli_Protobuf_CallFunction.with { + $0.isGuarded = op.isGuarded + } case .callFunctionWithSpread(let op): $0.callFunctionWithSpread = Fuzzilli_Protobuf_CallFunctionWithSpread.with { $0.spreads = op.spreads @@ -871,22 +929,31 @@ extension Instruction: ProtobufConvertible { $0.isGuarded = op.isGuarded } case .callComputedMethod(let op): - $0.callComputedMethod = Fuzzilli_Protobuf_CallComputedMethod.with { $0.isGuarded = op.isGuarded } - case .callComputedMethodWithSpread(let op): - $0.callComputedMethodWithSpread = Fuzzilli_Protobuf_CallComputedMethodWithSpread.with { - $0.spreads = op.spreads + $0.callComputedMethod = Fuzzilli_Protobuf_CallComputedMethod.with { $0.isGuarded = op.isGuarded } + case .callComputedMethodWithSpread(let op): + $0.callComputedMethodWithSpread = + Fuzzilli_Protobuf_CallComputedMethodWithSpread.with { + $0.spreads = op.spreads + $0.isGuarded = op.isGuarded + } case .unaryOperation(let op): - $0.unaryOperation = Fuzzilli_Protobuf_UnaryOperation.with { $0.op = convertEnum(op.op, UnaryOperator.allCases) } + $0.unaryOperation = Fuzzilli_Protobuf_UnaryOperation.with { + $0.op = convertEnum(op.op, UnaryOperator.allCases) + } case .binaryOperation(let op): - $0.binaryOperation = Fuzzilli_Protobuf_BinaryOperation.with { $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.binaryOperation = Fuzzilli_Protobuf_BinaryOperation.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .ternaryOperation: $0.ternaryOperation = Fuzzilli_Protobuf_TernaryOperation() case .reassign: $0.reassign = Fuzzilli_Protobuf_Reassign() case .update(let op): - $0.update = Fuzzilli_Protobuf_Update.with { $0.op = convertEnum(op.op, BinaryOperator.allCases) } + $0.update = Fuzzilli_Protobuf_Update.with { + $0.op = convertEnum(op.op, BinaryOperator.allCases) + } case .dup: $0.dup = Fuzzilli_Protobuf_Dup() case .destructArray(let op): @@ -910,20 +977,25 @@ extension Instruction: ProtobufConvertible { $0.hasRestElement_p = op.hasRestElement } case .compare(let op): - $0.compare = Fuzzilli_Protobuf_Compare.with { $0.op = convertEnum(op.op, Comparator.allCases) } + $0.compare = Fuzzilli_Protobuf_Compare.with { + $0.op = convertEnum(op.op, Comparator.allCases) + } case .createNamedVariable(let op): $0.createNamedVariable = Fuzzilli_Protobuf_CreateNamedVariable.with { $0.variableName = op.variableName - $0.declarationMode = convertEnum(op.declarationMode, NamedVariableDeclarationMode.allCases) + $0.declarationMode = convertEnum( + op.declarationMode, NamedVariableDeclarationMode.allCases) } case .createNamedDisposableVariable(let op): - $0.createNamedDisposableVariable = Fuzzilli_Protobuf_CreateNamedDisposableVariable.with { - $0.variableName = op.variableName - } + $0.createNamedDisposableVariable = + Fuzzilli_Protobuf_CreateNamedDisposableVariable.with { + $0.variableName = op.variableName + } case .createNamedAsyncDisposableVariable(let op): - $0.createNamedAsyncDisposableVariable = Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable.with { - $0.variableName = op.variableName - } + $0.createNamedAsyncDisposableVariable = + Fuzzilli_Protobuf_CreateNamedAsyncDisposableVariable.with { + $0.variableName = op.variableName + } case .eval(let op): $0.eval = Fuzzilli_Protobuf_Eval.with { $0.code = op.code @@ -932,22 +1004,34 @@ extension Instruction: ProtobufConvertible { case .callSuperConstructor: $0.callSuperConstructor = Fuzzilli_Protobuf_CallSuperConstructor() case .callSuperMethod(let op): - $0.callSuperMethod = Fuzzilli_Protobuf_CallSuperMethod.with { $0.methodName = op.methodName } + $0.callSuperMethod = Fuzzilli_Protobuf_CallSuperMethod.with { + $0.methodName = op.methodName + } case .getPrivateProperty(let op): - $0.getPrivateProperty = Fuzzilli_Protobuf_GetPrivateProperty.with { $0.propertyName = op.propertyName } + $0.getPrivateProperty = Fuzzilli_Protobuf_GetPrivateProperty.with { + $0.propertyName = op.propertyName + } case .setPrivateProperty(let op): - $0.setPrivateProperty = Fuzzilli_Protobuf_SetPrivateProperty.with { $0.propertyName = op.propertyName } + $0.setPrivateProperty = Fuzzilli_Protobuf_SetPrivateProperty.with { + $0.propertyName = op.propertyName + } case .updatePrivateProperty(let op): $0.updatePrivateProperty = Fuzzilli_Protobuf_UpdatePrivateProperty.with { $0.propertyName = op.propertyName $0.op = convertEnum(op.op, BinaryOperator.allCases) } case .callPrivateMethod(let op): - $0.callPrivateMethod = Fuzzilli_Protobuf_CallPrivateMethod.with { $0.methodName = op.methodName } + $0.callPrivateMethod = Fuzzilli_Protobuf_CallPrivateMethod.with { + $0.methodName = op.methodName + } case .getSuperProperty(let op): - $0.getSuperProperty = Fuzzilli_Protobuf_GetSuperProperty.with { $0.propertyName = op.propertyName } + $0.getSuperProperty = Fuzzilli_Protobuf_GetSuperProperty.with { + $0.propertyName = op.propertyName + } case .setSuperProperty(let op): - $0.setSuperProperty = Fuzzilli_Protobuf_SetSuperProperty.with { $0.propertyName = op.propertyName } + $0.setSuperProperty = Fuzzilli_Protobuf_SetSuperProperty.with { + $0.propertyName = op.propertyName + } case .getComputedSuperProperty(_): $0.getComputedSuperProperty = Fuzzilli_Protobuf_GetComputedSuperProperty() case .setComputedSuperProperty(_): @@ -992,7 +1076,9 @@ extension Instruction: ProtobufConvertible { case .switchBreak: $0.switchBreak = Fuzzilli_Protobuf_SwitchBreak() case .endSwitchCase(let op): - $0.endSwitchCase = Fuzzilli_Protobuf_EndSwitchCase.with { $0.fallsThrough = op.fallsThrough } + $0.endSwitchCase = Fuzzilli_Protobuf_EndSwitchCase.with { + $0.fallsThrough = op.fallsThrough + } case .endSwitch: $0.endSwitch = Fuzzilli_Protobuf_EndSwitch() case .beginWhileLoopHeader: @@ -1121,13 +1207,21 @@ extension Instruction: ProtobufConvertible { $0.outputCount = Int32(op.outputCount) } case .wasmi32CompareOp(let op): - $0.wasmi32CompareOp = Fuzzilli_Protobuf_Wasmi32CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmi32CompareOp = Fuzzilli_Protobuf_Wasmi32CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmi64CompareOp(let op): - $0.wasmi64CompareOp = Fuzzilli_Protobuf_Wasmi64CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmi64CompareOp = Fuzzilli_Protobuf_Wasmi64CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmf32CompareOp(let op): - $0.wasmf32CompareOp = Fuzzilli_Protobuf_Wasmf32CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmf32CompareOp = Fuzzilli_Protobuf_Wasmf32CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmf64CompareOp(let op): - $0.wasmf64CompareOp = Fuzzilli_Protobuf_Wasmf64CompareOp.with { $0.compareOperator = Int32(op.compareOpKind.rawValue) } + $0.wasmf64CompareOp = Fuzzilli_Protobuf_Wasmf64CompareOp.with { + $0.compareOperator = Int32(op.compareOpKind.rawValue) + } case .wasmi64BinOp(let op): $0.wasmi64BinOp = Fuzzilli_Protobuf_Wasmi64BinOp.with { $0.op = convertEnum(op.binOpKind, WasmIntegerBinaryOpKind.allCases) @@ -1170,25 +1264,43 @@ extension Instruction: ProtobufConvertible { case .wasmWrapi64Toi32(_): $0.wasmWrapi64Toi32 = Fuzzilli_Protobuf_WasmWrapi64Toi32() case .wasmTruncatef32Toi32(let op): - $0.wasmTruncatef32Toi32 = Fuzzilli_Protobuf_WasmTruncatef32Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef32Toi32 = Fuzzilli_Protobuf_WasmTruncatef32Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef64Toi32(let op): - $0.wasmTruncatef64Toi32 = Fuzzilli_Protobuf_WasmTruncatef64Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef64Toi32 = Fuzzilli_Protobuf_WasmTruncatef64Toi32.with { + $0.isSigned = op.isSigned + } case .wasmExtendi32Toi64(let op): - $0.wasmExtendi32Toi64 = Fuzzilli_Protobuf_WasmExtendi32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmExtendi32Toi64 = Fuzzilli_Protobuf_WasmExtendi32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef32Toi64(let op): - $0.wasmTruncatef32Toi64 = Fuzzilli_Protobuf_WasmTruncatef32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef32Toi64 = Fuzzilli_Protobuf_WasmTruncatef32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncatef64Toi64(let op): - $0.wasmTruncatef64Toi64 = Fuzzilli_Protobuf_WasmTruncatef64Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncatef64Toi64 = Fuzzilli_Protobuf_WasmTruncatef64Toi64.with { + $0.isSigned = op.isSigned + } case .wasmConverti32Tof32(let op): - $0.wasmConverti32Tof32 = Fuzzilli_Protobuf_WasmConverti32Tof32.with { $0.isSigned = op.isSigned } + $0.wasmConverti32Tof32 = Fuzzilli_Protobuf_WasmConverti32Tof32.with { + $0.isSigned = op.isSigned + } case .wasmConverti64Tof32(let op): - $0.wasmConverti64Tof32 = Fuzzilli_Protobuf_WasmConverti64Tof32.with { $0.isSigned = op.isSigned } + $0.wasmConverti64Tof32 = Fuzzilli_Protobuf_WasmConverti64Tof32.with { + $0.isSigned = op.isSigned + } case .wasmDemotef64Tof32(_): $0.wasmDemotef64Tof32 = Fuzzilli_Protobuf_WasmDemotef64Tof32() case .wasmConverti32Tof64(let op): - $0.wasmConverti32Tof64 = Fuzzilli_Protobuf_WasmConverti32Tof64.with { $0.isSigned = op.isSigned } + $0.wasmConverti32Tof64 = Fuzzilli_Protobuf_WasmConverti32Tof64.with { + $0.isSigned = op.isSigned + } case .wasmConverti64Tof64(let op): - $0.wasmConverti64Tof64 = Fuzzilli_Protobuf_WasmConverti64Tof64.with { $0.isSigned = op.isSigned } + $0.wasmConverti64Tof64 = Fuzzilli_Protobuf_WasmConverti64Tof64.with { + $0.isSigned = op.isSigned + } case .wasmPromotef32Tof64(_): $0.wasmPromotef32Tof64 = Fuzzilli_Protobuf_WasmPromotef32Tof64() case .wasmReinterpretf32Asi32(_): @@ -1210,15 +1322,23 @@ extension Instruction: ProtobufConvertible { case .wasmSignExtend32Intoi64(_): $0.wasmSignExtend32Intoi64 = Fuzzilli_Protobuf_WasmSignExtend32Intoi64() case .wasmTruncateSatf32Toi32(let op): - $0.wasmTruncateSatf32Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf32Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf64Toi32(let op): - $0.wasmTruncateSatf64Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi32.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf64Toi32 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi32.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf32Toi64(let op): - $0.wasmTruncateSatf32Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf32Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf32Toi64.with { + $0.isSigned = op.isSigned + } case .wasmTruncateSatf64Toi64(let op): - $0.wasmTruncateSatf64Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi64.with { $0.isSigned = op.isSigned } + $0.wasmTruncateSatf64Toi64 = Fuzzilli_Protobuf_WasmTruncateSatf64Toi64.with { + $0.isSigned = op.isSigned + } - case .wasmReassign(_): + case .wasmReassign(_): $0.wasmReassign = Fuzzilli_Protobuf_WasmReassign() case .wasmDefineGlobal(let op): $0.wasmDefineGlobal = Fuzzilli_Protobuf_WasmDefineGlobal.with { @@ -1299,12 +1419,12 @@ extension Instruction: ProtobufConvertible { } case .wasmMemoryLoad(let op): $0.wasmMemoryLoad = Fuzzilli_Protobuf_WasmMemoryLoad.with { - $0.loadType = convertWasmMemoryLoadType(op.loadType); + $0.loadType = convertWasmMemoryLoadType(op.loadType) $0.staticOffset = op.staticOffset } case .wasmMemoryStore(let op): $0.wasmMemoryStore = Fuzzilli_Protobuf_WasmMemoryStore.with { - $0.storeType = convertWasmMemoryStoreType(op.storeType); + $0.storeType = convertWasmMemoryStoreType(op.storeType) $0.staticOffset = op.staticOffset } case .wasmAtomicLoad(let op): @@ -1441,7 +1561,9 @@ extension Instruction: ProtobufConvertible { case .wasmSelect(_): $0.wasmSelect = Fuzzilli_Protobuf_WasmSelect() case .constSimd128(let op): - $0.constSimd128 = Fuzzilli_Protobuf_ConstSimd128.with { $0.value = op.value.map{ UInt32($0) } } + $0.constSimd128 = Fuzzilli_Protobuf_ConstSimd128.with { + $0.value = op.value.map { UInt32($0) } + } case .wasmSimd128IntegerUnOp(let op): $0.wasmSimd128IntegerUnOp = Fuzzilli_Protobuf_WasmSimd128IntegerUnOp.with { $0.shape = UInt32(op.shape.rawValue) @@ -1453,7 +1575,8 @@ extension Instruction: ProtobufConvertible { $0.binaryOperator = Int32(op.binOpKind.rawValue) } case .wasmSimd128IntegerTernaryOp(let op): - $0.wasmSimd128IntegerTernaryOp = Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp.with { + $0.wasmSimd128IntegerTernaryOp = Fuzzilli_Protobuf_WasmSimd128IntegerTernaryOp.with + { $0.shape = UInt32(op.shape.rawValue) $0.opcode = Int32(op.ternaryOpKind.rawValue) } @@ -1513,15 +1636,17 @@ extension Instruction: ProtobufConvertible { case .wasmEndTypeGroup(_): $0.wasmEndTypeGroup = Fuzzilli_Protobuf_WasmEndTypeGroup() case .wasmDefineAdHocSignatureType(let op): - $0.wasmDefineAdHocSignatureType = Fuzzilli_Protobuf_WasmDefineAdHocSignatureType.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) - } + $0.wasmDefineAdHocSignatureType = + Fuzzilli_Protobuf_WasmDefineAdHocSignatureType.with { + $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) + $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + } case .wasmDefineAdHocModuleSignatureType(let op): - $0.wasmDefineAdHocModuleSignatureType = Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType.with { - $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) - $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) - } + $0.wasmDefineAdHocModuleSignatureType = + Fuzzilli_Protobuf_WasmDefineAdHocModuleSignatureType.with { + $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) + $0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum) + } case .wasmDefineSignatureType(let op): $0.wasmDefineSignatureType = Fuzzilli_Protobuf_WasmDefineSignatureType.with { $0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum) @@ -1542,7 +1667,8 @@ extension Instruction: ProtobufConvertible { } } case .wasmDefineForwardOrSelfReference(_): - $0.wasmDefineForwardOrSelfReference = Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference() + $0.wasmDefineForwardOrSelfReference = + Fuzzilli_Protobuf_WasmDefineForwardOrSelfReference() case .wasmResolveForwardReference(_): $0.wasmResolveForwardReference = Fuzzilli_Protobuf_WasmResolveForwardReference() case .wasmArrayNewFixed(_): @@ -1618,9 +1744,11 @@ extension Instruction: ProtobufConvertible { let inouts = proto.inouts.map({ Variable(number: Int($0)) }) // Helper function to convert between the Swift and Protobuf enums. - func convertEnum(_ p: P, _ allValues: [S]) throws -> S where P.RawValue == Int { + func convertEnum(_ p: P, _ allValues: [S]) throws -> S + where P.RawValue == Int { guard allValues.indices.contains(p.rawValue) else { - throw FuzzilliError.instructionDecodingError("invalid enum value \(p.rawValue) for type \(S.self)") + throw FuzzilliError.instructionDecodingError( + "invalid enum value \(p.rawValue) for type \(S.self)") } return allValues[p.rawValue] } @@ -1659,101 +1787,106 @@ extension Instruction: ProtobufConvertible { if wasmType.refType.kind == .index { return .wasmRef(.Index(), nullability: wasmType.refType.nullability) } - let heapType: WasmAbstractHeapType = switch wasmType.refType.kind { - case .externref: - .WasmExtern - case .funcref: - .WasmFunc - case .exnref: - .WasmExn - case .i31Ref: - .WasmI31 - case .anyref: - .WasmAny - case .eqref: - .WasmEq - case .structref: - .WasmStruct - case .arrayref: - .WasmArray - case .noneref: - .WasmNone - case .noexternref: - .WasmNoExtern - case .nofuncref: - .WasmNoFunc - case .noexnref: - .WasmNoExn - case .index: - fatalError("Unexpected index type.") - case .UNRECOGNIZED(let value): - fatalError("Unrecognized wasm reference type \(value)") - } + let heapType: WasmAbstractHeapType = + switch wasmType.refType.kind { + case .externref: + .WasmExtern + case .funcref: + .WasmFunc + case .exnref: + .WasmExn + case .i31Ref: + .WasmI31 + case .anyref: + .WasmAny + case .eqref: + .WasmEq + case .structref: + .WasmStruct + case .arrayref: + .WasmArray + case .noneref: + .WasmNone + case .noexternref: + .WasmNoExtern + case .nofuncref: + .WasmNoFunc + case .noexnref: + .WasmNoExn + case .index: + fatalError("Unexpected index type.") + case .UNRECOGNIZED(let value): + fatalError("Unrecognized wasm reference type \(value)") + } return .wasmRef(heapType, nullability: wasmType.refType.nullability) case .none: fatalError("Absent wasm type") } } - func convertProtoWasmMemoryLoadType(_ loadType: Fuzzilli_Protobuf_WasmMemoryLoadType) -> WasmMemoryLoadType { + func convertProtoWasmMemoryLoadType(_ loadType: Fuzzilli_Protobuf_WasmMemoryLoadType) + -> WasmMemoryLoadType + { switch loadType { - case .i32Loadmem: - return .I32LoadMem - case .i64Loadmem: - return .I64LoadMem - case .f32Loadmem: - return .F32LoadMem - case .f64Loadmem: - return .F64LoadMem - case .i32Loadmem8S: - return .I32LoadMem8S - case .i32Loadmem8U: - return .I32LoadMem8U - case .i32Loadmem16S: - return .I32LoadMem16S - case .i32Loadmem16U: - return .I32LoadMem16U - case .i64Loadmem8S: - return .I64LoadMem8S - case .i64Loadmem8U: - return .I64LoadMem8U - case .i64Loadmem16S: - return .I64LoadMem16S - case .i64Loadmem16U: - return .I64LoadMem16U - case .i64Loadmem32S: - return .I64LoadMem32S - case .i64Loadmem32U: - return .I64LoadMem32U - default: - fatalError("Wrong WasmMemoryLoadType") + case .i32Loadmem: + return .I32LoadMem + case .i64Loadmem: + return .I64LoadMem + case .f32Loadmem: + return .F32LoadMem + case .f64Loadmem: + return .F64LoadMem + case .i32Loadmem8S: + return .I32LoadMem8S + case .i32Loadmem8U: + return .I32LoadMem8U + case .i32Loadmem16S: + return .I32LoadMem16S + case .i32Loadmem16U: + return .I32LoadMem16U + case .i64Loadmem8S: + return .I64LoadMem8S + case .i64Loadmem8U: + return .I64LoadMem8U + case .i64Loadmem16S: + return .I64LoadMem16S + case .i64Loadmem16U: + return .I64LoadMem16U + case .i64Loadmem32S: + return .I64LoadMem32S + case .i64Loadmem32U: + return .I64LoadMem32U + default: + fatalError("Wrong WasmMemoryLoadType") } } - func convertProtoWasmMemoryStoreType(_ loadType: Fuzzilli_Protobuf_WasmMemoryStoreType) -> WasmMemoryStoreType { + func convertProtoWasmMemoryStoreType(_ loadType: Fuzzilli_Protobuf_WasmMemoryStoreType) + -> WasmMemoryStoreType + { switch loadType { - case .i32Storemem: - return .I32StoreMem - case .i64Storemem: - return .I64StoreMem - case .f32Storemem: - return .F32StoreMem - case .f64Storemem: - return .F64StoreMem - case .i32Storemem8: - return .I32StoreMem8 - case .i32Storemem16: - return .I32StoreMem16 - case .i64Storemem8: - return .I64StoreMem8 - case .i64Storemem16: - return .I64StoreMem16 - case .i64Storemem32: - return .I64StoreMem32 - case .s128Storemem: - return .S128StoreMem - default: - fatalError("Wrong WasmMemoryStoreType") + case .i32Storemem: + return .I32StoreMem + case .i64Storemem: + return .I64StoreMem + case .f32Storemem: + return .F32StoreMem + case .f64Storemem: + return .F64StoreMem + case .i32Storemem8: + return .I32StoreMem8 + case .i32Storemem16: + return .I32StoreMem16 + case .i64Storemem8: + return .I64StoreMem8 + case .i64Storemem16: + return .I64StoreMem16 + case .i64Storemem32: + return .I64StoreMem32 + case .s128Storemem: + return .S128StoreMem + default: + fatalError("Wrong WasmMemoryStoreType") } } @@ -1787,18 +1920,20 @@ extension Instruction: ProtobufConvertible { } } - func convertProtoWasmCatchKind(_ catchKind: Fuzzilli_Protobuf_WasmCatchKind) -> WasmBeginTryTable.CatchKind { + func convertProtoWasmCatchKind(_ catchKind: Fuzzilli_Protobuf_WasmCatchKind) + -> WasmBeginTryTable.CatchKind + { switch catchKind { - case .noRef: - return .NoRef - case .ref: - return .Ref - case .allNoRef: - return .AllNoRef - case .allRef: - return .AllRef - case .UNRECOGNIZED(let i): - fatalError("Invalid WasmCatchKind \(i)") + case .noRef: + return .NoRef + case .ref: + return .Ref + case .allNoRef: + return .AllNoRef + case .allRef: + return .AllRef + case .UNRECOGNIZED(let i): + fatalError("Invalid WasmCatchKind \(i)") } } @@ -1807,15 +1942,17 @@ extension Instruction: ProtobufConvertible { } func WasmSignatureFromProto(_ signature: Fuzzilli_Protobuf_WasmSignature) -> WasmSignature { - return WasmSignature(expects: signature.parameterTypes.map(WasmTypeEnumToILType), - returns: signature.outputTypes.map(WasmTypeEnumToILType)) + return WasmSignature( + expects: signature.parameterTypes.map(WasmTypeEnumToILType), + returns: signature.outputTypes.map(WasmTypeEnumToILType)) } let op: Operation switch operation { case .opIdx(let idx): guard let cachedOp = opCache?.get(Int(idx)) else { - throw FuzzilliError.instructionDecodingError("invalid operation index or no decoding context available") + throw FuzzilliError.instructionDecodingError( + "invalid operation index or no decoding context available") } op = cachedOp case .loadInteger(let p): @@ -1825,7 +1962,7 @@ extension Instruction: ProtobufConvertible { case .loadFloat(let p): op = LoadFloat(value: p.value) case .loadString(let p): - let customName = p.customName.isEmpty ? nil: p.customName; + let customName = p.customName.isEmpty ? nil : p.customName op = LoadString(value: p.value, customName: customName) case .loadBoolean(let p): op = LoadBoolean(value: p.value) @@ -1856,7 +1993,8 @@ extension Instruction: ProtobufConvertible { case .objectLiteralSetPrototype: op = ObjectLiteralSetPrototype() case .beginObjectLiteralMethod(let p): - op = BeginObjectLiteralMethod(methodName: p.methodName, parameters: convertParameters(p.parameters)) + op = BeginObjectLiteralMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters)) case .endObjectLiteralMethod: op = EndObjectLiteralMethod() case .beginObjectLiteralComputedMethod(let p): @@ -1882,23 +2020,28 @@ extension Instruction: ProtobufConvertible { case .endObjectLiteral: op = EndObjectLiteral() case .beginClassDefinition(let p): - op = BeginClassDefinition(hasSuperclass: p.hasSuperclass_p, isExpression: p.isExpression) + op = BeginClassDefinition( + hasSuperclass: p.hasSuperclass_p, isExpression: p.isExpression) case .beginClassConstructor(let p): op = BeginClassConstructor(parameters: convertParameters(p.parameters)) case .endClassConstructor: op = EndClassConstructor() case .classAddProperty(let p): - op = ClassAddProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + op = ClassAddProperty( + propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) case .classAddElement(let p): op = ClassAddElement(index: p.index, hasValue: p.hasValue_p, isStatic: p.isStatic) case .classAddComputedProperty(let p): op = ClassAddComputedProperty(hasValue: p.hasValue_p, isStatic: p.isStatic) case .beginClassMethod(let p): - op = BeginClassMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters), + isStatic: p.isStatic) case .endClassMethod: op = EndClassMethod() case .beginClassComputedMethod(let p): - op = BeginClassComputedMethod(parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassComputedMethod( + parameters: convertParameters(p.parameters), isStatic: p.isStatic) case .endClassComputedMethod: op = EndClassComputedMethod() case .beginClassGetter(let p): @@ -1922,9 +2065,12 @@ extension Instruction: ProtobufConvertible { case .endClassStaticInitializer: op = EndClassStaticInitializer() case .classAddPrivateProperty(let p): - op = ClassAddPrivateProperty(propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) + op = ClassAddPrivateProperty( + propertyName: p.propertyName, hasValue: p.hasValue_p, isStatic: p.isStatic) case .beginClassPrivateMethod(let p): - op = BeginClassPrivateMethod(methodName: p.methodName, parameters: convertParameters(p.parameters), isStatic: p.isStatic) + op = BeginClassPrivateMethod( + methodName: p.methodName, parameters: convertParameters(p.parameters), + isStatic: p.isStatic) case .endClassPrivateMethod: op = EndClassPrivateMethod() case .endClassDefinition: @@ -1944,7 +2090,9 @@ extension Instruction: ProtobufConvertible { case .setProperty(let p): op = SetProperty(propertyName: p.propertyName, isGuarded: p.isGuarded) case .updateProperty(let p): - op = UpdateProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .deleteProperty(let p): op = DeleteProperty(propertyName: p.propertyName, isGuarded: p.isGuarded) case .configureProperty(let p): @@ -1952,13 +2100,16 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureProperty(propertyName: p.propertyName, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureProperty( + propertyName: p.propertyName, flags: flags, + type: try convertEnum(p.type, PropertyType.allCases)) case .getElement(let p): op = GetElement(index: p.index, isGuarded: p.isGuarded) case .setElement(let p): op = SetElement(index: p.index) case .updateElement(let p): - op = UpdateElement(index: p.index, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateElement( + index: p.index, operator: try convertEnum(p.op, BinaryOperator.allCases)) case .deleteElement(let p): op = DeleteElement(index: p.index, isGuarded: p.isGuarded) case .configureElement(let p): @@ -1966,7 +2117,8 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureElement(index: p.index, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureElement( + index: p.index, flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) case .getComputedProperty(let p): op = GetComputedProperty(isGuarded: p.isGuarded) case .setComputedProperty: @@ -1980,7 +2132,8 @@ extension Instruction: ProtobufConvertible { if p.isWritable { flags.insert(.writable) } if p.isConfigurable { flags.insert(.configurable) } if p.isEnumerable { flags.insert(.enumerable) } - op = ConfigureComputedProperty(flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) + op = ConfigureComputedProperty( + flags: flags, type: try convertEnum(p.type, PropertyType.allCases)) case .typeOf: op = TypeOf() case .void: @@ -2043,19 +2196,25 @@ extension Instruction: ProtobufConvertible { case .callFunction(let p): op = CallFunction(numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .callFunctionWithSpread(let p): - op = CallFunctionWithSpread(numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallFunctionWithSpread( + numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) case .construct(let p): op = Construct(numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .constructWithSpread(let p): - op = ConstructWithSpread(numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = ConstructWithSpread( + numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) case .callMethod(let p): - op = CallMethod(methodName: p.methodName, numArguments: inouts.count - 2, isGuarded: p.isGuarded) + op = CallMethod( + methodName: p.methodName, numArguments: inouts.count - 2, isGuarded: p.isGuarded) case .callMethodWithSpread(let p): - op = CallMethodWithSpread(methodName: p.methodName, numArguments: inouts.count - 2, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallMethodWithSpread( + methodName: p.methodName, numArguments: inouts.count - 2, spreads: p.spreads, + isGuarded: p.isGuarded) case .callComputedMethod(let p): op = CallComputedMethod(numArguments: inouts.count - 3, isGuarded: p.isGuarded) case .callComputedMethodWithSpread(let p): - op = CallComputedMethodWithSpread(numArguments: inouts.count - 3, spreads: p.spreads, isGuarded: p.isGuarded) + op = CallComputedMethodWithSpread( + numArguments: inouts.count - 3, spreads: p.spreads, isGuarded: p.isGuarded) case .unaryOperation(let p): op = UnaryOperation(try convertEnum(p.op, UnaryOperator.allCases)) case .binaryOperation(let p): @@ -2071,15 +2230,20 @@ extension Instruction: ProtobufConvertible { case .destructArray(let p): op = DestructArray(indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) case .destructArrayAndReassign(let p): - op = DestructArrayAndReassign(indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) + op = DestructArrayAndReassign( + indices: p.indices.map({ Int64($0) }), lastIsRest: p.lastIsRest) case .destructObject(let p): op = DestructObject(properties: p.properties, hasRestElement: p.hasRestElement_p) case .destructObjectAndReassign(let p): - op = DestructObjectAndReassign(properties: p.properties, hasRestElement: p.hasRestElement_p) + op = DestructObjectAndReassign( + properties: p.properties, hasRestElement: p.hasRestElement_p) case .compare(let p): op = Compare(try convertEnum(p.op, Comparator.allCases)) case .createNamedVariable(let p): - op = CreateNamedVariable(p.variableName, declarationMode: try convertEnum(p.declarationMode, NamedVariableDeclarationMode.allCases)) + op = CreateNamedVariable( + p.variableName, + declarationMode: try convertEnum( + p.declarationMode, NamedVariableDeclarationMode.allCases)) case .createNamedDisposableVariable(let p): op = CreateNamedDisposableVariable(p.variableName) case .createNamedAsyncDisposableVariable(let p): @@ -2096,7 +2260,9 @@ extension Instruction: ProtobufConvertible { case .setPrivateProperty(let p): op = SetPrivateProperty(propertyName: p.propertyName) case .updatePrivateProperty(let p): - op = UpdatePrivateProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdatePrivateProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .callPrivateMethod(let p): op = CallPrivateMethod(methodName: p.methodName, numArguments: inouts.count - 2) case .getSuperProperty(let p): @@ -2108,13 +2274,17 @@ extension Instruction: ProtobufConvertible { case .setComputedSuperProperty(_): op = SetComputedSuperProperty() case .updateSuperProperty(let p): - op = UpdateSuperProperty(propertyName: p.propertyName, operator: try convertEnum(p.op, BinaryOperator.allCases)) + op = UpdateSuperProperty( + propertyName: p.propertyName, + operator: try convertEnum(p.op, BinaryOperator.allCases)) case .explore(let p): op = Explore(id: p.id, numArguments: inouts.count - 1, rngSeed: UInt32(p.rngSeed)) case .probe(let p): op = Probe(id: p.id) case .fixup(let p): - op = Fixup(id: p.id, action: p.action, originalOperation: p.originalOperation, numArguments: inouts.count - (p.hasOutput_p ? 1 : 0), hasOutput: p.hasOutput_p) + op = Fixup( + id: p.id, action: p.action, originalOperation: p.originalOperation, + numArguments: inouts.count - (p.hasOutput_p ? 1 : 0), hasOutput: p.hasOutput_p) case .beginWith: op = BeginWith() case .endWith: @@ -2168,11 +2338,13 @@ extension Instruction: ProtobufConvertible { case .beginForOfLoop: op = BeginForOfLoop() case .beginForOfLoopWithDestruct(let p): - op = BeginForOfLoopWithDestruct(indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) + op = BeginForOfLoopWithDestruct( + indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) case .endForOfLoop: op = EndForOfLoop() case .beginRepeatLoop(let p): - op = BeginRepeatLoop(iterations: Int(p.iterations), exposesLoopCounter: p.exposesLoopCounter) + op = BeginRepeatLoop( + iterations: Int(p.iterations), exposesLoopCounter: p.exposesLoopCounter) case .endRepeatLoop: op = EndRepeatLoop() case .loopBreak: @@ -2202,10 +2374,13 @@ extension Instruction: ProtobufConvertible { case .nop: op = Nop() case .createWasmGlobal(let p): - op = CreateWasmGlobal(value: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) + op = CreateWasmGlobal( + value: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) case .createWasmMemory(let p): let maxPages = p.wasmMemory.hasMaxPages ? Int(p.wasmMemory.maxPages) : nil - op = CreateWasmMemory(limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) + op = CreateWasmMemory( + limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), + isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) case .createWasmTable(let p): let maxSize: Int? if p.hasMaxSize { @@ -2213,7 +2388,9 @@ extension Instruction: ProtobufConvertible { } else { maxSize = nil } - op = CreateWasmTable(elementType: WasmTypeEnumToILType(p.elementType), limits: Limits(min: Int(p.minSize), max: maxSize), isTable64: p.isTable64) + op = CreateWasmTable( + elementType: WasmTypeEnumToILType(p.elementType), + limits: Limits(min: Int(p.minSize), max: maxSize), isTable64: p.isTable64) case .createWasmJstag(_): op = CreateWasmJSTag() case .createWasmTag(let p): @@ -2249,13 +2426,17 @@ extension Instruction: ProtobufConvertible { // Wasm Numerical Operations case .wasmi32CompareOp(let p): - op = Wasmi32CompareOp(compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmi32CompareOp( + compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmi64CompareOp(let p): - op = Wasmi64CompareOp(compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmi64CompareOp( + compareOpKind: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmf32CompareOp(let p): - op = Wasmf32CompareOp(compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmf32CompareOp( + compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmf64CompareOp(let p): - op = Wasmf64CompareOp(compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + op = Wasmf64CompareOp( + compareOpKind: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) case .wasmi32EqualZero(_): op = Wasmi32EqualZero() case .wasmi64EqualZero(_): @@ -2333,14 +2514,18 @@ extension Instruction: ProtobufConvertible { case .wasmReassign(_): op = WasmReassign() case .wasmDefineGlobal(let p): - op = WasmDefineGlobal(wasmGlobal: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) + op = WasmDefineGlobal( + wasmGlobal: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) case .wasmDefineTable(let p): - op = WasmDefineTable(elementType: WasmTypeEnumToILType(p.elementType), - limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), - definedEntries: p.definedEntries.map { entry in - WasmTableType.IndexInTableAndWasmSignature(indexInTable: Int(entry.index), signature: WasmSignatureFromProto(entry.signature)) - }, - isTable64: p.isTable64) + op = WasmDefineTable( + elementType: WasmTypeEnumToILType(p.elementType), + limits: Limits(min: Int(p.minSize), max: p.hasMaxSize ? Int(p.maxSize) : nil), + definedEntries: p.definedEntries.map { entry in + WasmTableType.IndexInTableAndWasmSignature( + indexInTable: Int(entry.index), + signature: WasmSignatureFromProto(entry.signature)) + }, + isTable64: p.isTable64) case .wasmDefineElementSegment(let p): op = WasmDefineElementSegment(size: p.size) case .wasmDropElementSegment(_): @@ -2351,7 +2536,9 @@ extension Instruction: ProtobufConvertible { op = WasmTableCopy() case .wasmDefineMemory(let p): let maxPages = p.wasmMemory.hasMaxPages ? Int(p.wasmMemory.maxPages) : nil - op = WasmDefineMemory(limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) + op = WasmDefineMemory( + limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), + isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64) case .wasmDefineDataSegment(let p): op = WasmDefineDataSegment(segment: [UInt8](p.segment)) case .wasmLoadGlobal(let p): @@ -2367,7 +2554,8 @@ extension Instruction: ProtobufConvertible { let outputs = p.outputTypes.map(WasmTypeEnumToILType) op = WasmCallIndirect(signature: parameters => outputs) case .wasmCallDirect(let p): - op = WasmCallDirect(parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) + op = WasmCallDirect( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmReturnCallDirect(let p): op = WasmReturnCallDirect(parameterCount: Int(p.parameterCount)) case .wasmReturnCallIndirect(let p): @@ -2375,9 +2563,12 @@ extension Instruction: ProtobufConvertible { let outputs = p.outputTypes.map(WasmTypeEnumToILType) op = WasmReturnCallIndirect(signature: parameters => outputs) case .wasmMemoryLoad(let p): - op = WasmMemoryLoad(loadType: convertProtoWasmMemoryLoadType(p.loadType), staticOffset: p.staticOffset) + op = WasmMemoryLoad( + loadType: convertProtoWasmMemoryLoadType(p.loadType), staticOffset: p.staticOffset) case .wasmMemoryStore(let p): - op = WasmMemoryStore(storeType: convertProtoWasmMemoryStoreType(p.storeType), staticOffset: p.staticOffset) + op = WasmMemoryStore( + storeType: convertProtoWasmMemoryStoreType(p.storeType), + staticOffset: p.staticOffset) case .wasmMemorySize(_): op = WasmMemorySize() case .wasmMemoryGrow(_): @@ -2416,8 +2607,9 @@ extension Instruction: ProtobufConvertible { case .wasmBeginCatchAll(let p): op = WasmBeginCatchAll(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginCatch(let p): - op = WasmBeginCatch(blockOutputCount: Int(p.blockOutputCount), - labelParameterCount: Int(p.labelParameterCount)) + op = WasmBeginCatch( + blockOutputCount: Int(p.blockOutputCount), + labelParameterCount: Int(p.labelParameterCount)) case .wasmEndTry(let p): op = WasmEndTry(blockOutputCount: Int(p.blockOutputCount)) case .wasmBeginTryDelegate(let p): @@ -2435,13 +2627,19 @@ extension Instruction: ProtobufConvertible { case .wasmBranch(_): op = WasmBranch(parameterCount: inouts.count - 1) case .wasmBranchIf(let p): - op = WasmBranchIf(parameterCount: inouts.count - 2, hint: try convertEnum(p.hint, WasmBranchHint.allCases)) + op = WasmBranchIf( + parameterCount: inouts.count - 2, + hint: try convertEnum(p.hint, WasmBranchHint.allCases)) case .wasmBranchTable(let p): - op = WasmBranchTable(parameterCount: inouts.count - Int(p.valueCount) - 2, valueCount: Int(p.valueCount)) + op = WasmBranchTable( + parameterCount: inouts.count - Int(p.valueCount) - 2, valueCount: Int(p.valueCount)) case .wasmBeginIf(let p): - op = WasmBeginIf(parameterCount: Int(p.parameterCount), hint: try convertEnum(p.hint, WasmBranchHint.allCases), inverted: p.inverted) + op = WasmBeginIf( + parameterCount: Int(p.parameterCount), + hint: try convertEnum(p.hint, WasmBranchHint.allCases), inverted: p.inverted) case .wasmBeginElse(let p): - op = WasmBeginElse(parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) + op = WasmBeginElse( + parameterCount: Int(p.parameterCount), outputCount: Int(p.outputCount)) case .wasmEndIf(let p): op = WasmEndIf(outputCount: Int(p.outputCount)) case .wasmNop(_): @@ -2451,7 +2649,7 @@ extension Instruction: ProtobufConvertible { case .wasmSelect(_): op = WasmSelect() case .constSimd128(let p): - op = ConstSimd128(value: p.value.map{ UInt8($0) }) + op = ConstSimd128(value: p.value.map { UInt8($0) }) case .wasmSimd128IntegerUnOp(let p): let shape = WasmSimd128Shape(rawValue: UInt8(p.shape))! let unOpKind = WasmSimd128IntegerUnOpKind(rawValue: Int(p.unaryOperator))! @@ -2478,41 +2676,61 @@ extension Instruction: ProtobufConvertible { op = WasmSimd128FloatTernaryOp(shape: shape, ternaryOpKind: ternaryOpKind) case .wasmSimd128Compare(let p): let shape = WasmSimd128Shape(rawValue: UInt8(p.shape))! - let compareOpKind = if shape.isFloat() { - WasmSimd128CompareOpKind.fKind(value: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) - } else { - WasmSimd128CompareOpKind.iKind(value: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) - } + let compareOpKind = + if shape.isFloat() { + WasmSimd128CompareOpKind.fKind( + value: WasmFloatCompareOpKind(rawValue: UInt8(p.compareOperator))!) + } else { + WasmSimd128CompareOpKind.iKind( + value: WasmIntegerCompareOpKind(rawValue: UInt8(p.compareOperator))!) + } op = WasmSimd128Compare(shape: shape, compareOpKind: compareOpKind) case .wasmSimdSplat(let p): op = WasmSimdSplat(try convertEnum(p.kind, WasmSimdSplat.Kind.allCases)) case .wasmSimdExtractLane(let p): - op = WasmSimdExtractLane(kind: try convertEnum(p.kind, WasmSimdExtractLane.Kind.allCases), lane: Int(p.lane)) + op = WasmSimdExtractLane( + kind: try convertEnum(p.kind, WasmSimdExtractLane.Kind.allCases), lane: Int(p.lane)) case .wasmSimdReplaceLane(let p): - op = WasmSimdReplaceLane(kind: try convertEnum(p.kind, WasmSimdReplaceLane.Kind.allCases), lane: Int(p.lane)) + op = WasmSimdReplaceLane( + kind: try convertEnum(p.kind, WasmSimdReplaceLane.Kind.allCases), lane: Int(p.lane)) case .wasmSimdLoad(let p): - op = WasmSimdLoad(kind: try convertEnum(p.kind, WasmSimdLoad.Kind.allCases), staticOffset: p.staticOffset) + op = WasmSimdLoad( + kind: try convertEnum(p.kind, WasmSimdLoad.Kind.allCases), + staticOffset: p.staticOffset) case .wasmSimdLoadLane(let p): - op = WasmSimdLoadLane(kind: try convertEnum(p.kind, WasmSimdLoadLane.Kind.allCases), staticOffset: p.staticOffset, lane: Int(p.lane)) + op = WasmSimdLoadLane( + kind: try convertEnum(p.kind, WasmSimdLoadLane.Kind.allCases), + staticOffset: p.staticOffset, lane: Int(p.lane)) case .wasmSimdStoreLane(let p): - op = WasmSimdStoreLane(kind: try convertEnum(p.kind, WasmSimdStoreLane.Kind.allCases), staticOffset: p.staticOffset, lane: Int(p.lane)) + op = WasmSimdStoreLane( + kind: try convertEnum(p.kind, WasmSimdStoreLane.Kind.allCases), + staticOffset: p.staticOffset, lane: Int(p.lane)) case .wasmBeginTypeGroup(_): op = WasmBeginTypeGroup() case .wasmEndTypeGroup(_): assert(inouts.count % 2 == 0) op = WasmEndTypeGroup(typesCount: inouts.count / 2) case .wasmDefineArrayType(let p): - op = WasmDefineArrayType(elementType: WasmTypeEnumToILType(p.elementType), mutability: p.mutability) + op = WasmDefineArrayType( + elementType: WasmTypeEnumToILType(p.elementType), mutability: p.mutability) case .wasmDefineSignatureType(let p): - op = WasmDefineSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineAdHocSignatureType(let p): - op = WasmDefineAdHocSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineAdHocSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineAdHocModuleSignatureType(let p): - op = WasmDefineAdHocModuleSignatureType(signature: p.parameterTypes.map(WasmTypeEnumToILType) => p.outputTypes.map(WasmTypeEnumToILType)) + op = WasmDefineAdHocModuleSignatureType( + signature: p.parameterTypes.map(WasmTypeEnumToILType) + => p.outputTypes.map(WasmTypeEnumToILType)) case .wasmDefineStructType(let p): - op = WasmDefineStructType(fields: p.fields.map { field in - return WasmDefineStructType.Field(type: WasmTypeEnumToILType(field.type), mutability: field.mutability) - }) + op = WasmDefineStructType( + fields: p.fields.map { field in + return WasmDefineStructType.Field( + type: WasmTypeEnumToILType(field.type), mutability: field.mutability) + }) case .wasmDefineForwardOrSelfReference(_): op = WasmDefineForwardOrSelfReference() case .wasmResolveForwardReference(_): @@ -2536,7 +2754,8 @@ extension Instruction: ProtobufConvertible { case .wasmStructSet(let p): op = WasmStructSet(fieldIndex: Int(p.fieldIndex)) case .wasmRefNull(let p): - op = p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) + op = + p.hasType ? WasmRefNull(type: WasmTypeEnumToILType(p.type)) : WasmRefNull(type: nil) case .wasmRefIsNull(_): op = WasmRefIsNull() case .wasmRefEq(_): @@ -2550,13 +2769,19 @@ extension Instruction: ProtobufConvertible { case .wasmI31Get(let p): op = WasmI31Get(isSigned: p.isSigned) case .wasmAtomicLoad(let p): - op = WasmAtomicLoad(loadType: try convertEnum(p.loadType, WasmAtomicLoadType.allCases), offset: p.offset) + op = WasmAtomicLoad( + loadType: try convertEnum(p.loadType, WasmAtomicLoadType.allCases), offset: p.offset + ) case .wasmAtomicStore(let p): - op = WasmAtomicStore(storeType: try convertEnum(p.storeType, WasmAtomicStoreType.allCases), offset: p.offset) + op = WasmAtomicStore( + storeType: try convertEnum(p.storeType, WasmAtomicStoreType.allCases), + offset: p.offset) case .wasmAtomicRmw(let p): - op = WasmAtomicRMW(op: try convertEnum(p.op, WasmAtomicRMWType.allCases), offset: p.offset) + op = WasmAtomicRMW( + op: try convertEnum(p.op, WasmAtomicRMWType.allCases), offset: p.offset) case .wasmAtomicCmpxchg(let p): - op = WasmAtomicCmpxchg(op: try convertEnum(p.op, WasmAtomicCmpxchgType.allCases), offset: p.offset) + op = WasmAtomicCmpxchg( + op: try convertEnum(p.op, WasmAtomicCmpxchgType.allCases), offset: p.offset) case .wasmAnyConvertExtern(_): op = WasmAnyConvertExtern() case .wasmExternConvertAny(_): @@ -2564,7 +2789,8 @@ extension Instruction: ProtobufConvertible { } guard op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count else { - throw FuzzilliError.instructionDecodingError("incorrect number of in- and outputs for operation \(op)") + throw FuzzilliError.instructionDecodingError( + "incorrect number of in- and outputs for operation \(op)") } opCache?.add(op) diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 8b55de0a5..8c49dcc19 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -35,11 +35,11 @@ public struct JSTyper: Analyzer { private var typeGroups: [[Variable]] = [] // Tracks the direct and transitive dependencies of each type group index to the respective // type group indices. - private var typeGroupDependencies: [Int:Set] = [:] - private var selfReferences: [Variable: [(inout JSTyper, Variable?) -> ()]] = [:] + private var typeGroupDependencies: [Int: Set] = [:] + private var selfReferences: [Variable: [(inout JSTyper, Variable?) -> Void]] = [:] private var isWithinTypeGroup = false // Tracks the type definition variable for each Wasm index type. - private var wasmTypeDefMap = [WasmTypeDescription:Variable]() + private var wasmTypeDefMap = [WasmTypeDescription: Variable]() // Tracks the active function definitions and contains the instruction that started the function. private var activeFunctionDefinitions = Stack() @@ -64,7 +64,7 @@ public struct JSTyper: Analyzer { var functionImports: [(Variable, Signature)] = [] var functionDefines: [Variable] = [] - var globals : [Variable] { + var globals: [Variable] { return globalImports + globalDefines } @@ -124,12 +124,16 @@ public struct JSTyper: Analyzer { var activeClasses = Stack() public func getGroup(withName name: String) -> ObjectGroup? { - if let group = activeObjectGroups.elementsStartingAtTop().first(where: {group in group.name == name}) { + if let group = activeObjectGroups.elementsStartingAtTop().first(where: { group in + group.name == name + }) { return group - } else if let cls = activeClasses.elementsStartingAtTop().first(where: {cls in cls.objectGroup.name == name}) { + } else if let cls = activeClasses.elementsStartingAtTop().first(where: { cls in + cls.objectGroup.name == name + }) { return cls.objectGroup } else { - return self.finalizedObjectGroups.first(where: {group in group.name == name}) + return self.finalizedObjectGroups.first(where: { group in group.name == name }) } } @@ -173,46 +177,66 @@ public struct JSTyper: Analyzer { public func createNewWasmModule() { let instanceName = "_fuzz_WasmModule\(numObjectGroups)" - let instanceType = ILType.object(ofGroup: instanceName, withProperties: ["exports"], withMethods: []) + let instanceType = ILType.object( + ofGroup: instanceName, withProperties: ["exports"], withMethods: []) let instanceNameExports = "_fuzz_WasmExports\(numObjectGroups)" - let instanceTypeExports = ILType.object(ofGroup: instanceNameExports, withProperties: [], withMethods: []) + let instanceTypeExports = ILType.object( + ofGroup: instanceNameExports, withProperties: [], withMethods: []) // This ObjectGroup tracking the Module itself is basically finished as it only has the `.exports` property // which we track, the rest is tracked on the ObjectGroup tracking the `.exports` field of this Module. // The ObjectGroup tracking the `.exports` field will be further modified to track exported functions and other properties. - let objectGroupModule = ObjectGroup(name: instanceName, instanceType: instanceType, properties: ["exports": instanceTypeExports], methods: [:]) + let objectGroupModule = ObjectGroup( + name: instanceName, instanceType: instanceType, + properties: ["exports": instanceTypeExports], methods: [:]) activeObjectGroups.push(objectGroupModule) - let objectGroupModuleExports = ObjectGroup(name: instanceNameExports, instanceType: instanceTypeExports, properties: [:], methods: [:]) + let objectGroupModuleExports = ObjectGroup( + name: instanceNameExports, instanceType: instanceTypeExports, properties: [:], + methods: [:]) activeObjectGroups.push(objectGroupModuleExports) } func createNewObjectLiteral() { let instanceName = "_fuzz_Object\(numObjectGroups)" - let instanceType: ILType = .object(ofGroup: instanceName, withProperties: [], withMethods: []) + let instanceType: ILType = .object( + ofGroup: instanceName, withProperties: [], withMethods: []) // This is the dynamic object group. - let objectGroup = ObjectGroup(name: instanceName, instanceType: instanceType, properties: [:], methods: [:]) + let objectGroup = ObjectGroup( + name: instanceName, instanceType: instanceType, properties: [:], methods: [:]) activeObjectGroups.push(objectGroup) } - func createNewClass(withSuperType superType: ILType, propertyMap: [String: ILType], methodMap: [String: [Signature]], superConstructorType: ILType, forOutput output: Variable) { + func createNewClass( + withSuperType superType: ILType, propertyMap: [String: ILType], + methodMap: [String: [Signature]], superConstructorType: ILType, + forOutput output: Variable + ) { let numGroups = numObjectGroups let instanceName = "_fuzz_Class\(numGroups)" // This type and the object group will be updated dynamically - let instanceType: ILType = .object(ofGroup: instanceName, withProperties: Array(superType.properties), withMethods: Array(superType.methods)) + let instanceType: ILType = .object( + ofGroup: instanceName, withProperties: Array(superType.properties), + withMethods: Array(superType.methods)) // This is the wip object group. - let objectGroup = ObjectGroup(name: instanceName, instanceType: instanceType, properties: propertyMap, overloads: methodMap) + let objectGroup = ObjectGroup( + name: instanceName, instanceType: instanceType, properties: propertyMap, + overloads: methodMap) activeObjectGroups.push(objectGroup) let classInstanceName = "_fuzz_Constructor\(numGroups)" - let classObjectGroup = ObjectGroup(name: classInstanceName, instanceType: .object(ofGroup: classInstanceName), properties: [:], overloads: [:]) + let classObjectGroup = ObjectGroup( + name: classInstanceName, instanceType: .object(ofGroup: classInstanceName), + properties: [:], overloads: [:]) - let classDefinition = ClassDefinition(output: output, objectGroup: classObjectGroup, superType: superType, superConstructorType: superConstructorType) + let classDefinition = ClassDefinition( + output: output, objectGroup: classObjectGroup, superType: superType, + superConstructorType: superConstructorType) activeClasses.push(classDefinition) } @@ -222,7 +246,8 @@ public struct JSTyper: Analyzer { public func addClassStaticProperty(propertyName: String) { let classType = activeClasses.top.objectGroup.instanceType - let newType = ILType.object(ofGroup: classType.group, withProperties: [propertyName]) + classType + let newType = + ILType.object(ofGroup: classType.group, withProperties: [propertyName]) + classType assert(newType != .nothing) activeClasses.top.objectGroup.properties[propertyName] = .jsAnything activeClasses.top.objectGroup.instanceType = newType @@ -230,17 +255,23 @@ public struct JSTyper: Analyzer { public func updateClassStaticPropertyType(propertyName: String, type: ILType) { assert(activeClasses.top.objectGroup.instanceType.properties.contains(propertyName)) - assert(activeClasses.top.objectGroup.properties.contains(where: {k, v in k == propertyName})) + assert( + activeClasses.top.objectGroup.properties.contains(where: { k, v in k == propertyName + })) activeClasses.top.objectGroup.properties[propertyName] = type } public func addClassStaticMethod(methodName: String) { let classType = activeClasses.top.objectGroup.instanceType - let newType = ILType.object(ofGroup: classType.group, withMethods: [methodName]) + classType + let newType = + ILType.object(ofGroup: classType.group, withMethods: [methodName]) + classType assert(newType != .nothing) activeClasses.top.objectGroup.instanceType = newType - activeClasses.top.objectGroup.methods[methodName] = activeClasses.top.objectGroup.methods[methodName] ?? [] + [Signature.forUnknownFunction] + activeClasses.top.objectGroup.methods[methodName] = + activeClasses.top.objectGroup.methods[methodName] ?? [] + [ + Signature.forUnknownFunction + ] activeClasses.top.objectGroup.instanceType = newType } @@ -269,12 +300,16 @@ public struct JSTyper: Analyzer { // as such "defined in Wasm" (i.e. requiredContext contains wasm) below means "defined in this module". // This is a feature as the module doesn't care as these imports always have to come from JS. - public func addWasmFunction(withSignature signature: Signature, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmFunction( + withSignature signature: Signature, forDefinition instr: Instruction, + forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. - let haveFunction = seenWasmVars.functionImports.contains(where: { - $0.0 == variable && $0.1 == signature - }) || seenWasmVars.functionDefines.contains(variable) + let haveFunction = + seenWasmVars.functionImports.contains(where: { + $0.0 == variable && $0.1 == signature + }) || seenWasmVars.functionDefines.contains(variable) if !haveFunction { if instr.op.requiredContext.inWasm { @@ -291,7 +326,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmGlobal(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmGlobal( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before if !seenWasmVars.globals.contains(variable) { @@ -308,7 +345,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmTable(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmTable( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -324,7 +363,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmMemory(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmMemory( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -340,7 +381,9 @@ public struct JSTyper: Analyzer { } } - public func addWasmTag(withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable) { + public func addWasmTag( + withType type: ILType, forDefinition instr: Instruction, forVariable variable: Variable + ) { // The instruction might have multiple outputs, i.e. a DestructObject, which is why we cannot know which output variable the correct one is. // Add this property only if we have not seen it before var propertyName: String @@ -358,7 +401,9 @@ public struct JSTyper: Analyzer { public func addMethod(methodName: String, of groupType: ObjectGroupType) { let topGroup = activeObjectGroups.top - let newType = ILType.object(ofGroup: topGroup.name, withMethods: [methodName]) + topGroup.instanceType + let newType = + ILType.object(ofGroup: topGroup.name, withMethods: [methodName]) + + topGroup.instanceType assert(newType != .nothing) activeObjectGroups.top.instanceType = newType activeObjectGroups.top.methods[methodName] = [] @@ -376,7 +421,9 @@ public struct JSTyper: Analyzer { public func addProperty(propertyName: String) { let topGroup = activeObjectGroups.top - let newType = ILType.object(ofGroup: topGroup.name, withProperties: [propertyName]) + topGroup.instanceType + let newType = + ILType.object(ofGroup: topGroup.name, withProperties: [propertyName]) + + topGroup.instanceType assert(newType != .nothing) activeObjectGroups.top.instanceType = newType } @@ -413,7 +460,8 @@ public struct JSTyper: Analyzer { private mutating func registerWasmMemoryUse(for memory: Variable) { let definingInstruction = defUseAnalyzer.definition(of: memory) - dynamicObjectGroupManager.addWasmMemory(withType: type(of: memory), forDefinition: definingInstruction, forVariable: memory) + dynamicObjectGroupManager.addWasmMemory( + withType: type(of: memory), forDefinition: definingInstruction, forVariable: memory) } // Array for collecting type changes during instruction execution. @@ -452,7 +500,9 @@ public struct JSTyper: Analyzer { return typeDef } - mutating func addSignatureType(def: Variable, signature: WasmSignature, inputs: ArraySlice) { + mutating func addSignatureType( + def: Variable, signature: WasmSignature, inputs: ArraySlice + ) { assert(isWithinTypeGroup) var inputs = inputs.makeIterator() let tgIndex = typeGroups.count - 1 @@ -471,19 +521,25 @@ public struct JSTyper: Analyzer { if elementDesc == .selfReference { // Register a resolver callback. See `addArrayType` for details. if isParameter { - selfReferences[typeDef, default: []].append({typer, replacement in - let desc = typer.type(of: def).wasmTypeDefinition!.description as! WasmSignatureTypeDescription + selfReferences[typeDef, default: []].append({ typer, replacement in + let desc = + typer.type(of: def).wasmTypeDefinition!.description + as! WasmSignatureTypeDescription var params = desc.signature.parameterTypes let nullability = params[i].wasmReferenceType!.nullability - params[i] = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability) + params[i] = typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: nullability) desc.signature = params => desc.signature.outputTypes }) } else { - selfReferences[typeDef, default: []].append({typer, replacement in - let desc = typer.type(of: def).wasmTypeDefinition!.description as! WasmSignatureTypeDescription + selfReferences[typeDef, default: []].append({ typer, replacement in + let desc = + typer.type(of: def).wasmTypeDefinition!.description + as! WasmSignatureTypeDescription var outputTypes = desc.signature.outputTypes let nullability = outputTypes[i].wasmReferenceType!.nullability - outputTypes[i] = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability) + outputTypes[i] = typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: nullability) desc.signature = desc.signature.parameterTypes => outputTypes }) } @@ -495,24 +551,33 @@ public struct JSTyper: Analyzer { } let resolvedParameterTypes = signature.parameterTypes.enumerated().map(resolveType) - isParameter = false // TODO(mliedtke): Is there a nicer way to capture this? + isParameter = false // TODO(mliedtke): Is there a nicer way to capture this? let resolvedOutputTypes = signature.outputTypes.enumerated().map(resolveType) - set(def, .wasmTypeDef(description: WasmSignatureTypeDescription(signature: resolvedParameterTypes => resolvedOutputTypes, typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmSignatureTypeDescription( + signature: resolvedParameterTypes => resolvedOutputTypes, + typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } - mutating func addArrayType(def: Variable, elementType: ILType, mutability: Bool, elementRef: Variable? = nil) { + mutating func addArrayType( + def: Variable, elementType: ILType, mutability: Bool, elementRef: Variable? = nil + ) { assert(isWithinTypeGroup) let tgIndex = typeGroups.count - 1 let resolvedElementType: ILType if let elementRef = elementRef { let elementNullability = elementType.wasmReferenceType!.nullability let typeDefType = type(of: elementRef) - guard let elementDesc = typeDefType.wasmTypeDefinition?.description else { + guard let elementDesc = typeDefType.wasmTypeDefinition?.description else { // TODO(mliedtke): Investigate. The `typeDefType` should be `.wasmTypeDef`. // The `elementType` should be `.wasmRef(.Index)`? let missesDef = typeDefType.wasmTypeDefinition != nil - fatalError("Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), elementType = \(elementType)") + fatalError( + "Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), elementType = \(elementType)" + ) } if elementDesc == .selfReference { // Register a "resolver" callback that does one of the two: @@ -525,55 +590,71 @@ public struct JSTyper: Analyzer { // This callback will be called either when using a WasmResolveForwardReferenceType // operation (triggering case 2) or when reaching the wasmEndTypeGroup of the // current type group (case 1). - selfReferences[elementRef, default: []].append({typer, replacement in - (typer.type(of: def).wasmTypeDefinition!.description as! WasmArrayTypeDescription).elementType - = typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) + selfReferences[elementRef, default: []].append({ typer, replacement in + (typer.type(of: def).wasmTypeDefinition!.description + as! WasmArrayTypeDescription).elementType = typer.type( + of: replacement ?? def + ).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) }) } - resolvedElementType = type(of: elementRef).wasmTypeDefinition!.getReferenceTypeTo(nullability: elementNullability) + resolvedElementType = type(of: elementRef).wasmTypeDefinition!.getReferenceTypeTo( + nullability: elementNullability) registerTypeGroupDependency(from: tgIndex, to: elementDesc.typeGroupIndex) } else { resolvedElementType = elementType } - set(def, .wasmTypeDef(description: WasmArrayTypeDescription( - elementType: resolvedElementType, - mutability: mutability, - typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmArrayTypeDescription( + elementType: resolvedElementType, + mutability: mutability, + typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } - mutating func addStructType(def: Variable, fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)]) { + mutating func addStructType( + def: Variable, fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] + ) { let tgIndex = typeGroups.count - 1 let resolvedFields = fieldsWithRefs.enumerated().map { (fieldIndex, fieldWithInput) in let (field, fieldTypeRef) = fieldWithInput if let fieldTypeRef { let fieldNullability = field.type.wasmReferenceType!.nullability let typeDefType = type(of: fieldTypeRef) - guard let fieldTypeDesc = typeDefType.wasmTypeDefinition?.description else { + guard let fieldTypeDesc = typeDefType.wasmTypeDefinition?.description else { // TODO(mliedtke): Investigate. let missesDef = typeDefType.wasmTypeDefinition != nil - fatalError("Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), field.type = \(field.type)") + fatalError( + "Missing \(missesDef ? "definition" : "description") for type definition type \(typeDefType), field.type = \(field.type)" + ) } if fieldTypeDesc == .selfReference { // Register a resolver callback. See `addArrayType` for details. - selfReferences[fieldTypeRef, default: []].append({typer, replacement in - (typer.type(of: def).wasmTypeDefinition!.description! as! WasmStructTypeDescription).fields[fieldIndex].type = - typer.type(of: replacement ?? def).wasmTypeDefinition!.getReferenceTypeTo(nullability: fieldNullability) + selfReferences[fieldTypeRef, default: []].append({ typer, replacement in + (typer.type(of: def).wasmTypeDefinition!.description! + as! WasmStructTypeDescription).fields[fieldIndex].type = + typer.type(of: replacement ?? def).wasmTypeDefinition! + .getReferenceTypeTo(nullability: fieldNullability) }) } registerTypeGroupDependency(from: tgIndex, to: fieldTypeDesc.typeGroupIndex) return WasmStructTypeDescription.Field( - type: type(of: fieldTypeRef).wasmTypeDefinition!.getReferenceTypeTo(nullability: fieldNullability), + type: type(of: fieldTypeRef).wasmTypeDefinition!.getReferenceTypeTo( + nullability: fieldNullability), mutability: field.mutability) } else { return field } } - set(def, .wasmTypeDef(description: WasmStructTypeDescription( - fields: resolvedFields, typeGroupIndex: tgIndex))) + set( + def, + .wasmTypeDef( + description: WasmStructTypeDescription( + fields: resolvedFields, typeGroupIndex: tgIndex))) typeGroups[typeGroups.count - 1].append(def) } @@ -608,7 +689,9 @@ public struct JSTyper: Analyzer { } mutating func setReferenceType(of: Variable, typeDef: Variable, nullability: Bool) { - setType(of: of, to: type(of: typeDef).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability)) + setType( + of: of, + to: type(of: typeDef).wasmTypeDefinition!.getReferenceTypeTo(nullability: nullability)) } // Returns the type description for the provided variable which has to be either a type @@ -624,7 +707,9 @@ public struct JSTyper: Analyzer { // Helper function to type a "regular" wasm begin block (block, if, try). mutating func wasmTypeBeginBlock(_ instr: Instruction, _ signature: WasmSignature) { setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(), signature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } } @@ -645,7 +730,7 @@ public struct JSTyper: Analyzer { // This typer is currently "Outside" of the wasm module, we just type // the instructions here such that we can set the type of the module at // the end. Figure out how we can set the correct type at the end? - if (instr.op is WasmOperation) { + if instr.op is WasmOperation { switch instr.op.opcode { case .consti64(_): setType(of: instr.output, to: .wasmi64) @@ -656,61 +741,61 @@ public struct JSTyper: Analyzer { case .constf32(_): setType(of: instr.output, to: .wasmf32) case .wasmi32CompareOp(_), - .wasmi64CompareOp(_), - .wasmf32CompareOp(_), - .wasmf64CompareOp(_): + .wasmi64CompareOp(_), + .wasmf32CompareOp(_), + .wasmf64CompareOp(_): setType(of: instr.output, to: .wasmi32) case .wasmi32EqualZero(_), - .wasmi64EqualZero(_): + .wasmi64EqualZero(_): setType(of: instr.output, to: .wasmi32) case .wasmi32BinOp(_), - .wasmi32UnOp(_), - .wasmWrapi64Toi32(_), - .wasmTruncatef32Toi32(_), - .wasmTruncatef64Toi32(_), - .wasmReinterpretf32Asi32(_), - .wasmSignExtend8Intoi32(_), - .wasmSignExtend16Intoi32(_), - .wasmTruncateSatf32Toi32(_), - .wasmTruncateSatf64Toi32(_): + .wasmi32UnOp(_), + .wasmWrapi64Toi32(_), + .wasmTruncatef32Toi32(_), + .wasmTruncatef64Toi32(_), + .wasmReinterpretf32Asi32(_), + .wasmSignExtend8Intoi32(_), + .wasmSignExtend16Intoi32(_), + .wasmTruncateSatf32Toi32(_), + .wasmTruncateSatf64Toi32(_): setType(of: instr.output, to: .wasmi32) case .wasmi64BinOp(_), - .wasmi64UnOp(_), - .wasmExtendi32Toi64(_), - .wasmTruncatef32Toi64(_), - .wasmTruncatef64Toi64(_), - .wasmReinterpretf64Asi64(_), - .wasmSignExtend8Intoi64(_), - .wasmSignExtend16Intoi64(_), - .wasmSignExtend32Intoi64(_), - .wasmTruncateSatf32Toi64(_), - .wasmTruncateSatf64Toi64(_): + .wasmi64UnOp(_), + .wasmExtendi32Toi64(_), + .wasmTruncatef32Toi64(_), + .wasmTruncatef64Toi64(_), + .wasmReinterpretf64Asi64(_), + .wasmSignExtend8Intoi64(_), + .wasmSignExtend16Intoi64(_), + .wasmSignExtend32Intoi64(_), + .wasmTruncateSatf32Toi64(_), + .wasmTruncateSatf64Toi64(_): setType(of: instr.output, to: .wasmi64) case .wasmf32BinOp(_), - .wasmf32UnOp(_), - .wasmConverti32Tof32(_), - .wasmConverti64Tof32(_), - .wasmDemotef64Tof32(_), - .wasmReinterpreti32Asf32(_): + .wasmf32UnOp(_), + .wasmConverti32Tof32(_), + .wasmConverti64Tof32(_), + .wasmDemotef64Tof32(_), + .wasmReinterpreti32Asf32(_): setType(of: instr.output, to: .wasmf32) case .wasmf64BinOp(_), - .wasmf64UnOp(_), - .wasmConverti32Tof64(_), - .wasmConverti64Tof64(_), - .wasmPromotef32Tof64(_), - .wasmReinterpreti64Asf64(_): + .wasmf64UnOp(_), + .wasmConverti32Tof64(_), + .wasmConverti64Tof64(_), + .wasmPromotef32Tof64(_), + .wasmReinterpreti64Asf64(_): setType(of: instr.output, to: .wasmf64) case .constSimd128(_), - .wasmSimd128Compare(_), - .wasmSimd128IntegerBinOp(_), - .wasmSimd128IntegerTernaryOp(_), - .wasmSimd128FloatUnOp(_), - .wasmSimd128FloatBinOp(_), - .wasmSimd128FloatTernaryOp(_), - .wasmSimdSplat(_), - .wasmSimdLoad(_), - .wasmSimdLoadLane(_), - .wasmSimdReplaceLane(_): + .wasmSimd128Compare(_), + .wasmSimd128IntegerBinOp(_), + .wasmSimd128IntegerTernaryOp(_), + .wasmSimd128FloatUnOp(_), + .wasmSimd128FloatBinOp(_), + .wasmSimd128FloatTernaryOp(_), + .wasmSimdSplat(_), + .wasmSimdLoad(_), + .wasmSimdLoadLane(_), + .wasmSimdReplaceLane(_): setType(of: instr.output, to: .wasmSimd128) case .wasmSimd128IntegerUnOp(let op): var outputType: ILType = .wasmSimd128 @@ -725,28 +810,44 @@ public struct JSTyper: Analyzer { case .wasmSimdExtractLane(let op): setType(of: instr.output, to: op.kind.laneType()) case .wasmDefineGlobal(let op): - let type = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: op.wasmGlobal.toType(), isMutable: op.isMutable)) - dynamicObjectGroupManager.addWasmGlobal(withType: type, forDefinition: instr, forVariable: instr.output) + let type = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType( + valueType: op.wasmGlobal.toType(), isMutable: op.isMutable)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type, forDefinition: instr, forVariable: instr.output) setType(of: instr.output, to: type) case .wasmDefineTable(let op): - setType(of: instr.output, to: .wasmTable(wasmTableType: WasmTableType(elementType: op.elementType, limits: op.limits, isTable64: op.isTable64, knownEntries: op.definedEntries))) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.output), forDefinition: instr, forVariable: instr.output) + setType( + of: instr.output, + to: .wasmTable( + wasmTableType: WasmTableType( + elementType: op.elementType, limits: op.limits, isTable64: op.isTable64, + knownEntries: op.definedEntries))) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.output), forDefinition: instr, + forVariable: instr.output) // Also re-export all functions that we now import through the activeElementSection for (idx, entry) in op.definedEntries.enumerated() { let definingInstruction = defUseAnalyzer.definition(of: instr.input(idx)) // TODO(cffsmith): Once we change the way we track signatures, we should also store the JS Signature here if we have one. The table might contain JS functions but we lose that signature in the entries. Which is why we convert back into JS Signatures here. - let jsSignature = ProgramBuilder.convertWasmSignatureToJsSignature(entry.signature) - dynamicObjectGroupManager.addWasmFunction(withSignature: jsSignature, forDefinition: definingInstruction, forVariable: instr.input(idx)) + let jsSignature = ProgramBuilder.convertWasmSignatureToJsSignature( + entry.signature) + dynamicObjectGroupManager.addWasmFunction( + withSignature: jsSignature, forDefinition: definingInstruction, + forVariable: instr.input(idx)) } case .wasmDefineElementSegment(let op): setType(of: instr.output, to: .wasmElementSegment(segmentLength: Int(op.size))) case .wasmDropElementSegment(_): type(of: instr.input(0)).wasmElementSegmentType!.markAsDropped() case .wasmTableInit(_), - .wasmTableCopy(_): + .wasmTableCopy(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) - // Ignore changed function signatures - it is too hard to reason about them statically. + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) + // Ignore changed function signatures - it is too hard to reason about them statically. case .wasmDefineMemory(let op): setType(of: instr.output, to: op.wasmMemory) registerWasmMemoryUse(for: instr.output) @@ -756,31 +857,48 @@ public struct JSTyper: Analyzer { type(of: instr.input(0)).wasmDataSegmentType!.markAsDropped() case .wasmDefineTag(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.output, to: .object(ofGroup: "WasmTag", withWasmType: WasmTagType(signature.parameterTypes))) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.output), forDefinition: instr, forVariable: instr.output) + setType( + of: instr.output, + to: .object( + ofGroup: "WasmTag", withWasmType: WasmTagType(signature.parameterTypes))) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: instr.output), forDefinition: instr, + forVariable: instr.output) case .wasmThrow(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmLoadGlobal(let op): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: op.globalType) case .wasmStoreGlobal(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmGlobal(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmGlobal( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmTableGet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) let tableType = type(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: tableType, forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: tableType, forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: tableType.wasmTableType!.elementType) case .wasmTableSet(_): let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) case .wasmTableSize(_), - .wasmTableGrow(_): + .wasmTableGrow(_): let isTable64 = type(of: instr.input(0)).wasmTableType?.isTable64 ?? false let definingInstruction = defUseAnalyzer.definition(of: instr.input(0)) - dynamicObjectGroupManager.addWasmTable(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0)) + dynamicObjectGroupManager.addWasmTable( + withType: type(of: instr.input(0)), forDefinition: definingInstruction, + forVariable: instr.input(0)) setType(of: instr.output, to: isTable64 ? .wasmi64 : .wasmi32) case .wasmMemoryStore(_): registerWasmMemoryUse(for: instr.input(0)) @@ -799,7 +917,7 @@ public struct JSTyper: Analyzer { registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: op.op.type()) case .wasmMemorySize(_), - .wasmMemoryGrow(_): + .wasmMemoryGrow(_): let isMemory64 = type(of: instr.input(0)).wasmMemoryType?.isMemory64 ?? false registerWasmMemoryUse(for: instr.input(0)) setType(of: instr.output, to: isMemory64 ? .wasmi64 : .wasmi32) @@ -812,14 +930,19 @@ public struct JSTyper: Analyzer { } let definingInstruction = defUseAnalyzer.definition(of: instr.input(1)) // Here we query the typer for the signature of the instruction as that is the correct "JS" Signature instead of taking the call-site specific converted wasm signature. - dynamicObjectGroupManager.addWasmFunction(withSignature: type(of: instr.input(1)).signature ?? Signature.forUnknownFunction, forDefinition: definingInstruction, forVariable: instr.input(1)) + dynamicObjectGroupManager.addWasmFunction( + withSignature: type(of: instr.input(1)).signature + ?? Signature.forUnknownFunction, forDefinition: definingInstruction, + forVariable: instr.input(1)) case .beginWasmFunction(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeBeginBlock(instr, signature) case .endWasmFunction(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature setType(of: instr.output, to: .wasmFunctionDef(signature)) - dynamicObjectGroupManager.addWasmFunction(withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), forDefinition: instr, forVariable: instr.output) + dynamicObjectGroupManager.addWasmFunction( + withSignature: ProgramBuilder.convertWasmSignatureToJsSignature(signature), + forDefinition: instr, forVariable: instr.output) case .wasmSelect(_): setType(of: instr.output, to: type(of: instr.input(0))) case .wasmBeginBlock(_): @@ -837,7 +960,7 @@ public struct JSTyper: Analyzer { wasmTypeEndBlock(instr, signature.outputTypes) wasmTypeBeginBlock(instr, signature) case .wasmEndIf(_): - let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, signature.outputTypes) case .wasmBeginLoop(_): // Note that different to all other blocks the loop's label parameters are the input types @@ -845,7 +968,9 @@ public struct JSTyper: Analyzer { // beginning of the loop block instead of the end.) let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature setType(of: instr.innerOutputs.first!, to: .label(signature.parameterTypes)) - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(), signature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(), signature.parameterTypes) + { setType(of: innerOutput, to: paramType) } case .wasmEndLoop(_): @@ -857,14 +982,16 @@ public struct JSTyper: Analyzer { instr.inputs.forEach { input in if type(of: input).isWasmTagType { let definingInstruction = defUseAnalyzer.definition(of: input) - dynamicObjectGroupManager.addWasmTag(withType: type(of: input), forDefinition: definingInstruction, forVariable: input) + dynamicObjectGroupManager.addWasmTag( + withType: type(of: input), forDefinition: definingInstruction, + forVariable: input) } } case .wasmEndTryTable(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeEndBlock(instr, signature.outputTypes) case .wasmBeginTry(_): - let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature + let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature wasmTypeBeginBlock(instr, signature) case .wasmBeginCatchAll(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature @@ -877,7 +1004,8 @@ public struct JSTyper: Analyzer { // by this Wasm module. let tag = instr.input(1) let definingInstruction = defUseAnalyzer.definition(of: tag) - dynamicObjectGroupManager.addWasmTag(withType: type(of: tag), + dynamicObjectGroupManager.addWasmTag( + withType: type(of: tag), forDefinition: definingInstruction, forVariable: tag) // The second inner output is the exception label which is used for rethrowing the // exception with the legacy exception handling proposal. (This is similar to the @@ -887,7 +1015,9 @@ public struct JSTyper: Analyzer { // This guarantees that the inner outputs are properly typed, even if a mutator // changed the tag variable to something that's not typed as a Wasm tag anymore. let tagSignature = type(of: instr.input(2)).wasmFunctionSignatureDefSignature - for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) { + for (innerOutput, paramType) in zip( + instr.innerOutputs.dropFirst(2), tagSignature.parameterTypes) + { setType(of: innerOutput, to: paramType) } for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) { @@ -907,15 +1037,15 @@ public struct JSTyper: Analyzer { for (output, outputType) in zip(instr.outputs, signature.outputTypes) { setType(of: output, to: outputType) } - // We don't need to update the DynamicObjectGroupManager, as all functions that can be called here are .wasmFunctionDef types, this means we have already added them when we saw the EndWasmFunction instruction. + // We don't need to update the DynamicObjectGroupManager, as all functions that can be called here are .wasmFunctionDef types, this means we have already added them when we saw the EndWasmFunction instruction. case .wasmCallIndirect(let op): for (output, outputType) in zip(instr.outputs, op.signature.outputTypes) { setType(of: output, to: outputType) } - // Functions that can be called through a table are also already added by the wasmDefineTable instruction. - // No need to analyze this and add them to the DynamicObjectGroupManager. + // Functions that can be called through a table are also already added by the wasmDefineTable instruction. + // No need to analyze this and add them to the DynamicObjectGroupManager. case .wasmArrayNewFixed(_), - .wasmArrayNewDefault(_): + .wasmArrayNewDefault(_): setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: false) case .wasmArrayLen(_): setType(of: instr.output, to: .wasmi32) @@ -925,13 +1055,13 @@ public struct JSTyper: Analyzer { case .wasmArraySet(_): break case .wasmStructNew(_), - .wasmStructNewDefault(_): + .wasmStructNewDefault(_): setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: false) case .wasmStructGet(let op): let typeDesc = getTypeDescription(of: instr.input(0)) as! WasmStructTypeDescription setType(of: instr.output, to: typeDesc.fields[op.fieldIndex].type.unpacked()) case .wasmStructSet(_): - break; + break case .wasmRefNull(let op): if instr.hasInputs { setReferenceType(of: instr.output, typeDef: instr.input(0), nullability: true) @@ -951,7 +1081,8 @@ public struct JSTyper: Analyzer { case .wasmRefCast(let op): if op.type.requiredInputCount() == 1 { let nullable = op.type.wasmReferenceType!.nullability - setReferenceType(of: instr.output, typeDef: instr.input(1), nullability: nullable) + setReferenceType( + of: instr.output, typeDef: instr.input(1), nullability: nullable) } else { setType(of: instr.output, to: op.type) } @@ -964,7 +1095,8 @@ public struct JSTyper: Analyzer { // TODO(pawkra): forward shared bit & update the comment // extern.convert_any forwards the nullability from the input. let null = type(of: instr.input(0)).wasmReferenceType!.nullability - setType(of: instr.output, to: .wasmRef(.WasmExtern, shared: false, nullability: null)) + setType( + of: instr.output, to: .wasmRef(.WasmExtern, shared: false, nullability: null)) case .wasmDefineAdHocSignatureType(let op): startTypeGroup() addSignatureType(def: instr.output, signature: op.signature, inputs: instr.inputs) @@ -1036,7 +1168,9 @@ public struct JSTyper: Analyzer { } /// Sets a program-wide signature for the instruction at the given index, which must be the start of a function or method definition. - public mutating func setParameters(forSubroutineStartingAt index: Int, to parameterTypes: ParameterList) { + public mutating func setParameters( + forSubroutineStartingAt index: Int, to parameterTypes: ParameterList + ) { // Currently we expect this to only be used for the next instruction. assert(index == indexOfLastInstruction + 1) signatures[index] = parameterTypes @@ -1046,7 +1180,9 @@ public struct JSTyper: Analyzer { // Do lookup on our local type information first. if let groupName = objType.group { if let group = dynamicObjectGroupManager.getGroup(withName: groupName) { - if let signatures = group.methods[methodName], !signatures.isEmpty, objType.methods.contains(methodName) { + if let signatures = group.methods[methodName], !signatures.isEmpty, + objType.methods.contains(methodName) + { return signatures } else { // This means the objectGroup doesn't have the function but we did see the objectGroup. @@ -1069,9 +1205,13 @@ public struct JSTyper: Analyzer { if let groupName = objType.group { if let group = dynamicObjectGroupManager.getGroup(withName: groupName) { // Check if we have it in the group and on the actual passed in ILType as it might've been deleted. - if let type = group.properties[propertyName], objType.properties.contains(propertyName) { + if let type = group.properties[propertyName], + objType.properties.contains(propertyName) + { return type - } else if let type = group.methods[propertyName], objType.methods.contains(propertyName) { + } else if let type = group.methods[propertyName], + objType.methods.contains(propertyName) + { // If no property is present, look up the name in the methods instead. // Retrieving a method "as a property" results in a variable that is a function // with the method's signature. However, it loses the this-binding: @@ -1104,7 +1244,9 @@ public struct JSTyper: Analyzer { /// Attempts to infer the constructed type of the given constructor. public func inferConstructedType(of constructor: Variable) -> ILType { - if let signature = state.type(of: constructor).constructorSignature, signature.outputType != .jsAnything { + if let signature = state.type(of: constructor).constructorSignature, + signature.outputType != .jsAnything + { return signature.outputType } return .object() @@ -1129,8 +1271,12 @@ public struct JSTyper: Analyzer { /// Attempts to infer the parameter types of the given subroutine definition. /// If parameter types have been added for this function, they are returned, otherwise generic parameter types (i.e. .jsAnything parameters) for the parameters specified in the operation are generated. - private func inferSubroutineParameterList(of op: BeginAnySubroutine, at index: Int) -> ParameterList { - return signatures[index] ?? ParameterList(numParameters: op.parameters.count, hasRestParam: op.parameters.hasRestParameter) + private func inferSubroutineParameterList(of op: BeginAnySubroutine, at index: Int) + -> ParameterList + { + return signatures[index] + ?? ParameterList( + numParameters: op.parameters.count, hasRestParam: op.parameters.hasRestParameter) } // Set type to current state and save type change event @@ -1156,15 +1302,22 @@ public struct JSTyper: Analyzer { case .beginPlainFunction(let op): // Plain functions can also be used as constructors. // The return value type will only be known after fully processing the function definitions. - set(instr.output, .functionAndConstructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + set( + instr.output, + .functionAndConstructor( + inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): - set(instr.output, .function(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + set( + instr.output, + .function(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginConstructor(let op): - set(instr.output, .constructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) + set( + instr.output, + .constructor(inferSubroutineParameterList(of: op, at: instr.index) => .jsAnything)) case .beginCodeString: set(instr.output, .jsString) case .beginClassDefinition(let op): @@ -1177,18 +1330,25 @@ public struct JSTyper: Analyzer { // the |this| value inside the constructor. However, we don't currently support multiple signatures // for the same callable (the call signature and the construct signature), so here in that case // we just ignore the super type. - if let constructorReturnType = superConstructorType.constructorSignature?.outputType, constructorReturnType.Is(.object()) { + if let constructorReturnType = superConstructorType.constructorSignature? + .outputType, constructorReturnType.Is(.object()) + { superType = constructorReturnType } } - let propertySuperTypeMap = Dictionary(uniqueKeysWithValues: superType.properties.map { name in - (name, inferPropertyType(of: name, on: superType)) - }) - let methodSuperTypeMap = Dictionary(uniqueKeysWithValues: superType.methods.map { name in - (name, inferMethodSignatures(of: name, on: superType)) - }) + let propertySuperTypeMap = Dictionary( + uniqueKeysWithValues: superType.properties.map { name in + (name, inferPropertyType(of: name, on: superType)) + }) + let methodSuperTypeMap = Dictionary( + uniqueKeysWithValues: superType.methods.map { name in + (name, inferMethodSignatures(of: name, on: superType)) + }) - dynamicObjectGroupManager.createNewClass(withSuperType: superType, propertyMap: propertySuperTypeMap, methodMap: methodSuperTypeMap, superConstructorType: superConstructorType, forOutput: instr.output) + dynamicObjectGroupManager.createNewClass( + withSuperType: superType, propertyMap: propertySuperTypeMap, + methodMap: methodSuperTypeMap, superConstructorType: superConstructorType, + forOutput: instr.output) // We only know here that this is going to be a constructor() type. // On endClassDefinition below, the exact type is refined. But we @@ -1197,7 +1357,10 @@ public struct JSTyper: Analyzer { set(instr.output, .constructor()) case .endClassDefinition: let (instanceType, classDefinition) = dynamicObjectGroupManager.finalizeClass() - set(classDefinition.output, classDefinition.objectGroup.instanceType + .constructor(classDefinition.constructorParameters => instanceType)) + set( + classDefinition.output, + classDefinition.objectGroup.instanceType + + .constructor(classDefinition.constructorParameters => instanceType)) default: // Only instructions starting a block with output variables should be handled here. assert(instr.numOutputs == 0 || !instr.isBlockStart) @@ -1210,13 +1373,13 @@ public struct JSTyper: Analyzer { } switch instr.op.opcode { case .beginObjectLiteral, - .endObjectLiteral, - .beginClassDefinition, - .endClassDefinition, - .beginClassStaticInitializer, - .endClassStaticInitializer, - .beginWasmModule, - .endWasmModule: + .endObjectLiteral, + .beginClassDefinition, + .endClassDefinition, + .beginClassStaticInitializer, + .endClassStaticInitializer, + .beginWasmModule, + .endWasmModule: // Object literals and class definitions don't create any conditional branches, only methods and accessors inside of them. These are handled further below. break case .beginIf: @@ -1244,12 +1407,12 @@ public struct JSTyper: Analyzer { // Loop headers execute unconditionally (at least once). break case .beginDoWhileLoopBody, - .beginDoWhileLoopHeader, - .endDoWhileLoop: + .beginDoWhileLoopHeader, + .endDoWhileLoop: // Do-While loop headers _and_ bodies execute unconditionally (at least once). break case .beginForLoopInitializer, - .beginForLoopCondition: + .beginForLoopCondition: // The initializer and the condition of a for-loop's header execute unconditionally. break case .beginForLoopAfterthought: @@ -1266,66 +1429,66 @@ public struct JSTyper: Analyzer { case .endForLoop: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginWhileLoopBody, - .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct, - .beginRepeatLoop, - .beginCodeString: + .beginForInLoop, + .beginForOfLoop, + .beginForOfLoopWithDestruct, + .beginRepeatLoop, + .beginCodeString: state.startGroupOfConditionallyExecutingBlocks() // Push an empty state representing the case when the loop body (or code string) is not executed at all state.enterConditionallyExecutingBlock(typeChanges: &typeChanges) // Push a new state tracking the types inside the loop state.enterConditionallyExecutingBlock(typeChanges: &typeChanges) case .endWhileLoop, - .endForInLoop, - .endForOfLoop, - .endRepeatLoop, - .endCodeString: + .endForInLoop, + .endForOfLoop, + .endRepeatLoop, + .endCodeString: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter, - .beginPlainFunction, - .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor, - .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassPrivateMethod: + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, + .beginPlainFunction, + .beginArrowFunction, + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor, + .beginClassConstructor, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassPrivateMethod: activeFunctionDefinitions.push(instr) state.startSubroutine() case .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter, - .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endConstructor, - .endClassConstructor, - .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter, - .endClassPrivateMethod: + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, + .endPlainFunction, + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endConstructor, + .endClassConstructor, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter, + .endClassPrivateMethod: // // Infer the return type of the subroutine (if necessary for the signature). // @@ -1337,7 +1500,8 @@ public struct JSTyper: Analyzer { defaultReturnValueType = type(of: begin.innerOutput(0)) } - let returnValueType = state.endSubroutine(typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) + let returnValueType = state.endSubroutine( + typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) // Check if the signature is needed, otherwise, we don't need the return value type. if begin.numOutputs == 1 { @@ -1346,13 +1510,20 @@ public struct JSTyper: Analyzer { if let signature = funcType.signature { switch begin.op.opcode { case .beginGeneratorFunction, - .beginAsyncGeneratorFunction: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => .jsGenerator)) + .beginAsyncGeneratorFunction: + setType( + of: begin.output, + to: funcType.settingSignature(to: signature.parameters => .jsGenerator)) case .beginAsyncFunction, - .beginAsyncArrowFunction: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => .jsPromise)) + .beginAsyncArrowFunction: + setType( + of: begin.output, + to: funcType.settingSignature(to: signature.parameters => .jsPromise)) default: - setType(of: begin.output, to: funcType.settingSignature(to: signature.parameters => returnValueType)) + setType( + of: begin.output, + to: funcType.settingSignature( + to: signature.parameters => returnValueType)) } } } @@ -1364,57 +1535,71 @@ public struct JSTyper: Analyzer { assert(begin.op is BeginClassMethod) let beginOp = begin.op as! BeginClassMethod if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateClassStaticMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) } else { - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) } case .endClassGetter(_): assert(begin.op is BeginClassGetter) let beginOp = begin.op as! BeginClassGetter if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } else { - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } case .endClassSetter(_): assert(begin.op is BeginClassSetter) let beginOp = begin.op as! BeginClassSetter if beginOp.isStatic { - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } else { - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) } case .endObjectLiteralMethod(_): assert(begin.op is BeginObjectLiteralMethod) let beginOp = begin.op as! BeginObjectLiteralMethod - dynamicObjectGroupManager.updateMethodSignature(methodName: beginOp.methodName, signature: inferSubroutineParameterList(of: beginOp, at: begin.index) => returnValueType) + dynamicObjectGroupManager.updateMethodSignature( + methodName: beginOp.methodName, + signature: inferSubroutineParameterList(of: beginOp, at: begin.index) + => returnValueType) case .endObjectLiteralGetter(_): assert(begin.op is BeginObjectLiteralGetter) let beginOp = begin.op as! BeginObjectLiteralGetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) case .endObjectLiteralSetter(_): assert(begin.op is BeginObjectLiteralSetter) let beginOp = begin.op as! BeginObjectLiteralSetter - dynamicObjectGroupManager.updatePropertyType(propertyName: beginOp.propertyName, type: returnValueType) + dynamicObjectGroupManager.updatePropertyType( + propertyName: beginOp.propertyName, type: returnValueType) default: break } - case .beginTry, - .beginCatch, - .beginFinally, - .endTryCatchFinally: + .beginCatch, + .beginFinally, + .endTryCatchFinally: break case .beginWith, - .endWith: + .endWith: break case .beginBlockStatement, - .endBlockStatement: + .endBlockStatement: break case .wasmBeginTypeGroup, - .wasmEndTypeGroup: - break + .wasmEndTypeGroup: + break default: assert(instr.isSimple) } @@ -1425,7 +1610,9 @@ public struct JSTyper: Analyzer { return } // Helper function to process parameters - func processParameterDeclarations(_ parameterVariables: ArraySlice, parameters: ParameterList) { + func processParameterDeclarations( + _ parameterVariables: ArraySlice, parameters: ParameterList + ) { let types = computeParameterTypes(from: parameters) assert(types.count == parameterVariables.count) for (param, type) in zip(parameterVariables, types) { @@ -1445,26 +1632,28 @@ public struct JSTyper: Analyzer { // TODO: fetch all output types from the environment instead of hardcoding them. // Helper function to set output type of binary/reassignment operations - func analyzeBinaryOperation(operator op: BinaryOperator, withInputs inputs: ArraySlice) -> ILType { + func analyzeBinaryOperation( + operator op: BinaryOperator, withInputs inputs: ArraySlice + ) -> ILType { switch op { case .Add: return maybeBigIntOr(.primitive) case .Sub, - .Mul, - .Exp, - .Div, - .Mod: + .Mul, + .Exp, + .Div, + .Mod: return maybeBigIntOr(.number) case .BitAnd, - .BitOr, - .Xor, - .LShift, - .RShift, - .UnRShift: + .BitOr, + .Xor, + .LShift, + .RShift, + .UnRShift: return maybeBigIntOr(.integer) case .LogicAnd, - .LogicOr, - .NullCoalesce: + .LogicOr, + .NullCoalesce: return state.type(of: inputs[0]) | state.type(of: inputs[1]) } } @@ -1526,7 +1715,7 @@ public struct JSTyper: Analyzer { case .createNamedVariable(let op): if op.hasInitialValue { set(instr.output, type(ofInput: 0)) - } else if (environment.hasBuiltin(op.variableName)) { + } else if environment.hasBuiltin(op.variableName) { set(instr.output, environment.type(ofBuiltin: op.variableName)) } else { set(instr.output, .jsAnything) @@ -1554,24 +1743,29 @@ public struct JSTyper: Analyzer { dynamicObjectGroupManager.createNewObjectLiteral() case .objectLiteralAddProperty(let op): - dynamicObjectGroupManager.addProperty(propertyName: op.propertyName, withType: type(ofInput: 0)) + dynamicObjectGroupManager.addProperty( + propertyName: op.propertyName, withType: type(ofInput: 0)) case .objectLiteralAddElement, - .objectLiteralAddComputedProperty, - .objectLiteralCopyProperties: + .objectLiteralAddComputedProperty, + .objectLiteralCopyProperties: // We cannot currently determine the properties/methods added by these operations. break case .beginObjectLiteralMethod(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .objectLiteral) case .beginObjectLiteralComputedMethod(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginObjectLiteralGetter(let op): // The first inner output is the explicit |this| parameter for the constructor @@ -1587,13 +1781,17 @@ public struct JSTyper: Analyzer { // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) case .beginObjectLiteralComputedSetter(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .endObjectLiteral: let instanceType = dynamicObjectGroupManager.finalizeObjectLiteral() @@ -1609,41 +1807,57 @@ public struct JSTyper: Analyzer { case .classAddProperty(let op): if op.isStatic { dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updateClassStaticPropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + dynamicObjectGroupManager.updateClassStaticPropertyType( + propertyName: op.propertyName, + type: op.hasValue ? type(ofInput: 0) : .jsAnything) } else { dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) - dynamicObjectGroupManager.updatePropertyType(propertyName: op.propertyName, type: op.hasValue ? type(ofInput: 0) : .jsAnything) + dynamicObjectGroupManager.updatePropertyType( + propertyName: op.propertyName, + type: op.hasValue ? type(ofInput: 0) : .jsAnything) } case .beginClassStaticInitializer: // The first inner output is the explicit |this| - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) case .beginClassMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) dynamicObjectGroupManager.addClassStaticMethod(methodName: op.methodName) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) dynamicObjectGroupManager.addMethod(methodName: op.methodName, of: .jsClass) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassComputedMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassGetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) assert(instr.numInnerOutputs == 1) dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) } else { @@ -1654,7 +1868,9 @@ public struct JSTyper: Analyzer { case .beginClassComputedGetter(let op): if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } @@ -1662,36 +1878,48 @@ public struct JSTyper: Analyzer { case .beginClassSetter(let op): // The first inner output is the explicit |this| parameter for the constructor if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) dynamicObjectGroupManager.addClassStaticProperty(propertyName: op.propertyName) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) dynamicObjectGroupManager.addProperty(propertyName: op.propertyName) } assert(instr.numInnerOutputs == 2) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassComputedSetter(let op): if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginClassPrivateMethod(let op): // The first inner output is the explicit |this| if op.isStatic { - set(instr.innerOutput(0), dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) + set( + instr.innerOutput(0), + dynamicObjectGroupManager.activeClasses.top.objectGroup.instanceType) } else { set(instr.innerOutput(0), dynamicObjectGroupManager.top.instanceType) } - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .createArray, - .createIntArray, - .createFloatArray, - .createArrayWithSpread: + .createIntArray, + .createFloatArray, + .createArrayWithSpread: set(instr.output, .jsArray) case .createTemplateString: @@ -1713,18 +1941,18 @@ public struct JSTyper: Analyzer { set(instr.input(0), type(ofInput: 0).removing(propertyOrMethod: op.propertyName)) set(instr.output, .boolean) - // TODO: An additional analyzer is required to determine the runtime value of the input variable + // TODO: An additional analyzer is required to determine the runtime value of the input variable case .deleteComputedProperty, - .deleteElement: + .deleteElement: set(instr.output, .boolean) - // TODO: An additional analyzer is required to determine the runtime value of the output variable generated from the following operations - // For now we treat this as .jsAnything + // TODO: An additional analyzer is required to determine the runtime value of the output variable generated from the following operations + // For now we treat this as .jsAnything case .getElement, - .getComputedProperty, - .getComputedSuperProperty, - .callComputedMethod, - .callComputedMethodWithSpread: + .getComputedProperty, + .getComputedSuperProperty, + .callComputedMethod, + .callComputedMethodWithSpread: set(instr.output, .jsAnything) case .ternaryOperation: @@ -1732,11 +1960,11 @@ public struct JSTyper: Analyzer { set(instr.output, outputType) case .callFunction, - .callFunctionWithSpread: + .callFunctionWithSpread: set(instr.output, inferCallResultType(of: instr.input(0))) case .construct, - .constructWithSpread: + .constructWithSpread: set(instr.output, inferConstructedType(of: instr.input(0))) case .callMethod(let op): @@ -1744,18 +1972,21 @@ public struct JSTyper: Analyzer { // op.numInputs - 1 because the signature.numParameters does not include the receiver. // TODO: We could make the overload resolution here more accurate // by also comparing the types of parameters. - let sig = sigs.filter({$0.numParameters == op.numInputs - 1}).first ?? chooseUniform(from: sigs) + let sig = + sigs.filter({ $0.numParameters == op.numInputs - 1 }).first + ?? chooseUniform(from: sigs) set(instr.output, sig.outputType) case .callMethodWithSpread(let op): - let sig = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) + let sig = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) set(instr.output, sig.outputType) case .unaryOperation(let op): switch op.op { case .PreInc, - .PreDec, - .PostInc, - .PostDec: + .PreDec, + .PostInc, + .PostDec: set(instr.input(0), maybeBigIntOr(.primitive)) set(instr.output, maybeBigIntOr(.primitive)) case .Plus: @@ -1803,10 +2034,10 @@ public struct JSTyper: Analyzer { } case .destructArray: - instr.outputs.forEach{set($0, .jsAnything)} + instr.outputs.forEach { set($0, .jsAnything) } case .destructArrayAndReassign: - instr.inputs.dropFirst().forEach{set($0, .jsAnything)} + instr.inputs.dropFirst().forEach { set($0, .jsAnything) } case .destructObject(let op): for (property, output) in zip(op.properties, instr.outputs) { @@ -1848,20 +2079,25 @@ public struct JSTyper: Analyzer { } case .beginPlainFunction(let op as BeginAnyFunction), - .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): - processParameterDeclarations(instr.innerOutputs, parameters: inferSubroutineParameterList(of: op, at: instr.index)) + .beginArrowFunction(let op as BeginAnyFunction), + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + processParameterDeclarations( + instr.innerOutputs, + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .beginConstructor(let op): // The first inner output is the explicit |this| parameter for the constructor set(instr.innerOutput(0), .object()) - processParameterDeclarations(instr.innerOutputs(1...), parameters: inferSubroutineParameterList(of: op, at: instr.index)) + processParameterDeclarations( + instr.innerOutputs(1...), + parameters: inferSubroutineParameterList(of: op, at: instr.index)) case .callSuperMethod(let op): - let sig = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: currentSuperType())) + let sig = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: currentSuperType())) set(instr.output, sig.outputType) case .getPrivateProperty: @@ -1875,7 +2111,7 @@ public struct JSTyper: Analyzer { case .getSuperProperty(let op): set(instr.output, inferPropertyType(of: op.propertyName, on: currentSuperType())) - // TODO: support superclass property assignment + // TODO: support superclass property assignment case .beginForLoopCondition: // For now, we use only the initial type of the loop variables (at the point of the for-loop's initializer block) @@ -1916,26 +2152,46 @@ public struct JSTyper: Analyzer { // TODO: also add other macro instructions here. case .createWasmGlobal(let op): - set(instr.output, .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: op.value.toType(), isMutable: op.isMutable))) + set( + instr.output, + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType( + valueType: op.value.toType(), isMutable: op.isMutable))) case .createWasmMemory(let op): - set(instr.output, .wasmMemory(limits: op.memType.limits, isShared: op.memType.isShared, isMemory64: op.memType.isMemory64)) + set( + instr.output, + .wasmMemory( + limits: op.memType.limits, isShared: op.memType.isShared, + isMemory64: op.memType.isMemory64)) case .createWasmTable(let op): - set(instr.output, .wasmTable(wasmTableType: WasmTableType(elementType: op.tableType.elementType, limits: op.tableType.limits, isTable64: op.tableType.isTable64, knownEntries: []))) + set( + instr.output, + .wasmTable( + wasmTableType: WasmTableType( + elementType: op.tableType.elementType, limits: op.tableType.limits, + isTable64: op.tableType.isTable64, knownEntries: []))) case .createWasmJSTag(_): - set(instr.output, .object(ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true))) + set( + instr.output, + .object( + ofGroup: "WasmTag", withWasmType: WasmTagType([.wasmExternRef()], isJSTag: true) + )) case .createWasmTag(let op): - set(instr.output, .object(ofGroup: "WasmTag", withWasmType: WasmTagType(op.parameterTypes))) + set( + instr.output, + .object(ofGroup: "WasmTag", withWasmType: WasmTagType(op.parameterTypes))) case .wrapSuspending(_): // This operation takes a function but produces an object that can be called from WebAssembly. // TODO: right now this "loses" the signature of the JS function, this is unfortunate but won't break fuzzing, in the template we can just store the signature. // The WasmJsCall generator just won't work as it requires a callable. // In the future we should also attach a WasmTypeExtension to this object that stores the signature of input(0) here. - set(instr.output, .object(ofGroup:"WasmSuspendingObject")) + set(instr.output, .object(ofGroup: "WasmSuspendingObject")) case .wrapPromising(_): // Here we basically pass through the type transparently as we just annotate this exported function as "promising" @@ -1943,7 +2199,8 @@ public struct JSTyper: Analyzer { set(instr.output, type(ofInput: 0)) case .bindMethod(let op): - let signature = chooseUniform(from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) + let signature = chooseUniform( + from: inferMethodSignatures(of: op.methodName, on: instr.input(0))) // We need to prepend the this argument now. We pick .object() here as the widest type because of the following: // - a lot of builtin methods (such as the ones on `Array.prototype`) work on any JavaScript object // - [$constructor.prototype.foo.bind] is a common pattern and the `this` would be set to the type of constructor.prototype instead of the constructor's instance type. @@ -1973,7 +2230,7 @@ public struct JSTyper: Analyzer { case .wasmEndTypeGroup(_): // For now just forward the type information based on the inputs. - zip(instr.inputs, instr.outputs).forEach {input, output in + zip(instr.inputs, instr.outputs).forEach { input, output in set(output, state.type(of: input)) } finishTypeGroup() @@ -1986,11 +2243,14 @@ public struct JSTyper: Analyzer { case .wasmDefineArrayType(let op): let elementRef = op.elementType.requiredInputCount() == 1 ? instr.input(0) : nil - addArrayType(def: instr.output, elementType: op.elementType, mutability: op.mutability, elementRef: elementRef) + addArrayType( + def: instr.output, elementType: op.elementType, mutability: op.mutability, + elementRef: elementRef) case .wasmDefineStructType(let op): var inputIndex = 0 - let fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] = op.fields.map { field in + let fieldsWithRefs: [(WasmStructTypeDescription.Field, Variable?)] = op.fields.map { + field in if field.type.requiredInputCount() == 0 { return (field, nil) } else { @@ -2019,7 +2279,9 @@ public struct JSTyper: Analyzer { default: // Only simple instructions and block instruction with inner outputs are handled here - assert(instr.isNop || (instr.numOutputs == 0 || (instr.isBlock && instr.numInnerOutputs == 0))) + assert( + instr.isNop + || (instr.numOutputs == 0 || (instr.isBlock && instr.numInnerOutputs == 0))) } // We explicitly type the outputs of guarded operations as .jsAnything for two reasons: @@ -2146,7 +2408,11 @@ public struct JSTyper: Analyzer { assert(parentState === states.secondToTop.last!) // If an oldType is specified, it must match the type in the next most recent state // (but here we just check that one of the parent states contains it). - assert(oldType == nil || states.elementsStartingAtTop().contains(where: { $0.last!.types[v] == oldType! })) + assert( + oldType == nil + || states.elementsStartingAtTop().contains(where: { + $0.last!.types[v] == oldType! + })) // Set the old type in the parent state if it doesn't yet exist to satisfy "activeState[v] != nil => parentState[v] != nil". // Use .nothing to express that the variable is only defined in the child state. @@ -2164,7 +2430,10 @@ public struct JSTyper: Analyzer { } mutating func updateReturnValueType(to t: ILType) { - assert(states.elementsStartingAtTop().contains(where: { $0.last!.isSubroutineState }), "Handling a `return` but neither the active state nor any of its parent states represents a subroutine") + assert( + states.elementsStartingAtTop().contains(where: { $0.last!.isSubroutineState }), + "Handling a `return` but neither the active state nor any of its parent states represents a subroutine" + ) guard !activeState.hasReturned else { // In this case, we have already set the return value in this branch of (conditional) // execution and so are executing inside dead code, so don't update the return value. @@ -2189,7 +2458,9 @@ public struct JSTyper: Analyzer { /// Enter a new conditionally executing block and append it to the currently active group of such blocks. /// As such, either this block or one of its "sibling" blocks in the current group may execute at runtime. - mutating func enterConditionallyExecutingBlock(typeChanges: inout [(Variable, ILType)], isDefaultSwitchCaseState: Bool = false) { + mutating func enterConditionallyExecutingBlock( + typeChanges: inout [(Variable, ILType)], isDefaultSwitchCaseState: Bool = false + ) { assert(states.top.isEmpty || !states.top.last!.isSubroutineState) // Reset current state to parent state @@ -2198,7 +2469,9 @@ public struct JSTyper: Analyzer { // 1. Variable does not exist in sibling scope (t == .nothing) // 2. Variable is only local in sibling state (parent == .nothing) // 3. No type change happened - if t != .nothing && parentState.types[v] != .nothing && parentState.types[v] != overallState.types[v] { + if t != .nothing && parentState.types[v] != .nothing + && parentState.types[v] != overallState.types[v] + { typeChanges.append((v, parentState.types[v]!)) overallState.types[v] = parentState.types[v]! } @@ -2212,8 +2485,11 @@ public struct JSTyper: Analyzer { /// /// This will compute the new variable types assuming that exactly one of the blocks in the group will be executed /// at runtime and will then return to the previously active state. - mutating func endGroupOfConditionallyExecutingBlocks(typeChanges: inout [(Variable, ILType)]) { - let returnValueType = mergeNewestConditionalBlocks(typeChanges: &typeChanges, defaultReturnValueType: .nothing) + mutating func endGroupOfConditionallyExecutingBlocks( + typeChanges: inout [(Variable, ILType)] + ) { + let returnValueType = mergeNewestConditionalBlocks( + typeChanges: &typeChanges, defaultReturnValueType: .nothing) assert(returnValueType == nil) } @@ -2233,7 +2509,8 @@ public struct JSTyper: Analyzer { /// Enter a new conditionally executing block representing a default switch case. mutating func enterSwitchDefaultCase(typeChanges: inout [(Variable, ILType)]) { - enterConditionallyExecutingBlock(typeChanges: &typeChanges, isDefaultSwitchCaseState: true) + enterConditionallyExecutingBlock( + typeChanges: &typeChanges, isDefaultSwitchCaseState: true) } /// Finalizes the current group of conditionally executing blocks representing a switch construct. @@ -2276,8 +2553,13 @@ public struct JSTyper: Analyzer { /// /// This behaves similar to `endGroupOfConditionallyExecutingBlocks()` and computes variable type changes assuming that the\ /// function body may or may not have been executed, but it additionally computes and returns the inferred type for the subroutine's return value. - mutating func endSubroutine(typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType) -> ILType { - guard let returnValueType = mergeNewestConditionalBlocks(typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) else { + mutating func endSubroutine( + typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType + ) -> ILType { + guard + let returnValueType = mergeNewestConditionalBlocks( + typeChanges: &typeChanges, defaultReturnValueType: defaultReturnValueType) + else { fatalError("Leaving a subroutine that was never entered") } return returnValueType @@ -2287,17 +2569,22 @@ public struct JSTyper: Analyzer { /// /// This computes the new types assuming that exactly one of the conditional blocks will execute at runtime. If the currently /// active state is a subroutine state, this will return the final return value type, otherwise it will return nil. - private mutating func mergeNewestConditionalBlocks(typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType) -> ILType? { + private mutating func mergeNewestConditionalBlocks( + typeChanges: inout [(Variable, ILType)], defaultReturnValueType: ILType + ) -> ILType? { let statesToMerge = states.pop() - let maybeReturnValueType = computeReturnValueType(whenMerging: statesToMerge, defaultReturnValueType: defaultReturnValueType) + let maybeReturnValueType = computeReturnValueType( + whenMerging: statesToMerge, defaultReturnValueType: defaultReturnValueType) let newTypes = computeVariableTypes(whenMerging: statesToMerge) makeParentStateTheActiveStateAndUpdateVariableTypes(to: newTypes, &typeChanges) return maybeReturnValueType } - private func computeReturnValueType(whenMerging states: [State], defaultReturnValueType: ILType) -> ILType? { + private func computeReturnValueType( + whenMerging states: [State], defaultReturnValueType: ILType + ) -> ILType? { assert(states.last === activeState) // Need to compute how many sibling states have returned and what their overall return value type is. @@ -2375,7 +2662,9 @@ public struct JSTyper: Analyzer { return newTypes } - private mutating func makeParentStateTheActiveStateAndUpdateVariableTypes(to newTypes: VariableMap, _ typeChanges: inout [(Variable, ILType)]) { + private mutating func makeParentStateTheActiveStateAndUpdateVariableTypes( + to newTypes: VariableMap, _ typeChanges: inout [(Variable, ILType)] + ) { // The previous parent state is now the active state let oldParentState = parentState activeState = parentState diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 2770d45f1..958602acf 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -14,8 +14,15 @@ /// A JavaScript operation in the FuzzIL language. class JsOperation: Operation { - override init(numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .javascript, contextOpened: Context = .empty) { - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, firstVariadicInput: firstVariadicInput, attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + override init( + numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .javascript, contextOpened: Context = .empty + ) { + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + firstVariadicInput: firstVariadicInput, attributes: attributes, + requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -50,10 +57,19 @@ class GuardableOperation: JsOperation { /// is emitted around the operation or not. let isGuarded: Bool - init(isGuarded: Bool, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .javascript) { - assert(attributes.isDisjoint(with: [.isBlockStart, .isBlockEnd]), "Only simple operations can be guardable") + init( + isGuarded: Bool, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .javascript + ) { + assert( + attributes.isDisjoint(with: [.isBlockStart, .isBlockEnd]), + "Only simple operations can be guardable") self.isGuarded = isGuarded - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, firstVariadicInput: firstVariadicInput, attributes: attributes, requiredContext: requiredContext) + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + firstVariadicInput: firstVariadicInput, attributes: attributes, + requiredContext: requiredContext) } // Helper functions to enable guards. @@ -82,19 +98,25 @@ class GuardableOperation: JsOperation { case .callFunction(let op): return CallFunction(numArguments: op.numArguments, isGuarded: true) case .callFunctionWithSpread(let op): - return CallFunctionWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallFunctionWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) case .construct(let op): return Construct(numArguments: op.numArguments, isGuarded: true) case .constructWithSpread(let op): - return ConstructWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return ConstructWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) case .callMethod(let op): - return CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: true) + return CallMethod( + methodName: op.methodName, numArguments: op.numArguments, isGuarded: true) case .callMethodWithSpread(let op): - return CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, + isGuarded: true) case .callComputedMethod(let op): return CallComputedMethod(numArguments: op.numArguments, isGuarded: true) case .callComputedMethodWithSpread(let op): - return CallComputedMethodWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) + return CallComputedMethodWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: true) default: fatalError("All guardable operations should be handled") } @@ -126,19 +148,25 @@ class GuardableOperation: JsOperation { case .callFunction(let op): return CallFunction(numArguments: op.numArguments, isGuarded: false) case .callFunctionWithSpread(let op): - return CallFunctionWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallFunctionWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) case .construct(let op): return Construct(numArguments: op.numArguments, isGuarded: false) case .constructWithSpread(let op): - return ConstructWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return ConstructWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) case .callMethod(let op): - return CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: false) + return CallMethod( + methodName: op.methodName, numArguments: op.numArguments, isGuarded: false) case .callMethodWithSpread(let op): - return CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments, spreads: op.spreads, + isGuarded: false) case .callComputedMethod(let op): return CallComputedMethod(numArguments: op.numArguments, isGuarded: false) case .callComputedMethodWithSpread(let op): - return CallComputedMethodWithSpread(numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) + return CallComputedMethodWithSpread( + numArguments: op.numArguments, spreads: op.spreads, isGuarded: false) default: fatalError("All guardable operations should be handled") } @@ -272,7 +300,7 @@ final class LoadArguments: JsOperation { /// baz += "bla"; /// print(baz); /// -public enum NamedVariableDeclarationMode : CaseIterable { +public enum NamedVariableDeclarationMode: CaseIterable { // The variable is assumed to already exist and therefore is not declared again. // This is for example used for global variables and builtins, but also to support // variable and function hoisting where an identifier is used before it is defined. @@ -304,7 +332,8 @@ final class CreateNamedVariable: JsOperation { init(_ name: String, declarationMode: NamedVariableDeclarationMode) { self.variableName = name self.declarationMode = declarationMode - super.init(numInputs: declarationMode == .none ? 0 : 1, numOutputs: 1, attributes: .isMutable) + super.init( + numInputs: declarationMode == .none ? 0 : 1, numOutputs: 1, attributes: .isMutable) } } @@ -405,42 +434,44 @@ public struct RegExpFlags: OptionSet, Hashable { return flags } - static let empty = RegExpFlags([]) - static let caseInsensitive = RegExpFlags(rawValue: 1 << 0) // i - static let global = RegExpFlags(rawValue: 1 << 1) // g - static let multiline = RegExpFlags(rawValue: 1 << 2) // m - static let dotall = RegExpFlags(rawValue: 1 << 3) // s - static let unicode = RegExpFlags(rawValue: 1 << 4) // u - static let sticky = RegExpFlags(rawValue: 1 << 5) // y - static let hasIndices = RegExpFlags(rawValue: 1 << 6) // d - static let unicodeSets = RegExpFlags(rawValue: 1 << 7) // v + static let empty = RegExpFlags([]) + static let caseInsensitive = RegExpFlags(rawValue: 1 << 0) // i + static let global = RegExpFlags(rawValue: 1 << 1) // g + static let multiline = RegExpFlags(rawValue: 1 << 2) // m + static let dotall = RegExpFlags(rawValue: 1 << 3) // s + static let unicode = RegExpFlags(rawValue: 1 << 4) // u + static let sticky = RegExpFlags(rawValue: 1 << 5) // y + static let hasIndices = RegExpFlags(rawValue: 1 << 6) // d + static let unicodeSets = RegExpFlags(rawValue: 1 << 7) // v public static func random() -> RegExpFlags { - var flags = RegExpFlags(rawValue: UInt32.random(in: 0..<(1<<8))) + var flags = RegExpFlags(rawValue: UInt32.random(in: 0..<(1 << 8))) if flags.contains(.unicode) && flags.contains(.unicodeSets) { // clear one of them as they are mutually exclusive, they will throw a runtime exception if used together. - withEqualProbability({ - flags.subtract(.unicode) - }, { - flags.subtract(.unicodeSets) - }) + withEqualProbability( + { + flags.subtract(.unicode) + }, + { + flags.subtract(.unicodeSets) + }) } return flags } - private static let flagToCharDict: [RegExpFlags:String] = [ - .empty: "", + private static let flagToCharDict: [RegExpFlags: String] = [ + .empty: "", .caseInsensitive: "i", - .global: "g", - .multiline: "m", - .dotall: "s", - .unicode: "u", - .sticky: "y", - .hasIndices: "d", - .unicodeSets: "v", + .global: "g", + .multiline: "m", + .dotall: "s", + .unicode: "u", + .sticky: "y", + .hasIndices: "d", + .unicodeSets: "v", ] - static func |(lhs: RegExpFlags, rhs: RegExpFlags) -> RegExpFlags { + static func | (lhs: RegExpFlags, rhs: RegExpFlags) -> RegExpFlags { return RegExpFlags(rawValue: lhs.rawValue | rhs.rawValue) } } @@ -528,7 +559,6 @@ final class ObjectLiteralAddComputedProperty: JsOperation { } } - // A spread operation (e.g. `...v13,`) copying the properties from another object final class ObjectLiteralCopyProperties: JsOperation { override var opcode: Opcode { .objectLiteralCopyProperties(self) } @@ -557,7 +587,10 @@ final class BeginObjectLiteralMethod: BeginAnySubroutine { init(methodName: String, parameters: Parameters) { self.methodName = methodName // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -571,7 +604,10 @@ final class BeginObjectLiteralComputedMethod: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -588,7 +624,10 @@ final class BeginObjectLiteralGetter: BeginAnySubroutine { init(propertyName: String) { self.propertyName = propertyName // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 0), numInnerOutputs: 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -602,7 +641,10 @@ final class BeginObjectLiteralComputedGetter: BeginAnySubroutine { init() { // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -619,7 +661,10 @@ final class BeginObjectLiteralSetter: BeginAnySubroutine { init(propertyName: String) { self.propertyName = propertyName // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 1), numInnerOutputs: 2, + attributes: [.isBlockStart, .isMutable], requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -633,7 +678,10 @@ final class BeginObjectLiteralComputedSetter: BeginAnySubroutine { init() { // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) + super.init( + parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, + attributes: .isBlockStart, requiredContext: .objectLiteral, + contextOpened: [.javascript, .subroutine, .method]) } } @@ -707,7 +755,9 @@ final class BeginClassDefinition: JsOperation { init(hasSuperclass: Bool, isExpression: Bool) { self.hasSuperclass = hasSuperclass self.isExpression = isExpression - super.init(numInputs: hasSuperclass ? 1 : 0, numOutputs: 1, attributes: .isBlockStart, contextOpened: .classDefinition) + super.init( + numInputs: hasSuperclass ? 1 : 0, numOutputs: 1, attributes: .isBlockStart, + contextOpened: .classDefinition) } } @@ -716,7 +766,10 @@ final class BeginClassConstructor: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart, .isSingular], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart, .isSingular], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -736,7 +789,8 @@ final class ClassAddProperty: JsOperation { init(propertyName: String, hasValue: Bool, isStatic: Bool) { self.propertyName = propertyName self.isStatic = isStatic - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + super.init( + numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } @@ -752,7 +806,8 @@ final class ClassAddElement: JsOperation { init(index: Int64, hasValue: Bool, isStatic: Bool) { self.index = index self.isStatic = isStatic - super.init(numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) + super.init( + numInputs: hasValue ? 1 : 0, attributes: .isMutable, requiredContext: .classDefinition) } } @@ -780,7 +835,10 @@ final class BeginClassMethod: BeginAnySubroutine { self.methodName = methodName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: [.isMutable, .isBlockStart], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -795,7 +853,10 @@ final class BeginClassComputedMethod: BeginAnySubroutine { init(parameters: Parameters, isStatic: Bool) { self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + attributes: [.isBlockStart], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -813,7 +874,10 @@ final class BeginClassGetter: BeginAnySubroutine { self.propertyName = propertyName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 0), numInnerOutputs: 1, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 0), numInnerOutputs: 1, + attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -829,7 +893,10 @@ final class BeginClassComputedGetter: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 0), numInputs: 1, numInnerOutputs: 1, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -847,7 +914,10 @@ final class BeginClassSetter: BeginAnySubroutine { self.propertyName = propertyName self.isStatic = isStatic // First inner output is the explicit |this| parameter - super.init(parameters: Parameters(count: 1), numInnerOutputs: 2, attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 1), numInnerOutputs: 2, + attributes: [.isBlockStart, .isMutable], requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -863,7 +933,10 @@ final class BeginClassComputedSetter: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter // The first input is the computed property name - super.init(parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: Parameters(count: 1), numInputs: 1, numInnerOutputs: 2, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -877,7 +950,9 @@ final class BeginClassStaticInitializer: JsOperation { init() { // Inner output is the explicit |this| parameter // Static initializer blocks do not have .subroutine context as `return` is disallowed inside of them. - super.init(numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .method, .classMethod]) + super.init( + numInnerOutputs: 1, attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .method, .classMethod]) } } @@ -918,7 +993,10 @@ final class BeginClassPrivateMethod: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter. // See comment in ClassAddPrivateProperty for why this operation isn't mutable. - super.init(parameters: parameters, numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) + super.init( + parameters: parameters, numInnerOutputs: parameters.count + 1, + attributes: .isBlockStart, requiredContext: .classDefinition, + contextOpened: [.javascript, .subroutine, .method, .classMethod]) } } @@ -942,7 +1020,9 @@ final class CreateArray: JsOperation { } init(numInitialValues: Int) { - super.init(numInputs: numInitialValues, numOutputs: 1, firstVariadicInput: 0, attributes: [.isVariadic]) + super.init( + numInputs: numInitialValues, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isVariadic]) } } @@ -980,7 +1060,8 @@ final class CreateArrayWithSpread: JsOperation { if spreads.count > 0 { flags.insert(.isMutable) } - super.init(numInputs: spreads.count, numOutputs: 1, firstVariadicInput: 0, attributes: flags) + super.init( + numInputs: spreads.count, numOutputs: 1, firstVariadicInput: 0, attributes: flags) } } @@ -997,7 +1078,9 @@ final class CreateTemplateString: JsOperation { init(parts: [String]) { assert(parts.count > 0) self.parts = parts - super.init(numInputs: parts.count - 1, numOutputs: 1, firstVariadicInput: 0, attributes: [.isMutable, .isVariadic]) + super.init( + numInputs: parts.count - 1, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isMutable, .isVariadic]) } } @@ -1054,9 +1137,9 @@ public struct PropertyFlags: OptionSet { self.rawValue = rawValue } - static let writable = PropertyFlags(rawValue: 1 << 0) - static let configurable = PropertyFlags(rawValue: 1 << 1) - static let enumerable = PropertyFlags(rawValue: 1 << 2) + static let writable = PropertyFlags(rawValue: 1 << 0) + static let configurable = PropertyFlags(rawValue: 1 << 1) + static let enumerable = PropertyFlags(rawValue: 1 << 2) public static func random() -> PropertyFlags { return PropertyFlags(rawValue: UInt8.random(in: 0..<8)) @@ -1255,11 +1338,17 @@ public struct Parameters { class BeginAnySubroutine: JsOperation { let parameters: Parameters - init(parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, contextOpened: Context) { + init( + parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, + contextOpened: Context + ) { assert(contextOpened.contains(.subroutine)) assert(attributes.contains(.isBlockStart)) self.parameters = parameters - super.init(numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + super.init( + numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, + attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -1274,11 +1363,12 @@ class EndAnySubroutine: JsOperation { // Functions beginnings are not considered mutable since it likely makes little sense to change things like the number of parameters. class BeginAnyFunction: BeginAnySubroutine { init(parameters: Parameters, contextOpened: Context = [.javascript, .subroutine]) { - super.init(parameters: parameters, - numInputs: 0, - numOutputs: 1, - numInnerOutputs: parameters.count, - contextOpened: contextOpened) + super.init( + parameters: parameters, + numInputs: 0, + numOutputs: 1, + numInnerOutputs: parameters.count, + contextOpened: contextOpened) } } class EndAnyFunction: EndAnySubroutine {} @@ -1292,7 +1382,10 @@ class BeginAnyNamedFunction: BeginAnyFunction { // lifter cannot guarantee that there are no name collisions with other named functions. let functionName: String? - init(parameters: Parameters, functionName: String?, contextOpened: Context = [.javascript, .subroutine]) { + init( + parameters: Parameters, functionName: String?, + contextOpened: Context = [.javascript, .subroutine] + ) { assert(functionName == nil || !functionName!.isEmpty) self.functionName = functionName super.init(parameters: parameters, contextOpened: contextOpened) @@ -1320,7 +1413,9 @@ final class BeginGeneratorFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginGeneratorFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .generatorFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .generatorFunction]) } } final class EndGeneratorFunction: EndAnyFunction { @@ -1332,7 +1427,9 @@ final class BeginAsyncFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginAsyncFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .asyncFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .asyncFunction]) } } final class EndAsyncFunction: EndAnyFunction { @@ -1344,7 +1441,8 @@ final class BeginAsyncArrowFunction: BeginAnyFunction { override var opcode: Opcode { .beginAsyncArrowFunction(self) } init(parameters: Parameters) { - super.init(parameters: parameters, contextOpened: [.javascript, .subroutine, .asyncFunction]) + super.init( + parameters: parameters, contextOpened: [.javascript, .subroutine, .asyncFunction]) } } final class EndAsyncArrowFunction: EndAnyFunction { @@ -1356,7 +1454,9 @@ final class BeginAsyncGeneratorFunction: BeginAnyNamedFunction { override var opcode: Opcode { .beginAsyncGeneratorFunction(self) } init(parameters: Parameters, functionName: String?) { - super.init(parameters: parameters, functionName: functionName, contextOpened: [.javascript, .subroutine, .asyncFunction, .generatorFunction]) + super.init( + parameters: parameters, functionName: functionName, + contextOpened: [.javascript, .subroutine, .asyncFunction, .generatorFunction]) } } final class EndAsyncGeneratorFunction: EndAnyFunction { @@ -1370,7 +1470,9 @@ final class BeginConstructor: BeginAnySubroutine { override var opcode: Opcode { .beginConstructor(self) } init(parameters: Parameters) { - super.init(parameters: parameters, numOutputs: 1, numInnerOutputs: parameters.count + 1, contextOpened: [.javascript, .subroutine]) + super.init( + parameters: parameters, numOutputs: 1, numInnerOutputs: parameters.count + 1, + contextOpened: [.javascript, .subroutine]) } } final class EndConstructor: EndAnySubroutine { @@ -1412,7 +1514,9 @@ final class Return: JsOperation { } init(hasReturnValue: Bool) { - super.init(numInputs: hasReturnValue ? 1 : 0, attributes: [.isJump], requiredContext: [.javascript, .subroutine]) + super.init( + numInputs: hasReturnValue ? 1 : 0, attributes: [.isJump], + requiredContext: [.javascript, .subroutine]) } } @@ -1426,7 +1530,9 @@ final class Yield: JsOperation { } init(hasArgument: Bool) { - super.init(numInputs: hasArgument ? 1 : 0, numOutputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) + super.init( + numInputs: hasArgument ? 1 : 0, numOutputs: 1, attributes: [], + requiredContext: [.javascript, .generatorFunction]) } } @@ -1435,7 +1541,8 @@ final class YieldEach: JsOperation { override var opcode: Opcode { .yieldEach(self) } init() { - super.init(numInputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) + super.init( + numInputs: 1, attributes: [], requiredContext: [.javascript, .generatorFunction]) } } @@ -1443,7 +1550,9 @@ final class Await: JsOperation { override var opcode: Opcode { .await(self) } init() { - super.init(numInputs: 1, numOutputs: 1, attributes: [], requiredContext: [.javascript, .asyncFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [], + requiredContext: [.javascript, .asyncFunction]) } } @@ -1456,7 +1565,9 @@ final class CallFunction: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The called function is the first input. - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall]) } } @@ -1474,7 +1585,9 @@ final class CallFunctionWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The called function is the first input. - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall, .isMutable]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall, .isMutable]) } } @@ -1487,7 +1600,9 @@ final class Construct: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The constructor is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall]) } } @@ -1505,7 +1620,9 @@ final class ConstructWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The constructor is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall, .isMutable]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall, .isMutable]) } } @@ -1521,7 +1638,9 @@ final class CallMethod: GuardableOperation { init(methodName: String, numArguments: Int, isGuarded: Bool) { self.methodName = methodName // The reference object is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isMutable, .isVariadic, .isCall]) } } @@ -1541,7 +1660,9 @@ final class CallMethodWithSpread: GuardableOperation { self.methodName = methodName self.spreads = spreads // The reference object is the first input - super.init(isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isMutable, .isVariadic, .isCall]) } } @@ -1554,7 +1675,9 @@ final class CallComputedMethod: GuardableOperation { init(numArguments: Int, isGuarded: Bool) { // The reference object is the first input and the method name is the second input - super.init(isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, attributes: [.isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, + attributes: [.isVariadic, .isCall]) } } @@ -1572,19 +1695,21 @@ final class CallComputedMethodWithSpread: GuardableOperation { assert(spreads.count == numArguments) self.spreads = spreads // The reference object is the first input and the method name is the second input - super.init(isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, attributes: [.isMutable, .isVariadic, .isCall]) + super.init( + isGuarded: isGuarded, numInputs: numArguments + 2, numOutputs: 1, firstVariadicInput: 2, + attributes: [.isMutable, .isVariadic, .isCall]) } } public enum UnaryOperator: String, CaseIterable { - case PreInc = "++" - case PreDec = "--" - case PostInc = "++ " // Raw value must be unique - case PostDec = "-- " // Raw value must be unique + case PreInc = "++" + case PreDec = "--" + case PostInc = "++ " // Raw value must be unique + case PostDec = "-- " // Raw value must be unique case LogicalNot = "!" case BitwiseNot = "~" - case Plus = "+" - case Minus = "-" + case Plus = "+" + case Minus = "-" var token: String { return self.rawValue.trimmingCharacters(in: [" "]) @@ -1611,19 +1736,19 @@ final class UnaryOperation: JsOperation { } public enum BinaryOperator: String, CaseIterable { - case Add = "+" - case Sub = "-" - case Mul = "*" - case Div = "/" - case Mod = "%" - case BitAnd = "&" - case BitOr = "|" + case Add = "+" + case Sub = "-" + case Mul = "*" + case Div = "/" + case Mod = "%" + case BitAnd = "&" + case BitOr = "|" case LogicAnd = "&&" - case LogicOr = "||" - case Xor = "^" - case LShift = "<<" - case RShift = ">>" - case Exp = "**" + case LogicOr = "||" + case Xor = "^" + case LShift = "<<" + case RShift = ">>" + case Exp = "**" case UnRShift = ">>>" // Nullish coalescing operator (??) case NullCoalesce = "??" @@ -1693,7 +1818,9 @@ final class DestructArray: JsOperation { init(indices: [Int64], lastIsRest: Bool) { assert(indices == indices.sorted(), "Indices must be sorted in ascending order") assert(indices.count == Set(indices).count, "Indices must not have duplicates") - assert(!lastIsRest || !indices.isEmpty, "DestructArray with lastIsRest requires at least one index") + assert( + !lastIsRest || !indices.isEmpty, + "DestructArray with lastIsRest requires at least one index") self.indices = indices self.lastIsRest = lastIsRest super.init(numInputs: 1, numOutputs: indices.count) @@ -1707,10 +1834,12 @@ final class DestructArrayAndReassign: JsOperation { let indices: [Int64] let lastIsRest: Bool - init(indices: [Int64], lastIsRest:Bool) { + init(indices: [Int64], lastIsRest: Bool) { assert(indices == indices.sorted(), "Indices must be sorted in ascending order") assert(indices.count == Set(indices).count, "Indices must not have duplicates") - assert(!lastIsRest || !indices.isEmpty, "DestructArray with lastIsRest requires at least one index") + assert( + !lastIsRest || !indices.isEmpty, + "DestructArray with lastIsRest requires at least one index") self.indices = indices self.lastIsRest = lastIsRest // The first input is the array being destructed @@ -1740,7 +1869,7 @@ final class DestructObjectAndReassign: JsOperation { let properties: [String] let hasRestElement: Bool - init(properties: [String], hasRestElement:Bool) { + init(properties: [String], hasRestElement: Bool) { self.properties = properties self.hasRestElement = hasRestElement // The first input is the object being destructed @@ -1750,13 +1879,13 @@ final class DestructObjectAndReassign: JsOperation { // This array must be kept in sync with the Comparator Enum in operations.proto public enum Comparator: String, CaseIterable { - case equal = "==" - case strictEqual = "===" - case notEqual = "!=" - case strictNotEqual = "!==" - case lessThan = "<" - case lessThanOrEqual = "<=" - case greaterThan = ">" + case equal = "==" + case strictEqual = "===" + case notEqual = "!=" + case strictNotEqual = "!==" + case lessThan = "<" + case lessThanOrEqual = "<=" + case greaterThan = ">" case greaterThanOrEqual = ">=" var token: String { @@ -1797,7 +1926,9 @@ final class BeginWith: JsOperation { override var opcode: Opcode { .beginWith(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript]) } } @@ -1817,7 +1948,9 @@ final class CallSuperConstructor: JsOperation { } init(numArguments: Int) { - super.init(numInputs: numArguments, firstVariadicInput: 0, attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .method]) + super.init( + numInputs: numArguments, firstVariadicInput: 0, attributes: [.isVariadic, .isCall], + requiredContext: [.javascript, .method]) } } @@ -1832,7 +1965,9 @@ final class CallSuperMethod: JsOperation { init(methodName: String, numArguments: Int) { self.methodName = methodName - super.init(numInputs: numArguments, numOutputs: 1, firstVariadicInput: 0, attributes: [.isCall, .isMutable, .isVariadic], requiredContext: [.javascript, .method]) + super.init( + numInputs: numArguments, numOutputs: 1, firstVariadicInput: 0, + attributes: [.isCall, .isMutable, .isVariadic], requiredContext: [.javascript, .method]) } } @@ -1889,7 +2024,9 @@ final class CallPrivateMethod: JsOperation { self.methodName = methodName // The reference object is the first input. // See comment in GetPrivateProperty for why these aren't mutable. - super.init(numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .classMethod]) + super.init( + numInputs: numArguments + 1, numOutputs: 1, firstVariadicInput: 1, + attributes: [.isVariadic, .isCall], requiredContext: [.javascript, .classMethod]) } } @@ -1931,7 +2068,6 @@ final class GetComputedSuperProperty: JsOperation { } } - final class UpdateSuperProperty: JsOperation { override var opcode: Opcode { .updateSuperProperty(self) } @@ -1953,7 +2089,9 @@ final class BeginIf: JsOperation { init(inverted: Bool) { self.inverted = inverted - super.init(numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -1961,7 +2099,9 @@ final class BeginElse: JsOperation { override var opcode: Opcode { .beginElse(self) } init() { - super.init(attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2018,7 +2158,8 @@ final class BeginWhileLoopHeader: JsOperation { override var opcode: Opcode { .beginWhileLoopHeader(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2027,7 +2168,9 @@ final class BeginWhileLoopBody: JsOperation { override var opcode: Opcode { .beginWhileLoopBody(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2043,7 +2186,9 @@ final class BeginDoWhileLoopBody: JsOperation { override var opcode: Opcode { .beginDoWhileLoopBody(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2051,7 +2196,9 @@ final class BeginDoWhileLoopHeader: JsOperation { override var opcode: Opcode { .beginDoWhileLoopHeader(self) } init() { - super.init(attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2100,7 +2247,8 @@ final class BeginForLoopInitializer: JsOperation { override var opcode: Opcode { .beginForLoopInitializer(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2112,7 +2260,10 @@ final class BeginForLoopCondition: JsOperation { } init(numLoopVariables: Int) { - super.init(numInputs: numLoopVariables, numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: numLoopVariables, numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2124,7 +2275,10 @@ final class BeginForLoopAfterthought: JsOperation { } init(numLoopVariables: Int) { - super.init(numInputs: 1, numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + numInputs: 1, numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: .javascript) } } @@ -2136,7 +2290,10 @@ final class BeginForLoopBody: JsOperation { } init(numLoopVariables: Int) { - super.init(numInnerOutputs: numLoopVariables, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInnerOutputs: numLoopVariables, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2152,7 +2309,10 @@ final class BeginForInLoop: JsOperation { override var opcode: Opcode { .beginForInLoop(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2168,7 +2328,10 @@ final class BeginForOfLoop: JsOperation { override var opcode: Opcode { .beginForOfLoop(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2182,7 +2345,10 @@ final class BeginForOfLoopWithDestruct: JsOperation { assert(indices.count >= 1) self.indices = indices self.hasRestElement = hasRestElement - super.init(numInputs: 1, numInnerOutputs: indices.count, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInputs: 1, numInnerOutputs: indices.count, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2210,7 +2376,10 @@ final class BeginRepeatLoop: JsOperation { init(iterations: Int, exposesLoopCounter: Bool = true) { self.iterations = iterations - super.init(numInnerOutputs: exposesLoopCounter ? 1 : 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init( + numInnerOutputs: exposesLoopCounter ? 1 : 0, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop]) } } @@ -2250,7 +2419,9 @@ final class BeginCatch: JsOperation { override var opcode: Opcode { .beginCatch(self) } init() { - super.init(numInnerOutputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) + super.init( + numInnerOutputs: 1, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) } } @@ -2300,7 +2471,8 @@ final class BeginBlockStatement: JsOperation { override var opcode: Opcode { .beginBlockStatement(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init( + attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) } } @@ -2374,7 +2546,9 @@ final class BeginSwitchCase: JsOperation { override var opcode: Opcode { .beginSwitchCase(self) } init() { - super.init(numInputs: 1, attributes: [.isBlockStart, .resumesSurroundingContext], requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) + super.init( + numInputs: 1, attributes: [.isBlockStart, .resumesSurroundingContext], + requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) } } @@ -2385,7 +2559,9 @@ final class BeginSwitchDefaultCase: JsOperation { override var opcode: Opcode { .beginSwitchDefaultCase(self) } init() { - super.init(attributes: [.isBlockStart, .resumesSurroundingContext, .isSingular], requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) + super.init( + attributes: [.isBlockStart, .resumesSurroundingContext, .isSingular], + requiredContext: .switchBlock, contextOpened: [.switchCase, .javascript]) } } @@ -2429,7 +2605,9 @@ final class LoadNewTarget: JsOperation { final class BeginWasmModule: JsOperation { override var opcode: Opcode { .beginWasmModule(self) } init() { - super.init(numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], contextOpened: [.wasm]) + super.init( + numOutputs: 0, attributes: [.isBlockStart], requiredContext: [.javascript], + contextOpened: [.wasm]) } } @@ -2476,7 +2654,8 @@ class BindFunction: JsOperation { override var opcode: Opcode { .bindFunction(self) } init(numInputs: Int) { - super.init(numInputs: numInputs, numOutputs: 1, firstVariadicInput: 1, + super.init( + numInputs: numInputs, numOutputs: 1, firstVariadicInput: 1, attributes: [.isVariadic], requiredContext: .javascript) } } @@ -2497,14 +2676,14 @@ class CreateWasmGlobal: JsOperation { // This instruction is used to create strongly typed WasmMemories in the JS world that can be imported by a WasmModule. class CreateWasmMemory: JsOperation { - override var opcode: Opcode { .createWasmMemory(self) } + override var opcode: Opcode { .createWasmMemory(self) } - let memType: WasmMemoryType + let memType: WasmMemoryType - init(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) { - self.memType = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) - super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) - } + init(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) { + self.memType = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) + super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) + } } // This instruction is used to create strongly typed WasmTables in the JS world that can be imported by a WasmModule. @@ -2515,7 +2694,8 @@ class CreateWasmTable: JsOperation { let tableType: WasmTableType init(elementType: ILType, limits: Limits, isTable64: Bool) { - self.tableType = WasmTableType(elementType: elementType, limits: limits, isTable64: isTable64, knownEntries: []) + self.tableType = WasmTableType( + elementType: elementType, limits: limits, isTable64: isTable64, knownEntries: []) super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.javascript]) } } @@ -2538,13 +2718,14 @@ class CreateWasmTag: JsOperation { } } -class WasmTypeOperation : Operation {} +class WasmTypeOperation: Operation {} class WasmBeginTypeGroup: WasmTypeOperation { override var opcode: Opcode { .wasmBeginTypeGroup(self) } init() { - super.init(attributes: [.isBlockStart], requiredContext: [.javascript], - contextOpened: [.wasmTypeGroup]) + super.init( + attributes: [.isBlockStart], requiredContext: [.javascript], + contextOpened: [.wasmTypeGroup]) } } @@ -2555,21 +2736,24 @@ class WasmEndTypeGroup: WasmTypeOperation { } init(typesCount: Int) { - super.init(numInputs: typesCount, numOutputs: typesCount, firstVariadicInput: 0, - attributes: [.isBlockEnd, .resumesSurroundingContext, .isVariadic, .isNotInputMutable], - requiredContext: [.wasmTypeGroup]) + super.init( + numInputs: typesCount, numOutputs: typesCount, firstVariadicInput: 0, + attributes: [.isBlockEnd, .resumesSurroundingContext, .isVariadic, .isNotInputMutable], + requiredContext: [.wasmTypeGroup]) } } class WasmDefineArrayType: WasmTypeOperation { override var opcode: Opcode { .wasmDefineArrayType(self) } - let elementType : ILType + let elementType: ILType let mutability: Bool init(elementType: ILType, mutability: Bool) { self.elementType = elementType self.mutability = mutability - super.init(numInputs: elementType.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmTypeGroup]) + super.init( + numInputs: elementType.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmTypeGroup]) } } @@ -2594,7 +2778,8 @@ class WasmDefineSignatureType: WasmTypeOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasmTypeGroup]) } } @@ -2644,7 +2829,9 @@ final class Explore: JsInternalOperation { init(id: String, numArguments: Int, rngSeed: UInt32) { // IDs should be valid JavaScript property names since they will typically be used in that way. - assert(id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) && id.contains(where: { $0.isLetter })) + assert( + id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) + && id.contains(where: { $0.isLetter })) self.id = id self.rngSeed = rngSeed @@ -2661,7 +2848,9 @@ final class Probe: JsInternalOperation { init(id: String) { // IDs should be valid JavaScript property names since they will typically be used in that way. - assert(id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) && id.contains(where: { $0.isLetter })) + assert( + id.allSatisfy({ $0.isASCII && ($0.isLetter || $0.isNumber) }) + && id.contains(where: { $0.isLetter })) self.id = id super.init(numInputs: 1) @@ -2685,7 +2874,8 @@ final class Fixup: JsInternalOperation { return numOutputs == 1 } - init(id: String, action: String, originalOperation: String, numArguments: Int, hasOutput: Bool) { + init(id: String, action: String, originalOperation: String, numArguments: Int, hasOutput: Bool) + { self.id = id self.action = action self.originalOperation = originalOperation diff --git a/Sources/Fuzzilli/FuzzIL/Operation.swift b/Sources/Fuzzilli/FuzzIL/Operation.swift index 6d5e12860..2a4f9b910 100644 --- a/Sources/Fuzzilli/FuzzIL/Operation.swift +++ b/Sources/Fuzzilli/FuzzIL/Operation.swift @@ -58,7 +58,11 @@ public class Operation { fatalError("Operations must override the opcode getter. \(self.name) does not") } - init(numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, firstVariadicInput: Int = -1, attributes: Attributes = [], requiredContext: Context = .empty, contextOpened: Context = .empty) { + init( + numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, + firstVariadicInput: Int = -1, attributes: Attributes = [], + requiredContext: Context = .empty, contextOpened: Context = .empty + ) { assert(attributes.contains(.isVariadic) == (firstVariadicInput != -1)) assert(firstVariadicInput == -1 || firstVariadicInput <= numInputs) assert(contextOpened == .empty || attributes.contains(.isBlockStart)) @@ -87,28 +91,28 @@ public class Operation { // is the isStrict member of function definitions: the value space is two // (true or false) and mutating the isStrict member is probably not very // interesting compared to mutations on other operations. - static let isMutable = Attributes(rawValue: 1 << 0) + static let isMutable = Attributes(rawValue: 1 << 0) // The operation performs a subroutine call. - static let isCall = Attributes(rawValue: 1 << 1) + static let isCall = Attributes(rawValue: 1 << 1) // The operation is the start of a block. - static let isBlockStart = Attributes(rawValue: 1 << 2) + static let isBlockStart = Attributes(rawValue: 1 << 2) // The operation is the end of a block. - static let isBlockEnd = Attributes(rawValue: 1 << 3) + static let isBlockEnd = Attributes(rawValue: 1 << 3) // The operation is used for internal purposes and should not // be visible to the user (e.g. appear in emitted samples). - static let isInternal = Attributes(rawValue: 1 << 4) + static let isInternal = Attributes(rawValue: 1 << 4) // The operation behaves like an (unconditional) jump. Any // code until the next block end is therefore dead code. - static let isJump = Attributes(rawValue: 1 << 5) + static let isJump = Attributes(rawValue: 1 << 5) // The operation can take a variable number of inputs. // The firstVariadicInput contains the index of the first variadic input. - static let isVariadic = Attributes(rawValue: 1 << 6) + static let isVariadic = Attributes(rawValue: 1 << 6) // This operation should occur at most once in its surrounding context. // If there are multiple singular operations in the same context, then @@ -119,7 +123,7 @@ public class Operation { // block instead of ignoring all but the first one. However, that would // complicate code generation and splicing which cannot generally // uphold this property. - static let isSingular = Attributes(rawValue: 1 << 7) + static let isSingular = Attributes(rawValue: 1 << 7) // The operation propagates the surrounding context. // Most control-flow operations keep their surrounding context active. @@ -127,15 +131,15 @@ public class Operation { // The instruction resumes the context from before its parent context. // This is useful for example for BeginSwitch and BeginSwitchCase. - static let resumesSurroundingContext = Attributes(rawValue: 1 << 9) + static let resumesSurroundingContext = Attributes(rawValue: 1 << 9) // The instruction is a Nop operation. - static let isNop = Attributes(rawValue: 1 << 10) + static let isNop = Attributes(rawValue: 1 << 10) // The instruction cannot be mutated with the input mutator // This is not the case for most instructions except wasm instructions where we need to // preserve types for correctness. Note: this is different than the .isMutable attribute. - static let isNotInputMutable = Attributes(rawValue: 1 << 11) + static let isNotInputMutable = Attributes(rawValue: 1 << 11) } } @@ -154,7 +158,6 @@ final class Nop: Operation { } } - // Expose the name of an operation as instance and class variable extension Operation { var name: String { diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index b8c8bec2e..9b2c81122 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -59,7 +59,10 @@ public final class Program: CustomStringConvertible { } /// Construct a program with the given code and type information. - public convenience init(code: Code, parent: Program? = nil, comments: ProgramComments = ProgramComments(), contributors: Contributors = Contributors()) { + public convenience init( + code: Code, parent: Program? = nil, comments: ProgramComments = ProgramComments(), + contributors: Contributors = Contributors() + ) { // We should never see instructions with set flags here, as Flags are currently only used temporarily (e.g. Minimizer) assert(code.allSatisfy { instr in instr.flags == Instruction.Flags.empty }) self.init(with: code) @@ -151,14 +154,16 @@ extension Program: ProtobufConvertible { do { code.append(try Instruction(from: protoInstr, with: opCache)) } catch FuzzilliError.instructionDecodingError(let reason) { - throw FuzzilliError.programDecodingError("could not decode instruction #\(i): \(reason)") + throw FuzzilliError.programDecodingError( + "could not decode instruction #\(i): \(reason)") } } do { try code.check() } catch FuzzilliError.codeVerificationError(let reason) { - throw FuzzilliError.programDecodingError("decoded code is not statically valid: \(reason)") + throw FuzzilliError.programDecodingError( + "decoded code is not statically valid: \(reason)") } self.init(code: code) diff --git a/Sources/Fuzzilli/FuzzIL/ProgramComments.swift b/Sources/Fuzzilli/FuzzIL/ProgramComments.swift index 90a9dfd97..e53e14fc9 100644 --- a/Sources/Fuzzilli/FuzzIL/ProgramComments.swift +++ b/Sources/Fuzzilli/FuzzIL/ProgramComments.swift @@ -37,7 +37,7 @@ public struct ProgramComments { } } - private var comments: [Int32:String] = [:] + private var comments: [Int32: String] = [:] public init() {} diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index 567d58756..f8a60233c 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - // Miscellaneous semantics of FuzzIL. Also see JSTyper for execution semantics of operations. extension Operation { @@ -24,20 +23,20 @@ extension Operation { switch opcode { case .callFunction, - .callMethod, - .callComputedMethod: - // We assume that a constructor doesn't modify its arguments when called. + .callMethod, + .callComputedMethod: + // We assume that a constructor doesn't modify its arguments when called. return true case .setProperty, - .updateProperty, - .setElement, - .updateElement, - .setComputedProperty, - .updateComputedProperty, - .yield, - .deleteProperty, - .deleteComputedProperty, - .deleteElement: + .updateProperty, + .setElement, + .updateElement, + .setComputedProperty, + .updateComputedProperty, + .yield, + .deleteProperty, + .deleteComputedProperty, + .deleteElement: return inputIdx == 0 default: return false @@ -47,12 +46,12 @@ extension Operation { func reassigns(input inputIdx: Int) -> Bool { switch opcode { case .reassign, - .update: + .update: return inputIdx == 0 case .unaryOperation(let op): return op.op.reassignsInput case .destructArrayAndReassign, - .destructObjectAndReassign: + .destructObjectAndReassign: return inputIdx != 0 default: return false @@ -117,7 +116,7 @@ extension Instruction { case (.loadNull, .loadNull): canFold = true case (.loadRegExp(let op1), .loadRegExp(let op2)): - canFold = op1.pattern == op2.pattern && op1.flags == op2.flags + canFold = op1.pattern == op2.pattern && op1.flags == op2.flags default: assert(self.op.name != other.op.name) } @@ -145,7 +144,7 @@ extension Operation { case .beginObjectLiteralComputedSetter: return endOp is EndObjectLiteralComputedSetter case .beginClassDefinition: - return endOp is EndClassDefinition + return endOp is EndClassDefinition case .beginClassConstructor: return endOp is EndClassConstructor case .beginClassMethod: @@ -187,7 +186,7 @@ extension Operation { case .beginSwitch: return endOp is EndSwitch case .beginSwitchCase, - .beginSwitchDefaultCase: + .beginSwitchDefaultCase: return endOp is EndSwitchCase case .beginWhileLoopHeader: return endOp is BeginWhileLoopBody @@ -208,7 +207,7 @@ extension Operation { case .beginForInLoop: return endOp is EndForInLoop case .beginForOfLoop, - .beginForOfLoopWithDestruct: + .beginForOfLoopWithDestruct: return endOp is EndForOfLoop case .beginRepeatLoop: return endOp is EndRepeatLoop @@ -233,7 +232,7 @@ extension Operation { case .wasmBeginTryTable: return endOp is WasmEndTryTable case .wasmBeginTry, - .wasmBeginCatch: + .wasmBeginCatch: return endOp is WasmEndTry || endOp is WasmBeginCatch || endOp is WasmBeginCatchAll case .wasmBeginCatchAll: return endOp is WasmEndTry diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index b463f8432..2fc55cec3 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -112,34 +112,34 @@ public struct ILType: Hashable { public static let undefined = ILType(definiteType: .undefined) /// An integer type. - public static let integer = ILType(definiteType: .integer) + public static let integer = ILType(definiteType: .integer) /// A bigInt type. - public static let bigint = ILType(definiteType: .bigint) + public static let bigint = ILType(definiteType: .bigint) /// A floating point number. - public static let float = ILType(definiteType: .float) + public static let float = ILType(definiteType: .float) /// A string. - public static let string = ILType(definiteType: .string) + public static let string = ILType(definiteType: .string) /// A boolean. - public static let boolean = ILType(definiteType: .boolean) + public static let boolean = ILType(definiteType: .boolean) /// A RegExp - public static let regexp = ILType(definiteType: .regexp) + public static let regexp = ILType(definiteType: .regexp) /// A type that can be iterated over, such as an array or a generator. - public static let iterable = ILType(definiteType: .iterable) + public static let iterable = ILType(definiteType: .iterable) /// The type that subsumes all others (in js). - public static let jsAnything = ILType(definiteType: .nothing, possibleType: .jsAnything) + public static let jsAnything = ILType(definiteType: .nothing, possibleType: .jsAnything) /// The type that subsumes all others (in wasm). - public static let wasmAnything = ILType(definiteType: .nothing, possibleType: .wasmAnything) + public static let wasmAnything = ILType(definiteType: .nothing, possibleType: .wasmAnything) /// The type that is subsumed by all others. - public static let nothing = ILType(definiteType: .nothing, possibleType: .nothing) + public static let nothing = ILType(definiteType: .nothing, possibleType: .nothing) /// A number: either an integer or a float. public static let number: ILType = .integer | .float @@ -151,14 +151,20 @@ public struct ILType: Hashable { public static let nullish: ILType = .undefined /// Constructs an object type. - public static func object(ofGroup group: String? = nil, withProperties properties: [String] = [], withMethods methods: [String] = [], withWasmType wasmExt: WasmTypeExtension? = nil) -> ILType { - let ext = TypeExtension(group: group, properties: Set(properties), methods: Set(methods), signature: nil, wasmExt: wasmExt) + public static func object( + ofGroup group: String? = nil, withProperties properties: [String] = [], + withMethods methods: [String] = [], withWasmType wasmExt: WasmTypeExtension? = nil + ) -> ILType { + let ext = TypeExtension( + group: group, properties: Set(properties), methods: Set(methods), signature: nil, + wasmExt: wasmExt) return ILType(definiteType: .object, ext: ext) } /// Constructs an enum type, which is a string with a limited set of allowed values. public static func enumeration(ofName name: String, withValues values: [String]) -> ILType { - let ext = TypeExtension(group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) + let ext = TypeExtension( + group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) return ILType(definiteType: .string, ext: ext) } @@ -167,7 +173,8 @@ public struct ILType: Hashable { /// Most code will treat these as strings, but the JavaScriptEnvironment can register /// producingGenerators for them so they can be generated more intelligently. public static func namedString(ofName name: String) -> ILType { - let ext = TypeExtension(group: name, properties: Set(), methods: Set(), signature: nil, wasmExt: nil) + let ext = TypeExtension( + group: name, properties: Set(), methods: Set(), signature: nil, wasmExt: nil) return ILType(definiteType: .string, ext: ext) } @@ -194,8 +201,11 @@ public struct ILType: Hashable { /// An unbound function. This is a function with this === null which requires to get a this /// bound (e.g. via .bind(), .call() or .apply()). - public static func unboundFunction(_ signature: Signature? = nil, receiver: ILType? = nil) -> ILType { - let ext = TypeExtension(properties: Set(), methods: Set(), signature: signature, receiver: receiver) + public static func unboundFunction(_ signature: Signature? = nil, receiver: ILType? = nil) + -> ILType + { + let ext = TypeExtension( + properties: Set(), methods: Set(), signature: signature, receiver: receiver) return ILType(definiteType: [.unboundFunction], ext: ext) } @@ -203,38 +213,59 @@ public struct ILType: Hashable { // This type is used to indicate block labels in wasm. public static func label(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { - return ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) + return ILType( + definiteType: .label, + ext: TypeExtension( + group: "WasmLabel", properties: [], methods: [], signature: nil, + wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) } - public static let anyLabel: ILType = ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) + public static let anyLabel: ILType = ILType( + definiteType: .label, + ext: TypeExtension( + group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) /// A label that allows rethrowing the caught exception of a catch block. public static let exceptionLabel: ILType = ILType(definiteType: .exceptionLabel) - public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) -> ILType { + public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) + -> ILType + { let wasmMemExt = WasmMemoryType(limits: limits, isShared: isShared, isMemory64: isMemory64) - return .object(ofGroup: "WasmMemory", withProperties: ["buffer"], withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"], withWasmType: wasmMemExt) + return .object( + ofGroup: "WasmMemory", withProperties: ["buffer"], + withMethods: ["grow", "toResizableBuffer", "toFixedLengthBuffer"], + withWasmType: wasmMemExt) } - public static func wasmDataSegment(segmentLength: Int? = nil) -> ILType { + public static func wasmDataSegment(segmentLength: Int? = nil) -> ILType { let maybeWasmExtention = segmentLength.map { WasmDataSegmentType(segmentLength: $0) } - let typeExtension = TypeExtension(group: "WasmDataSegment", properties: Set(), methods: Set(), signature: nil, wasmExt: maybeWasmExtention) + let typeExtension = TypeExtension( + group: "WasmDataSegment", properties: Set(), methods: Set(), signature: nil, + wasmExt: maybeWasmExtention) return ILType(definiteType: .wasmDataSegment, ext: typeExtension) } - public static func wasmElementSegment(segmentLength: Int? = nil) -> ILType { + public static func wasmElementSegment(segmentLength: Int? = nil) -> ILType { let maybeWasmExtention = segmentLength.map { WasmElementSegmentType(segmentLength: $0) } - let typeExtension = TypeExtension(group: "WasmElementSegment", properties: Set(), methods: Set(), signature: nil, wasmExt: maybeWasmExtention) + let typeExtension = TypeExtension( + group: "WasmElementSegment", properties: Set(), methods: Set(), signature: nil, + wasmExt: maybeWasmExtention) return ILType(definiteType: .wasmElementSegment, ext: typeExtension) } public static func wasmTable(wasmTableType: WasmTableType) -> ILType { - return .object(ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"], withWasmType: wasmTableType) + return .object( + ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"], + withWasmType: wasmTableType) } public static func wasmFunctionDef(_ signature: WasmSignature? = nil) -> ILType { - return ILType(definiteType: .wasmFunctionDef, - ext: TypeExtension(properties: Set(), methods: Set(), signature: nil, wasmExt: WasmFunctionDefinition(signature))) + return ILType( + definiteType: .wasmFunctionDef, + ext: TypeExtension( + properties: Set(), methods: Set(), signature: nil, + wasmExt: WasmFunctionDefinition(signature))) } // @@ -247,20 +278,48 @@ public struct ILType: Hashable { public static let wasmi64 = ILType(definiteType: .wasmi64) public static let wasmf32 = ILType(definiteType: .wasmf32) public static let wasmf64 = ILType(definiteType: .wasmf64) - public static func wasmExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: true) } - public static func wasmRefExtern(shared: Bool = false) -> ILType { wasmRef(.WasmExtern, shared: shared, nullability: false) } - public static func wasmFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmFunc, shared: shared, nullability: true) } - public static func wasmExnRef(shared: Bool = false) -> ILType { wasmRef(.WasmExn, shared: shared, nullability: true) } - public static func wasmI31Ref(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: true) } - public static func wasmRefI31(shared: Bool = false) -> ILType { wasmRef(.WasmI31, shared: shared, nullability: false) } - public static func wasmAnyRef(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: true) } - public static func wasmRefAny(shared: Bool = false) -> ILType { wasmRef(.WasmAny, shared: shared, nullability: false) } - public static func wasmNullRef(shared: Bool = false) -> ILType { wasmRef(.WasmNone, shared: shared, nullability: true) } - public static func wasmNullExternRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoExtern, shared: shared, nullability: true) } - public static func wasmNullFuncRef(shared: Bool = false) -> ILType { wasmRef(.WasmNoFunc, shared: shared, nullability: true) } - public static func wasmEqRef(shared: Bool = false) -> ILType { wasmRef(.WasmEq, shared: shared, nullability: true) } - public static func wasmStructRef(shared: Bool = false) -> ILType { wasmRef(.WasmStruct, shared: shared, nullability: true) } - public static func wasmArrayRef(shared: Bool = false) -> ILType { wasmRef(.WasmArray, shared: shared, nullability: true) } + public static func wasmExternRef(shared: Bool = false) -> ILType { + wasmRef(.WasmExtern, shared: shared, nullability: true) + } + public static func wasmRefExtern(shared: Bool = false) -> ILType { + wasmRef(.WasmExtern, shared: shared, nullability: false) + } + public static func wasmFuncRef(shared: Bool = false) -> ILType { + wasmRef(.WasmFunc, shared: shared, nullability: true) + } + public static func wasmExnRef(shared: Bool = false) -> ILType { + wasmRef(.WasmExn, shared: shared, nullability: true) + } + public static func wasmI31Ref(shared: Bool = false) -> ILType { + wasmRef(.WasmI31, shared: shared, nullability: true) + } + public static func wasmRefI31(shared: Bool = false) -> ILType { + wasmRef(.WasmI31, shared: shared, nullability: false) + } + public static func wasmAnyRef(shared: Bool = false) -> ILType { + wasmRef(.WasmAny, shared: shared, nullability: true) + } + public static func wasmRefAny(shared: Bool = false) -> ILType { + wasmRef(.WasmAny, shared: shared, nullability: false) + } + public static func wasmNullRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNone, shared: shared, nullability: true) + } + public static func wasmNullExternRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNoExtern, shared: shared, nullability: true) + } + public static func wasmNullFuncRef(shared: Bool = false) -> ILType { + wasmRef(.WasmNoFunc, shared: shared, nullability: true) + } + public static func wasmEqRef(shared: Bool = false) -> ILType { + wasmRef(.WasmEq, shared: shared, nullability: true) + } + public static func wasmStructRef(shared: Bool = false) -> ILType { + wasmRef(.WasmStruct, shared: shared, nullability: true) + } + public static func wasmArrayRef(shared: Bool = false) -> ILType { + wasmRef(.WasmArray, shared: shared, nullability: true) + } public static let wasmSimd128 = ILType(definiteType: .wasmSimd128) public static let wasmGenericRef = ILType(definiteType: .wasmRef) @@ -277,22 +336,28 @@ public struct ILType: Hashable { static func wasmTypeDef(description: WasmTypeDescription? = nil) -> ILType { let typeDef = WasmTypeDefinition() typeDef.description = description - return ILType(definiteType: .wasmTypeDef, ext: TypeExtension( - properties: [], methods: [], signature: nil, wasmExt: typeDef)) + return ILType( + definiteType: .wasmTypeDef, + ext: TypeExtension( + properties: [], methods: [], signature: nil, wasmExt: typeDef)) } static func wasmSelfReference() -> ILType { wasmTypeDef(description: .selfReference) } - static func wasmRef(_ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true) -> ILType { + static func wasmRef( + _ heapType: WasmAbstractHeapType, shared: Bool = false, nullability: Bool = true + ) -> ILType { .wasmRef(.Abstract(.init(heapType, shared: shared)), nullability: nullability) } static func wasmRef(_ kind: WasmReferenceType.Kind, nullability: Bool) -> ILType { - return ILType(definiteType: .wasmRef, ext: TypeExtension( - properties: [], methods: [], signature: nil, - wasmExt: WasmReferenceType(kind, nullability: nullability))) + return ILType( + definiteType: .wasmRef, + ext: TypeExtension( + properties: [], methods: [], signature: nil, + wasmExt: WasmReferenceType(kind, nullability: nullability))) } static func wasmIndexRef(_ desc: WasmTypeDescription, nullability: Bool) -> ILType { @@ -300,7 +365,8 @@ public struct ILType: Hashable { } // The union of all primitive wasm types - public static let wasmPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef + public static let wasmPrimitive = + .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 | .wasmSimd128 | .wasmGenericRef public static let wasmNumericalPrimitive = .wasmi32 | .wasmi64 | .wasmf32 | .wasmf64 @@ -332,10 +398,11 @@ public struct ILType: Hashable { return ILType(definiteType: definiteType) } - public static func ==(lhs: ILType, rhs: ILType) -> Bool { - return lhs.definiteType == rhs.definiteType && lhs.possibleType == rhs.possibleType && lhs.ext == rhs.ext + public static func == (lhs: ILType, rhs: ILType) -> Bool { + return lhs.definiteType == rhs.definiteType && lhs.possibleType == rhs.possibleType + && lhs.ext == rhs.ext } - public static func !=(lhs: ILType, rhs: ILType) -> Bool { + public static func != (lhs: ILType, rhs: ILType) -> Bool { return !(lhs == rhs) } @@ -394,13 +461,18 @@ public struct ILType: Hashable { if isUnion { // Verify that either the other definite type is empty or that there is some overlap between // our possible type and the other definite type - guard other.definiteType.isEmpty || !other.definiteType.intersection(self.possibleType).isEmpty else { + guard + other.definiteType.isEmpty + || !other.definiteType.intersection(self.possibleType).isEmpty + else { return false } // Given the above, we can subtract the other's definite type here from its possible type so that // e.g. StringObjects are correctly subsumed by both .string and .object. - guard self.possibleType.isSuperset(of: other.possibleType.subtracting(other.definiteType)) else { + guard + self.possibleType.isSuperset(of: other.possibleType.subtracting(other.definiteType)) + else { return false } } @@ -424,7 +496,8 @@ public struct ILType: Hashable { } // Either our type must be a generic callable without a signature, or our signature must subsume the other type's signature. - guard signature == nil || (other.signature != nil && signature!.subsumes(other.signature!)) else { + guard signature == nil || (other.signature != nil && signature!.subsumes(other.signature!)) + else { return false } @@ -437,13 +510,17 @@ public struct ILType: Hashable { return false } - guard receiver == nil || (other.receiver != nil && receiver!.subsumes(other.receiver!)) else { + guard receiver == nil || (other.receiver != nil && receiver!.subsumes(other.receiver!)) + else { return false } // Wasm type extension. - guard !self.hasWasmTypeInfo || (other.hasWasmTypeInfo - && self.wasmType!.subsumes(other.wasmType!)) else { + guard + !self.hasWasmTypeInfo + || (other.hasWasmTypeInfo + && self.wasmType!.subsumes(other.wasmType!)) + else { return false } @@ -463,15 +540,27 @@ public struct ILType: Hashable { // If you add a new custom object group, please check the logic below. // Make sure that the groups themselves are not prefixes. - assert(JSTyper.ObjectGroupManager.ObjectGroupType.allCases == [.wasmModule, .wasmExports, .objectLiteral, .jsClass]) + assert( + JSTyper.ObjectGroupManager.ObjectGroupType.allCases == [ + .wasmModule, .wasmExports, .objectLiteral, .jsClass, + ]) - let objectGroupTypes = ["_fuzz_Object", "_fuzz_WasmModule", "_fuzz_WasmExports", "_fuzz_Class", "_fuzz_Constructor"] + let objectGroupTypes = [ + "_fuzz_Object", "_fuzz_WasmModule", "_fuzz_WasmExports", "_fuzz_Class", + "_fuzz_Constructor", + ] for groupType in objectGroupTypes { if rhs.hasPrefix(groupType) && lhs.hasPrefix(groupType) { // Check that they differ only in a number at the end. - assert(rhs.range(of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil) != nil && - lhs.range(of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil) != nil) + assert( + rhs.range( + of: "\(groupType)\\d+", options: .regularExpression, range: nil, locale: nil + ) != nil + && lhs.range( + of: "\(groupType)\\d+", options: .regularExpression, range: nil, + locale: nil) != nil + ) return true } } @@ -479,15 +568,14 @@ public struct ILType: Hashable { return false } - public static func >=(lhs: ILType, rhs: ILType) -> Bool { + public static func >= (lhs: ILType, rhs: ILType) -> Bool { return lhs.subsumes(rhs) } - public static func <=(lhs: ILType, rhs: ILType) -> Bool { + public static func <= (lhs: ILType, rhs: ILType) -> Bool { return rhs.subsumes(lhs) } - // // Access to extended type data // @@ -544,7 +632,6 @@ public struct ILType: Hashable { return wasmMemoryType != nil && ext?.group == "WasmMemory" } - public var wasmDataSegmentType: WasmDataSegmentType? { return ext?.wasmExt as? WasmDataSegmentType } @@ -561,7 +648,6 @@ public struct ILType: Hashable { return wasmElementSegmentType != nil } - public var wasmTableType: WasmTableType? { return ext?.wasmExt as? WasmTableType } @@ -659,8 +745,8 @@ public struct ILType: Hashable { public func requiredInputCount() -> Int { if let ref = wasmReferenceType { switch ref.kind { - case .Index: return 1 - case .Abstract: return 0 + case .Index: return 1 + case .Abstract: return 0 } } return 0 @@ -675,7 +761,6 @@ public struct ILType: Hashable { return isPacked() ? .wasmi32 : self } - // // Type operations // @@ -692,13 +777,17 @@ public struct ILType: Hashable { /// WasmTypeExtensions (currently WasmReferenceType), there are more complex union rules. public func union(with other: ILType) -> ILType { // Trivial cases. - if self == .jsAnything && other.Is(.jsAnything) || other == .jsAnything && self.Is(.jsAnything) { + if self == .jsAnything && other.Is(.jsAnything) + || other == .jsAnything && self.Is(.jsAnything) + { return .jsAnything } else if self == .nothing { return other } else if other == .nothing { return self - } else if self == .wasmAnything && other.Is(.wasmAnything) || other == .wasmAnything && self.Is(.wasmAnything) { + } else if self == .wasmAnything && other.Is(.wasmAnything) + || other == .wasmAnything && self.Is(.wasmAnything) + { return .wasmAnything } @@ -717,10 +806,13 @@ public struct ILType: Hashable { // that means finding the set of shared properties and methods, which is imprecise but correct. let commonProperties = self.properties.intersection(other.properties) let commonMethods = self.methods.intersection(other.methods) - let signature = self.signature == other.signature ? self.signature : nil // TODO: this is overly coarse, we could also see if one signature subsumes the other, then take the subsuming one. - let receiver = other.receiver != nil ? self.receiver?.intersection(with: other.receiver!) : nil + let signature = self.signature == other.signature ? self.signature : nil // TODO: this is overly coarse, we could also see if one signature subsumes the other, then take the subsuming one. + let receiver = + other.receiver != nil ? self.receiver?.intersection(with: other.receiver!) : nil var group = self.group == other.group ? self.group : nil - let wasmExt = self.wasmType != nil && other.wasmType != nil ? self.wasmType!.union(other.wasmType!) : nil + let wasmExt = + self.wasmType != nil && other.wasmType != nil + ? self.wasmType!.union(other.wasmType!) : nil // Object groups are used to describe certain wasm types. If the WasmTypeExtension is lost, // the group should also be invalidated. This ensures that e.g. any // `.object(ofGroup: "WasmTag")` always has a `.wasmTagType` extension. @@ -728,14 +820,18 @@ public struct ILType: Hashable { group = nil } - return ILType(definiteType: definiteType, possibleType: possibleType, ext: TypeExtension(group: group, properties: commonProperties, methods: commonMethods, signature: signature, wasmExt: wasmExt, receiver: receiver)) + return ILType( + definiteType: definiteType, possibleType: possibleType, + ext: TypeExtension( + group: group, properties: commonProperties, methods: commonMethods, + signature: signature, wasmExt: wasmExt, receiver: receiver)) } - public static func |(lhs: ILType, rhs: ILType) -> ILType { + public static func | (lhs: ILType, rhs: ILType) -> ILType { return lhs.union(with: rhs) } - public static func |=(lhs: inout ILType, rhs: ILType) { + public static func |= (lhs: inout ILType, rhs: ILType) { lhs = lhs | rhs } @@ -794,39 +890,52 @@ public struct ILType: Hashable { // For signatures we take a shortcut: if one signature subsumes the other, then the intersection // must be the subsumed signature. Additionally, we know that if there is an intersection, the // return value must be the intersection of the return values, so we can compute that up-front. - let returnValue = (self.signature?.outputType ?? .jsAnything) & (other.signature?.outputType ?? .jsAnything) + let returnValue = + (self.signature?.outputType ?? .jsAnything) + & (other.signature?.outputType ?? .jsAnything) guard returnValue != .nothing else { return .nothing } let ourSignature = self.signature?.replacingOutputType(with: returnValue) let otherSignature = other.signature?.replacingOutputType(with: returnValue) let signature: Signature? - if ourSignature == nil || (otherSignature != nil && ourSignature!.subsumes(otherSignature!)) { + if ourSignature == nil || (otherSignature != nil && ourSignature!.subsumes(otherSignature!)) + { signature = otherSignature - } else if otherSignature == nil || (ourSignature != nil && otherSignature!.subsumes(ourSignature!)) { + } else if otherSignature == nil + || (ourSignature != nil && otherSignature!.subsumes(ourSignature!)) + { signature = ourSignature } else { return .nothing } - let receiver = self.receiver != nil && other.receiver != nil ? self.receiver!.union(with: other.receiver!) : self.receiver ?? other.receiver + let receiver = + self.receiver != nil && other.receiver != nil + ? self.receiver!.union(with: other.receiver!) : self.receiver ?? other.receiver // If either value is nil, the result is the non-nil value. If both are non-nil, the result // is their intersection if valid, otherwise .nothing is returned. var wasmExt: WasmTypeExtension? = self.wasmType ?? other.wasmType if self.wasmType != nil && other.wasmType != nil { - guard let wasmIntersection = self.wasmType!.intersection(other.wasmType!) else { return .nothing } + guard let wasmIntersection = self.wasmType!.intersection(other.wasmType!) else { + return .nothing + } wasmExt = wasmIntersection } - return ILType(definiteType: definiteType, possibleType: possibleType, ext: TypeExtension(group: group, properties: properties, methods: methods, signature: signature, wasmExt: wasmExt, receiver: receiver)) + return ILType( + definiteType: definiteType, possibleType: possibleType, + ext: TypeExtension( + group: group, properties: properties, methods: methods, signature: signature, + wasmExt: wasmExt, receiver: receiver)) } - public static func &(lhs: ILType, rhs: ILType) -> ILType { + public static func & (lhs: ILType, rhs: ILType) -> ILType { return lhs.intersection(with: rhs) } - public static func &=(lhs: inout ILType, rhs: ILType) { + public static func &= (lhs: inout ILType, rhs: ILType) { lhs = lhs & rhs } @@ -838,12 +947,14 @@ public struct ILType: Hashable { } // Merging of callables with different signatures is not allowed. - guard self.signature == nil || other.signature == nil || self.signature == other.signature else { + guard self.signature == nil || other.signature == nil || self.signature == other.signature + else { return false } // Merging of unbound fucntions with different receivers is not allowed. - guard self.receiver == nil || other.receiver == nil || self.receiver == other.receiver else { + guard self.receiver == nil || other.receiver == nil || self.receiver == other.receiver + else { return false } @@ -858,7 +969,10 @@ public struct ILType: Hashable { } // Merging objects with different wasm extensions is not allowed. - guard self.ext?.wasmExt == nil || other.ext?.wasmExt == nil || self.ext?.wasmExt == other.ext?.wasmExt else { + guard + self.ext?.wasmExt == nil || other.ext?.wasmExt == nil + || self.ext?.wasmExt == other.ext?.wasmExt + else { return false } @@ -888,15 +1002,18 @@ public struct ILType: Hashable { let wasmExt = self.wasmType ?? other.wasmType // We just take the self.wasmExt as they have to be the same, see `canMerge`. - let ext = TypeExtension(group: group, properties: self.properties.union(other.properties), methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, receiver: receiver) + let ext = TypeExtension( + group: group, properties: self.properties.union(other.properties), + methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, + receiver: receiver) return ILType(definiteType: definiteType, possibleType: possibleType, ext: ext) } - public static func +(lhs: ILType, rhs: ILType) -> ILType { + public static func + (lhs: ILType, rhs: ILType) -> ILType { return lhs.merging(with: rhs) } - public static func +=(lhs: inout ILType, rhs: ILType) { + public static func += (lhs: inout ILType, rhs: ILType) { lhs = lhs.merging(with: rhs) } @@ -913,7 +1030,9 @@ public struct ILType: Hashable { } var newProperties = properties newProperties.insert(property) - let newExt = TypeExtension(group: group, properties: newProperties, methods: methods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: newProperties, methods: methods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -933,7 +1052,9 @@ public struct ILType: Hashable { newProperties.remove(name) var newMethods = methods newMethods.remove(name) - let newExt = TypeExtension(group: group, properties: newProperties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: newProperties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -944,7 +1065,9 @@ public struct ILType: Hashable { } var newMethods = methods newMethods.insert(method) - let newExt = TypeExtension(group: group, properties: properties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: properties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -960,7 +1083,9 @@ public struct ILType: Hashable { } var newMethods = methods newMethods.remove(method) - let newExt = TypeExtension(group: group, properties: properties, methods: newMethods, signature: signature, wasmExt: wasmType) + let newExt = TypeExtension( + group: group, properties: properties, methods: newMethods, signature: signature, + wasmExt: wasmType) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -968,7 +1093,8 @@ public struct ILType: Hashable { guard Is(.function() | .constructor()) else { return self } - let newExt = TypeExtension(group: group, properties: properties, methods: methods, signature: signature) + let newExt = TypeExtension( + group: group, properties: properties, methods: methods, signature: signature) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1086,7 +1212,8 @@ extension ILType: CustomStringConvertible { return ".constructor()" } case .unboundFunction: - return ".unboundFunction(\(signature?.format(abbreviate: abbreviate) ?? "nil"), receiver: \(receiver?.format(abbreviate: abbreviate) ?? "nil"))" + return + ".unboundFunction(\(signature?.format(abbreviate: abbreviate) ?? "nil"), receiver: \(receiver?.format(abbreviate: abbreviate) ?? "nil"))" case .wasmi32: return ".wasmi32" case .wasmi64: @@ -1112,14 +1239,14 @@ extension ILType: CustomStringConvertible { } let nullPrefix = refType.nullability ? "null " : "" switch refType.kind { - case .Abstract(let heapTypeInfo): - let sharedPrefix = heapTypeInfo.shared ? "shared " : "" - return ".wasmRef(.Abstract(\(nullPrefix)\(sharedPrefix)\(heapTypeInfo.heapType)))" - case .Index(let indexRef): - if let desc = indexRef.get() { - return ".wasmRef(\(nullPrefix)Index \(desc.format(abbreviate: abbreviate)))" - } - return ".wasmRef(\(nullPrefix)Index)" + case .Abstract(let heapTypeInfo): + let sharedPrefix = heapTypeInfo.shared ? "shared " : "" + return ".wasmRef(.Abstract(\(nullPrefix)\(sharedPrefix)\(heapTypeInfo.heapType)))" + case .Index(let indexRef): + if let desc = indexRef.get() { + return ".wasmRef(\(nullPrefix)Index \(desc.format(abbreviate: abbreviate)))" + } + return ".wasmRef(\(nullPrefix)Index)" } case .wasmFunctionDef: if let signature = wasmFunctionDefSignature { @@ -1171,35 +1298,35 @@ struct BaseType: OptionSet, Hashable { let rawValue: UInt32 // Base types - static let nothing = BaseType([]) - static let undefined = BaseType(rawValue: 1 << 0) - static let integer = BaseType(rawValue: 1 << 1) - static let bigint = BaseType(rawValue: 1 << 2) - static let float = BaseType(rawValue: 1 << 3) - static let boolean = BaseType(rawValue: 1 << 4) - static let string = BaseType(rawValue: 1 << 5) - static let regexp = BaseType(rawValue: 1 << 6) - static let object = BaseType(rawValue: 1 << 7) - static let function = BaseType(rawValue: 1 << 8) + static let nothing = BaseType([]) + static let undefined = BaseType(rawValue: 1 << 0) + static let integer = BaseType(rawValue: 1 << 1) + static let bigint = BaseType(rawValue: 1 << 2) + static let float = BaseType(rawValue: 1 << 3) + static let boolean = BaseType(rawValue: 1 << 4) + static let string = BaseType(rawValue: 1 << 5) + static let regexp = BaseType(rawValue: 1 << 6) + static let object = BaseType(rawValue: 1 << 7) + static let function = BaseType(rawValue: 1 << 8) static let constructor = BaseType(rawValue: 1 << 9) static let unboundFunction = BaseType(rawValue: 1 << 10) - static let iterable = BaseType(rawValue: 1 << 11) + static let iterable = BaseType(rawValue: 1 << 11) // Wasm Types - static let wasmi32 = BaseType(rawValue: 1 << 12) - static let wasmi64 = BaseType(rawValue: 1 << 13) - static let wasmf32 = BaseType(rawValue: 1 << 14) - static let wasmf64 = BaseType(rawValue: 1 << 15) + static let wasmi32 = BaseType(rawValue: 1 << 12) + static let wasmi64 = BaseType(rawValue: 1 << 13) + static let wasmf32 = BaseType(rawValue: 1 << 14) + static let wasmf64 = BaseType(rawValue: 1 << 15) // These are wasm internal types, these are never lifted as such and are only used to glue together dataflow in wasm. - static let label = BaseType(rawValue: 1 << 16) + static let label = BaseType(rawValue: 1 << 16) // Any catch block exposes such a label now to rethrow the exception caught by that catch. // Note that in wasm the label is actually the try block's label but as rethrows are only possible inside a catch // block, semantically having a label on the catch makes more sense. static let exceptionLabel = BaseType(rawValue: 1 << 17) // This is a reference to a table, which can be passed around to table instructions // The lifter will resolve this to the proper index when lifting. - static let wasmSimd128 = BaseType(rawValue: 1 << 18) + static let wasmSimd128 = BaseType(rawValue: 1 << 18) static let wasmFunctionDef = BaseType(rawValue: 1 << 19) // Wasm-gc types @@ -1215,11 +1342,21 @@ struct BaseType: OptionSet, Hashable { static let wasmDataSegment = BaseType(rawValue: 1 << 24) static let wasmElementSegment = BaseType(rawValue: 1 << 25) - static let jsAnything = BaseType([.undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable]) - - static let wasmAnything = BaseType([.wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef]) - - static let allBaseTypes: [BaseType] = [.undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable, .wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef] + static let jsAnything = BaseType([ + .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, + .unboundFunction, .bigint, .regexp, .iterable, + ]) + + static let wasmAnything = BaseType([ + .wasmf32, .wasmi32, .wasmf64, .wasmi64, .wasmRef, .wasmSimd128, .wasmTypeDef, + .wasmFunctionDef, + ]) + + static let allBaseTypes: [BaseType] = [ + .undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, + .unboundFunction, .bigint, .regexp, .iterable, .wasmf32, .wasmi32, .wasmf64, .wasmi64, + .wasmRef, .wasmSimd128, .wasmTypeDef, .wasmFunctionDef, + ] } class TypeExtension: Hashable { @@ -1241,8 +1378,13 @@ class TypeExtension: Hashable { // The receiver type of a function (used for unbound functions). let receiver: ILType? - init?(group: String? = nil, properties: Set, methods: Set, signature: Signature?, wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil) { - if group == nil && properties.isEmpty && methods.isEmpty && signature == nil && wasmExt == nil && receiver == nil { + init?( + group: String? = nil, properties: Set, methods: Set, signature: Signature?, + wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil + ) { + if group == nil && properties.isEmpty && methods.isEmpty && signature == nil + && wasmExt == nil && receiver == nil + { return nil } @@ -1254,7 +1396,7 @@ class TypeExtension: Hashable { self.receiver = receiver } - static func ==(lhs: TypeExtension, rhs: TypeExtension) -> Bool { + static func == (lhs: TypeExtension, rhs: TypeExtension) -> Bool { return lhs.properties == rhs.properties && lhs.methods == rhs.methods && lhs.group == rhs.group @@ -1276,7 +1418,7 @@ class TypeExtension: Hashable { // Base class that all Wasm types wih TypeExtension should inherit from. public class WasmTypeExtension: Hashable { - public static func ==(lhs: WasmTypeExtension, rhs: WasmTypeExtension) -> Bool { + public static func == (lhs: WasmTypeExtension, rhs: WasmTypeExtension) -> Bool { lhs.isEqual(to: rhs) } @@ -1392,7 +1534,7 @@ public class WasmLabelType: WasmTypeExtension { } public class WasmTypeDefinition: WasmTypeExtension { - var description : WasmTypeDescription? = nil + var description: WasmTypeDescription? = nil override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmTypeDefinition else { return false } @@ -1438,10 +1580,10 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { // runtime errors when trying to do so.) func isUsableInJS() -> Bool { switch self { - case .WasmExn, .WasmNoExn: - return false - default: - return true + case .WasmExn, .WasmNoExn: + return false + default: + return true } } @@ -1451,14 +1593,14 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { func getBottom() -> Self { switch self { - case .WasmExtern, .WasmNoExtern: - return .WasmNoExtern - case .WasmFunc, .WasmNoFunc: - return .WasmNoFunc - case .WasmAny, .WasmEq, .WasmI31, .WasmStruct, .WasmArray, .WasmNone: - return .WasmNone - case .WasmExn, .WasmNoExn: - return .WasmNoExn + case .WasmExtern, .WasmNoExtern: + return .WasmNoExtern + case .WasmFunc, .WasmNoFunc: + return .WasmNoFunc + case .WasmAny, .WasmEq, .WasmI31, .WasmStruct, .WasmArray, .WasmNone: + return .WasmNone + case .WasmExn, .WasmNoExn: + return .WasmNoExn } } @@ -1483,14 +1625,14 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { let a = min(self, other) let b = max(self, other) return switch a { - case .WasmAny: - .WasmAny - case .WasmEq, .WasmI31, .WasmStruct: - .WasmEq - case .WasmArray: - .WasmAny - case .WasmExtern, .WasmFunc, .WasmExn, .WasmNone, .WasmNoExtern, .WasmNoFunc, .WasmNoExn: - fatalError("unhandled subtyping for a=\(a) b=\(b)") + case .WasmAny: + .WasmAny + case .WasmEq, .WasmI31, .WasmStruct: + .WasmEq + case .WasmArray: + .WasmAny + case .WasmExtern, .WasmFunc, .WasmExn, .WasmNone, .WasmNoExtern, .WasmNoFunc, .WasmNoExn: + fatalError("unhandled subtyping for a=\(a) b=\(b)") } } @@ -1519,7 +1661,7 @@ public enum WasmAbstractHeapType: CaseIterable, Comparable { } } -public class HeapTypeInfo : Hashable { +public class HeapTypeInfo: Hashable { public let heapType: WasmAbstractHeapType public let shared: Bool @@ -1528,13 +1670,13 @@ public class HeapTypeInfo : Hashable { self.shared = shared } - public static func ==(lhs: HeapTypeInfo, rhs: HeapTypeInfo) -> Bool { + public static func == (lhs: HeapTypeInfo, rhs: HeapTypeInfo) -> Bool { return lhs.heapType == rhs.heapType && lhs.shared == rhs.shared } func union(_ other: HeapTypeInfo) -> HeapTypeInfo? { - if (shared != other.shared) { - return nil; + if shared != other.shared { + return nil } if let unionHeapType = heapType.union(other.heapType) { return HeapTypeInfo(unionHeapType, shared: shared) @@ -1543,8 +1685,8 @@ public class HeapTypeInfo : Hashable { } func intersection(_ other: HeapTypeInfo) -> HeapTypeInfo? { - if (shared != other.shared) { - return nil; + if shared != other.shared { + return nil } if let intersectionHeapType = heapType.intersection(other.heapType) { return HeapTypeInfo(intersectionHeapType, shared: shared) @@ -1553,13 +1695,12 @@ public class HeapTypeInfo : Hashable { } func subsumes(_ other: HeapTypeInfo) -> Bool { - if (shared != other.shared) { - return false; + if shared != other.shared { + return false } return heapType.subsumes(other.heapType) } - public func hash(into hasher: inout Hasher) { hasher.combine(heapType) hasher.combine(shared) @@ -1567,7 +1708,7 @@ public class HeapTypeInfo : Hashable { } // A wrapper around a WasmTypeDescription without owning the WasmTypeDescription. -struct UnownedWasmTypeDescription : Hashable { +struct UnownedWasmTypeDescription: Hashable { private unowned var description: WasmTypeDescription? init(_ description: WasmTypeDescription? = nil) { @@ -1580,7 +1721,7 @@ struct UnownedWasmTypeDescription : Hashable { } public class WasmReferenceType: WasmTypeExtension { - enum Kind : Hashable { + enum Kind: Hashable { // A user defined (indexed) wasm-gc type. Note that the WasmReferenceType may not own the // WasmTypeDescription as that would create cyclic references in case of self or forward // references (e.g. an array could have its own type as an element type) leading to memory @@ -1592,68 +1733,74 @@ public class WasmReferenceType: WasmTypeExtension { func union(_ other: Self) -> Self? { switch self { - case .Index(let desc): - switch other { - case .Index(let otherDesc): - if desc.get() == nil || otherDesc.get() == nil { - return .Index(.init()) - } - if desc.get() == otherDesc.get() { - return self - } - if let abstract = desc.get()?.abstractHeapSupertype, - let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - let upperBound = abstract.union(otherAbstract) { - return .Abstract(upperBound) - } - case .Abstract(let otherAbstract): - if let abstractSuper = desc.get()?.abstractHeapSupertype, - let upperBound = abstractSuper.union(otherAbstract) { - return .Abstract(upperBound) - } + case .Index(let desc): + switch other { + case .Index(let otherDesc): + if desc.get() == nil || otherDesc.get() == nil { + return .Index(.init()) } - case .Abstract(let heapType): - switch other { - case .Index(let otherDesc): - if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - let upperBound = heapType.union(otherAbstract) { - return .Abstract(upperBound) - } - case .Abstract(let otherHeapType): - if let upperBound = heapType.union(otherHeapType) { - return .Abstract(upperBound) - } + if desc.get() == otherDesc.get() { + return self } + if let abstract = desc.get()?.abstractHeapSupertype, + let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + let upperBound = abstract.union(otherAbstract) + { + return .Abstract(upperBound) + } + case .Abstract(let otherAbstract): + if let abstractSuper = desc.get()?.abstractHeapSupertype, + let upperBound = abstractSuper.union(otherAbstract) + { + return .Abstract(upperBound) + } + } + case .Abstract(let heapType): + switch other { + case .Index(let otherDesc): + if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + let upperBound = heapType.union(otherAbstract) + { + return .Abstract(upperBound) + } + case .Abstract(let otherHeapType): + if let upperBound = heapType.union(otherHeapType) { + return .Abstract(upperBound) + } + } } return nil } func intersection(_ other: Self) -> Self? { switch self { - case .Index(let desc): - switch other { - case .Index(let otherDesc): - if desc.get() == otherDesc.get() || desc.get() == nil || otherDesc.get() == nil { - return .Index(desc) - } - case .Abstract(let otherAbstract): - if let abstractSuper = desc.get()?.abstractHeapSupertype, - otherAbstract.subsumes(abstractSuper) { - return self - } + case .Index(let desc): + switch other { + case .Index(let otherDesc): + if desc.get() == otherDesc.get() || desc.get() == nil || otherDesc.get() == nil + { + return .Index(desc) } - case .Abstract(let heapType): - switch other { - case .Index(let otherDesc): - if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, - heapType.subsumes(otherAbstract) { - return other - } - case .Abstract(let otherHeapType): - if let lowerBound = heapType.intersection(otherHeapType) { - return .Abstract(lowerBound) - } + case .Abstract(let otherAbstract): + if let abstractSuper = desc.get()?.abstractHeapSupertype, + otherAbstract.subsumes(abstractSuper) + { + return self } + } + case .Abstract(let heapType): + switch other { + case .Index(let otherDesc): + if let otherAbstract = otherDesc.get()?.abstractHeapSupertype, + heapType.subsumes(otherAbstract) + { + return other + } + case .Abstract(let otherHeapType): + if let lowerBound = heapType.intersection(otherHeapType) { + return .Abstract(lowerBound) + } + } } return nil } @@ -1668,10 +1815,10 @@ public class WasmReferenceType: WasmTypeExtension { func isAbstract() -> Bool { switch self.kind { - case .Abstract(_): - return true - case .Index(_): - return false + case .Abstract(_): + return true + case .Index(_): + return false } } @@ -1724,7 +1871,8 @@ public class WasmMemoryType: WasmTypeExtension { override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmMemoryType else { return false } - return self.limits == other.limits && self.isShared == other.isShared && self.isMemory64 == other.isMemory64 + return self.limits == other.limits && self.isShared == other.isShared + && self.isMemory64 == other.isMemory64 } override public func hash(into hasher: inout Hasher) { @@ -1808,7 +1956,8 @@ public class WasmTableType: WasmTypeExtension { override func isEqual(to other: WasmTypeExtension) -> Bool { guard let other = other as? WasmTableType else { return false } - return self.elementType == other.elementType && self.limits == other.limits && self.isTable64 == other.isTable64 && self.knownEntries == other.knownEntries + return self.elementType == other.elementType && self.limits == other.limits + && self.isTable64 == other.isTable64 && self.knownEntries == other.knownEntries } override public func hash(into hasher: inout Hasher) { @@ -1818,7 +1967,10 @@ public class WasmTableType: WasmTypeExtension { hasher.combine(knownEntries) } - init(elementType: ILType, limits: Limits, isTable64: Bool, knownEntries: [IndexInTableAndWasmSignature]) { + init( + elementType: ILType, limits: Limits, isTable64: Bool, + knownEntries: [IndexInTableAndWasmSignature] + ) { // TODO(manoskouk): Assert table type is reference type. self.elementType = elementType self.limits = limits @@ -1834,18 +1986,22 @@ public enum Parameter: Hashable { case rest(ILType) // Convenience constructors for plain parameters. - public static let integer = Parameter.plain(.integer) - public static let bigint = Parameter.plain(.bigint) - public static let float = Parameter.plain(.float) - public static let string = Parameter.plain(.string) - public static let boolean = Parameter.plain(.boolean) - public static let regexp = Parameter.plain(.regexp) - public static let iterable = Parameter.plain(.iterable) + public static let integer = Parameter.plain(.integer) + public static let bigint = Parameter.plain(.bigint) + public static let float = Parameter.plain(.float) + public static let string = Parameter.plain(.string) + public static let boolean = Parameter.plain(.boolean) + public static let regexp = Parameter.plain(.regexp) + public static let iterable = Parameter.plain(.iterable) public static let jsAnything = Parameter.plain(.jsAnything) - public static let number = Parameter.plain(.number) - public static let primitive = Parameter.plain(.primitive) - public static func object(ofGroup group: String? = nil, withProperties properties: [String] = [], withMethods methods: [String] = []) -> Parameter { - return Parameter.plain(.object(ofGroup: group, withProperties: properties, withMethods: methods)) + public static let number = Parameter.plain(.number) + public static let primitive = Parameter.plain(.primitive) + public static func object( + ofGroup group: String? = nil, withProperties properties: [String] = [], + withMethods methods: [String] = [] + ) -> Parameter { + return Parameter.plain( + .object(ofGroup: group, withProperties: properties, withMethods: methods)) } public static func function(_ signature: Signature? = nil) -> Parameter { return Parameter.plain(.function(signature)) @@ -1869,18 +2025,18 @@ public enum Parameter: Hashable { fileprivate func format(abbreviate: Bool) -> String { switch self { - case .plain(let t): - return t.format(abbreviate: abbreviate) - case .opt(let t): - return ".opt(\(t.format(abbreviate: abbreviate)))" - case .rest(let t): - return "\(t.format(abbreviate: abbreviate))..." + case .plain(let t): + return t.format(abbreviate: abbreviate) + case .opt(let t): + return ".opt(\(t.format(abbreviate: abbreviate)))" + case .rest(let t): + return "\(t.format(abbreviate: abbreviate))..." } } } // A ParameterList represents all parameters in a function signature. -public typealias ParameterList = Array +public typealias ParameterList = [Parameter] extension ParameterList { // Construct a generic parameter list with `numParameters` parameters of type `.jsAnything` init(numParameters: Int, hasRestParam: Bool) { @@ -1918,11 +2074,11 @@ extension ParameterList { /// Returns an array of `ILType`s. Requires the parameters to be plain parameters only. func convertPlainToILTypes() -> [ILType] { return map { param in - switch (param) { - case .plain(let plain): - return plain - default: - fatalError("Unexpected non-plain parameter \(param)") + switch param { + case .plain(let plain): + return plain + default: + fatalError("Unexpected non-plain parameter \(param)") } } } @@ -2085,11 +2241,11 @@ public struct Signature: Hashable, CustomStringConvertible { return true } - public static func >=(lhs: Signature, rhs: Signature) -> Bool { + public static func >= (lhs: Signature, rhs: Signature) -> Bool { return lhs.subsumes(rhs) } - public static func <=(lhs: Signature, rhs: Signature) -> Bool { + public static func <= (lhs: Signature, rhs: Signature) -> Bool { return rhs.subsumes(lhs) } } @@ -2109,7 +2265,8 @@ public struct WasmSignature: Hashable, CustomStringConvertible { } func format(abbreviate: Bool) -> String { - let inputs = parameterTypes.map({ $0.format(abbreviate: abbreviate) }).joined(separator: ", ") + let inputs = parameterTypes.map({ $0.format(abbreviate: abbreviate) }).joined( + separator: ", ") let outputs = outputTypes.map({ $0.format(abbreviate: abbreviate) }).joined(separator: ", ") return "[\(inputs)] => [\(outputs)]" } @@ -2127,7 +2284,7 @@ public postfix func ... (t: ILType) -> Parameter { } /// The convenience infix operator => is used to construct function signatures. -infix operator =>: AdditionPrecedence +infix operator => : AdditionPrecedence public func => (parameters: [Parameter], returnType: ILType) -> Signature { return Signature(expects: ParameterList(parameters), returns: returnType) } @@ -2176,7 +2333,8 @@ class WasmSignatureTypeDescription: WasmTypeDescription { init(signature: WasmSignature, typeGroupIndex: Int) { self.signature = signature // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmFunc, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2184,8 +2342,8 @@ class WasmSignatureTypeDescription: WasmTypeDescription { if abbreviate { return abbreviated } - let paramTypes = signature.parameterTypes.map {$0.abbreviated}.joined(separator: ", ") - let outputTypes = signature.outputTypes.map {$0.abbreviated}.joined(separator: ", ") + let paramTypes = signature.parameterTypes.map { $0.abbreviated }.joined(separator: ", ") + let outputTypes = signature.outputTypes.map { $0.abbreviated }.joined(separator: ", ") return "\(abbreviated)[[\(paramTypes)] => [\(outputTypes)]]" } } @@ -2198,7 +2356,8 @@ class WasmArrayTypeDescription: WasmTypeDescription { self.elementType = elementType self.mutability = mutability // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmArray, shared: false)) } override func format(abbreviate: Bool) -> String { @@ -2230,7 +2389,9 @@ class WasmStructTypeDescription: WasmTypeDescription { init(fields: [Field], typeGroupIndex: Int) { self.fields = fields // TODO(pawkra): support shared variant. - super.init(typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmStruct, shared: false)) + super.init( + typeGroupIndex: typeGroupIndex, superType: HeapTypeInfo.init(.WasmStruct, shared: false) + ) } override func format(abbreviate: Bool) -> String { diff --git a/Sources/Fuzzilli/FuzzIL/Variable.swift b/Sources/Fuzzilli/FuzzIL/Variable.swift index 8c46fb94e..ca6882715 100644 --- a/Sources/Fuzzilli/FuzzIL/Variable.swift +++ b/Sources/Fuzzilli/FuzzIL/Variable.swift @@ -40,7 +40,7 @@ public struct Variable: Hashable, CustomStringConvertible { return "v\(number)" } - public static func ==(lhs: Variable, rhs: Variable) -> Bool { + public static func == (lhs: Variable, rhs: Variable) -> Bool { return lhs.number == rhs.number } @@ -50,7 +50,7 @@ public struct Variable: Hashable, CustomStringConvertible { } extension Variable: Comparable { - public static func <(lhs: Variable, rhs: Variable) -> Bool { + public static func < (lhs: Variable, rhs: Variable) -> Bool { return lhs.number < rhs.number } } diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index cc9daa405..ef8e416b6 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. - import Foundation struct WasmConstants { - static let specWasmMemPageSize: Int = 65536 // 64 KB + static let specWasmMemPageSize: Int = 65536 // 64 KB // These are the limits defined in v8/src/wasm/wasm-limits.h which is based on https://www.w3.org/TR/wasm-js-api-2/#limits. // Note that the memory64 limits will be merged later on. // This constant limits the amount of *declared* memory. At runtime, memory can grow up to only a limit based on the architecture type. - static let specMaxWasmMem32Pages: Int = 65536 // 4GB - static let specMaxWasmMem64Pages: Int = 262144; // 16GB + static let specMaxWasmMem32Pages: Int = 65536 // 4GB + static let specMaxWasmMem64Pages: Int = 262144 // 16GB } // Base class for all wasm operations. -public class WasmOperation : Operation { +public class WasmOperation: Operation { } final class Consti64: WasmOperation { @@ -89,8 +88,8 @@ final class WasmReturn: WasmOperation { // public enum WasmIntegerCompareOpKind: UInt8, CaseIterable { - case Eq = 0 - case Ne = 1 + case Eq = 0 + case Ne = 1 case Lt_s = 2 case Lt_u = 3 case Gt_s = 4 @@ -124,7 +123,8 @@ final class Wasmi32CompareOp: WasmOperation { init(compareOpKind: WasmIntegerCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -134,7 +134,8 @@ final class Wasmi64CompareOp: WasmOperation { init(compareOpKind: WasmIntegerCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -170,7 +171,8 @@ final class Wasmf32CompareOp: WasmOperation { init(compareOpKind: WasmFloatCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -180,7 +182,8 @@ final class Wasmf64CompareOp: WasmOperation { init(compareOpKind: WasmFloatCompareOpKind) { self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -238,7 +241,8 @@ final class Wasmi32BinOp: WasmOperation { init(binOpKind: WasmIntegerBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -248,7 +252,8 @@ final class Wasmi64BinOp: WasmOperation { init(binOpKind: WasmIntegerBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -304,18 +309,18 @@ public enum WasmAtomicRMWType: UInt8, CaseIterable { func type() -> ILType { switch self { case .i32Add, .i32Add8U, .i32Add16U, - .i32Sub, .i32Sub8U, .i32Sub16U, - .i32And, .i32And8U, .i32And16U, - .i32Or, .i32Or8U, .i32Or16U, - .i32Xor, .i32Xor8U, .i32Xor16U, - .i32Xchg, .i32Xchg8U, .i32Xchg16U: + .i32Sub, .i32Sub8U, .i32Sub16U, + .i32And, .i32And8U, .i32And16U, + .i32Or, .i32Or8U, .i32Or16U, + .i32Xor, .i32Xor8U, .i32Xor16U, + .i32Xchg, .i32Xchg8U, .i32Xchg16U: return .wasmi32 case .i64Add, .i64Add8U, .i64Add16U, .i64Add32U, - .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U, - .i64And, .i64And8U, .i64And16U, .i64And32U, - .i64Or, .i64Or8U, .i64Or16U, .i64Or32U, - .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U, - .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: + .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U, + .i64And, .i64And8U, .i64And16U, .i64And32U, + .i64Or, .i64Or8U, .i64Or16U, .i64Or32U, + .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U, + .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: return .wasmi64 } } @@ -323,29 +328,29 @@ public enum WasmAtomicRMWType: UInt8, CaseIterable { func naturalAlignment() -> Int64 { switch self { case .i32Add8U, .i64Add8U, - .i32Sub8U, .i64Sub8U, - .i32And8U, .i64And8U, - .i32Or8U, .i64Or8U, - .i32Xor8U, .i64Xor8U, - .i32Xchg8U, .i64Xchg8U: + .i32Sub8U, .i64Sub8U, + .i32And8U, .i64And8U, + .i32Or8U, .i64Or8U, + .i32Xor8U, .i64Xor8U, + .i32Xchg8U, .i64Xchg8U: return 1 case .i32Add16U, .i64Add16U, - .i32Sub16U, .i64Sub16U, - .i32And16U, .i64And16U, - .i32Or16U, .i64Or16U, - .i32Xor16U, .i64Xor16U, - .i32Xchg16U, .i64Xchg16U: + .i32Sub16U, .i64Sub16U, + .i32And16U, .i64And16U, + .i32Or16U, .i64Or16U, + .i32Xor16U, .i64Xor16U, + .i32Xchg16U, .i64Xchg16U: return 2 case .i32Add, .i64Add32U, - .i32Sub, .i64Sub32U, - .i32And, .i64And32U, - .i32Or, .i64Or32U, - .i32Xor, .i64Xor32U, - .i32Xchg, .i64Xchg32U: + .i32Sub, .i64Sub32U, + .i32And, .i64And32U, + .i32Or, .i64Or32U, + .i32Xor, .i64Xor32U, + .i32Xchg, .i64Xchg32U: return 4 case .i64Add, .i64Sub, - .i64And, .i64Or, - .i64Xor, .i64Xchg: + .i64And, .i64Or, + .i64Xor, .i64Xchg: return 8 } } @@ -357,7 +362,8 @@ final class Wasmi32UnOp: WasmOperation { init(unOpKind: WasmIntegerUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -367,7 +373,8 @@ final class Wasmi64UnOp: WasmOperation { init(unOpKind: WasmIntegerUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -405,7 +412,8 @@ final class Wasmf32BinOp: WasmOperation { init(binOpKind: WasmFloatBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -415,27 +423,30 @@ final class Wasmf64BinOp: WasmOperation { init(binOpKind: WasmFloatBinaryOpKind) { self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class Wasmf32UnOp: WasmOperation { - override var opcode: Opcode { .wasmf32UnOp(self)} + override var opcode: Opcode { .wasmf32UnOp(self) } let unOpKind: WasmFloatUnaryOpKind init(unOpKind: WasmFloatUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class Wasmf64UnOp: WasmOperation { - override var opcode: Opcode { .wasmf64UnOp(self)} + override var opcode: Opcode { .wasmf64UnOp(self) } let unOpKind: WasmFloatUnaryOpKind init(unOpKind: WasmFloatUnaryOpKind) { self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -703,7 +714,6 @@ public enum WasmGlobal { // This is the case for imported Globals, we just need the type here. case imported(ILType) - func toType() -> ILType { switch self { case .wasmi64: @@ -728,7 +738,7 @@ public enum WasmGlobal { } } -func typeString() -> String { + func typeString() -> String { switch self { case .wasmi64(_): return "i64" @@ -749,9 +759,8 @@ func typeString() -> String { } } - // Returns a JS string representing the initial value. -func valueToString() -> String { + func valueToString() -> String { switch self { case .wasmi64(let val): return "\(val)n" @@ -764,7 +773,7 @@ func valueToString() -> String { case .externref: return "" case .exnref, - .i31ref: + .i31ref: return "null" default: fatalError("Unimplemented / unhandled") @@ -794,7 +803,10 @@ final class WasmDefineTable: WasmOperation { let definedEntries: [WasmTableType.IndexInTableAndWasmSignature] let isTable64: Bool - init(elementType: ILType, limits: Limits, definedEntries: [WasmTableType.IndexInTableAndWasmSignature], isTable64: Bool) { + init( + elementType: ILType, limits: Limits, + definedEntries: [WasmTableType.IndexInTableAndWasmSignature], isTable64: Bool + ) { self.elementType = elementType self.limits = limits self.isTable64 = isTable64 @@ -804,10 +816,11 @@ final class WasmDefineTable: WasmOperation { let isWasmFuncRef = elementType == .wasmFuncRef() assert(isWasmFuncRef || definedEntries.isEmpty) - super.init(numInputs: isWasmFuncRef ? definedEntries.count : 0, - numOutputs: 1, - attributes: [.isMutable], - requiredContext: [.wasm]) + super.init( + numInputs: isWasmFuncRef ? definedEntries.count : 0, + numOutputs: 1, + attributes: [.isMutable], + requiredContext: [.wasm]) } } @@ -892,7 +905,9 @@ final class WasmLoadGlobal: WasmOperation { init(globalType: ILType) { assert(globalType.Is(.wasmPrimitive)) self.globalType = globalType - super.init(numInputs: 1, numOutputs: 1, attributes: [.isNotInputMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isNotInputMutable], + requiredContext: [.wasmFunction]) } } @@ -947,7 +962,9 @@ final class WasmCallIndirect: WasmOperation { init(signature: WasmSignature) { self.signature = signature - super.init(numInputs: 2 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + signature.parameterTypes.count, numOutputs: signature.outputTypes.count, + requiredContext: [.wasmFunction]) } } @@ -955,20 +972,24 @@ final class WasmCallDirect: WasmOperation { override var opcode: Opcode { .wasmCallDirect(self) } init(parameterCount: Int, outputCount: Int) { - super.init(numInputs: 1 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallDirect: WasmOperation { override var opcode: Opcode { .wasmReturnCallDirect(self) } init(parameterCount: Int) { - super.init(numInputs: 1 + parameterCount, numOutputs: 0, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numOutputs: 0, attributes: [.isJump], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmReturnCallIndirect: WasmOperation { @@ -977,7 +998,9 @@ final class WasmReturnCallIndirect: WasmOperation { init(signature: WasmSignature) { self.signature = signature - super.init(numInputs: 2 + signature.parameterTypes.count, numOutputs: 0, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + signature.parameterTypes.count, numOutputs: 0, attributes: [.isJump], + requiredContext: [.wasmFunction]) } } @@ -1012,24 +1035,24 @@ public enum WasmMemoryLoadType: UInt8, CaseIterable { func numberType() -> ILType { switch self { - case .I32LoadMem, - .I32LoadMem8S, - .I32LoadMem8U, - .I32LoadMem16S, - .I32LoadMem16U: - return .wasmi32 - case .I64LoadMem, - .I64LoadMem8S, - .I64LoadMem8U, - .I64LoadMem16S, - .I64LoadMem16U, - .I64LoadMem32S, - .I64LoadMem32U: - return .wasmi64 - case .F32LoadMem: - return .wasmf32 - case .F64LoadMem: - return .wasmf64 + case .I32LoadMem, + .I32LoadMem8S, + .I32LoadMem8U, + .I32LoadMem16S, + .I32LoadMem16U: + return .wasmi32 + case .I64LoadMem, + .I64LoadMem8S, + .I64LoadMem8U, + .I64LoadMem16S, + .I64LoadMem16U, + .I64LoadMem32S, + .I64LoadMem32U: + return .wasmi64 + case .F32LoadMem: + return .wasmf32 + case .F64LoadMem: + return .wasmf64 } } } @@ -1043,7 +1066,8 @@ final class WasmMemoryLoad: WasmOperation { init(loadType: WasmMemoryLoadType, staticOffset: Int64) { self.loadType = loadType self.staticOffset = staticOffset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1058,25 +1082,25 @@ public enum WasmMemoryStoreType: UInt8, CaseIterable { case I64StoreMem8 = 0x3c case I64StoreMem16 = 0x3d case I64StoreMem32 = 0x3e - case S128StoreMem = 0x0B // Requires SIMD prefix! + case S128StoreMem = 0x0B // Requires SIMD prefix! func numberType() -> ILType { switch self { - case .I32StoreMem, - .I32StoreMem8, - .I32StoreMem16: - return .wasmi32 - case .I64StoreMem, - .I64StoreMem8, - .I64StoreMem16, - .I64StoreMem32: - return .wasmi64 - case .F32StoreMem: - return .wasmf32 - case .F64StoreMem: - return .wasmf64 - case .S128StoreMem: - return .wasmSimd128 + case .I32StoreMem, + .I32StoreMem8, + .I32StoreMem16: + return .wasmi32 + case .I64StoreMem, + .I64StoreMem8, + .I64StoreMem16, + .I64StoreMem32: + return .wasmi64 + case .F32StoreMem: + return .wasmf32 + case .F64StoreMem: + return .wasmf64 + case .S128StoreMem: + return .wasmSimd128 } } } @@ -1217,7 +1241,9 @@ final class WasmJsCall: WasmOperation { override var opcode: Opcode { .wasmJsCall(self) } init(parameterCount: Int, outputCount: Int) { - super.init(numInputs: 2 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + parameterCount, numOutputs: outputCount, requiredContext: [.wasmFunction] + ) } var parameterCount: Int { numInputs - 2 } @@ -1241,21 +1267,26 @@ final class WasmBeginBlock: WasmOperation { init(parameterCount: Int) { // Inputs: The signature plus the arguments. // Inner outputs: The label plus the arguments. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmEndBlock: WasmOperation { override var opcode: Opcode { .wasmEndBlock(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } -public enum WasmBranchHint: CaseIterable { +public enum WasmBranchHint: CaseIterable { case None case Likely case Unlikely @@ -1274,10 +1305,13 @@ final class WasmBeginIf: WasmOperation { // it needs to be the last one pushed to it. // Inputs: The signature, the arguments and the condition. // Inner outputs: 1 label (used for branch instructions) plus all the parameters. - super.init(numInputs: 2 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext, .isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext, .isMutable], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 2} + var parameterCount: Int { numInputs - 2 } } final class WasmBeginElse: WasmOperation { @@ -1288,21 +1322,26 @@ final class WasmBeginElse: WasmOperation { // The WasmBeginElse acts both as a block end for the true case and as a block start for the // false case. As such, its input types are the results from the true block and its inner // output types are the same as for the corresponding WasmBeginIf. - super.init(numInputs: 1 + outputCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInnerOutputs - 1} - var outputCount: Int {numInputs - 1} + var parameterCount: Int { numInnerOutputs - 1 } + var outputCount: Int { numInputs - 1 } } final class WasmEndIf: WasmOperation { override var opcode: Opcode { .wasmEndIf(self) } init(outputCount: Int = 0) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd], + requiredContext: [.wasmFunction]) } - var outputCount: Int {numInputs - 1} + var outputCount: Int { numInputs - 1 } } final class WasmBeginLoop: WasmOperation { @@ -1311,14 +1350,17 @@ final class WasmBeginLoop: WasmOperation { init(parameterCount: Int) { // Inputs: the signature + the inputs to the loop. // inner outputs: The loop label + the arguments of the loop. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + attributes: [.isBlockStart, .propagatesSurroundingContext], + requiredContext: [.wasmFunction]) } convenience init(with signature: WasmSignature) { self.init(parameterCount: signature.parameterTypes.count) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmEndLoop: WasmOperation { @@ -1326,14 +1368,16 @@ final class WasmEndLoop: WasmOperation { init(outputCount: Int) { // Inputs: the signature + the outputs of the loop. - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, + attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } // A try_table is a mix between a `br_table` (just with target blocks associated with different tags) // and the legacy `try` block. final class WasmBeginTryTable: WasmOperation { - enum CatchKind : UInt8 { + enum CatchKind: UInt8 { case NoRef = 0x0 case Ref = 0x1 case AllNoRef = 0x2 @@ -1345,22 +1389,24 @@ final class WasmBeginTryTable: WasmOperation { init(parameterCount: Int, catches: [CatchKind]) { self.catches = catches - let inputTagCount = catches.count {$0 == .Ref || $0 == .NoRef} + let inputTagCount = catches.count { $0 == .Ref || $0 == .NoRef } let inputLabelCount = catches.count - super.init(numInputs: 1 + parameterCount + inputLabelCount + inputTagCount, + super.init( + numInputs: 1 + parameterCount + inputLabelCount + inputTagCount, numInnerOutputs: parameterCount + 1, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInnerOutputs - 1} + var parameterCount: Int { numInnerOutputs - 1 } } final class WasmEndTryTable: WasmOperation { override var opcode: Opcode { .wasmEndTryTable(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: outputCount, + super.init( + numInputs: 1 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } @@ -1371,33 +1417,34 @@ final class WasmBeginTry: WasmOperation { init(parameterCount: Int) { // Inputs: The block signature and the block arguments. // Inner outputs: The label and the block parameters. - super.init(numInputs: 1 + parameterCount, + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } } -final class WasmBeginCatchAll : WasmOperation { +final class WasmBeginCatchAll: WasmOperation { override var opcode: Opcode { .wasmBeginCatchAll(self) } init(blockOutputCount: Int) { // Inputs: The block signature and the outputs of the preceding try or catch block. super.init( numInputs: 1 + blockOutputCount, - numInnerOutputs: 1, // the label + numInnerOutputs: 1, // the label attributes: [ .isBlockEnd, .isBlockStart, .propagatesSurroundingContext, // Wasm only allows a single catch_all per try block. - .isSingular + .isSingular, ], requiredContext: [.wasmFunction]) } } -final class WasmBeginCatch : WasmOperation { +final class WasmBeginCatch: WasmOperation { override var opcode: Opcode { .wasmBeginCatch(self) } init(blockOutputCount: Int, labelParameterCount: Int) { @@ -1421,15 +1468,16 @@ final class WasmBeginCatch : WasmOperation { requiredContext: [.wasmFunction]) } - var blockOutputCount: Int {numInputs - 3} - var labelParameterCount: Int {numInnerOutputs - 2} + var blockOutputCount: Int { numInputs - 3 } + var labelParameterCount: Int { numInnerOutputs - 2 } } final class WasmEndTry: WasmOperation { override var opcode: Opcode { .wasmEndTry(self) } init(blockOutputCount: Int) { - super.init(numInputs: 1 + blockOutputCount, numOutputs: blockOutputCount, + super.init( + numInputs: 1 + blockOutputCount, numOutputs: blockOutputCount, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) } } @@ -1441,7 +1489,8 @@ final class WasmBeginTryDelegate: WasmOperation { init(parameterCount: Int) { // inputs: The signature and the arguments. // innerOutputs: The label and the arguments. - super.init(numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, + super.init( + numInputs: 1 + parameterCount, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart, .propagatesSurroundingContext], requiredContext: [.wasmFunction]) } @@ -1455,7 +1504,8 @@ final class WasmEndTryDelegate: WasmOperation { init(outputCount: Int) { // Inputs: The signature, the label to delegate an exception to plus all the outputs of the // try block. - super.init(numInputs: 2 + outputCount, numOutputs: outputCount, + super.init( + numInputs: 2 + outputCount, numOutputs: outputCount, attributes: [.isBlockEnd, .resumesSurroundingContext], requiredContext: [.wasmFunction]) } } @@ -1465,7 +1515,8 @@ final class WasmThrow: WasmOperation { init(parameterCount: Int) { // Inputs: the tag to be thrown plus the arguments for each parameter type of the tag. - super.init(numInputs: 1 + parameterCount, attributes: [.isJump], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount, attributes: [.isJump], requiredContext: [.wasmFunction]) } } @@ -1494,7 +1545,7 @@ final class WasmBranch: WasmOperation { super.init(numInputs: 1 + parameterCount, requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 1} + var parameterCount: Int { numInputs - 1 } } final class WasmBranchIf: WasmOperation { @@ -1504,10 +1555,12 @@ final class WasmBranchIf: WasmOperation { init(parameterCount: Int, hint: WasmBranchHint) { self.hint = hint // The inputs are the label, the arguments and the condition. - super.init(numInputs: 1 + parameterCount + 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + parameterCount + 1, attributes: [.isMutable], + requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - 2} + var parameterCount: Int { numInputs - 2 } } final class WasmBranchTable: WasmOperation { @@ -1522,7 +1575,7 @@ final class WasmBranchTable: WasmOperation { super.init(numInputs: valueCount + 1 + parameterCount + 1, requiredContext: [.wasmFunction]) } - var parameterCount: Int {numInputs - valueCount - 2} + var parameterCount: Int { numInputs - valueCount - 2 } } // TODO: make this comprehensive, currently only works for locals, or assumes every thing it reassigns to is a local. @@ -1545,7 +1598,9 @@ final class BeginWasmFunction: WasmOperation { override var opcode: Opcode { .beginWasmFunction(self) } init(parameterCount: Int) { - super.init(numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], requiredContext: [.wasm], contextOpened: [.wasmFunction]) + super.init( + numInputs: 1, numInnerOutputs: 1 + parameterCount, attributes: [.isBlockStart], + requiredContext: [.wasm], contextOpened: [.wasmFunction]) } var parameterCount: Int { numInnerOutputs - 1 } @@ -1555,7 +1610,9 @@ final class EndWasmFunction: WasmOperation { override var opcode: Opcode { .endWasmFunction(self) } init(outputCount: Int) { - super.init(numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + outputCount, numOutputs: 1, attributes: [.isBlockEnd], + requiredContext: [.wasmFunction]) } var outputCount: Int { numInputs - 1 } @@ -1570,7 +1627,9 @@ final class WasmNop: WasmOperation { init(outputType: ILType, innerOutputTypes: [ILType]) { self.outputType = outputType self.innerOutputTypes = innerOutputTypes - super.init(numOutputs: outputType != .nothing ? 1 : 0, numInnerOutputs: innerOutputTypes.count, attributes: [.isInternal, .isNop], requiredContext: [.wasmFunction]) + super.init( + numOutputs: outputType != .nothing ? 1 : 0, numInnerOutputs: innerOutputTypes.count, + attributes: [.isInternal, .isNop], requiredContext: [.wasmFunction]) } } @@ -1586,7 +1645,7 @@ final class ConstSimd128: WasmOperation { let value: [UInt8] init(value: [UInt8]) { - self.value = value; + self.value = value super.init(numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1618,23 +1677,23 @@ extension WasmSimd128CompareOpKind: CustomStringConvertible { } public enum WasmSimd128Shape: UInt8, CaseIterable { - case i8x16 = 0 - case i16x8 = 1 - case i32x4 = 2 - case i64x2 = 3 - case f32x4 = 4 - case f64x2 = 5 + case i8x16 = 0 + case i16x8 = 1 + case i32x4 = 2 + case i64x2 = 3 + case f32x4 = 4 + case f64x2 = 5 func isFloat() -> Bool { switch self { - case .i8x16, - .i16x8, - .i32x4, - .i64x2: - return false - case .f32x4, - .f64x2: - return true + case .i8x16, + .i16x8, + .i32x4, + .i64x2: + return false + case .f32x4, + .f64x2: + return true } } } @@ -1647,7 +1706,8 @@ final class WasmSimd128Compare: WasmOperation { init(shape: WasmSimd128Shape, compareOpKind: WasmSimd128CompareOpKind) { self.shape = shape self.compareOpKind = compareOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1661,40 +1721,40 @@ public enum WasmSimd128IntegerUnOpKind: Int, CaseIterable { case extadd_pairwise_i8x16_u = 1 case extadd_pairwise_i16x8_s = -30 case extadd_pairwise_i16x8_u = -29 - case abs = 4 - case neg = 5 - case popcnt = 6 - case all_true = 7 - case bitmask = 8 - case extend_low_s = 11 - case extend_high_s = 12 - case extend_low_u = 13 - case extend_high_u = 14 - - case relaxed_trunc_f32x4_s = 101 - case relaxed_trunc_f32x4_u = 102 + case abs = 4 + case neg = 5 + case popcnt = 6 + case all_true = 7 + case bitmask = 8 + case extend_low_s = 11 + case extend_high_s = 12 + case extend_low_u = 13 + case extend_high_u = 14 + + case relaxed_trunc_f32x4_s = 101 + case relaxed_trunc_f32x4_u = 102 case relaxed_trunc_f64x2_s_zero = 103 case relaxed_trunc_f64x2_u_zero = 104 func isValidForShape(shape: WasmSimd128Shape) -> Bool { if shape.isFloat() { return false } switch self { - case .extadd_pairwise_i8x16_s: return shape == .i16x8 - case .extadd_pairwise_i8x16_u: return shape == .i16x8 - case .extadd_pairwise_i16x8_s: return shape == .i32x4 - case .extadd_pairwise_i16x8_u: return shape == .i32x4 - case .abs: return true - case .neg: return true - case .popcnt: return shape == .i8x16 - case .all_true: return true - case .bitmask: return true - case .extend_low_s: return shape != .i8x16 - case .extend_high_s: return shape != .i8x16 - case .extend_low_u: return shape != .i8x16 - case .extend_high_u: return shape != .i8x16 - - case .relaxed_trunc_f32x4_s: return shape == .i32x4 - case .relaxed_trunc_f32x4_u: return shape == .i32x4 + case .extadd_pairwise_i8x16_s: return shape == .i16x8 + case .extadd_pairwise_i8x16_u: return shape == .i16x8 + case .extadd_pairwise_i16x8_s: return shape == .i32x4 + case .extadd_pairwise_i16x8_u: return shape == .i32x4 + case .abs: return true + case .neg: return true + case .popcnt: return shape == .i8x16 + case .all_true: return true + case .bitmask: return true + case .extend_low_s: return shape != .i8x16 + case .extend_high_s: return shape != .i8x16 + case .extend_low_u: return shape != .i8x16 + case .extend_high_u: return shape != .i8x16 + + case .relaxed_trunc_f32x4_s: return shape == .i32x4 + case .relaxed_trunc_f32x4_u: return shape == .i32x4 case .relaxed_trunc_f64x2_s_zero: return shape == .i32x4 case .relaxed_trunc_f64x2_u_zero: return shape == .i32x4 } @@ -1710,7 +1770,8 @@ final class WasmSimd128IntegerUnOp: WasmOperation { assert(unOpKind.isValidForShape(shape: shape)) self.shape = shape self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1721,42 +1782,42 @@ public enum WasmSimd128IntegerBinOpKind: Int, CaseIterable { // i32x4: 0x9C + offset // i64x2: 0xBC + offset case q15mulr_sat_s = 6 - case narrow_s = 9 - case narrow_u = 10 - - case shl = 15 - case shr_s = 16 - case shr_u = 17 - case add = 18 - case add_sat_s = 19 - case add_sat_u = 20 - case sub = 21 - case sub_sat_s = 22 - case sub_sat_u = 23 - - case mul = 25 - case min_s = 26 - case min_u = 27 - case max_s = 28 - case max_u = 29 - case dot_i16x8_s = 30 - case avgr_u = 31 - case extmul_low_s = 32 + case narrow_s = 9 + case narrow_u = 10 + + case shl = 15 + case shr_s = 16 + case shr_u = 17 + case add = 18 + case add_sat_s = 19 + case add_sat_u = 20 + case sub = 21 + case sub_sat_s = 22 + case sub_sat_u = 23 + + case mul = 25 + case min_s = 26 + case min_u = 27 + case max_s = 28 + case max_u = 29 + case dot_i16x8_s = 30 + case avgr_u = 31 + case extmul_low_s = 32 case extmul_high_s = 33 - case extmul_low_u = 34 + case extmul_low_u = 34 case extmul_high_u = 35 - case relaxed_q15_mulr_s = 149 - case relaxed_dot_i8x16_i7x16_s = 150 + case relaxed_q15_mulr_s = 149 + case relaxed_dot_i8x16_i7x16_s = 150 - case relaxed_swizzle = 164 + case relaxed_swizzle = 164 func isShift() -> Bool { switch self { - case .shl, .shr_s, .shr_u: - return true - default: - return false + case .shl, .shr_s, .shr_u: + return true + default: + return false } } @@ -1764,32 +1825,32 @@ public enum WasmSimd128IntegerBinOpKind: Int, CaseIterable { if shape.isFloat() { return false } switch self { case .q15mulr_sat_s: return shape == .i16x8 - case .narrow_s: return shape == .i8x16 || shape == .i16x8 - case .narrow_u: return shape == .i8x16 || shape == .i16x8 - case .shl: return true - case .shr_s: return true - case .shr_u: return true - case .add: return true - case .add_sat_s: return shape == .i8x16 || shape == .i16x8 - case .add_sat_u: return shape == .i8x16 || shape == .i16x8 - case .sub: return true - case .sub_sat_s: return shape == .i8x16 || shape == .i16x8 - case .sub_sat_u: return shape == .i8x16 || shape == .i16x8 - case .mul: return shape != .i8x16 - case .min_s: return shape != .i64x2 - case .min_u: return shape != .i64x2 - case .max_s: return shape != .i64x2 - case .max_u: return shape != .i64x2 - case .dot_i16x8_s: return shape == .i32x4 - case .avgr_u: return shape == .i8x16 || shape == .i16x8 - case .extmul_low_s: return shape != .i8x16 + case .narrow_s: return shape == .i8x16 || shape == .i16x8 + case .narrow_u: return shape == .i8x16 || shape == .i16x8 + case .shl: return true + case .shr_s: return true + case .shr_u: return true + case .add: return true + case .add_sat_s: return shape == .i8x16 || shape == .i16x8 + case .add_sat_u: return shape == .i8x16 || shape == .i16x8 + case .sub: return true + case .sub_sat_s: return shape == .i8x16 || shape == .i16x8 + case .sub_sat_u: return shape == .i8x16 || shape == .i16x8 + case .mul: return shape != .i8x16 + case .min_s: return shape != .i64x2 + case .min_u: return shape != .i64x2 + case .max_s: return shape != .i64x2 + case .max_u: return shape != .i64x2 + case .dot_i16x8_s: return shape == .i32x4 + case .avgr_u: return shape == .i8x16 || shape == .i16x8 + case .extmul_low_s: return shape != .i8x16 case .extmul_high_s: return shape != .i8x16 - case .extmul_low_u: return shape != .i8x16 + case .extmul_low_u: return shape != .i8x16 case .extmul_high_u: return shape != .i8x16 - case .relaxed_q15_mulr_s: return shape == .i16x8 - case .relaxed_dot_i8x16_i7x16_s: return shape == .i16x8 - case .relaxed_swizzle: return shape == .i8x16 + case .relaxed_q15_mulr_s: return shape == .i16x8 + case .relaxed_dot_i8x16_i7x16_s: return shape == .i16x8 + case .relaxed_swizzle: return shape == .i8x16 } } } @@ -1803,7 +1864,8 @@ final class WasmSimd128IntegerBinOp: WasmOperation { assert(binOpKind.isValidForShape(shape: shape)) self.shape = shape self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1819,8 +1881,8 @@ public enum WasmSimd128IntegerTernaryOpKind: Int, CaseIterable { func isValidForShape(shape: WasmSimd128Shape) -> Bool { if shape.isFloat() { return false } switch self { - case .relaxed_laneselect: return true - case .relaxed_dot_i8x16_i7x16_add_s: return shape == .i32x4 + case .relaxed_laneselect: return true + case .relaxed_dot_i8x16_i7x16_add_s: return shape == .i32x4 } } } @@ -1834,7 +1896,8 @@ final class WasmSimd128IntegerTernaryOp: WasmOperation { assert(ternaryOpKind.isValidForShape(shape: shape)) self.shape = shape self.ternaryOpKind = ternaryOpKind - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1861,7 +1924,8 @@ final class WasmSimd128FloatUnOp: WasmOperation { assert(unOpKind.isValidForShape(shape: shape)) self.shape = shape self.unOpKind = unOpKind - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1901,15 +1965,17 @@ final class WasmSimd128FloatBinOp: WasmOperation { assert(binOpKind.isValidForShape(shape: shape)) self.shape = shape self.binOpKind = binOpKind - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } func getOpcode() -> Int { - let base = if(binOpKind.isRelaxed()) { - shape == .f32x4 ? 0x100 : 0x102; - } else { - shape == .f32x4 ? 0xE4 : 0xF0; - } + let base = + if binOpKind.isRelaxed() { + shape == .f32x4 ? 0x100 : 0x102 + } else { + shape == .f32x4 ? 0xE4 : 0xF0 + } return base + binOpKind.rawValue } } @@ -1934,7 +2000,8 @@ final class WasmSimd128FloatTernaryOp: WasmOperation { assert(ternaryOpKind.isValidForShape(shape: shape)) self.shape = shape self.ternaryOpKind = ternaryOpKind - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -1949,14 +2016,14 @@ final class WasmSimdSplat: WasmOperation { func laneType() -> ILType { switch self { - case .I8x16, .I16x8, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16, .I16x8, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } } @@ -1983,27 +2050,27 @@ final class WasmSimdExtractLane: WasmOperation { func laneType() -> ILType { switch self { - case .I8x16S, .I8x16U, .I16x8S, .I16x8U, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16S, .I8x16U, .I16x8S, .I16x8U, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } func laneCount() -> Int { switch self { - case .I8x16S, .I8x16U: - return 16 - case .I16x8S, .I16x8U: - return 8 - case .I32x4, .F32x4: - return 4 - case .I64x2, .F64x2: - return 2 + case .I8x16S, .I8x16U: + return 16 + case .I16x8S, .I16x8U: + return 8 + case .I32x4, .F32x4: + return 4 + case .I64x2, .F64x2: + return 2 } } } @@ -2014,8 +2081,9 @@ final class WasmSimdExtractLane: WasmOperation { init(kind: Kind, lane: Int) { self.kind = kind - self.lane = lane; - super.init(numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 1, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2030,27 +2098,27 @@ final class WasmSimdReplaceLane: WasmOperation { func laneCount() -> Int { switch self { - case .I8x16: - return 16 - case .I16x8: - return 8 - case .I32x4, .F32x4: - return 4 - case .I64x2, .F64x2: - return 2 + case .I8x16: + return 16 + case .I16x8: + return 8 + case .I32x4, .F32x4: + return 4 + case .I64x2, .F64x2: + return 2 } } func laneType() -> ILType { switch self { - case .I8x16, .I16x8, .I32x4: - return .wasmi32 - case .I64x2: - return .wasmi64 - case .F32x4: - return .wasmf32 - case .F64x2: - return .wasmf64 + case .I8x16, .I16x8, .I32x4: + return .wasmi32 + case .I64x2: + return .wasmi64 + case .F32x4: + return .wasmf32 + case .F64x2: + return .wasmf64 } } } @@ -2061,12 +2129,12 @@ final class WasmSimdReplaceLane: WasmOperation { init(kind: Kind, lane: Int) { self.kind = kind - self.lane = lane; - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } - final class WasmSimdStoreLane: WasmOperation { enum Kind: UInt8, CaseIterable { case Store8 = 0x58 @@ -2076,14 +2144,14 @@ final class WasmSimdStoreLane: WasmOperation { func laneCount() -> Int { switch self { - case .Store8: - return 16 - case .Store16: - return 8 - case .Store32: - return 4 - case .Store64: - return 2 + case .Store8: + return 16 + case .Store16: + return 8 + case .Store32: + return 4 + case .Store64: + return 2 } } } @@ -2096,7 +2164,7 @@ final class WasmSimdStoreLane: WasmOperation { init(kind: Kind, staticOffset: Int64, lane: Int) { self.kind = kind self.staticOffset = staticOffset - self.lane = lane; + self.lane = lane super.init(numInputs: 3, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2110,14 +2178,14 @@ final class WasmSimdLoadLane: WasmOperation { func laneCount() -> Int { switch self { - case .Load8: - return 16 - case .Load16: - return 8 - case .Load32: - return 4 - case .Load64: - return 2 + case .Load8: + return 16 + case .Load16: + return 8 + case .Load32: + return 4 + case .Load64: + return 2 } } } @@ -2130,26 +2198,27 @@ final class WasmSimdLoadLane: WasmOperation { init(kind: Kind, staticOffset: Int64, lane: Int) { self.kind = kind self.staticOffset = staticOffset - self.lane = lane; - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + self.lane = lane + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } final class WasmSimdLoad: WasmOperation { enum Kind: UInt8, CaseIterable { - case LoadS128 = 0x00 - case Load8x8S = 0x01 - case Load8x8U = 0x02 - case Load16x4S = 0x03 - case Load16x4U = 0x04 - case Load32x2S = 0x05 - case Load32x2U = 0x06 - case Load8Splat = 0x07 + case LoadS128 = 0x00 + case Load8x8S = 0x01 + case Load8x8U = 0x02 + case Load16x4S = 0x03 + case Load16x4U = 0x04 + case Load32x2S = 0x05 + case Load32x2U = 0x06 + case Load8Splat = 0x07 case Load16Splat = 0x08 case Load32Splat = 0x09 case Load64Splat = 0x0A - case Load32Zero = 0x5C - case Load64Zero = 0x5D + case Load32Zero = 0x5C + case Load64Zero = 0x5D } override var opcode: Opcode { .wasmSimdLoad(self) } @@ -2160,7 +2229,8 @@ final class WasmSimdLoad: WasmOperation { init(kind: Kind, staticOffset: Int64) { self.kind = kind self.staticOffset = staticOffset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2323,7 +2393,9 @@ class WasmRefTest: WasmOperation { init(refType: ILType) { self.type = refType - super.init(numInputs: 1 + type.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) } } @@ -2332,7 +2404,9 @@ class WasmRefCast: WasmOperation { let type: ILType init(refType: ILType) { self.type = refType - super.init(numInputs: 1 + type.requiredInputCount(), numOutputs: 1, requiredContext: [.wasmFunction]) + super.init( + numInputs: 1 + type.requiredInputCount(), numOutputs: 1, + requiredContext: [.wasmFunction]) } } @@ -2349,7 +2423,8 @@ final class WasmAtomicLoad: WasmOperation { init(loadType: WasmAtomicLoadType, offset: Int64) { self.loadType = loadType self.offset = offset - super.init(numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 2, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2366,7 +2441,8 @@ final class WasmAtomicStore: WasmOperation { init(storeType: WasmAtomicStoreType, offset: Int64) { self.storeType = storeType self.offset = offset - super.init(numInputs: 3, numOutputs: 0, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 0, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2379,7 +2455,8 @@ final class WasmAtomicRMW: WasmOperation { init(op: WasmAtomicRMWType, offset: Int64) { self.op = op self.offset = offset - super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2424,7 +2501,8 @@ final class WasmAtomicCmpxchg: WasmOperation { init(op: WasmAtomicCmpxchgType, offset: Int64) { self.op = op self.offset = offset - super.init(numInputs: 4, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) + super.init( + numInputs: 4, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction]) } } @@ -2435,7 +2513,8 @@ final class WasmDefineAdHocSignatureType: WasmOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasmFunction]) } } @@ -2452,7 +2531,8 @@ final class WasmDefineAdHocModuleSignatureType: WasmOperation { init(signature: WasmSignature) { self.signature = signature let numInputs = (signature.outputTypes + signature.parameterTypes).map { - $0.requiredInputCount() }.reduce(0) { $0 + $1 } + $0.requiredInputCount() + }.reduce(0) { $0 + $1 } super.init(numInputs: numInputs, numOutputs: 1, requiredContext: [.wasm]) } } diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 787db836c..09b1ce265 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -21,12 +21,12 @@ public enum Timeout { case value(UInt32) case interval(UInt32, UInt32) - public func maxTimeout() -> UInt32{ + public func maxTimeout() -> UInt32 { switch self { - case .value(let value): - return value - case .interval(_, let max): - return max + case .value(let value): + return value + case .interval(_, let max): + return max } } } @@ -119,9 +119,9 @@ public class Fuzzer { logger.info("Changing state from \(state) to \(newState)") // Some state transitions are forbidden, check for those here. - assert(newState != .uninitialized) // We never transition into .uninitialized - assert(newState != .waiting || state == .uninitialized) // We're only transitioning into .waiting during initialization - assert(state != .fuzzing) // Currently we never transition out of .fuzzing (although we could allow scheduling a corpus import while already fuzzing) + assert(newState != .uninitialized) // We never transition into .uninitialized + assert(newState != .waiting || state == .uninitialized) // We're only transitioning into .waiting during initialization + assert(state != .fuzzing) // Currently we never transition out of .fuzzing (although we could allow scheduling a corpus import while already fuzzing) state = newState } @@ -182,13 +182,17 @@ public class Fuzzer { /// Constructs a new fuzzer instance with the provided components. public init( - configuration: Configuration, scriptRunner: ScriptRunner, referenceScriptRunner: ScriptRunner?, engine: FuzzEngine, mutators: WeightedList, - codeGenerators: WeightedList, programTemplates: WeightedList, evaluator: ProgramEvaluator, - environment: JavaScriptEnvironment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, queue: DispatchQueue? = nil + configuration: Configuration, scriptRunner: ScriptRunner, + referenceScriptRunner: ScriptRunner?, engine: FuzzEngine, mutators: WeightedList, + codeGenerators: WeightedList, + programTemplates: WeightedList, evaluator: ProgramEvaluator, + environment: JavaScriptEnvironment, lifter: Lifter, corpus: Corpus, minimizer: Minimizer, + queue: DispatchQueue? = nil ) { let uniqueId = UUID() self.id = uniqueId - self.queue = queue ?? DispatchQueue(label: "Fuzzer \(uniqueId)", target: DispatchQueue.global()) + self.queue = + queue ?? DispatchQueue(label: "Fuzzer \(uniqueId)", target: DispatchQueue.global()) self.config = configuration self.events = Events() @@ -226,7 +230,7 @@ public class Fuzzer { } /// Schedule work on this fuzzer's dispatch queue. - public func async(do block: @escaping () -> ()) { + public func async(do block: @escaping () -> Void) { queue.async { guard !self.isStopped else { return } block() @@ -234,7 +238,7 @@ public class Fuzzer { } /// Schedule work on this fuzzer's dispatch queue and wait for its completion. - public func sync(do block: () -> ()) { + public func sync(do block: () -> Void) { queue.sync { guard !self.isStopped else { return } block() @@ -259,7 +263,7 @@ public class Fuzzer { modules[module.name] = module // We only allow one instance of certain modules. - assert(modules.values.filter( { $0 is DistributedFuzzingChildNode }).count <= 1) + assert(modules.values.filter({ $0 is DistributedFuzzingChildNode }).count <= 1) } /// Initializes this fuzzer. @@ -298,7 +302,9 @@ public class Fuzzer { let interval = now.timeIntervalSince(lastCheck) lastCheck = now if interval > 180 { - self.logger.warning("Fuzzer appears unresponsive (watchdog only triggered after \(Int(interval))s instead of 60s).") + self.logger.warning( + "Fuzzer appears unresponsive (watchdog only triggered after \(Int(interval))s instead of 60s)." + ) } } @@ -312,13 +318,17 @@ public class Fuzzer { let percentage = Statistics.percentageOrNa(stub.invocationSuccessRate, 7) let name = stub.name.rightPadded(toLength: nameMaxLength) let invocations = String(format: "%12d", stub.invocationCount) - self.logger.warning("Code generator \(name) might have too restrictive dynamic requirements. Its successful invocation rate is only \(percentage)% after \(invocations) invocations") + self.logger.warning( + "Code generator \(name) might have too restrictive dynamic requirements. Its successful invocation rate is only \(percentage)% after \(invocations) invocations" + ) } if stub.totalSamples >= 100 && stub.correctnessRate! < 0.05 { let name = stub.name.rightPadded(toLength: nameMaxLength) let percentage = Statistics.percentageOrNa(stub.correctnessRate, 7) let totalSamples = String(format: "%10d", stub.totalSamples) - self.logger.warning("Code generator \(name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples") + self.logger.warning( + "Code generator \(name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples" + ) } } } @@ -326,7 +336,9 @@ public class Fuzzer { if template.totalSamples >= 100 && template.correctnessRate! < 0.05 { let percentage = Statistics.percentageOrNa(template.correctnessRate, 7) let totalSamples = String(format: "%10d", template.totalSamples) - self.logger.warning("Program template \(template.name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples") + self.logger.warning( + "Program template \(template.name) might be broken. Correctness rate is only \(percentage)% after \(totalSamples) generated samples" + ) } } } @@ -414,7 +426,9 @@ public class Fuzzer { } /// Registers a new listener for the given event. - public func registerEventListener(for event: Event, listener: @escaping Event.EventListener) { + public func registerEventListener( + for event: Event, listener: @escaping Event.EventListener + ) { dispatchPrecondition(condition: .onQueue(queue)) event.addListener(listener) } @@ -439,7 +453,9 @@ public class Fuzzer { } private func containsWasm(_ program: Program) -> Bool { - program.code.contains { $0.op.requiredContext.contains(.wasm) || $0.op.requiredContext.contains(.wasmTypeGroup)} + program.code.contains { + $0.op.requiredContext.contains(.wasm) || $0.op.requiredContext.contains(.wasmTypeGroup) + } } /// Imports a potentially interesting program into this fuzzer. @@ -449,7 +465,9 @@ public class Fuzzer { /// When dropout is enabled, a configurable percentage of programs will be ignored during importing. This /// mechanism can help reduce the similarity of different fuzzer instances. @discardableResult - public func importProgram(_ program: Program, origin: ProgramOrigin, enableDropout: Bool = false) -> ImportResult { + public func importProgram( + _ program: Program, origin: ProgramOrigin, enableDropout: Bool = false + ) -> ImportResult { dispatchPrecondition(condition: .onQueue(queue)) if enableDropout && probability(config.dropoutRate) { @@ -460,8 +478,10 @@ public class Fuzzer { if let path = config.storagePath { // Create a folder to store the excluded program if not existent, yet. let dirName = "\(path)/\(Configuration.excludedWasmDirectory)" - try! FileManager.default.createDirectory(atPath: dirName, withIntermediateDirectories: true) - (modules["Storage"] as! Storage).storeProgram(program, + try! FileManager.default.createDirectory( + atPath: dirName, withIntermediateDirectories: true) + (modules["Storage"] as! Storage).storeProgram( + program, as: "program_\(program.id).fzil", in: dirName) } return .needsWasm @@ -474,14 +494,18 @@ public class Fuzzer { case .crashed(let termsig): // Here we explicitly deal with the possibility that an interesting sample // from another instance triggers a crash in this instance. - processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) + processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) case .differential: - processDifferential(program, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin) + processDifferential( + program, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin) case .succeeded: if let aspects = evaluator.evaluate(execution) { - wasImported = processMaybeInteresting(program, havingAspects: aspects, origin: origin) + wasImported = processMaybeInteresting( + program, havingAspects: aspects, origin: origin) } if case .corpusImport(let mode) = origin, mode == .full, !wasImported { @@ -507,10 +531,14 @@ public class Fuzzer { let execution = execute(program, purpose: .programImport) if case .crashed(let termsig) = execution.outcome { - processCrash(program, withSignal: termsig, withStderr: execution.stderr, withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) + processCrash( + program, withSignal: termsig, withStderr: execution.stderr, + withStdout: execution.stdout, origin: origin, withExectime: execution.execTime) } else { // Non-deterministic crash - dispatchEvent(events.CrashFound, data: (program, behaviour: .flaky, isUnique: true, origin: origin)) + dispatchEvent( + events.CrashFound, + data: (program, behaviour: .flaky, isUnique: true, origin: origin)) } } @@ -547,7 +575,7 @@ public class Fuzzer { let dummy = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } var variablesToReplaceWithDummy = VariableSet() - b.adopting() { + b.adopting { for instr in program.code { var removeInstruction = false switch instr.op.opcode { @@ -561,7 +589,9 @@ public class Fuzzer { } if !removeInstruction { - let inouts = instr.inouts.map({ variablesToReplaceWithDummy.contains($0) ? dummy : b.adopt($0) }) + let inouts = instr.inouts.map({ + variablesToReplaceWithDummy.contains($0) ? dummy : b.adopt($0) + }) let newInstr = Instruction(instr.op, inouts: inouts, flags: instr.flags) b.append(newInstr) } @@ -583,17 +613,19 @@ public class Fuzzer { /// (e.g. because it throws a runtime exception), then this function will try to "fix" the program so that it /// executes successfully and can be imported. private static let maxProgramImportFixupAttempts = 3 - public func importProgramWithFixup(_ originalProgram: Program, origin: ProgramOrigin) -> (result: ImportResult, fixupAttempts: Int) { + public func importProgramWithFixup(_ originalProgram: Program, origin: ProgramOrigin) -> ( + result: ImportResult, fixupAttempts: Int + ) { var program = originalProgram var result = importProgram(program, origin: origin) // Only attempt fixup if the program failed to execute successfully. In particular, ignore timeouts and // crashes here, but also take into account that not all successfully executing programs will be imported. switch result { - case .dropped, .needsWasm, .imported: - return (result, 0) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 0) + case .failed(_): + break } let b = makeBuilder() @@ -614,13 +646,12 @@ public class Fuzzer { program = removeCallsTo(filteredFunctions, from: program) result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: - return (result, 1) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 1) + case .failed(_): + break } - // Second attempt at fixing the program: enable guards (try-catch) for all guardable operations, then // remove all guards that aren't needed (because no exception is thrown). for instr in program.code { @@ -636,20 +667,21 @@ public class Fuzzer { } result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: - return (result, 2) - case .failed(_): - break + case .dropped, .needsWasm, .imported: + return (result, 2) + case .failed(_): + break } // Third and final attempt at fixing up the program: simply wrap the entire program in a try-catch block. - b.buildTryCatchFinally(tryBody: { - b.adopting() { - for instr in program.code { - b.adopt(instr) + b.buildTryCatchFinally( + tryBody: { + b.adopting { + for instr in program.code { + b.adopt(instr) + } } - } - }, catchBody: { _ in }) + }, catchBody: { _ in }) program = b.finalize() result = importProgram(program, origin: origin) @@ -662,7 +694,9 @@ public class Fuzzer { /// Corpus import happens asynchronously as it may take a considerable amount of time (each program /// needs to be executed and possibly minimized). During corpus import, the current progress can be /// obtained from corpusImportProgress(). - public func scheduleCorpusImport(_ corpus: [Program], importMode: CorpusImportMode, enableDropout: Bool = false) { + public func scheduleCorpusImport( + _ corpus: [Program], importMode: CorpusImportMode, enableDropout: Bool = false + ) { dispatchPrecondition(condition: .onQueue(queue)) // Currently we only allow corpus import when the fuzzer is still uninitialized. // If necessary, this can be changed, but we'd need to be able to correctly handle the .waiting -> .corpusImport state transition. @@ -703,7 +737,9 @@ public class Fuzzer { /// - timeout: The timeout after which to abort execution. If nil, the default timeout of this fuzzer will be used. /// - purpose: The purpose of this program execution. /// - Returns: An Execution structure representing the execution outcome. - public func execute(_ program: Program, withTimeout timeout: UInt32? = nil, purpose: ExecutionPurpose) -> Execution { + public func execute( + _ program: Program, withTimeout timeout: UInt32? = nil, purpose: ExecutionPurpose + ) -> Execution { dispatchPrecondition(condition: .onQueue(queue)) assert(runner.isInitialized) @@ -713,8 +749,11 @@ public class Fuzzer { let execution = runner.run(script, withTimeout: timeout ?? config.timeout) dispatchEvent(events.PostExecute, data: execution) - if (isDifferentialFuzzing && purpose.supportsDifferentialRun && execution.outcome == .succeeded) { - return executeDifferentialIfNeeded(execution, program, script, withTimeout: timeout ?? config.timeout) + if isDifferentialFuzzing && purpose.supportsDifferentialRun + && execution.outcome == .succeeded + { + return executeDifferentialIfNeeded( + execution, program, script, withTimeout: timeout ?? config.timeout) } return execution @@ -724,7 +763,9 @@ public class Fuzzer { /// This function will first determine which (if any) of the interesting aspects are triggered reliably, then schedule the program for minimization and inclusion in the corpus. /// Returns true if this program was interesting (i.e. had at least some interesting aspects that are triggered reliably), false if not. @discardableResult - func processMaybeInteresting(_ program: Program, havingAspects aspects: ProgramAspects, origin: ProgramOrigin) -> Bool { + func processMaybeInteresting( + _ program: Program, havingAspects aspects: ProgramAspects, origin: ProgramOrigin + ) -> Bool { var aspects = aspects // Determine which (if any) aspects of the program are triggered deterministially. @@ -737,11 +778,13 @@ public class Fuzzer { repeat { attempt += 1 if attempt > maxAttempts { - logger.warning("Sample did not converage after \(maxAttempts) attempts. Discarding it") + logger.warning( + "Sample did not converage after \(maxAttempts) attempts. Discarding it") return false } - guard let intersection = evaluator.computeAspectIntersection(of: program, with: aspects) else { + guard let intersection = evaluator.computeAspectIntersection(of: program, with: aspects) + else { // This likely means that no aspects are triggered deterministically, so discard this sample. return false } @@ -763,7 +806,8 @@ public class Fuzzer { if origin == .local { program.comments.add("Program is interesting due to \(aspects)", at: .footer) } else { - program.comments.add("Imported program is interesting due to \(aspects)", at: .footer) + program.comments.add( + "Imported program is interesting due to \(aspects)", at: .footer) } } assert(!program.code.contains(where: { $0.op is JsInternalOperation })) @@ -781,7 +825,9 @@ public class Fuzzer { // Minimization should be performed as part of the fuzzing dispatch group. This way, the next fuzzing iteration // will only start once the curent sample has been fully processed and inserted into the corpus. fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: aspects, limit: config.minimizationLimit) { minimizedProgram in + minimizer.withMinimizedCopy( + program, withAspects: aspects, limit: config.minimizationLimit + ) { minimizedProgram in self.fuzzGroup.leave() finishProcessing(minimizedProgram) } @@ -790,7 +836,10 @@ public class Fuzzer { } /// Collect information about a crash. - func collectCrashInfo(for program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, withExectime exectime: TimeInterval) -> [String] { + func collectCrashInfo( + for program: Program, withSignal termsig: Int, withStderr stderr: String, + withStdout stdout: String, withExectime exectime: TimeInterval + ) -> [String] { var info = [String]() info.append("CRASH INFO") info.append("==========") @@ -804,24 +853,33 @@ public class Fuzzer { info.append(stdout.trimmingCharacters(in: .newlines)) info.append("FUZZER ARGS: \(config.arguments.joined(separator: " "))") info.append("TARGET ARGS: \(runner.processArguments.joined(separator: " "))") - info.append("CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") + info.append( + "CONTRIBUTORS: \(program.contributors.map({ $0.name }).joined(separator: ", "))") info.append("EXECUTION TIME: \(Int(exectime * 1000))ms") return info } /// Process a program that causes a crash. - func processCrash(_ program: Program, withSignal termsig: Int, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval) { + func processCrash( + _ program: Program, withSignal termsig: Int, withStderr stderr: String, + withStdout stdout: String, origin: ProgramOrigin, withExectime exectime: TimeInterval + ) { func processCommon(_ program: Program) { let hasCrashInfo = program.comments.at(.footer)?.contains("CRASH INFO") ?? false if !hasCrashInfo { - for line in collectCrashInfo(for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, withExectime: exectime) { + for line in collectCrashInfo( + for: program, withSignal: termsig, withStderr: stderr, withStdout: stdout, + withExectime: exectime) + { program.comments.add(line, at: .footer) } } assert(program.comments.at(.footer)?.contains("CRASH INFO") ?? false) // Check for uniqueness only after minimization - let execution = execute(program, withTimeout: self.config.timeout * 2, purpose: .checkForDeterministicBehavior) + let execution = execute( + program, withTimeout: self.config.timeout * 2, + purpose: .checkForDeterministicBehavior) if case .crashed = execution.outcome { let isUnique = evaluator.evaluateCrash(execution) != nil dispatchEvent(events.CrashFound, data: (program, .deterministic, isUnique, origin)) @@ -835,14 +893,19 @@ public class Fuzzer { } fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .crashed(termsig))) { minimizedProgram in + minimizer.withMinimizedCopy( + program, withAspects: ProgramAspects(outcome: .crashed(termsig)) + ) { minimizedProgram in self.fuzzGroup.leave() processCommon(minimizedProgram) } } /// Process a program that causes difference between optimized and unoptimized executions - func processDifferential(_ program: Program, withStderr stderr: String, withStdout stdout: String, origin: ProgramOrigin) { + func processDifferential( + _ program: Program, withStderr stderr: String, withStdout stdout: String, + origin: ProgramOrigin + ) { func processCommon(_ program: Program) { let hasDiffInfo = program.comments.at(.footer)?.contains("DIFFERENTIAL INFO") ?? false if !hasDiffInfo { @@ -858,9 +921,12 @@ public class Fuzzer { program.comments.add(footerMessage, at: .footer) } - let execution = execute(program, withTimeout: self.config.timeout * 2, purpose: .checkForDeterministicBehavior) + let execution = execute( + program, withTimeout: self.config.timeout * 2, + purpose: .checkForDeterministicBehavior) if case .differential = execution.outcome { - dispatchEvent(events.DifferentialFound, data: (program, .deterministic, true, origin)) + dispatchEvent( + events.DifferentialFound, data: (program, .deterministic, true, origin)) } else { dispatchEvent(events.DifferentialFound, data: (program, .flaky, true, origin)) } @@ -871,7 +937,8 @@ public class Fuzzer { } fuzzGroup.enter() - minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { minimizedProgram in + minimizer.withMinimizedCopy(program, withAspects: ProgramAspects(outcome: .differential)) { + minimizedProgram in self.fuzzGroup.leave() processCommon(minimizedProgram) } @@ -924,34 +991,67 @@ public class Fuzzer { let program = currentCorpusImportJob.nextProgram() if currentCorpusImportJob.numberOfProgramsProcessedSoFar % 500 == 0 { - logger.info("Corpus import progress: processed \(currentCorpusImportJob.numberOfProgramsProcessedSoFar) of \(currentCorpusImportJob.totalNumberOfProgramsToImport) programs") + logger.info( + "Corpus import progress: processed \(currentCorpusImportJob.numberOfProgramsProcessedSoFar) of \(currentCorpusImportJob.totalNumberOfProgramsToImport) programs" + ) } - let (result, fixupAttempts) = importProgramWithFixup(program, origin: .corpusImport(mode: currentCorpusImportJob.importMode)) + let (result, fixupAttempts) = importProgramWithFixup( + program, origin: .corpusImport(mode: currentCorpusImportJob.importMode)) currentCorpusImportJob.notifyImportOutcome(result, fixupAttempts: fixupAttempts) if currentCorpusImportJob.isFinished { logger.info("Corpus import finished:") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs executed successfully") - logger.info(" Of which \(currentCorpusImportJob.numberOfProgramsThatWereImport) programs were added to the corpus") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatNeededFixup)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs needed fixup during import") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededOneFixupAttempt) succeeded after attempt 1") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededTwoFixupAttempts) succeeded after attempt 2") - logger.info(" \(currentCorpusImportJob.numberOfProgramsThatNeededThreeFixupAttempts) succeeded after attempt 3") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatFailedDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs failed to execute (even after fixup) and weren't imported") - logger.info("\(currentCorpusImportJob.numberOfProgramsThatTimedOutDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs timed out and weren't imported") + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs executed successfully" + ) + logger.info( + " Of which \(currentCorpusImportJob.numberOfProgramsThatWereImport) programs were added to the corpus" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatNeededFixup)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs needed fixup during import" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededOneFixupAttempt) succeeded after attempt 1" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededTwoFixupAttempts) succeeded after attempt 2" + ) + logger.info( + " \(currentCorpusImportJob.numberOfProgramsThatNeededThreeFixupAttempts) succeeded after attempt 3" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatFailedDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs failed to execute (even after fixup) and weren't imported" + ) + logger.info( + "\(currentCorpusImportJob.numberOfProgramsThatTimedOutDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs timed out and weren't imported" + ) if !config.isWasmEnabled { - logger.info("\(currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require Wasm which is disabled") - if currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled > 0 && config.storagePath != nil { - logger.info(" These programs have been stored at \(config.storagePath!)/\(Configuration.excludedWasmDirectory)/") + logger.info( + "\(currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require Wasm which is disabled" + ) + if currentCorpusImportJob.numberOfProgramsRequiringWasmButDisabled > 0 + && config.storagePath != nil + { + logger.info( + " These programs have been stored at \(config.storagePath!)/\(Configuration.excludedWasmDirectory)/" + ) } } - let successRatio = Double(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport) / Double(currentCorpusImportJob.totalNumberOfProgramsToImport) + let successRatio = + Double( + currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport) + / Double(currentCorpusImportJob.totalNumberOfProgramsToImport) let failureRatio = 1.0 - successRatio if failureRatio >= 0.25 { - let reason = config.isWasmEnabled ? "execute successfully" : "execute successfully or require currently disabled wasm" - logger.warning("\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported.") + let reason = + config.isWasmEnabled + ? "execute successfully" + : "execute successfully or require currently disabled wasm" + logger.warning( + "\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported." + ) } dispatchEvent(events.CorpusImportComplete) @@ -971,9 +1071,13 @@ public class Fuzzer { // have finished the initial corpus generation), then compare the corpus size and coverage. if iterationsSinceLastInterestingProgram > 100 { guard !corpus.isEmpty else { - logger.fatal("Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?") + logger.fatal( + "Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?" + ) } - logger.info("Initial corpus generation finished. Corpus now contains \(corpus.size) elements") + logger.info( + "Initial corpus generation finished. Corpus now contains \(corpus.size) elements" + ) changeState(to: .fuzzing) } @@ -1013,13 +1117,15 @@ public class Fuzzer { /// Runs a number of startup tests to check whether everything is configured correctly. /// Returns a recommended timeout. - public func runStartupTests(with timeout : Timeout) -> Timeout { + public func runStartupTests(with timeout: Timeout) -> Timeout { assert(isInitialized) // Check if we can execute programs var execution = execute(Program(), purpose: .startup) guard case .succeeded = execution.outcome else { - logger.fatal("Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?") + logger.fatal( + "Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?" + ) } // Check if we can detect failed executions (i.e. an exception was thrown) @@ -1028,7 +1134,9 @@ public class Fuzzer { b.throwException(exception) execution = execute(b.finalize(), purpose: .startup) guard case .failed = execution.outcome else { - logger.fatal("Cannot detect failed executions (exit code must be nonzero when an uncaught exception was thrown, but execution outcome was \(execution.outcome))") + logger.fatal( + "Cannot detect failed executions (exit code must be nonzero when an uncaught exception was thrown, but execution outcome was \(execution.outcome))" + ) } var maxExecutionTime: TimeInterval = 0 @@ -1047,19 +1155,22 @@ public class Fuzzer { execution = execute(b.finalize(), purpose: .startup) if execution.outcome == .timedOut { - logger.fatal("Testcase \"\(test)\" timed out, the configured timeout threshold " - + "(\(config.timeout)ms) might be too low") + logger.fatal( + "Testcase \"\(test)\" timed out, the configured timeout threshold " + + "(\(config.timeout)ms) might be too low") } switch expectedResult { case .shouldSucceed where execution.outcome != .succeeded: - logger.fatal("Testcase \"\(test)\" did not execute successfully" + - "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") + logger.fatal( + "Testcase \"\(test)\" did not execute successfully" + + "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") case .shouldCrash where !execution.outcome.isCrash(): logger.fatal("Testcase \"\(test)\" did not crash") case .shouldNotCrash where execution.outcome.isCrash(): - logger.fatal("Testcase \"\(test)\" unexpectedly crashed" + - "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") + logger.fatal( + "Testcase \"\(test)\" unexpectedly crashed" + + "\nstdout:\n\(execution.stdout)\nstderr:\n\(execution.stderr)") default: // Test passed break @@ -1074,7 +1185,9 @@ public class Fuzzer { } if !hasAnyCrashTests { - logger.warning("Cannot check if crashes are detected as there are no startup tests that should cause a crash") + logger.warning( + "Cannot check if crashes are detected as there are no startup tests that should cause a crash" + ) } // Determine recommended timeout value (rounded up to nearest multiple of 10ms) @@ -1082,10 +1195,12 @@ public class Fuzzer { let recommendedTimeout = 2 * maxExecutionTimeMs // Specify the actual timeout based on an interval if configured. - let actualTimeout : Timeout + let actualTimeout: Timeout if case .interval(let lowerLimit, let upperLimit) = timeout { let timeout = max(min(UInt32(recommendedTimeout), upperLimit), lowerLimit) - logger.info("Determined a timeout of \(timeout)ms based on the interval [\(lowerLimit), \(upperLimit)]") + logger.info( + "Determined a timeout of \(timeout)ms based on the interval [\(lowerLimit), \(upperLimit)]" + ) actualTimeout = Timeout.value(timeout) // Update the configuration used by the main thread. Worker threads @@ -1095,15 +1210,19 @@ public class Fuzzer { actualTimeout = timeout } - logger.info("Recommended timeout: at least \(recommendedTimeout)ms. Current timeout: \(config.timeout)ms") + logger.info( + "Recommended timeout: at least \(recommendedTimeout)ms. Current timeout: \(config.timeout)ms" + ) // Check if we can receive program output b = makeBuilder() let str = b.loadString("Hello World!") b.doPrint(str) - let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters(in: .whitespacesAndNewlines) + let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters( + in: .whitespacesAndNewlines) if output != "Hello World!" { - logger.warning("Cannot receive FuzzIL output (got \"\(output)\" instead of \"Hello World!\")") + logger.warning( + "Cannot receive FuzzIL output (got \"\(output)\" instead of \"Hello World!\")") } // Wrap the executor in a JavaScriptTestRunner @@ -1114,8 +1233,10 @@ public class Fuzzer { do { let output = try executor.executeScript("", withTimeout: 300).output if output.lengthOfBytes(using: .utf8) > 0 { - logger.warning("Runner has non-empty output for empty program! This might indicate that some flags are wrong.") - logger.warning("Output:\n\(output)" ) + logger.warning( + "Runner has non-empty output for empty program! This might indicate that some flags are wrong." + ) + logger.warning("Output:\n\(output)") } } catch { logger.warning("Could not run shell in standalone mode to check flags.") @@ -1125,7 +1246,9 @@ public class Fuzzer { return actualTimeout } - private func executeDifferentialIfNeeded(_ execution: Execution, _ program: Program, _ script: String, withTimeout timeout: UInt32) -> Execution { + private func executeDifferentialIfNeeded( + _ execution: Execution, _ program: Program, _ script: String, withTimeout timeout: UInt32 + ) -> Execution { do { let optPath = config.diffConfig!.getDumpFilename(isOptimized: true) let unoptPath = config.diffConfig!.getDumpFilename(isOptimized: false) @@ -1148,14 +1271,17 @@ public class Fuzzer { let unoptimizedDump = try String(contentsOfFile: unoptPath, encoding: .utf8) // While Dumpling is not super-stable we print out the program here to not miss anything. - let result = DiffExecution.diff(optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, unoptDumpOut: unoptimizedDump) + let result = DiffExecution.diff( + optExec: execution, unoptExec: unoptExecution, optDumpOut: optimizedDump, + unoptDumpOut: unoptimizedDump) if result.outcome == .differential { - logger.error(""" - ================================================================ - [DUMPLING] POTENTIAL DIFFERENTIAL DETECTED - ================================================================ - """) + logger.error( + """ + ================================================================ + [DUMPLING] POTENTIAL DIFFERENTIAL DETECTED + ================================================================ + """) logger.error(script) } @@ -1189,11 +1315,13 @@ public class Fuzzer { var numberOfProgramsThatNeededFixup: Int { assert(Fuzzer.maxProgramImportFixupAttempts == 3) - return numberOfProgramsThatNeededOneFixupAttempt + numberOfProgramsThatNeededTwoFixupAttempts + numberOfProgramsThatNeededThreeFixupAttempts + return numberOfProgramsThatNeededOneFixupAttempt + + numberOfProgramsThatNeededTwoFixupAttempts + + numberOfProgramsThatNeededThreeFixupAttempts } init(corpus: [Program], mode: CorpusImportMode) { - self.corpusToImport = corpus.reversed() // Programs are taken from the end. + self.corpusToImport = corpus.reversed() // Programs are taken from the end. self.importMode = mode self.totalNumberOfProgramsToImport = corpus.count } diff --git a/Sources/Fuzzilli/Lifting/Expression.swift b/Sources/Fuzzilli/Lifting/Expression.swift index ff149fdcb..c748ed2a4 100644 --- a/Sources/Fuzzilli/Lifting/Expression.swift +++ b/Sources/Fuzzilli/Lifting/Expression.swift @@ -84,9 +84,10 @@ public struct Expression: CustomStringConvertible { } func extended(by part: String) -> Expression { - return Expression(type: type, - text: text + part, - numSubexpressions: numSubexpressions) + return Expression( + type: type, + text: text + part, + numSubexpressions: numSubexpressions) } func extended(by part: Expression) -> Expression { @@ -96,20 +97,21 @@ public struct Expression: CustomStringConvertible { } else { newText = text + part.text } - return Expression(type: type, - text: newText, - numSubexpressions: numSubexpressions + 1) + return Expression( + type: type, + text: newText, + numSubexpressions: numSubexpressions + 1) } - static func +(lhs: Expression, rhs: Expression) -> Expression { + static func + (lhs: Expression, rhs: Expression) -> Expression { return lhs.extended(by: rhs) } - static func +(lhs: Expression, rhs: String) -> Expression { + static func + (lhs: Expression, rhs: String) -> Expression { return lhs.extended(by: rhs) } - static func +(lhs: Expression, rhs: Int64) -> Expression { + static func + (lhs: Expression, rhs: Int64) -> Expression { return lhs.extended(by: String(rhs)) } } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index b624f08a4..4dffd0123 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -23,7 +23,7 @@ public class FuzzILLifter: Lifter { return "v\(v.number)" } - private func lift(_ instr : Instruction, with w: inout ScriptWriter) { + private func lift(_ instr: Instruction, with w: inout ScriptWriter) { func input(_ n: Int) -> String { return lift(instr.input(n)) } @@ -73,16 +73,22 @@ public class FuzzILLifter: Lifter { case .createNamedVariable(let op): if op.hasInitialValue { - w.emit("\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)', \(input(0))") + w.emit( + "\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)', \(input(0))" + ) } else { - w.emit("\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)'") + w.emit( + "\(output()) <- CreateNamedVariable '\(op.variableName)', '\(op.declarationMode)'" + ) } case .createNamedDisposableVariable(let op): w.emit("\(output()) <- CreateNamedDisposableVariable '\(op.variableName)', \(input(0))") case .createNamedAsyncDisposableVariable(let op): - w.emit("\(output()) <- CreateNamedAsyncDisposableVariable '\(op.variableName)', \(input(0))") + w.emit( + "\(output()) <- CreateNamedAsyncDisposableVariable '\(op.variableName)', \(input(0))" + ) case .loadDisposableVariable: w.emit("\(output()) <- LoadDisposableVariable \(input(0))") @@ -171,15 +177,15 @@ public class FuzzILLifter: Lifter { let type = op.isExpression ? "exp" : "decl" var line = "\(output()) <- BeginClassDefinition (\(type))" if op.hasSuperclass { - line += " \(input(0))" + line += " \(input(0))" } w.emit(line) w.increaseIndentionLevel() case .beginClassConstructor: - let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassConstructor -> \(params)") - w.increaseIndentionLevel() + let params = instr.innerOutputs.map(lift).joined(separator: ", ") + w.emit("BeginClassConstructor -> \(params)") + w.increaseIndentionLevel() case .endClassConstructor: w.decreaseIndentionLevel() @@ -295,8 +301,8 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndClassPrivateMethod") case .endClassDefinition: - w.decreaseIndentionLevel() - w.emit("EndClassDefinition") + w.decreaseIndentionLevel() + w.emit("EndClassDefinition") case .createArray: let elems = instr.inputs.map(lift).joined(separator: ", ") @@ -340,7 +346,9 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.propertyName)'") case .configureProperty(let op): - w.emit("ConfigureProperty \(input(0)), '\(op.propertyName)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]") + w.emit( + "ConfigureProperty \(input(0)), '\(op.propertyName)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]" + ) case .getElement(let op): let opcode = op.isGuarded ? "GetElement (guarded)" : "GetElement" @@ -357,7 +365,9 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.index)'") case .configureElement(let op): - w.emit("ConfigureElement \(input(0)), '\(op.index)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]") + w.emit( + "ConfigureElement \(input(0)), '\(op.index)', '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 1).map(lift))]" + ) case .getComputedProperty(let op): let opcode = op.isGuarded ? "GetComputedProperty (guarded)" : "GetComputedProperty" @@ -370,11 +380,14 @@ public class FuzzILLifter: Lifter { w.emit("UpdateComputedProperty \(input(0)), \(input(1)), '\(op.op.token)',\(input(2))") case .deleteComputedProperty(let op): - let opcode = op.isGuarded ? "DeleteComputedProperty (guarded)" : "DeleteComputedProperty" + let opcode = + op.isGuarded ? "DeleteComputedProperty (guarded)" : "DeleteComputedProperty" w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1))") case .configureComputedProperty(let op): - w.emit("ConfigureComputedProperty \(input(0)), \(input(1)), '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 2).map(lift))]") + w.emit( + "ConfigureComputedProperty \(input(0)), \(input(1)), '\(op.flags)', '\(op.type)' [\(instr.inputs.suffix(from: 2).map(lift))]" + ) case .typeOf: w.emit("\(output()) <- TypeOf \(input(0))") @@ -389,21 +402,21 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- TestIn \(input(0)), \(input(1))") case .beginPlainFunction(let op as BeginAnyFunction), - .beginArrowFunction(let op as BeginAnyFunction), - .beginGeneratorFunction(let op as BeginAnyFunction), - .beginAsyncFunction(let op as BeginAnyFunction), - .beginAsyncArrowFunction(let op as BeginAnyFunction), - .beginAsyncGeneratorFunction(let op as BeginAnyFunction): + .beginArrowFunction(let op as BeginAnyFunction), + .beginGeneratorFunction(let op as BeginAnyFunction), + .beginAsyncFunction(let op as BeginAnyFunction), + .beginAsyncArrowFunction(let op as BeginAnyFunction), + .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") w.emit("\(output()) <- \(op.name) -> \(params)") w.increaseIndentionLevel() case .endPlainFunction(let op as EndAnyFunction), - .endArrowFunction(let op as EndAnyFunction), - .endGeneratorFunction(let op as EndAnyFunction), - .endAsyncFunction(let op as EndAnyFunction), - .endAsyncArrowFunction(let op as EndAnyFunction), - .endAsyncGeneratorFunction(let op as EndAnyFunction): + .endArrowFunction(let op as EndAnyFunction), + .endGeneratorFunction(let op as EndAnyFunction), + .endAsyncFunction(let op as EndAnyFunction), + .endAsyncArrowFunction(let op as EndAnyFunction), + .endAsyncGeneratorFunction(let op as EndAnyFunction): w.decreaseIndentionLevel() w.emit("\(op.name)") @@ -441,35 +454,54 @@ public class FuzzILLifter: Lifter { case .callFunction(let op): let opcode = op.isGuarded ? "CallFunction (guarded)" : "CallFunction" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .callFunctionWithSpread(let op): - let opcode = op.isGuarded ? "CallFunctionWithSpread (guarded)" : "CallFunctionWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + let opcode = + op.isGuarded ? "CallFunctionWithSpread (guarded)" : "CallFunctionWithSpread" + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .construct(let op): let opcode = op.isGuarded ? "Construct (guarded)" : "Construct" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .constructWithSpread(let op): let opcode = op.isGuarded ? "ConstructWithSpread (guarded)" : "ConstructWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .callMethod(let op): let opcode = op.isGuarded ? "CallMethod (guarded)" : "CallMethod" - w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .callMethodWithSpread(let op): let opcode = op.isGuarded ? "CallMethodWithSpread (guarded)" : "CallMethodWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .callComputedMethod(let op): let opcode = op.isGuarded ? "CallComputedMethod (guarded)" : "CallComputedMethod" - w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs))]" + ) case .callComputedMethodWithSpread(let op): - let opcode = op.isGuarded ? "CallComputedMethodWithSpread (guarded)" : "CallComputedMethodWithSpread" - w.emit("\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]") + let opcode = + op.isGuarded + ? "CallComputedMethodWithSpread (guarded)" : "CallComputedMethodWithSpread" + w.emit( + "\(output()) <- \(opcode) \(input(0)), \(input(1)), [\(liftCallArguments(instr.variadicInputs, spreading: op.spreads))]" + ) case .unaryOperation(let op): if op.op.isPostfix { @@ -495,19 +527,27 @@ public class FuzzILLifter: Lifter { case .destructArray(let op): let outputs = instr.outputs.map(lift) - w.emit("[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArray \(input(0))") + w.emit( + "[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArray \(input(0))" + ) case .destructArrayAndReassign(let op): let outputs = instr.inputs.dropFirst().map(lift) - w.emit("[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArrayAndReassign \(input(0))") + w.emit( + "[\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest))] <- DestructArrayAndReassign \(input(0))" + ) case .destructObject(let op): let outputs = instr.outputs.map(lift) - w.emit("{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObject \(input(0))") + w.emit( + "{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObject \(input(0))" + ) case .destructObjectAndReassign(let op): let outputs = instr.inputs.dropFirst().map(lift) - w.emit("{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObjectAndReassign \(input(0))") + w.emit( + "{\(liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement))} <- DestructObjectAndReassign \(input(0))" + ) case .compare(let op): w.emit("\(output()) <- Compare \(input(0)), '\(op.op.token)', \(input(1))") @@ -580,28 +620,32 @@ public class FuzzILLifter: Lifter { w.emit("EndSwitch") case .callSuperConstructor: - w.emit("CallSuperConstructor [\(liftCallArguments(instr.variadicInputs))]") + w.emit("CallSuperConstructor [\(liftCallArguments(instr.variadicInputs))]") case .callSuperMethod(let op): - w.emit("\(output()) <- CallSuperMethod '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- CallSuperMethod '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .getPrivateProperty(let op): - w.emit("\(output()) <- GetPrivateProperty '\(op.propertyName)'") + w.emit("\(output()) <- GetPrivateProperty '\(op.propertyName)'") case .setPrivateProperty(let op): - w.emit("SetPrivateProperty '\(op.propertyName)', \(input(0))") + w.emit("SetPrivateProperty '\(op.propertyName)', \(input(0))") case .updatePrivateProperty(let op): w.emit("UpdatePrivateProperty '\(op.propertyName)', '\(op.op.token)', \(input(0))") case .callPrivateMethod(let op): - w.emit("\(output()) <- CallPrivateMethod \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]") + w.emit( + "\(output()) <- CallPrivateMethod \(input(0)), '\(op.methodName)', [\(liftCallArguments(instr.variadicInputs))]" + ) case .getSuperProperty(let op): - w.emit("\(output()) <- GetSuperProperty '\(op.propertyName)'") + w.emit("\(output()) <- GetSuperProperty '\(op.propertyName)'") case .setSuperProperty(let op): - w.emit("SetSuperProperty '\(op.propertyName)', \(input(0))") + w.emit("SetSuperProperty '\(op.propertyName)', \(input(0))") case .getComputedSuperProperty(_): w.emit("\(output()) <- GetComputedSuperProperty \(input(0))") @@ -690,7 +734,9 @@ public class FuzzILLifter: Lifter { case .beginForOfLoopWithDestruct(let op): let outputs = instr.innerOutputs.map(lift) - w.emit("BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))]") + w.emit( + "BeginForOfLoopWithDestruct \(input(0)) -> [\(liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement))]" + ) w.increaseIndentionLevel() case .endForOfLoop: @@ -710,7 +756,7 @@ public class FuzzILLifter: Lifter { w.emit("EndRepeatLoop") case .loopBreak, - .switchBreak: + .switchBreak: w.emit("Break") case .loopContinue: @@ -765,14 +811,18 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- EndWasmModule") case .createWasmGlobal(let op): - let isMutable = op.isMutable ? ", mutable" : "" - w.emit("\(output()) <- CreateWasmGlobal \(op.value.typeString()): \(op.value.valueToString())\(isMutable)") + let isMutable = op.isMutable ? ", mutable" : "" + w.emit( + "\(output()) <- CreateWasmGlobal \(op.value.typeString()): \(op.value.valueToString())\(isMutable)" + ) case .createWasmMemory(let op): let maxPagesStr = op.memType.limits.max != nil ? "\(op.memType.limits.max!)" : "" let isMem64Str = op.memType.isMemory64 ? " memory64" : "" let sharedStr = op.memType.isShared ? " shared" : "" - w.emit("\(output()) <- CreateWasmMemory [\(op.memType.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)") + w.emit( + "\(output()) <- CreateWasmMemory [\(op.memType.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)" + ) case .createWasmTable(let op): var maxSizeStr = "" @@ -780,7 +830,9 @@ public class FuzzILLifter: Lifter { maxSizeStr = "\(maxSize)" } let isTable64Str = op.tableType.isTable64 ? ", table64" : "" - w.emit("\(output()) <- CreateWasmTable \(op.tableType.elementType) [\(op.tableType.limits.min),\(maxSizeStr)\(isTable64Str)]") + w.emit( + "\(output()) <- CreateWasmTable \(op.tableType.elementType) [\(op.tableType.limits.min),\(maxSizeStr)\(isTable64Str)]" + ) case .createWasmJSTag(_): w.emit("\(output()) <- CreateWasmJSTag") @@ -805,7 +857,9 @@ public class FuzzILLifter: Lifter { case .beginWasmFunction(_): // TODO(cffsmith): do this properly? - w.emit("BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "BeginWasmFunction \(input(0)) -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .endWasmFunction: @@ -821,7 +875,9 @@ public class FuzzILLifter: Lifter { "\(entry) : \(input(index))" }.joined(separator: ", ") let isTable64Str = op.isTable64 ? ", table64" : "" - w.emit("\(output()) <- WasmDefineTable \(op.elementType)\(isTable64Str), (\(op.limits.min), \(String(describing: op.limits.max))), [\(entries)]") + w.emit( + "\(output()) <- WasmDefineTable \(op.elementType)\(isTable64Str), (\(op.limits.min), \(String(describing: op.limits.max))), [\(entries)]" + ) case .wasmDefineElementSegment(_): w.emit("\(output()) <- WasmDefineElementSegment [...]") @@ -841,7 +897,9 @@ public class FuzzILLifter: Lifter { let maxPagesStr = mem.limits.max != nil ? "\(mem.limits.max!)" : "" let isMem64Str = mem.isMemory64 ? " memory64" : "" let sharedStr = mem.isShared ? " shared" : "" - w.emit("\(output()) <- WasmDefineMemory [\(mem.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)") + w.emit( + "\(output()) <- WasmDefineMemory [\(mem.limits.min),\(maxPagesStr)],\(isMem64Str)\(sharedStr)" + ) case .wasmDefineDataSegment(_): w.emit("\(output()) <- WasmDefineDataSegment [...]") @@ -865,22 +923,34 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmTableGrow \(input(0)), \(input(1)), \(input(2))") case .wasmMemoryLoad(let op): - w.emit("\(output()) <- WasmMemoryLoad '\(op.loadType)' \(input(0))[\(input(1)) + \(op.staticOffset)]") + w.emit( + "\(output()) <- WasmMemoryLoad '\(op.loadType)' \(input(0))[\(input(1)) + \(op.staticOffset)]" + ) case .wasmMemoryStore(let op): - w.emit("WasmMemoryStore '\(op.storeType)' \(input(0))[\(input(1)) + \(op.staticOffset)] <- \(input(2))") + w.emit( + "WasmMemoryStore '\(op.storeType)' \(input(0))[\(input(1)) + \(op.staticOffset)] <- \(input(2))" + ) case .wasmAtomicLoad(let op): - w.emit("\(output()) <- WasmAtomicLoad \(input(0))[\(input(1)) + \(op.offset)] [\(op.loadType)]") + w.emit( + "\(output()) <- WasmAtomicLoad \(input(0))[\(input(1)) + \(op.offset)] [\(op.loadType)]" + ) case .wasmAtomicStore(let op): - w.emit("WasmAtomicStore \(input(0))[\(input(1)) + \(op.offset)] <- \(input(2)) [\(op.storeType)]") + w.emit( + "WasmAtomicStore \(input(0))[\(input(1)) + \(op.offset)] <- \(input(2)) [\(op.storeType)]" + ) case .wasmAtomicRMW(let op): - w.emit("\(output()) <- WasmAtomicRMW \(input(0))[\(input(1)) + \(op.offset)] \(op.op) \(input(2))") + w.emit( + "\(output()) <- WasmAtomicRMW \(input(0))[\(input(1)) + \(op.offset)] \(op.op) \(input(2))" + ) case .wasmAtomicCmpxchg(let op): - w.emit("\(output()) <- WasmAtomicCmpxchg \(input(0))[\(input(1)) + \(op.offset)], \(input(2)), \(input(3)) [\(op.op)]") + w.emit( + "\(output()) <- WasmAtomicCmpxchg \(input(0))[\(input(1)) + \(op.offset)], \(input(2)), \(input(3)) [\(op.op)]" + ) case .wasmMemorySize(_): w.emit("\(output()) <- WasmMemorySize \(input(0))") @@ -961,25 +1031,43 @@ public class FuzzILLifter: Lifter { case .wasmWrapi64Toi32(_): w.emit("\(output()) <- WasmWrapi64Toi32 \(input(0))") case .wasmTruncatef32Toi32(let op): - w.emit("\(output()) <- WasmTruncatef32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef64Toi32(let op): - w.emit("\(output()) <- WasmTruncatef64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmExtendi32Toi64(let op): - w.emit("\(output()) <- WasmExtendi32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmExtendi32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef32Toi64(let op): - w.emit("\(output()) <- WasmTruncatef32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncatef64Toi64(let op): - w.emit("\(output()) <- WasmTruncatef64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncatef64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti32Tof32(let op): - w.emit("\(output()) <- WasmConverti32Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti32Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti64Tof32(let op): - w.emit("\(output()) <- WasmConverti64Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti64Tof32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmDemotef64Tof32(_): w.emit("\(output()) <- WasmDemotef64Tof32 \(input(0))") case .wasmConverti32Tof64(let op): - w.emit("\(output()) <- WasmConverti32Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti32Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmConverti64Tof64(let op): - w.emit("\(output()) <- WasmConverti64Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmConverti64Tof64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmPromotef32Tof64(_): w.emit("\(output()) <- WasmPromotef32Tof64 \(input(0))") case .wasmReinterpretf32Asi32(_): @@ -1001,13 +1089,21 @@ public class FuzzILLifter: Lifter { case .wasmSignExtend32Intoi64(_): w.emit("\(output()) <- WasmSignExtend32Intoi64 \(input(0))") case .wasmTruncateSatf32Toi32(let op): - w.emit("\(output()) <- WasmTruncateSatf32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf32Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf64Toi32(let op): - w.emit("\(output()) <- WasmTruncateSatf64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf64Toi32 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf32Toi64(let op): - w.emit("\(output()) <- WasmTruncateSatf32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf32Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmTruncateSatf64Toi64(let op): - w.emit("\(output()) <- WasmTruncateSatf64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))") + w.emit( + "\(output()) <- WasmTruncateSatf64Toi64 \(input(0)) (\(op.isSigned ? "signed" : "unsigned"))" + ) case .wasmReturn(let op): if op.numInputs > 0 { @@ -1025,7 +1121,9 @@ public class FuzzILLifter: Lifter { if op.outputCount == 0 { w.emit("WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]") } else { - w.emit("\(output()) <- WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]") + w.emit( + "\(output()) <- WasmJsCall \(instr.input(1)) [\(liftCallArguments(arguments[...]))]" + ) } case .wasmCallIndirect(let op): @@ -1057,7 +1155,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginBlock(_): // TODO(cffsmith): Maybe lift labels as e.g. L7 or something like that? let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginBlock [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginBlock [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndBlock(let op): @@ -1072,7 +1172,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginLoop(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginLoop [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginLoop [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndLoop(let op): @@ -1088,9 +1190,11 @@ public class FuzzILLifter: Lifter { case .wasmBeginTryTable(let op): let args = instr.inputs.map(lift) let blockArgs = args.prefix(1 + op.parameterCount).joined(separator: ", ") - w.emit("WasmBeginTryTable [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTryTable [\(blockArgs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel(by: 2) - var inputIndex = 1 + op.parameterCount + var inputIndex = 1 + op.parameterCount op.catches.forEach { kind in if kind == .Ref || kind == .NoRef { w.emit("catching \(kind) \(args[inputIndex]) to \(args[inputIndex + 1])") @@ -1114,7 +1218,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginTry(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginTry [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTry [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmBeginCatchAll(_): @@ -1127,7 +1233,9 @@ public class FuzzILLifter: Lifter { case .wasmBeginCatch(_): assert(instr.numOutputs == 0) w.decreaseIndentionLevel() - w.emit("WasmBeginCatch \(input(0)) [\(instr.numInputs > 1 ? input(1) : "")] -> L:\(instr.innerOutput(0)) E:\(instr.innerOutput(1)) [\(liftCallArguments(instr.innerOutputs(2...)))]") + w.emit( + "WasmBeginCatch \(input(0)) [\(instr.numInputs > 1 ? input(1) : "")] -> L:\(instr.innerOutput(0)) E:\(instr.innerOutput(1)) [\(liftCallArguments(instr.innerOutputs(2...)))]" + ) w.increaseIndentionLevel() case .wasmEndTry(let op): @@ -1150,7 +1258,9 @@ public class FuzzILLifter: Lifter { w.emit("WasmRethrow \(instr.input(0))") case .wasmBeginTryDelegate(_): - w.emit("WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginTryDelegate -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndTryDelegate(_): @@ -1170,35 +1280,44 @@ public class FuzzILLifter: Lifter { w.emit("WasmBranch: \(instr.inputs.map(lift).joined(separator: ", "))") case .wasmBranchIf(let op): - let hint = switch op.hint { + let hint = + switch op.hint { case .None: "" case .Likely: "likely " case .Unlikely: "unlikely " - } + } let condition = instr.inputs.last! let label = instr.inputs.first! let args = instr.inputs.dropFirst().dropLast().map(lift) w.emit("WasmBranchIf \(hint)\(condition) to \(label) [\(args.joined(separator: ", "))]") case .wasmBranchTable(let op): - let table = (0.. \(instr.input($1)), "}.joined() + let table = + (0.. \(instr.input($1)), " }.joined() + "default => \(instr.input(op.valueCount))" - w.emit("WasmBranchTable on \(instr.input(op.valueCount+1)) [\(table)] args: \(Array(instr.inputs)[(op.valueCount+2)...])") + w.emit( + "WasmBranchTable on \(instr.input(op.valueCount+1)) [\(table)] args: \(Array(instr.inputs)[(op.valueCount+2)...])" + ) case .wasmBeginIf(let op): let inputs = instr.inputs.map(lift).joined(separator: ", ") - let hint = switch op.hint { + let hint = + switch op.hint { case .None: "" case .Likely: "likely " case .Unlikely: "unlikely " - } - w.emit("WasmBeginIf \(op.inverted ? "inverted " : "")\(hint) [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + } + w.emit( + "WasmBeginIf \(op.inverted ? "inverted " : "")\(hint) [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmBeginElse(_): w.decreaseIndentionLevel() let inputs = instr.inputs.map(lift).joined(separator: ", ") - w.emit("WasmBeginElse [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]") + w.emit( + "WasmBeginElse [\(inputs)] -> L:\(instr.innerOutput(0)) [\(liftCallArguments(instr.innerOutputs(1...)))]" + ) w.increaseIndentionLevel() case .wasmEndIf(let op): @@ -1230,22 +1349,32 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmSimd128IntegerUnOp \(op.shape) \(op.unOpKind) \(input(0))") case .wasmSimd128IntegerBinOp(let op): - w.emit("\(output()) <- WasmSimd128IntegerBinOp \(op.shape) \(op.binOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128IntegerBinOp \(op.shape) \(op.binOpKind) \(input(0)) \(input(1))" + ) case .wasmSimd128IntegerTernaryOp(let op): - w.emit("\(output()) <- WasmSimd128IntegerTernaryOp \(op.shape) \(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))") + w.emit( + "\(output()) <- WasmSimd128IntegerTernaryOp \(op.shape) \(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))" + ) case .wasmSimd128FloatUnOp(let op): w.emit("\(output()) <- WasmSimd128FloatUnOp \(op.shape).\(op.unOpKind) \(input(0))") case .wasmSimd128FloatBinOp(let op): - w.emit("\(output()) <- WasmSimd128FloatBinOp \(op.shape).\(op.binOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128FloatBinOp \(op.shape).\(op.binOpKind) \(input(0)) \(input(1))" + ) case .wasmSimd128FloatTernaryOp(let op): - w.emit("\(output()) <- WasmSimd128FloatTernaryOp \(op.shape).\(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))") + w.emit( + "\(output()) <- WasmSimd128FloatTernaryOp \(op.shape).\(op.ternaryOpKind) \(input(0)) \(input(1)) \(input(2))" + ) case .wasmSimd128Compare(let op): - w.emit("\(output()) <- WasmSimd128Compare \(op.shape) \(op.compareOpKind) \(input(0)) \(input(1))") + w.emit( + "\(output()) <- WasmSimd128Compare \(op.shape) \(op.compareOpKind) \(input(0)) \(input(1))" + ) case .wasmSimdSplat(let op): w.emit("\(output()) <- WasmSimdSplat \(op.kind) \(input(0))") @@ -1257,13 +1386,19 @@ public class FuzzILLifter: Lifter { w.emit("\(output()) <- WasmSimdReplaceLane \(op.kind) \(input(0)) lane \(op.lane)") case .wasmSimdStoreLane(let op): - w.emit("WasmSimdStoreLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)") + w.emit( + "WasmSimdStoreLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)" + ) case .wasmSimdLoadLane(let op): - w.emit("\(output()) <- WasmSimdLoadLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)") + w.emit( + "\(output()) <- WasmSimdLoadLane \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset), \(input(2)) lane \(op.lane)" + ) case .wasmSimdLoad(let op): - w.emit("\(output()) <- WasmSimdLoad \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset)") + w.emit( + "\(output()) <- WasmSimdLoad \(op.kind) \(input(0)), \(input(1)) + \(op.staticOffset)" + ) case .wasmArrayNewFixed(_): let inputs = instr.inputs.map(lift).joined(separator: ", ") @@ -1350,10 +1485,13 @@ public class FuzzILLifter: Lifter { case .wasmDefineArrayType(let op): let typeInput = op.elementType.requiredInputCount() == 1 ? " \(input(0))" : "" - w.emit("\(output()) <- WasmDefineArrayType \(op.elementType) mutability=\(op.mutability)\(typeInput)") + w.emit( + "\(output()) <- WasmDefineArrayType \(op.elementType) mutability=\(op.mutability)\(typeInput)" + ) case .wasmDefineStructType(let op): - let fields = op.fields.map { "\($0.type) mutability=\($0.mutability)"}.joined(separator: ", ") + let fields = op.fields.map { "\($0.type) mutability=\($0.mutability)" }.joined( + separator: ", ") let inputs = instr.inputs.map(lift).joined(separator: ", ") w.emit("\(output()) <- WasmDefineStructType(\(fields)) [\(inputs)]") @@ -1377,7 +1515,9 @@ public class FuzzILLifter: Lifter { } for instr in program.code { - if options.contains(.includeComments), let comment = program.comments.at(.instruction(instr.index)) { + if options.contains(.includeComments), + let comment = program.comments.at(.instruction(instr.index)) + { w.emitComment(comment) } @@ -1401,7 +1541,9 @@ public class FuzzILLifter: Lifter { return w.code } - private func liftCallArguments(_ args: ArraySlice, spreading spreads: [Bool] = []) -> String { + private func liftCallArguments(_ args: ArraySlice, spreading spreads: [Bool] = []) + -> String + { var arguments = [String]() for (i, v) in args.enumerated() { if spreads.count > i && spreads[i] { @@ -1413,7 +1555,9 @@ public class FuzzILLifter: Lifter { return arguments.joined(separator: ", ") } - private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) -> String { + private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) + -> String + { assert(indices.count == outputs.count) var arrayPattern = "" @@ -1429,7 +1573,9 @@ public class FuzzILLifter: Lifter { return arrayPattern } - private func liftObjectDestructPattern(properties: [String], outputs: [String], hasRestElement: Bool) -> String { + private func liftObjectDestructPattern( + properties: [String], outputs: [String], hasRestElement: Bool + ) -> String { assert(outputs.count == properties.count + (hasRestElement ? 1 : 0)) var objectPattern = "" @@ -1443,4 +1589,3 @@ public class FuzzILLifter: Lifter { return objectPattern } } - diff --git a/Sources/Fuzzilli/Lifting/JSExpressions.swift b/Sources/Fuzzilli/Lifting/JSExpressions.swift index e06d4f7fd..08a7ff800 100644 --- a/Sources/Fuzzilli/Lifting/JSExpressions.swift +++ b/Sources/Fuzzilli/Lifting/JSExpressions.swift @@ -13,9 +13,9 @@ // limitations under the License. // JavaScript expressions. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence -public let Identifier = ExpressionType(precedence: 20, characteristic: .pure) -public let Literal = ExpressionType(precedence: 20, characteristic: .pure) -public let Keyword = ExpressionType(precedence: 20, characteristic: .pure) +public let Identifier = ExpressionType(precedence: 20, characteristic: .pure) +public let Literal = ExpressionType(precedence: 20, characteristic: .pure) +public let Keyword = ExpressionType(precedence: 20, characteristic: .pure) // RegExp are objects, and so for example for the FuzzIL program // v1 <- CreateRegExp // Compare v1, v1 @@ -25,25 +25,34 @@ public let Keyword = ExpressionType(precedence: 20, // and // /a/ === /a/; // (false) // the former being the correct JavaScript equivalent. -public let RegExpLiteral = ExpressionType(precedence: 20, characteristic: .effectful) -public let CallExpression = ExpressionType(precedence: 19, associativity: .left, characteristic: .effectful) -public let MemberExpression = ExpressionType(precedence: 19, associativity: .left, characteristic: .effectful) -public let NewExpression = ExpressionType(precedence: 19, characteristic: .effectful) +public let RegExpLiteral = ExpressionType(precedence: 20, characteristic: .effectful) +public let CallExpression = ExpressionType( + precedence: 19, associativity: .left, characteristic: .effectful) +public let MemberExpression = ExpressionType( + precedence: 19, associativity: .left, characteristic: .effectful) +public let NewExpression = ExpressionType(precedence: 19, characteristic: .effectful) // Artificial, need brackets around some literals for syntactic reasons -public let NumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let NumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) // A helper expression type since negative numbers are technically unary expressions, but then they wouldn't // be inlined since unary expressions aren't generally pure. -public let NegativeNumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) -public let StringLiteral = ExpressionType(precedence: 17, characteristic: .pure) -public let TemplateLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let ObjectLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let ArrayLiteral = ExpressionType(precedence: 17, characteristic: .effectful) -public let PostfixExpression = ExpressionType(precedence: 16, characteristic: .effectful) -public let UnaryExpression = ExpressionType(precedence: 15, associativity: .right, characteristic: .effectful) -public let BinaryExpression = ExpressionType(precedence: 14, associativity: .none, characteristic: .effectful) -public let TernaryExpression = ExpressionType(precedence: 4, associativity: .none, characteristic: .effectful) -public let AssignmentExpression = ExpressionType(precedence: 3, associativity: .right, characteristic: .effectful) -public let ArrowFunctionExpression = ExpressionType(precedence: 3, associativity: .right, characteristic: .effectful) -public let YieldExpression = ExpressionType(precedence: 2, associativity: .right, characteristic: .effectful) -public let SpreadExpression = ExpressionType(precedence: 2, characteristic: .effectful) -public let CommaExpression = ExpressionType(precedence: 1, associativity: .left, characteristic: .effectful) +public let NegativeNumberLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let StringLiteral = ExpressionType(precedence: 17, characteristic: .pure) +public let TemplateLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let ObjectLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let ArrayLiteral = ExpressionType(precedence: 17, characteristic: .effectful) +public let PostfixExpression = ExpressionType(precedence: 16, characteristic: .effectful) +public let UnaryExpression = ExpressionType( + precedence: 15, associativity: .right, characteristic: .effectful) +public let BinaryExpression = ExpressionType( + precedence: 14, associativity: .none, characteristic: .effectful) +public let TernaryExpression = ExpressionType( + precedence: 4, associativity: .none, characteristic: .effectful) +public let AssignmentExpression = ExpressionType( + precedence: 3, associativity: .right, characteristic: .effectful) +public let ArrowFunctionExpression = ExpressionType( + precedence: 3, associativity: .right, characteristic: .effectful) +public let YieldExpression = ExpressionType( + precedence: 2, associativity: .right, characteristic: .effectful) +public let SpreadExpression = ExpressionType(precedence: 2, characteristic: .effectful) +public let CommaExpression = ExpressionType( + precedence: 1, associativity: .left, characteristic: .effectful) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift index f65dd3cca..725796b69 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptExploreLifting.swift @@ -15,479 +15,479 @@ /// This file contains the JavaScript specific implementation of the Explore operation. See ExplorationMutator.swift for an overview of this feature. struct JavaScriptExploreLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - const explore = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + const explore = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - // - // "Import" the object introspection code. This is used to find properties and methods when exploring an object. - // - \(JavaScriptRuntimeAssistedMutatorLifting.introspectionCode) + // + // "Import" the object introspection code. This is used to find properties and methods when exploring an object. + // + \(JavaScriptRuntimeAssistedMutatorLifting.introspectionCode) - // - // "Import" the Action implementation code. - // - \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) + // + // "Import" the Action implementation code. + // + \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) - // JS Action Operation groups. See e.g. exploreNumber() for examples of how they are used. - const SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT, OP_UNSIGNED_RIGHT_SHIFT]; - // Unsigned shift is not defined for bigints. - const BIGINT_SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT]; - const BITWISE_OPS = [OP_BITWISE_OR, OP_BITWISE_AND, OP_BITWISE_XOR]; - const ARITHMETIC_OPS = [OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD]; - const UNARY_OPS = [OP_INC, OP_DEC, OP_NEG, OP_BITWISE_NOT]; - const COMPARISON_OPS = [OP_COMPARE_EQUAL, OP_COMPARE_STRICT_EQUAL, OP_COMPARE_NOT_EQUAL, OP_COMPARE_STRICT_NOT_EQUAL, OP_COMPARE_GREATER_THAN, OP_COMPARE_LESS_THAN, OP_COMPARE_GREATER_THAN_OR_EQUAL, OP_COMPARE_LESS_THAN_OR_EQUAL]; - const BOOLEAN_BINARY_OPS = [OP_LOGICAL_AND, OP_LOGICAL_OR]; - const BOOLEAN_UNARY_OPS = [OP_LOGICAL_NOT]; + // JS Action Operation groups. See e.g. exploreNumber() for examples of how they are used. + const SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT, OP_UNSIGNED_RIGHT_SHIFT]; + // Unsigned shift is not defined for bigints. + const BIGINT_SHIFT_OPS = [OP_LEFT_SHIFT, OP_SIGNED_RIGHT_SHIFT]; + const BITWISE_OPS = [OP_BITWISE_OR, OP_BITWISE_AND, OP_BITWISE_XOR]; + const ARITHMETIC_OPS = [OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD]; + const UNARY_OPS = [OP_INC, OP_DEC, OP_NEG, OP_BITWISE_NOT]; + const COMPARISON_OPS = [OP_COMPARE_EQUAL, OP_COMPARE_STRICT_EQUAL, OP_COMPARE_NOT_EQUAL, OP_COMPARE_STRICT_NOT_EQUAL, OP_COMPARE_GREATER_THAN, OP_COMPARE_LESS_THAN, OP_COMPARE_GREATER_THAN_OR_EQUAL, OP_COMPARE_LESS_THAN_OR_EQUAL]; + const BOOLEAN_BINARY_OPS = [OP_LOGICAL_AND, OP_LOGICAL_OR]; + const BOOLEAN_UNARY_OPS = [OP_LOGICAL_NOT]; - // - // Global constants. - // - // Property names to use when defining new properties. Should be kept in sync with the equivalent set in JavaScriptEnvironment.swift - const customPropertyNames = [\(JavaScriptEnvironment.CustomPropertyNames.map({ "\"\($0)\"" }).joined(separator: ", "))]; + // + // Global constants. + // + // Property names to use when defining new properties. Should be kept in sync with the equivalent set in JavaScriptEnvironment.swift + const customPropertyNames = [\(JavaScriptEnvironment.CustomPropertyNames.map({ "\"\($0)\"" }).joined(separator: ", "))]; - // Maximum number of parameters for function/method calls. Everything above this is consiered an invalid .length property of the function. - const MAX_PARAMETERS = 10; + // Maximum number of parameters for function/method calls. Everything above this is consiered an invalid .length property of the function. + const MAX_PARAMETERS = 10; - // Well known integer/number values to use when generating random values. - const WELL_KNOWN_INTEGERS = filter([\(JavaScriptEnvironment.InterestingIntegers.map(String.init).joined(separator: ", "))], isInteger); - const WELL_KNOWN_NUMBERS = concat(WELL_KNOWN_INTEGERS, [-1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6]); - const WELL_KNOWN_BIGINTS = [\(JavaScriptEnvironment.InterestingIntegers.map({ "\($0)n" }).joined(separator: ", "))]; + // Well known integer/number values to use when generating random values. + const WELL_KNOWN_INTEGERS = filter([\(JavaScriptEnvironment.InterestingIntegers.map(String.init).joined(separator: ", "))], isInteger); + const WELL_KNOWN_NUMBERS = concat(WELL_KNOWN_INTEGERS, [-1e6, -1e3, -5.0, -4.0, -3.0, -2.0, -1.0, -0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1e3, 1e6]); + const WELL_KNOWN_BIGINTS = [\(JavaScriptEnvironment.InterestingIntegers.map({ "\($0)n" }).joined(separator: ", "))]; - // - // Global state. - // + // + // Global state. + // - // The concrete argument values that will be used when executing the Action for the current exploration operation. - let exploreArguments; + // The concrete argument values that will be used when executing the Action for the current exploration operation. + let exploreArguments; - // The input containing the value being explored. This should always be the first input to every Action created during exploration. - let exploredValueInput; + // The input containing the value being explored. This should always be the first input to every Action created during exploration. + let exploredValueInput; - // Whether exploration is currently happening. This is required to detect recursive exploration, where for example a callback - // triggered during property enumeration triggers further exploration calls. See explore(). - let currentlyExploring = false; + // Whether exploration is currently happening. This is required to detect recursive exploration, where for example a callback + // triggered during property enumeration triggers further exploration calls. See explore(). + let currentlyExploring = false; - // - // Error and result reporting. - // - // Results (indexed by their ID) will be stored in here. - const results = { __proto__: null }; + // + // Error and result reporting. + // + // Results (indexed by their ID) will be stored in here. + const results = { __proto__: null }; - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ERROR: ' + msg); - } - - function recordFailure(id) { - // Delete the property if it already exists (from recordAction). - delete results[id]; - defineProperty(results, id, {__proto__: null, value: NO_ACTION}); - - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_FAILURE: ' + id); - } - - function recordAction(id, action) { - if (hasOwnProperty(results, id)) { - throw "Duplicate action for " + id; + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ERROR: ' + msg); } - if (action === NO_ACTION) { - // This is equivalent to a failure. - return recordFailure(id); + function recordFailure(id) { + // Delete the property if it already exists (from recordAction). + delete results[id]; + defineProperty(results, id, {__proto__: null, value: NO_ACTION}); + + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_FAILURE: ' + id); } - action.id = id; - - // These are configurable as they may need to be overwritten (by recordFailure) in the future. - defineProperty(results, id, {__proto__: null, value: action, configurable: true}); - - fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ACTION: ' + stringify(action)); - } - - function hasActionFor(id) { - return hasOwnProperty(results, id); - } - - function getActionFor(id) { - return results[id]; - } - - // - // Access to random inputs. - // - // These functions prefer to take an existing variable from the arguments to the Explore operations if it satistifes the specified criteria. Otherwise, they generate a new random value. - // Testing whether an argument satisfies some criteria (e.g. be a value in a certain range) may trigger type conversions. This is expected as it may lead to interesting values being used. - // These are grouped into a namespace object to make it more clear that they return an Input object (from one of the above constructors), rather than a value. - // - let Inputs = { - randomArgument() { - return new ArgumentInput(randomIntBelow(exploreArguments.length)); - }, - - randomArguments(n) { - let args = EmptyArray(); - for (let i = 0; i < n; i++) { - push(args, new ArgumentInput(randomIntBelow(exploreArguments.length))); + function recordAction(id, action) { + if (hasOwnProperty(results, id)) { + throw "Duplicate action for " + id; } - return args; - }, - randomArgumentForReplacing(propertyName, obj) { - let curValue = tryGetProperty(propertyName, obj); - if (isUndefined(curValue)) { - return Inputs.randomArgument(); + if (action === NO_ACTION) { + // This is equivalent to a failure. + return recordFailure(id); } - function isCompatible(arg) { - let sameType = typeof curValue === typeof arg; - if (sameType && isObject(curValue)) { - sameType = arg instanceof curValue.constructor; - } - return sameType; - } + action.id = id; - let idx = findIndex(exploreArguments, wrapInTryCatch(isCompatible)); - if (idx != -1) return new ArgumentInput(idx); - return Inputs.randomArgument(); - }, - - randomInt() { - let idx = findIndex(exploreArguments, isInteger); - if (idx != -1) return new ArgumentInput(idx); - return new IntInput(randomElement(WELL_KNOWN_INTEGERS)); - }, - - randomNumber() { - let idx = findIndex(exploreArguments, isNumber); - if (idx != -1) return new ArgumentInput(idx); - return new FloatInput(randomElement(WELL_KNOWN_NUMBERS)); - }, - - randomBigint() { - let idx = findIndex(exploreArguments, isBigint); - if (idx != -1) return new ArgumentInput(idx); - return new BigintInput(randomElement(WELL_KNOWN_BIGINTS)); - }, - - randomIntBetween(start, end) { - if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => NumberIsInteger(e) && (e >= start) && (e < end))); - if (idx != -1) return new ArgumentInput(idx); - return new IntInput(randomIntBetween(start, end)); - }, - - randomBigintBetween(start, end) { - if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; - if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular integers"; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= start) && (e < end))); - if (idx != -1) return new ArgumentInput(idx); - return new BigintInput(randomBigintBetween(start, end)); - }, - - randomNumberCloseTo(v) { - if (!isFinite(v)) throw "Argument to randomNumberCloseTo is not a finite number: " + v; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10) && (e <= v + 10))); - if (idx != -1) return new ArgumentInput(idx); - let step = randomIntBetween(-10, 10); - let value = v + step; - if (isInteger(value)) { - return new IntInput(value); - } else { - return new FloatInput(v + step); - } - }, - - randomBigintCloseTo(v) { - if (!isBigint(v)) throw "Argument to randomBigintCloseTo is not a bigint: " + v; - let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10n) && (e <= v + 10n))); - if (idx != -1) return new ArgumentInput(idx); - let step = randomBigintBetween(-10n, 10n); - let value = v + step; - return new BigintInput(value); - } - } + // These are configurable as they may need to be overwritten (by recordFailure) in the future. + defineProperty(results, id, {__proto__: null, value: action, configurable: true}); - // Heuristic to determine when a function should be invoked as a constructor. Used by the object and function exploration code. - function shouldTreatAsConstructor(f) { - let name = tryGetProperty('name', f); - - // If the function has no name (or a non-string name), it's probably a regular function (or something like an arrow function). - if (!isString(name) || name.length < 1) { - return probability(0.1); + fuzzilli('FUZZILLI_PRINT', 'EXPLORE_ACTION: ' + stringify(action)); } - // If the name is something like `f42`, it's probably a function defined by Fuzzilli. These can typicall be used as function or constructor, but prefer to call them as regular functions. - if (name[0] === 'f' && !isNaN(parseInteger(stringSlice(name, 1)))) { - return probability(0.2); + function hasActionFor(id) { + return hasOwnProperty(results, id); } - // Otherwise, the basic heuristic is that functions that start with an uppercase letter (e.g. Object, Uint8Array, etc.) are probably constructors (but not always, e.g. BigInt). - // This is also compatible with Fuzzilli's lifting of classes, as they will look something like this: `class V3 { ...`. - if (name[0] === toUpperCase(name[0])) { - return probability(0.9); - } else { - return probability(0.1); - } - } - - // - // Explore implementation for different basic types. - // - // These all return an Action object or the special NO_ACTION value (null). - // - function exploreObject(o) { - if (o === null) { - return exploreNullish(o); + function getActionFor(id) { + return results[id]; } - // TODO: Add special handling for ArrayBuffers: most of the time, wrap these into a Uint8Array to be able to modify them. - // TODO: Sometimes iterate over iterable objects (e.g. Arrays)? + // + // Access to random inputs. + // + // These functions prefer to take an existing variable from the arguments to the Explore operations if it satistifes the specified criteria. Otherwise, they generate a new random value. + // Testing whether an argument satisfies some criteria (e.g. be a value in a certain range) may trigger type conversions. This is expected as it may lead to interesting values being used. + // These are grouped into a namespace object to make it more clear that they return an Input object (from one of the above constructors), rather than a value. + // + let Inputs = { + randomArgument() { + return new ArgumentInput(randomIntBelow(exploreArguments.length)); + }, + + randomArguments(n) { + let args = EmptyArray(); + for (let i = 0; i < n; i++) { + push(args, new ArgumentInput(randomIntBelow(exploreArguments.length))); + } + return args; + }, - // Determine a random property, which can generally either be a method, an element, or a "regular" property. - let propertyName = randomPropertyOf(o); + randomArgumentForReplacing(propertyName, obj) { + let curValue = tryGetProperty(propertyName, obj); + if (isUndefined(curValue)) { + return Inputs.randomArgument(); + } - // Determine the appropriate action to perform given the selected property. - // If the property lookup failed (for whatever reason), we always define a new property. - if (propertyName === null) { - let propertyNameInput = new StringInput(randomElement(customPropertyNames)); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); - } else if (isInteger(propertyName)) { - let propertyNameInput = new IntInput(propertyName); - if (probability(0.5)) { - return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); - } else { - let newValue = Inputs.randomArgumentForReplacing(propertyName, o); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); - } - } else if (isString(propertyName)) { - let propertyNameInput = new StringInput(propertyName); - let propertyValue = tryGetProperty(propertyName, o); - if (isFunction(propertyValue)) { - // Perform a method call/construct. - let numParameters = tryGetProperty('length', propertyValue); - if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) return NO_ACTION; - let inputs = EmptyArray(); - push(inputs, exploredValueInput); - push(inputs, propertyNameInput); - for (let i = 0; i < numParameters; i++) { - push(inputs, Inputs.randomArgument()); + function isCompatible(arg) { + let sameType = typeof curValue === typeof arg; + if (sameType && isObject(curValue)) { + sameType = arg instanceof curValue.constructor; + } + return sameType; } - if (shouldTreatAsConstructor(propertyValue)) { - return new GuardedAction(OP_CONSTRUCT_METHOD, inputs); + + let idx = findIndex(exploreArguments, wrapInTryCatch(isCompatible)); + if (idx != -1) return new ArgumentInput(idx); + return Inputs.randomArgument(); + }, + + randomInt() { + let idx = findIndex(exploreArguments, isInteger); + if (idx != -1) return new ArgumentInput(idx); + return new IntInput(randomElement(WELL_KNOWN_INTEGERS)); + }, + + randomNumber() { + let idx = findIndex(exploreArguments, isNumber); + if (idx != -1) return new ArgumentInput(idx); + return new FloatInput(randomElement(WELL_KNOWN_NUMBERS)); + }, + + randomBigint() { + let idx = findIndex(exploreArguments, isBigint); + if (idx != -1) return new ArgumentInput(idx); + return new BigintInput(randomElement(WELL_KNOWN_BIGINTS)); + }, + + randomIntBetween(start, end) { + if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => NumberIsInteger(e) && (e >= start) && (e < end))); + if (idx != -1) return new ArgumentInput(idx); + return new IntInput(randomIntBetween(start, end)); + }, + + randomBigintBetween(start, end) { + if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; + if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular integers"; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= start) && (e < end))); + if (idx != -1) return new ArgumentInput(idx); + return new BigintInput(randomBigintBetween(start, end)); + }, + + randomNumberCloseTo(v) { + if (!isFinite(v)) throw "Argument to randomNumberCloseTo is not a finite number: " + v; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10) && (e <= v + 10))); + if (idx != -1) return new ArgumentInput(idx); + let step = randomIntBetween(-10, 10); + let value = v + step; + if (isInteger(value)) { + return new IntInput(value); } else { - return new GuardedAction(OP_CALL_METHOD, inputs); + return new FloatInput(v + step); } + }, + + randomBigintCloseTo(v) { + if (!isBigint(v)) throw "Argument to randomBigintCloseTo is not a bigint: " + v; + let idx = findIndex(exploreArguments, wrapInTryCatch((e) => (e >= v - 10n) && (e <= v + 10n))); + if (idx != -1) return new ArgumentInput(idx); + let step = randomBigintBetween(-10n, 10n); + let value = v + step; + return new BigintInput(value); + } + } + + // Heuristic to determine when a function should be invoked as a constructor. Used by the object and function exploration code. + function shouldTreatAsConstructor(f) { + let name = tryGetProperty('name', f); + + // If the function has no name (or a non-string name), it's probably a regular function (or something like an arrow function). + if (!isString(name) || name.length < 1) { + return probability(0.1); + } + + // If the name is something like `f42`, it's probably a function defined by Fuzzilli. These can typicall be used as function or constructor, but prefer to call them as regular functions. + if (name[0] === 'f' && !isNaN(parseInteger(stringSlice(name, 1)))) { + return probability(0.2); + } + + // Otherwise, the basic heuristic is that functions that start with an uppercase letter (e.g. Object, Uint8Array, etc.) are probably constructors (but not always, e.g. BigInt). + // This is also compatible with Fuzzilli's lifting of classes, as they will look something like this: `class V3 { ...`. + if (name[0] === toUpperCase(name[0])) { + return probability(0.9); } else { - // Perform a property access. - // Besides getting and setting the property, we also sometimes define a new property instead. - if (probability(1/3)) { - propertyNameInput = new StringInput(randomElement(customPropertyNames)); - return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); - } else if (probability(0.5)) { + return probability(0.1); + } + } + + // + // Explore implementation for different basic types. + // + // These all return an Action object or the special NO_ACTION value (null). + // + function exploreObject(o) { + if (o === null) { + return exploreNullish(o); + } + + // TODO: Add special handling for ArrayBuffers: most of the time, wrap these into a Uint8Array to be able to modify them. + // TODO: Sometimes iterate over iterable objects (e.g. Arrays)? + + // Determine a random property, which can generally either be a method, an element, or a "regular" property. + let propertyName = randomPropertyOf(o); + + // Determine the appropriate action to perform given the selected property. + // If the property lookup failed (for whatever reason), we always define a new property. + if (propertyName === null) { + let propertyNameInput = new StringInput(randomElement(customPropertyNames)); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); + } else if (isInteger(propertyName)) { + let propertyNameInput = new IntInput(propertyName); + if (probability(0.5)) { return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); } else { let newValue = Inputs.randomArgumentForReplacing(propertyName, o); return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); } + } else if (isString(propertyName)) { + let propertyNameInput = new StringInput(propertyName); + let propertyValue = tryGetProperty(propertyName, o); + if (isFunction(propertyValue)) { + // Perform a method call/construct. + let numParameters = tryGetProperty('length', propertyValue); + if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) return NO_ACTION; + let inputs = EmptyArray(); + push(inputs, exploredValueInput); + push(inputs, propertyNameInput); + for (let i = 0; i < numParameters; i++) { + push(inputs, Inputs.randomArgument()); + } + if (shouldTreatAsConstructor(propertyValue)) { + return new GuardedAction(OP_CONSTRUCT_METHOD, inputs); + } else { + return new GuardedAction(OP_CALL_METHOD, inputs); + } + } else { + // Perform a property access. + // Besides getting and setting the property, we also sometimes define a new property instead. + if (probability(1/3)) { + propertyNameInput = new StringInput(randomElement(customPropertyNames)); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, Inputs.randomArgument()]); + } else if (probability(0.5)) { + return new Action(OP_GET_PROPERTY, [exploredValueInput, propertyNameInput]); + } else { + let newValue = Inputs.randomArgumentForReplacing(propertyName, o); + return new Action(OP_SET_PROPERTY, [exploredValueInput, propertyNameInput, newValue]); + } + } + } else { + throw "Got unexpected property name from Inputs.randomPropertyOf(): " + propertyName; } - } else { - throw "Got unexpected property name from Inputs.randomPropertyOf(): " + propertyName; } - } - function exploreFunction(f) { - // Sometimes treat functions as objects. - // This will cause interesting properties like 'arguments' or 'prototype' to be accessed, methods like 'apply' or 'bind' to be called, and methods on builtin constructors like 'Array', and 'Object' to be used. - if (probability(0.5)) { - return exploreObject(f); - } + function exploreFunction(f) { + // Sometimes treat functions as objects. + // This will cause interesting properties like 'arguments' or 'prototype' to be accessed, methods like 'apply' or 'bind' to be called, and methods on builtin constructors like 'Array', and 'Object' to be used. + if (probability(0.5)) { + return exploreObject(f); + } - // Otherwise, call or construct the function/constructor. - let numParameters = tryGetProperty('length', f); - if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) { - numParameters = 0; - } - let inputs = EmptyArray(); - push(inputs, exploredValueInput); - for (let i = 0; i < numParameters; i++) { - push(inputs, Inputs.randomArgument()); - } - let operation = shouldTreatAsConstructor(f) ? OP_CONSTRUCT : OP_CALL_FUNCTION; - return new GuardedAction(operation, inputs); - } - - function exploreString(s) { - // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. - // TODO: sometimes access a character of the string or iterate over it? - if (probability(0.1) && isShortString(s)) { - return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); - } else { - return exploreObject(new String(s)); + // Otherwise, call or construct the function/constructor. + let numParameters = tryGetProperty('length', f); + if (!isInteger(numParameters) || numParameters > MAX_PARAMETERS || numParameters < 0) { + numParameters = 0; + } + let inputs = EmptyArray(); + push(inputs, exploredValueInput); + for (let i = 0; i < numParameters; i++) { + push(inputs, Inputs.randomArgument()); + } + let operation = shouldTreatAsConstructor(f) ? OP_CONSTRUCT : OP_CALL_FUNCTION; + return new GuardedAction(operation, inputs); } - } - - const ALL_NUMBER_OPERATIONS = concat(SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); - const ALL_NUMBER_OPERATIONS_AND_COMPARISONS = concat(ALL_NUMBER_OPERATIONS, COMPARISON_OPS); - function exploreNumber(n) { - // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. - let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(COMPARISON_OPS, operation)) { - if (isNaN(n)) { - // In that case, regular comparisons don't make sense, so just test for isNaN instead. - action.operation = OP_TEST_IS_NAN; - } else if (!isFinite(n)) { - // Similar to the NaN case, just test for isFinite here. - action.operation = OP_TEST_IS_FINITE; + + function exploreString(s) { + // Sometimes (rarely) compare the string against it's original value. Otherwise, treat the string as an object. + // TODO: sometimes access a character of the string or iterate over it? + if (probability(0.1) && isShortString(s)) { + return new Action(OP_COMPARE_EQUAL, [exploredValueInput, new StringInput(s)]); } else { - push(action.inputs, Inputs.randomNumberCloseTo(n)); + return exploreObject(new String(s)); } - } else if (includes(SHIFT_OPS, operation)) { - push(action.inputs, Inputs.randomIntBetween(1, 32)); - } else if (includes(BITWISE_OPS, operation)) { - push(action.inputs, Inputs.randomInt()); - } else if (includes(ARITHMETIC_OPS, operation)) { - if (isInteger(n)) { + } + + const ALL_NUMBER_OPERATIONS = concat(SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); + const ALL_NUMBER_OPERATIONS_AND_COMPARISONS = concat(ALL_NUMBER_OPERATIONS, COMPARISON_OPS); + function exploreNumber(n) { + // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. + let operation = randomElement(probability(0.5) ? ALL_NUMBER_OPERATIONS : ALL_NUMBER_OPERATIONS_AND_COMPARISONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(COMPARISON_OPS, operation)) { + if (isNaN(n)) { + // In that case, regular comparisons don't make sense, so just test for isNaN instead. + action.operation = OP_TEST_IS_NAN; + } else if (!isFinite(n)) { + // Similar to the NaN case, just test for isFinite here. + action.operation = OP_TEST_IS_FINITE; + } else { + push(action.inputs, Inputs.randomNumberCloseTo(n)); + } + } else if (includes(SHIFT_OPS, operation)) { + push(action.inputs, Inputs.randomIntBetween(1, 32)); + } else if (includes(BITWISE_OPS, operation)) { push(action.inputs, Inputs.randomInt()); - } else { - push(action.inputs, Inputs.randomNumber()); + } else if (includes(ARITHMETIC_OPS, operation)) { + if (isInteger(n)) { + push(action.inputs, Inputs.randomInt()); + } else { + push(action.inputs, Inputs.randomNumber()); + } } + return action; } - return action; - } - - const ALL_BIGINT_OPERATIONS = concat(BIGINT_SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); - const ALL_BIGINT_OPERATIONS_AND_COMPARISONS = concat(ALL_BIGINT_OPERATIONS, COMPARISON_OPS); - function exploreBigint(b) { - // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. - let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(COMPARISON_OPS, operation)) { - push(action.inputs, Inputs.randomBigintCloseTo(b)); - } else if (includes(BIGINT_SHIFT_OPS, operation)) { - push(action.inputs, Inputs.randomBigintBetween(1n, 128n)); - } else if (includes(BITWISE_OPS, operation) || includes(ARITHMETIC_OPS, operation)) { - push(action.inputs, Inputs.randomBigint()); - } - return action; - } - - function exploreSymbol(s) { - // Lookup or insert the symbol into the global symbol registry. This will also allow static typing of the output. - return new Action(OP_SYMBOL_REGISTRATION, [exploredValueInput]); - } - - const ALL_BOOLEAN_OPERATIONS = concat(BOOLEAN_BINARY_OPS, BOOLEAN_UNARY_OPS); - function exploreBoolean(b) { - let operation = randomElement(ALL_BOOLEAN_OPERATIONS); - - let action = new Action(operation, EmptyArray()); - push(action.inputs, exploredValueInput); - if (includes(BOOLEAN_BINARY_OPS, operation)) { - // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. - push(action.inputs, Inputs.randomArgument()); + + const ALL_BIGINT_OPERATIONS = concat(BIGINT_SHIFT_OPS, BITWISE_OPS, ARITHMETIC_OPS, UNARY_OPS); + const ALL_BIGINT_OPERATIONS_AND_COMPARISONS = concat(ALL_BIGINT_OPERATIONS, COMPARISON_OPS); + function exploreBigint(b) { + // Somewhat arbitrarily give comparisons a lower probability when choosing the operation to perform. + let operation = randomElement(probability(0.5) ? ALL_BIGINT_OPERATIONS : ALL_BIGINT_OPERATIONS_AND_COMPARISONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(COMPARISON_OPS, operation)) { + push(action.inputs, Inputs.randomBigintCloseTo(b)); + } else if (includes(BIGINT_SHIFT_OPS, operation)) { + push(action.inputs, Inputs.randomBigintBetween(1n, 128n)); + } else if (includes(BITWISE_OPS, operation) || includes(ARITHMETIC_OPS, operation)) { + push(action.inputs, Inputs.randomBigint()); + } + return action; } - return action; - } - - function exploreNullish(v) { - // Best thing we can do with nullish values is a NullCoalescing (??) operation. - return new Action(OP_NULL_COALESCE, [exploredValueInput, Inputs.randomArgument()]) - } - - // Explores the given value and returns an action to perform on it. - function exploreValue(id, v) { - if (isObject(v)) { - return exploreObject(v); - } else if (isFunction(v)) { - return exploreFunction(v); - } else if (isString(v)) { - return exploreString(v); - } else if (isNumber(v)) { - return exploreNumber(v); - } else if (isBigint(v)) { - return exploreBigint(v); - } else if (isSymbol(v)) { - return exploreSymbol(v); - } else if (isBoolean(v)) { - return exploreBoolean(v); - } else if (isUndefined(v)) { - return exploreNullish(v); - } else { - throw "Unexpected value type: " + typeof v; + + function exploreSymbol(s) { + // Lookup or insert the symbol into the global symbol registry. This will also allow static typing of the output. + return new Action(OP_SYMBOL_REGISTRATION, [exploredValueInput]); } - } - - // - // Exploration entrypoint. - // - function explore(id, v, currentThis, args, rngSeed) { - rng.reseed(rngSeed); - - // The given arguments may be used as inputs for the action. - if (isUndefined(args) || args.length < 1) throw "Exploration requires at least one additional argument"; - - // We may get here recursively for example if a Proxy is being explored which triggers further explore calls during e.g. property enumeration. - // Probably the best way to deal with these cases is to just bail out from recursive explorations. - if (currentlyExploring) return; - currentlyExploring = true; - - // Set the global state for this explore operation. - exploreArguments = args; - exploredValueInput = new SpecialInput("exploredValue"); - - // Check if we already have a result for this id, and if so repeat the same action again. Otherwise, explore. - let action; - if (hasActionFor(id)) { - action = getActionFor(id); - } else { - action = exploreValue(id, v); - recordAction(id, action); + + const ALL_BOOLEAN_OPERATIONS = concat(BOOLEAN_BINARY_OPS, BOOLEAN_UNARY_OPS); + function exploreBoolean(b) { + let operation = randomElement(ALL_BOOLEAN_OPERATIONS); + + let action = new Action(operation, EmptyArray()); + push(action.inputs, exploredValueInput); + if (includes(BOOLEAN_BINARY_OPS, operation)) { + // It probably doesn't make sense to hardcode boolean constants, so always use an existing argument. + push(action.inputs, Inputs.randomArgument()); + } + return action; } - // Now perform the selected action. - let context = { arguments: args, specialValues: { "exploredValue": v }, currentThis: currentThis }; - let success = execute(action, context); + function exploreNullish(v) { + // Best thing we can do with nullish values is a NullCoalescing (??) operation. + return new Action(OP_NULL_COALESCE, [exploredValueInput, Inputs.randomArgument()]) + } - // If the action failed, mark this explore operation as failing (which will set the action to NO_ACTION) so it won't be retried again. - if (!success) { - recordFailure(id); + // Explores the given value and returns an action to perform on it. + function exploreValue(id, v) { + if (isObject(v)) { + return exploreObject(v); + } else if (isFunction(v)) { + return exploreFunction(v); + } else if (isString(v)) { + return exploreString(v); + } else if (isNumber(v)) { + return exploreNumber(v); + } else if (isBigint(v)) { + return exploreBigint(v); + } else if (isSymbol(v)) { + return exploreSymbol(v); + } else if (isBoolean(v)) { + return exploreBoolean(v); + } else if (isUndefined(v)) { + return exploreNullish(v); + } else { + throw "Unexpected value type: " + typeof v; + } } - currentlyExploring = false; - } + // + // Exploration entrypoint. + // + function explore(id, v, currentThis, args, rngSeed) { + rng.reseed(rngSeed); + + // The given arguments may be used as inputs for the action. + if (isUndefined(args) || args.length < 1) throw "Exploration requires at least one additional argument"; + + // We may get here recursively for example if a Proxy is being explored which triggers further explore calls during e.g. property enumeration. + // Probably the best way to deal with these cases is to just bail out from recursive explorations. + if (currentlyExploring) return; + currentlyExploring = true; + + // Set the global state for this explore operation. + exploreArguments = args; + exploredValueInput = new SpecialInput("exploredValue"); - function exploreWithErrorHandling(id, v, thisValue, args, rngSeed) { - try { - explore(id, v, thisValue, args, rngSeed); - } catch (e) { - let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); - if (isNumber(line)) { - reportError("In line " + line + ": " + e); + // Check if we already have a result for this id, and if so repeat the same action again. Otherwise, explore. + let action; + if (hasActionFor(id)) { + action = getActionFor(id); } else { - reportError(e); + action = exploreValue(id, v); + recordAction(id, action); + } + + // Now perform the selected action. + let context = { arguments: args, specialValues: { "exploredValue": v }, currentThis: currentThis }; + let success = execute(action, context); + + // If the action failed, mark this explore operation as failing (which will set the action to NO_ACTION) so it won't be retried again. + if (!success) { + recordFailure(id); + } + + currentlyExploring = false; + } + + function exploreWithErrorHandling(id, v, thisValue, args, rngSeed) { + try { + explore(id, v, thisValue, args, rngSeed); + } catch (e) { + let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); + if (isNumber(line)) { + reportError("In line " + line + ": " + e); + } else { + reportError(e); + } } } - } - return exploreWithErrorHandling; - })(); + return exploreWithErrorHandling; + })(); - """ + """ static let exploreFunc = "explore" } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift index e267b1433..9d2c12360 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptFixupLifting.swift @@ -15,115 +15,115 @@ /// This file contains the JavaScript specific implementation of the Fixup operation. See FixupMutator.swift for an overview of this feature. struct JavaScriptFixupLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - - const fixup = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - - - // - // "Import" the Action implementation code. - // - \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) - - - // - // Error and result reporting. - // - // The actions to perform (indexed by their ID) will be stored in here. - // TODO: here and in ExploreLifting, should this be a Map instead? - const actions = { __proto__: null }; - // We remember which actions have failed in the past, so we only report failures once. - const failures = new SetConstructor(); - - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'FIXUP_ERROR: ' + msg); - } - - function recordFailure(id) { - setAdd(failures, id); - fuzzilli('FUZZILLI_PRINT', 'FIXUP_FAILURE: ' + id); - } - - function recordAction(id, action) { - if (action.id !== id) throw "Inconsistent action for id " + id; - if (hasOwnProperty(actions, id)) throw "Duplicate action for " + id; - - // These are configurable as they may need to be overwritten (by recordFailure) in the future. - defineProperty(actions, id, {__proto__: null, value: action, configurable: true}); - - fuzzilli('FUZZILLI_PRINT', 'FIXUP_ACTION: ' + stringify(action)); - } - - function hasActionFor(id) { - return hasOwnProperty(actions, id); - } - - function getActionFor(id) { - return actions[id]; - } - - function hasPreviouslyFailed(id) { - return setHas(failures, id); - } - - // - // Fixup function. - // - function fixup(id, originalAction, args, currentThis) { - // See if this is the first time that we're executing this action. If it is, then now is the (only) timewhen we can modify the action. - let action; - if (hasActionFor(id)) { - action = getActionFor(id); - } else { - // TODO: this is where we could change the action. - // If changing actions, we should try to not change the type of inputs though. For example, we probably should not - // turn a computed property load (where the property name is an argument input) into a "regular" property load - // (where the property name is a string input). - action = originalAction; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + + const fixup = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + + + // + // "Import" the Action implementation code. + // + \(JavaScriptRuntimeAssistedMutatorLifting.actionCode) + + + // + // Error and result reporting. + // + // The actions to perform (indexed by their ID) will be stored in here. + // TODO: here and in ExploreLifting, should this be a Map instead? + const actions = { __proto__: null }; + // We remember which actions have failed in the past, so we only report failures once. + const failures = new SetConstructor(); + + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'FIXUP_ERROR: ' + msg); + } + + function recordFailure(id) { + setAdd(failures, id); + fuzzilli('FUZZILLI_PRINT', 'FIXUP_FAILURE: ' + id); + } + + function recordAction(id, action) { + if (action.id !== id) throw "Inconsistent action for id " + id; + if (hasOwnProperty(actions, id)) throw "Duplicate action for " + id; + + // These are configurable as they may need to be overwritten (by recordFailure) in the future. + defineProperty(actions, id, {__proto__: null, value: action, configurable: true}); + + fuzzilli('FUZZILLI_PRINT', 'FIXUP_ACTION: ' + stringify(action)); } - // Now perform the selected action. - let context = { arguments: args, specialValues: {}, currentThis: currentThis, output: undefined }; - let success = execute(action, context); + function hasActionFor(id) { + return hasOwnProperty(actions, id); + } - // If the action failed and isn't guarded (either because it wasn't in the first place or because we've previously removed the guard), then record a failure. - // This will signal to Fuzzilli that the action either needs a guard or should be removed. - // As we may execute this action again, we remember which actions have failed in the past and only report the first failure. - if (!success && !hasPreviouslyFailed(id)) { - recordFailure(id); + function getActionFor(id) { + return actions[id]; } - // If this was the first time the action was executed, report the (possibly modified) action. - // This has to happen after executing the action as that may remove unecessary guards. - if (!hasActionFor(id)) { - recordAction(id, action); + function hasPreviouslyFailed(id) { + return setHas(failures, id); } - // Return the action's output value as it may be used by subsequent code. - return context.output; - } - - function fixupWithErrorHandling(id, originalAction, args, currentThis) { - try { - return fixup(id, originalAction, args, currentThis); - } catch (e) { - let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); - if (isNumber(line)) { - reportError("In line " + line + ": " + e); + // + // Fixup function. + // + function fixup(id, originalAction, args, currentThis) { + // See if this is the first time that we're executing this action. If it is, then now is the (only) timewhen we can modify the action. + let action; + if (hasActionFor(id)) { + action = getActionFor(id); } else { - reportError(e); + // TODO: this is where we could change the action. + // If changing actions, we should try to not change the type of inputs though. For example, we probably should not + // turn a computed property load (where the property name is an argument input) into a "regular" property load + // (where the property name is a string input). + action = originalAction; + } + + // Now perform the selected action. + let context = { arguments: args, specialValues: {}, currentThis: currentThis, output: undefined }; + let success = execute(action, context); + + // If the action failed and isn't guarded (either because it wasn't in the first place or because we've previously removed the guard), then record a failure. + // This will signal to Fuzzilli that the action either needs a guard or should be removed. + // As we may execute this action again, we remember which actions have failed in the past and only report the first failure. + if (!success && !hasPreviouslyFailed(id)) { + recordFailure(id); + } + + // If this was the first time the action was executed, report the (possibly modified) action. + // This has to happen after executing the action as that may remove unecessary guards. + if (!hasActionFor(id)) { + recordAction(id, action); + } + + // Return the action's output value as it may be used by subsequent code. + return context.output; + } + + function fixupWithErrorHandling(id, originalAction, args, currentThis) { + try { + return fixup(id, originalAction, args, currentThis); + } catch (e) { + let line = tryHasProperty('line', e) ? tryGetProperty('line', e) : tryGetProperty('lineNumber', e); + if (isNumber(line)) { + reportError("In line " + line + ": " + e); + } else { + reportError(e); + } } } - } - return fixupWithErrorHandling; - })(); - """ + return fixupWithErrorHandling; + })(); + """ static let fixupFunc = "fixup" } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index f38081d9f..8f12d3f0e 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -75,11 +75,13 @@ public class JavaScriptLifter: Lifter { } private var functionLiftingStack = Stack() - public init(prefix: String = "", - suffix: String = "", - ecmaVersion: ECMAScriptVersion, - environment: JavaScriptEnvironment, - alwaysEmitVariables: Bool = false) { + public init( + prefix: String = "", + suffix: String = "", + ecmaVersion: ECMAScriptVersion, + environment: JavaScriptEnvironment, + alwaysEmitVariables: Bool = false + ) { self.prefix = prefix self.suffix = suffix self.version = ecmaVersion @@ -88,11 +90,15 @@ public class JavaScriptLifter: Lifter { self.alwaysEmitVariables = alwaysEmitVariables } - func isUsedInBlock(variable: Variable, blockStart: Int, blockEnd: Int, analyzer: DefUseAnalyzer) -> Bool { + func isUsedInBlock(variable: Variable, blockStart: Int, blockEnd: Int, analyzer: DefUseAnalyzer) + -> Bool + { // Check if any use of 'variable' is inside [blockStart, blockEnd] // Note: The variable is defined at blockStart, so we only care about uses strictly after that. // And strictly before or at blockEnd (the EndInstruction itself can use the variable). - return analyzer.uses(of: variable).contains { $0.index > blockStart && $0.index <= blockEnd } + return analyzer.uses(of: variable).contains { + $0.index > blockStart && $0.index <= blockEnd + } } public func lift(_ program: Program, withOptions options: LiftingOptions) -> String { @@ -110,7 +116,9 @@ public class JavaScriptLifter: Lifter { var wasmInstructions = Code() // Map block start index to end index. - let blockEndIndices = program.code.reduce(into: (indices: [Int: Int](), stack: Stack())) { context, instr in + let blockEndIndices = program.code.reduce( + into: (indices: [Int: Int](), stack: Stack()) + ) { context, instr in if instr.isBlockEnd { let start = context.stack.pop() context.indices[start] = instr.index @@ -134,7 +142,11 @@ public class JavaScriptLifter: Lifter { typer = JSTyper(for: environment) } - var w = JavaScriptWriter(analyzer: analyzer, version: version, stripComments: !options.contains(.includeComments), includeLineNumbers: options.contains(.includeLineNumbers), alwaysEmitVariables: alwaysEmitVariables) + var w = JavaScriptWriter( + analyzer: analyzer, version: version, + stripComments: !options.contains(.includeComments), + includeLineNumbers: options.contains(.includeLineNumbers), + alwaysEmitVariables: alwaysEmitVariables) var wasmCodeStarts: Int? = nil var wasmTypeGroupStarts: Int? = nil @@ -176,7 +188,9 @@ public class JavaScriptLifter: Lifter { } for instr in program.code { - if options.contains(.includeComments), let comment = program.comments.at(.instruction(instr.index)) { + if options.contains(.includeComments), + let comment = program.comments.at(.instruction(instr.index)) + { w.emitComment(comment) } @@ -240,7 +254,9 @@ public class JavaScriptLifter: Lifter { // We need to declare all outputs of the guarded operation before the try-catch so that they are // visible to subsequent code. - assert(instr.numInnerOutputs == 0, "Inner outputs are not currently supported in guarded operations") + assert( + instr.numInnerOutputs == 0, + "Inner outputs are not currently supported in guarded operations") let neededOutputs = instr.allOutputs.filter({ analyzer.numUses(of: $0) > 0 }) if !neededOutputs.isEmpty { let VARS = w.declareAll(neededOutputs).joined(separator: ", ") @@ -260,9 +276,10 @@ public class JavaScriptLifter: Lifter { // We also have some lightweight checking logic to ensure that the input expressions are retrieved in the correct order. // This does not guarantee that they will also _evaluate_ in that order at runtime, but it's probably a decent approximation. guard let inputs = w.retrieve(expressionsFor: instr.inputs) else { - fatalError("Missing one or more expressions for inputs \(instr.inputs) of \(instr).\n" + - "Program is \(FuzzILLifter().lift(program, withOptions: .includeComments))\n" + - "Dying now.") + fatalError( + "Missing one or more expressions for inputs \(instr.inputs) of \(instr).\n" + + "Program is \(FuzzILLifter().lift(program, withOptions: .includeComments))\n" + + "Dying now.") } var nextExpressionToFetch = 0 func input(_ i: Int) -> Expression { @@ -302,7 +319,7 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .loadString(let op): - let escaped = op.value.replacingOccurrences(of: "\"", with:"\\\"") + let escaped = op.value.replacingOccurrences(of: "\"", with: "\\\"") w.assign(StringLiteral.new("\"\(escaped)\""), to: instr.output) case .loadRegExp(let op): @@ -355,20 +372,20 @@ public class JavaScriptLifter: Lifter { w.declare(instr.output, as: op.variableName) case .createNamedDisposableVariable(let op): - w.emit("using \(op.variableName) = \(input(0));"); + w.emit("using \(op.variableName) = \(input(0));") w.declare(instr.output, as: op.variableName) case .createNamedAsyncDisposableVariable(let op): - w.emit("await using \(op.variableName) = \(input(0));"); + w.emit("await using \(op.variableName) = \(input(0));") w.declare(instr.output, as: op.variableName) case .loadDisposableVariable: - let V = w.declare(instr.output); - w.emit("using \(V) = \(input(0));"); + let V = w.declare(instr.output) + w.emit("using \(V) = \(input(0));") case .loadAsyncDisposableVariable: - let V = w.declare(instr.output); - w.emit("await using \(V) = \(input(0));"); + let V = w.declare(instr.output) + w.emit("await using \(V) = \(input(0));") case .beginObjectLiteral: // We force all expressions to evaluate before the object literal. @@ -452,9 +469,9 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .endObjectLiteralGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralComputedSetter: + .endObjectLiteralSetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralComputedSetter: currentObjectLiteral.endMethod(&w) case .endObjectLiteral: @@ -462,14 +479,16 @@ public class JavaScriptLifter: Lifter { // Everything needs to be written into the object literal writer. let dummy = w.popTemporaryOutputBuffer() // The dummy might still contain the comments. - assert(dummy.isEmpty || dummy.split(separator: "\n").allSatisfy( {$0.hasPrefix("//")})) + assert( + dummy.isEmpty || dummy.split(separator: "\n").allSatisfy({ $0.hasPrefix("//") }) + ) let literal = objectLiteralStack.pop() if literal.isEmpty { w.assign(ObjectLiteral.new("{}"), to: instr.output) } else if literal.canInline { // In this case, we inline the object literal. - let code = "{ \(literal.fields.joined(separator: ", ")) }"; + let code = "{ \(literal.fields.joined(separator: ", ")) }" w.assign(ObjectLiteral.new(code), to: instr.output) } else { let LET = w.declarationKeyword(for: instr.output) @@ -600,11 +619,11 @@ public class JavaScriptLifter: Lifter { bindVariableToThis(instr.innerOutput(0)) case .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter: + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter: w.leaveCurrentBlock() w.emit("}") @@ -637,7 +656,8 @@ public class JavaScriptLifter: Lifter { case .createArray: // When creating arrays, treat undefined elements as holes. This also relies on literals always being inlined. - var elems = inputs.map({ $0.text }).map({ $0 == "undefined" ? "" : $0 }).joined(separator: ",") + var elems = inputs.map({ $0.text }).map({ $0 == "undefined" ? "" : $0 }).joined( + separator: ",") if elems.last == "," || (instr.inputs.count == 1 && elems == "") { // If the last element is supposed to be a hole, we need one additional comma elems += "," @@ -663,8 +683,8 @@ public class JavaScriptLifter: Lifter { elems.append(text == "undefined" ? "" : text) } } - var elemString = elems.joined(separator: ","); - if elemString.last == "," || (instr.inputs.count==1 && elemString=="") { + var elemString = elems.joined(separator: ",") + if elemString.last == "," || (instr.inputs.count == 1 && elemString == "") { // If the last element is supposed to be a hole, we need one additional commas elemString += "," } @@ -679,14 +699,17 @@ public class JavaScriptLifter: Lifter { parts.append("${\(VALUE)}\(op.parts[i])") } // See BeginCodeString case. - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let escapeSequence = String(repeating: "\\", count: count) - let expr = TemplateLiteral.new("\(escapeSequence)`" + parts.joined() + "\(escapeSequence)`") + let expr = TemplateLiteral.new( + "\(escapeSequence)`" + parts.joined() + "\(escapeSequence)`") w.assign(expr, to: instr.output) case .getProperty(let op): let obj = input(0) - let expr = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) + let expr = + MemberExpression.new() + obj + + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) w.assign(expr, to: instr.output) case .setProperty(let op): @@ -706,14 +729,17 @@ public class JavaScriptLifter: Lifter { case .deleteProperty(let op): // For aesthetic reasons, we don't want to inline the lhs of a property deletion, so force it to be stored in a variable. let obj = inputAsIdentifier(0) - let target = MemberExpression.new() + obj + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) + let target = + MemberExpression.new() + obj + + (liftMemberAccess(op.propertyName, isGuarded: op.isGuarded)) let expr = UnaryExpression.new() + "delete " + target w.assign(expr, to: instr.output) case .configureProperty(let op): let OBJ = input(0) let PROPERTY = op.propertyName - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst()) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst()) w.emit("Object.defineProperty(\(OBJ), \"\(PROPERTY)\", \(DESCRIPTOR));") case .getElement(let op): @@ -747,7 +773,8 @@ public class JavaScriptLifter: Lifter { case .configureElement(let op): let OBJ = input(0) let INDEX = op.index - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst()) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst()) w.emit("Object.defineProperty(\(OBJ), \(INDEX), \(DESCRIPTOR));") case .getComputedProperty(let op): @@ -781,7 +808,8 @@ public class JavaScriptLifter: Lifter { case .configureComputedProperty(let op): let OBJ = input(0) let PROPERTY = input(1) - let DESCRIPTOR = liftPropertyDescriptor(flags: op.flags, type: op.type, values: inputs.dropFirst(2)) + let DESCRIPTOR = liftPropertyDescriptor( + flags: op.flags, type: op.type, values: inputs.dropFirst(2)) w.emit("Object.defineProperty(\(OBJ), \(PROPERTY), \(DESCRIPTOR));") case .typeOf: @@ -808,8 +836,12 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "function", using: &w) case .beginArrowFunction(let op): - guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } - liftArrowFunctionDefinitionBegin(instr, parameters: op.parameters, isAsync: false, using: &w, functionEndIndex: endIndex, analyzer: analyzer) + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + instr, parameters: op.parameters, isAsync: false, using: &w, + functionEndIndex: endIndex, analyzer: analyzer) case .beginGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "function*", using: &w) @@ -818,14 +850,18 @@ public class JavaScriptLifter: Lifter { liftFunctionDefinitionBegin(instr, keyword: "async function", using: &w) case .beginAsyncArrowFunction(let op): - guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } - liftArrowFunctionDefinitionBegin(instr, parameters: op.parameters, isAsync: true, using: &w, functionEndIndex: endIndex, analyzer: analyzer) + guard let endIndex = blockEndIndices[instr.index] else { + fatalError("Block analysis failed") + } + liftArrowFunctionDefinitionBegin( + instr, parameters: op.parameters, isAsync: true, using: &w, + functionEndIndex: endIndex, analyzer: analyzer) case .beginAsyncGeneratorFunction: liftFunctionDefinitionBegin(instr, keyword: "async function*", using: &w) case .endArrowFunction(_), - .endAsyncArrowFunction: + .endAsyncArrowFunction: let state = functionLiftingStack.pop() if state.isSelfReferencing { w.leaveCurrentBlock() @@ -839,12 +875,14 @@ public class JavaScriptLifter: Lifter { let lastInstr = program.code[instr.index - 1] if lastInstr.index > state.startInstructionIndex, - let returnOp = lastInstr.op as? Return, - returnOp.hasReturnValue, - !trimmedBody.contains("\n"), - !trimmedBody.contains("//"), - trimmedBody.hasPrefix("return ") { - let content = trimmedBody.dropFirst("return ".count).trimmingCharacters(in: .whitespaces.union(.init(charactersIn: ";"))) + let returnOp = lastInstr.op as? Return, + returnOp.hasReturnValue, + !trimmedBody.contains("\n"), + !trimmedBody.contains("//"), + trimmedBody.hasPrefix("return ") + { + let content = trimmedBody.dropFirst("return ".count).trimmingCharacters( + in: .whitespaces.union(.init(charactersIn: ";"))) conciseBody = content.hasPrefix("{") ? "(\(content))" : content } @@ -857,9 +895,9 @@ public class JavaScriptLifter: Lifter { } case .endPlainFunction(_), - .endGeneratorFunction(_), - .endAsyncFunction(_), - .endAsyncGeneratorFunction: + .endGeneratorFunction(_), + .endAsyncFunction(_), + .endAsyncGeneratorFunction: w.leaveCurrentBlock() w.emit("}") @@ -919,7 +957,9 @@ public class JavaScriptLifter: Lifter { case .callFunctionWithSpread(let op): let f = inputAsIdentifier(0) let args = inputs.dropFirst() - let expr = CallExpression.new() + f + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + f + "(" + liftCallArguments(args, spreading: op.spreads) + + ")" w.assign(expr, to: instr.output) case .construct: @@ -932,7 +972,9 @@ public class JavaScriptLifter: Lifter { case .constructWithSpread(let op): let f = inputAsIdentifier(0) let args = inputs.dropFirst() - let expr = NewExpression.new() + "new " + f + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + NewExpression.new() + "new " + f + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" // For aesthetic reasons we disallow inlining "new" expressions so that their result is always assigned to a new variable. w.assign(expr, to: instr.output, allowInlining: false) @@ -947,7 +989,9 @@ public class JavaScriptLifter: Lifter { let obj = input(0) let method = MemberExpression.new() + obj + (liftMemberAccess(op.methodName)) let args = inputs.dropFirst() - let expr = CallExpression.new() + method + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + method + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" w.assign(expr, to: instr.output) case .callComputedMethod: @@ -961,7 +1005,9 @@ public class JavaScriptLifter: Lifter { let obj = input(0) let method = MemberExpression.new() + obj + "[" + input(1).text + "]" let args = inputs.dropFirst(2) - let expr = CallExpression.new() + method + "(" + liftCallArguments(args, spreading: op.spreads) + ")" + let expr = + CallExpression.new() + method + "(" + + liftCallArguments(args, spreading: op.spreads) + ")" w.assign(expr, to: instr.output) case .unaryOperation(let op): @@ -1017,7 +1063,8 @@ public class JavaScriptLifter: Lifter { case .destructArray(let op): let outputs = w.declareAll(instr.outputs) let ARRAY = input(0) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) let LET = w.varKeyword w.emit("\(LET) [\(PATTERN)] = \(ARRAY);") @@ -1025,13 +1072,15 @@ public class JavaScriptLifter: Lifter { assert(inputs.dropFirst().allSatisfy({ $0.type === Identifier })) let ARRAY = input(0) let outputs = inputs.dropFirst().map({ $0.text }) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.lastIsRest) w.emit("[\(PATTERN)] = \(ARRAY);") case .destructObject(let op): let outputs = w.declareAll(instr.outputs) let OBJ = input(0) - let PATTERN = liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftObjectDestructPattern( + properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) let LET = w.varKeyword w.emit("\(LET) {\(PATTERN)} = \(OBJ);") @@ -1039,7 +1088,8 @@ public class JavaScriptLifter: Lifter { assert(inputs.dropFirst().allSatisfy({ $0.type === Identifier })) let OBJ = input(0) let outputs = inputs.dropFirst().map({ $0.text }) - let PATTERN = liftObjectDestructPattern(properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftObjectDestructPattern( + properties: op.properties, outputs: outputs, hasRestElement: op.hasRestElement) w.emit("({\(PATTERN)} = \(OBJ));") case .compare(let op): @@ -1110,7 +1160,7 @@ public class JavaScriptLifter: Lifter { case .callSuperMethod(let op): let method = MemberExpression.new() + "super" + liftMemberAccess(op.methodName) - let expr = CallExpression.new() + method + "(" + liftCallArguments(inputs) + ")" + let expr = CallExpression.new() + method + "(" + liftCallArguments(inputs) + ")" w.assign(expr, to: instr.output) case .getPrivateProperty(let op): @@ -1259,7 +1309,8 @@ public class JavaScriptLifter: Lifter { if w.isCurrentTemporaryBufferEmpty && w.numPendingExpressions == 0 { // The "good" case: we can emit `let i = X, j = Y, ...` assert(loopVars.count == inputs.count) - let declarations = zip(loopVars, inputs).map({ "\($0) = \($1)" }).joined(separator: ", ") + let declarations = zip(loopVars, inputs).map({ "\($0) = \($1)" }).joined( + separator: ", ") initializer = "let \(declarations)" let code = w.popTemporaryOutputBuffer() assert(code.isEmpty) @@ -1274,7 +1325,8 @@ public class JavaScriptLifter: Lifter { initializer = "let \(I) = (() => {\n\(CODE) })()" } else { // Emit a `let [i, j, k] = (() => { ...; return [X, Y, Z]; })()` - let initialLoopVarValues = inputs.map({ $0.text }).joined(separator: ", ") + let initialLoopVarValues = inputs.map({ $0.text }).joined( + separator: ", ") w.emit("return [\(initialLoopVarValues)];") let VARS = loopVars.joined(separator: ", ") let CODE = w.popTemporaryOutputBuffer() @@ -1283,7 +1335,8 @@ public class JavaScriptLifter: Lifter { } } - forLoopHeaderStack.push(ForLoopHeader(initializer: initializer, loopVariables: loopVars)) + forLoopHeaderStack.push( + ForLoopHeader(initializer: initializer, loopVariables: loopVars)) handleBeginSingleExpressionContext(with: &w, initialIndentionLevel: 2) case .beginForLoopAfterthought: @@ -1304,16 +1357,19 @@ public class JavaScriptLifter: Lifter { var CONDITION = header.condition var AFTERTHOUGHT = handleEndSingleExpressionContext(with: &w) - if !INITIALIZER.contains("\n") && !CONDITION.contains("\n") && !AFTERTHOUGHT.contains("\n") { + if !INITIALIZER.contains("\n") && !CONDITION.contains("\n") + && !AFTERTHOUGHT.contains("\n") + { if !CONDITION.isEmpty { CONDITION = " " + CONDITION } if !AFTERTHOUGHT.isEmpty { AFTERTHOUGHT = " " + AFTERTHOUGHT } w.emit("for (\(INITIALIZER);\(CONDITION);\(AFTERTHOUGHT)) {") } else { - w.emitBlock(""" - for (\(INITIALIZER); - \(CONDITION); - \(AFTERTHOUGHT)) { - """) + w.emitBlock( + """ + for (\(INITIALIZER); + \(CONDITION); + \(AFTERTHOUGHT)) { + """) } w.declareAll(instr.innerOutputs, as: header.loopVariables) @@ -1343,7 +1399,8 @@ public class JavaScriptLifter: Lifter { case .beginForOfLoopWithDestruct(let op): let outputs = w.declareAll(instr.innerOutputs) - let PATTERN = liftArrayDestructPattern(indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement) + let PATTERN = liftArrayDestructPattern( + indices: op.indices, outputs: outputs, hasRestElement: op.hasRestElement) let LET = w.varKeyword let OBJ = input(0) w.emit("for (\(LET) [\(PATTERN)] of \(OBJ)) {") @@ -1370,7 +1427,7 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .loopBreak(_), - .switchBreak: + .switchBreak: w.emit("break;") case .loopContinue: @@ -1402,7 +1459,7 @@ public class JavaScriptLifter: Lifter { case .beginCodeString: // This power series (2**n -1) is used to generate a valid escape sequence for nested template literals. // Here n represents the nesting level. - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let ESCAPE = String(repeating: "\\", count: count) let V = w.declare(instr.output) let LET = w.declarationKeyword(for: instr.output) @@ -1413,7 +1470,7 @@ public class JavaScriptLifter: Lifter { case .endCodeString: codeStringNestingLevel -= 1 w.leaveCurrentBlock() - let count = Int(pow(2, Double(codeStringNestingLevel)))-1 + let count = Int(pow(2, Double(codeStringNestingLevel))) - 1 let ESCAPE = String(repeating: "\\", count: count) w.emit("\(ESCAPE)`;") @@ -1437,7 +1494,9 @@ public class JavaScriptLifter: Lifter { let LET = w.varKeyword let type = op.value.typeString() let value = op.value.valueToString() - w.emit("\(LET) \(V) = new WebAssembly.Global({ value: \"\(type)\", mutable: \(op.isMutable) }, \(value));") + w.emit( + "\(LET) \(V) = new WebAssembly.Global({ value: \"\(type)\", mutable: \(op.isMutable) }, \(value));" + ) case .createWasmMemory(let op): let V = w.declare(instr.output) @@ -1453,7 +1512,9 @@ public class JavaScriptLifter: Lifter { sharedStr = ", shared: true" } let addressType = isMemory64 ? "'i64'" : "'i32'" - w.emit("\(LET) \(V) = new WebAssembly.Memory({ initial: \(minPageStr)\(maxPagesStr)\(sharedStr), address: \(addressType) });") + w.emit( + "\(LET) \(V) = new WebAssembly.Memory({ initial: \(minPageStr)\(maxPagesStr)\(sharedStr), address: \(addressType) });" + ) case .wrapSuspending(_): let V = w.declare(instr.output) @@ -1494,7 +1555,9 @@ public class JavaScriptLifter: Lifter { let V = w.declare(instr.output, as: "v\(instr.output.number)") // TODO: support a better diagnostics mode which stores the .wasm binary file alongside the samples. do { - let (bytecode, importRefs) = try WasmLifter(withTyper: typer!, withWasmCode: wasmInstructions).lift() + let (bytecode, importRefs) = try WasmLifter( + withTyper: typer!, withWasmCode: wasmInstructions + ).lift() // Get and check that we have the imports here as expressions and fail otherwise. let imports: [(Variable, Expression)] = try importRefs.map { ref in if let expr = w.retrieve(expressionsFor: [ref]) { @@ -1503,11 +1566,17 @@ public class JavaScriptLifter: Lifter { throw WasmLifter.CompileError.failedRetrieval } } - w.emit("\(LET) \(V) = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([") + w.emit( + "\(LET) \(V) = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([" + ) w.enterNewBlock() let blockSize = 10 - for chunk in stride(from: 0, to: bytecode.count, by: blockSize).map({ Array(bytecode[$0 ..< Swift.min($0 + blockSize, bytecode.count)])}) { - let byteString = chunk.map({ String(format: "0x%02X", $0) }).joined(separator: ", ") + "," + for chunk in stride(from: 0, to: bytecode.count, by: blockSize).map({ + Array(bytecode[$0.. String { + private func handleEndSingleExpressionContext( + result maybeResult: Expression? = nil, with w: inout JavaScriptWriter + ) -> String { if w.isCurrentTemporaryBufferEmpty { // This means that the code consists entirely of expressions that can be inlined, and that the result // variable is either not an inlined expression (but instead e.g. the identifier for a local variable), or that @@ -1807,7 +1892,8 @@ public class JavaScriptLifter: Lifter { // // In this case, we can emit a single expression by combining all pending expressions using the comma operator. var COND = CommaExpression.new() - let expressions = w.takePendingExpressions() + (maybeResult != nil ? [maybeResult!] : []) + let expressions = + w.takePendingExpressions() + (maybeResult != nil ? [maybeResult!] : []) for expr in expressions { if COND.text.isEmpty { COND = COND + expr @@ -1841,7 +1927,7 @@ public class JavaScriptLifter: Lifter { } private func liftMemberAccess(_ name: String, isGuarded: Bool = false) -> String { - if environment.isValidDotNotationName(name){ + if environment.isValidDotNotationName(name) { return (isGuarded ? "?." : ".") + name } let safeName = environment.isValidPropertyIndex(name) ? name : "\"\(name)\"" @@ -1861,7 +1947,9 @@ public class JavaScriptLifter: Lifter { return paramList.joined(separator: ", ") } - private func liftFunctionDefinitionBegin(_ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter) { + private func liftFunctionDefinitionBegin( + _ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter + ) { // Function are lifted as `function f3(a4, a5, a6) { ...`. // This will produce functions with a recognizable .name property, which the JavaScriptExploreLifting code makes use of (see shouldTreatAsConstructor). guard let op = instr.op as? BeginAnyFunction else { @@ -1898,13 +1986,14 @@ public class JavaScriptLifter: Lifter { let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") let params = liftParameters(parameters, as: vars) - functionLiftingStack.push(FunctionLiftingState( - outputVariable: instr.output, - isSelfReferencing: isSelfReferencing, - parameters: params, - isAsync: isAsync, - startInstructionIndex: instr.index - )) + functionLiftingStack.push( + FunctionLiftingState( + outputVariable: instr.output, + isSelfReferencing: isSelfReferencing, + parameters: params, + isAsync: isAsync, + startInstructionIndex: instr.index + )) if isSelfReferencing { let keyword = w.declarationKeyword(for: instr.output) @@ -1918,8 +2007,9 @@ public class JavaScriptLifter: Lifter { } } - - private func liftCallArguments(_ args: Arguments, spreading spreads: [Bool] = []) -> String where Arguments.Element == Expression { + private func liftCallArguments( + _ args: Arguments, spreading spreads: [Bool] = [] + ) -> String where Arguments.Element == Expression { var arguments = [String]() for (i, a) in args.enumerated() { if spreads.count > i && spreads[i] { @@ -1932,7 +2022,9 @@ public class JavaScriptLifter: Lifter { return arguments.joined(separator: ", ") } - private func liftPropertyDescriptor(flags: PropertyFlags, type: PropertyType, values: ArraySlice) -> String { + private func liftPropertyDescriptor( + flags: PropertyFlags, type: PropertyType, values: ArraySlice + ) -> String { assert(values.count <= 2) var parts = [String]() if flags.contains(.writable) { @@ -1960,7 +2052,9 @@ public class JavaScriptLifter: Lifter { return "{ \(parts.joined(separator: ", ")) }" } - private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) -> String { + private func liftArrayDestructPattern(indices: [Int64], outputs: [String], hasRestElement: Bool) + -> String + { assert(indices.count == outputs.count) var arrayPattern = "" @@ -1976,7 +2070,9 @@ public class JavaScriptLifter: Lifter { return arrayPattern } - private func liftObjectDestructPattern(properties: [String], outputs: [String], hasRestElement: Bool) -> String { + private func liftObjectDestructPattern( + properties: [String], outputs: [String], hasRestElement: Bool + ) -> String { assert(outputs.count == properties.count + (hasRestElement ? 1 : 0)) var objectPattern = "" @@ -2006,13 +2102,13 @@ public class JavaScriptLifter: Lifter { private func haveSpecialHandlingForGuardedOp(_ op: Operation) -> Bool { switch op.opcode { - // We handle guarded property loads by emitting an optional chain, so no try-catch is necessary. + // We handle guarded property loads by emitting an optional chain, so no try-catch is necessary. case .getProperty, - .getElement, - .getComputedProperty, - .deleteProperty, - .deleteElement, - .deleteComputedProperty: + .getElement, + .getComputedProperty, + .deleteProperty, + .deleteElement, + .deleteComputedProperty: return true default: return false @@ -2066,8 +2162,13 @@ public class JavaScriptLifter: Lifter { // See `reassign()` for more details about reassignment inlining. private var inlinedReassignments = VariableMap() - init(analyzer: DefUseAnalyzer, version: ECMAScriptVersion, stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, alwaysEmitVariables: Bool = false) { - self.writer = ScriptWriter(stripComments: stripComments, includeLineNumbers: includeLineNumbers, indent: indent) + init( + analyzer: DefUseAnalyzer, version: ECMAScriptVersion, stripComments: Bool = false, + includeLineNumbers: Bool = false, indent: Int = 4, alwaysEmitVariables: Bool = false + ) { + self.writer = ScriptWriter( + stripComments: stripComments, includeLineNumbers: includeLineNumbers, indent: indent + ) self.analyzer = analyzer self.varKeyword = version == .es6 ? "let" : "var" self.constKeyword = version == .es6 ? "const" : "var" @@ -2095,7 +2196,9 @@ public class JavaScriptLifter: Lifter { // The expression cannot be inlined. Now decide whether to define the output variable or not. The output variable can be omitted if: // * It is not used by any following instructions, and // * It is not an Object literal, as that would not be valid syntax (it would mistakenly be interpreted as a block statement) - if analyzer.numUses(of: v) == 0 && expr.type !== ObjectLiteral && !alwaysEmitVariables { + if analyzer.numUses(of: v) == 0 && expr.type !== ObjectLiteral + && !alwaysEmitVariables + { emit("\(expr);") } else { let LET = declarationKeyword(for: v) @@ -2146,7 +2249,9 @@ public class JavaScriptLifter: Lifter { /// Otherwise, expression inlining will change the semantics of the program. /// /// This is a mutating operation as it can modify the list of pending expressions or emit pending expression to retain the correct ordering. - mutating func retrieve(expressionsFor queriedVariables: ArraySlice) -> [Expression]? { + mutating func retrieve(expressionsFor queriedVariables: ArraySlice) + -> [Expression]? + { // If any of the expression for the variables is pending, then one of two things will happen: // // 1. Iff the pending expressions that are being retrieved are an exact suffix match of the pending expressions list, then these pending expressions @@ -2182,13 +2287,16 @@ public class JavaScriptLifter: Lifter { // since they can only occur once (otherwise, they wouldn't be inlined), but is important // for inlined reassignments, e.g. to be able to correctly handle `foo(a = 42, a, bar(), a);` var queriedPendingExpressions = [Variable]() - for v in queriedVariables where pendingExpressions.contains(v) && !queriedPendingExpressions.contains(v) { + for v in queriedVariables + where pendingExpressions.contains(v) && !queriedPendingExpressions.contains(v) { queriedPendingExpressions.append(v) } for v in queriedPendingExpressions.reversed() { assert(matchingSuffixLength < pendingExpressions.count) let currentSuffixPosition = pendingExpressions.count - 1 - matchingSuffixLength - if matchingSuffixLength < pendingExpressions.count && v == pendingExpressions[currentSuffixPosition] { + if matchingSuffixLength < pendingExpressions.count + && v == pendingExpressions[currentSuffixPosition] + { matchingSuffixLength += 1 } } @@ -2274,7 +2382,9 @@ public class JavaScriptLifter: Lifter { /// Declare all of the given variables. Equivalent to calling declare() for each of them. /// The variable names will be constructed as prefix + v.number. By default, the prefix "v" is used. @discardableResult - mutating func declareAll(_ vars: Variables, usePrefix prefix: String = "v") -> [String] where Variables.Element == Variable { + mutating func declareAll( + _ vars: Variables, usePrefix prefix: String = "v" + ) -> [String] where Variables.Element == Variable { return vars.map({ declare($0, as: prefix + String($0.number)) }) } @@ -2333,7 +2443,9 @@ public class JavaScriptLifter: Lifter { temporaryOutputBufferStack.push(writer) pendingExpressionsStack.push(pendingExpressions) pendingExpressions = [] - writer = ScriptWriter(stripComments: writer.stripComments, includeLineNumbers: false, indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) + writer = ScriptWriter( + stripComments: writer.stripComments, includeLineNumbers: false, + indent: writer.indent.count, initialIndentionLevel: initialIndentionLevel) } mutating func popTemporaryOutputBuffer() -> String { diff --git a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift index c5347505a..d8f4ed15f 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptProbeLifting.swift @@ -15,137 +15,137 @@ /// This file contains the JavaScript specific implementation of the Probe operation. See ProbingMutator.swift for an overview of this feature. struct JavaScriptProbeLifting { static let prefixCode = """ - // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. - if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; - - const Probe = (function() { - // - // "Import" the common runtime-assisted mutator code. This will make various utility functions available. - // - \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) - - // Action constants. - const PROPERTY_LOAD = "loads"; - const PROPERTY_STORE = "stores"; - - // Property access outcomes. - const PROPERTY_NOT_FOUND = 0; - const PROPERTY_FOUND = 1; - - // - // Result recording and reporting. - // - let results = { __proto__: null }; - - function reportError(msg) { - fuzzilli('FUZZILLI_PRINT', 'PROBING_ERROR: ' + msg); - } - - function reportResults() { - fuzzilli('FUZZILLI_PRINT', 'PROBING_RESULTS: ' + stringify(results)); - } - - // Record a property action performed on a probe. - // |target| is expected to be the original prototype of the probe object. It is used to determine whether the accessed property exists anywhere in the prototype chain of the probe. - function recordAction(action, id, target, key) { - let outcome = PROPERTY_NOT_FOUND; - if (ReflectHas(target, key)) { - outcome = PROPERTY_FOUND; + // If a sample with this instrumentation crashes, it may need the `fuzzilli` function to reproduce the crash. + if (typeof fuzzilli === 'undefined') fuzzilli = function() {}; + + const Probe = (function() { + // + // "Import" the common runtime-assisted mutator code. This will make various utility functions available. + // + \(JavaScriptRuntimeAssistedMutatorLifting.commonCode) + + // Action constants. + const PROPERTY_LOAD = "loads"; + const PROPERTY_STORE = "stores"; + + // Property access outcomes. + const PROPERTY_NOT_FOUND = 0; + const PROPERTY_FOUND = 1; + + // + // Result recording and reporting. + // + let results = { __proto__: null }; + + function reportError(msg) { + fuzzilli('FUZZILLI_PRINT', 'PROBING_ERROR: ' + msg); } - let keyString = key; - if (typeof keyString !== 'string') { - try { - keyString = key.toString(); - if (typeof keyString !== 'string') throw 'not a string'; - } catch(e) { - // Got some "weird" property key. Ignore it. + function reportResults() { + fuzzilli('FUZZILLI_PRINT', 'PROBING_RESULTS: ' + stringify(results)); + } + + // Record a property action performed on a probe. + // |target| is expected to be the original prototype of the probe object. It is used to determine whether the accessed property exists anywhere in the prototype chain of the probe. + function recordAction(action, id, target, key) { + let outcome = PROPERTY_NOT_FOUND; + if (ReflectHas(target, key)) { + outcome = PROPERTY_FOUND; + } + + let keyString = key; + if (typeof keyString !== 'string') { + try { + keyString = key.toString(); + if (typeof keyString !== 'string') throw 'not a string'; + } catch(e) { + // Got some "weird" property key. Ignore it. + return; + } + } + + if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { + // Cannot deal with this property name. Ignore it. return; } - } - if (!isShortString(keyString) && !isNumericString(keyString) && !isSymbol(key)) { - // Cannot deal with this property name. Ignore it. - return; - } + if (isSymbol(key) && !stringStartsWith(keyString, 'Symbol(Symbol.')) { + // We can only deal with well-known symbols (e.g. "Symbol(Symbol.toPrimitive)"), and this isn't one. Ignore it. + return; + } - if (isSymbol(key) && !stringStartsWith(keyString, 'Symbol(Symbol.')) { - // We can only deal with well-known symbols (e.g. "Symbol(Symbol.toPrimitive)"), and this isn't one. Ignore it. - return; + if (!hasOwnProperty(results, id)) { + results[id] = { [PROPERTY_LOAD]: { __proto__: null }, [PROPERTY_STORE]: { __proto__: null } }; + } + + // If the same action is performed on the same probe multiple times, we keep the last result. + results[id][action][keyString] = outcome; } - if (!hasOwnProperty(results, id)) { - results[id] = { [PROPERTY_LOAD]: { __proto__: null }, [PROPERTY_STORE]: { __proto__: null } }; + function recordActionWithErrorHandling(action, id, target, key) { + try { + recordAction(action, id, target, key); + } catch(e) { + reportError(e); + } } - // If the same action is performed on the same probe multiple times, we keep the last result. - results[id][action][keyString] = outcome; - } + // + // Probe implementation. + // + function probe(id, value) { + let originalPrototype, newPrototype; + let handler = { + get(target, key, receiver) { + // Special logic to deal with programs that fetch the prototype of an object after it was turned into a probe. + // In that case, the probe Proxy would leak to the script, potentially causing incorrect behaviour. To deal with that, + // we (1) return the original prototype when __proto__ is loaded (but this can be "bypassed" through Object.getPrototypeOf) + // and (2) attempt to detect property accesses on the prototype itself (instead of on the probe) and handle those separately. + if (key === '__proto__' && receiver === value) return originalPrototype; + if (receiver === newPrototype) return ReflectGet(target, key); + recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); + return ReflectGet(target, key, receiver); + }, + set(target, key, value, receiver) { + if (receiver === newPrototype) return ReflectSet(target, key, value); + recordActionWithErrorHandling(PROPERTY_STORE, id, target, key); + return ReflectSet(target, key, value, receiver); + }, + has(target, key) { + // Treat this as a load. + recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); + return ReflectHas(target, key); + }, + }; - function recordActionWithErrorHandling(action, id, target, key) { - try { - recordAction(action, id, target, key); - } catch(e) { - reportError(e); + try { + // This can fail, e.g. due to "Cannot convert undefined or null to object" or if the object is non-extensible. In that case, do nothing. + originalPrototype = getPrototypeOf(value); + newPrototype = new ProxyConstructor(originalPrototype, handler); + setPrototypeOf(value, newPrototype); + } catch (e) {} } - } - - // - // Probe implementation. - // - function probe(id, value) { - let originalPrototype, newPrototype; - let handler = { - get(target, key, receiver) { - // Special logic to deal with programs that fetch the prototype of an object after it was turned into a probe. - // In that case, the probe Proxy would leak to the script, potentially causing incorrect behaviour. To deal with that, - // we (1) return the original prototype when __proto__ is loaded (but this can be "bypassed" through Object.getPrototypeOf) - // and (2) attempt to detect property accesses on the prototype itself (instead of on the probe) and handle those separately. - if (key === '__proto__' && receiver === value) return originalPrototype; - if (receiver === newPrototype) return ReflectGet(target, key); - recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); - return ReflectGet(target, key, receiver); - }, - set(target, key, value, receiver) { - if (receiver === newPrototype) return ReflectSet(target, key, value); - recordActionWithErrorHandling(PROPERTY_STORE, id, target, key); - return ReflectSet(target, key, value, receiver); - }, - has(target, key) { - // Treat this as a load. - recordActionWithErrorHandling(PROPERTY_LOAD, id, target, key); - return ReflectHas(target, key); - }, - }; - try { - // This can fail, e.g. due to "Cannot convert undefined or null to object" or if the object is non-extensible. In that case, do nothing. - originalPrototype = getPrototypeOf(value); - newPrototype = new ProxyConstructor(originalPrototype, handler); - setPrototypeOf(value, newPrototype); - } catch (e) {} - } - - function probeWithErrorHandling(id, value) { - try { - probe(id, value); - } catch(e) { - reportError(e); + function probeWithErrorHandling(id, value) { + try { + probe(id, value); + } catch(e) { + reportError(e); + } } - } - return { - probe: probeWithErrorHandling, - reportResults: reportResults - }; - })(); + return { + probe: probeWithErrorHandling, + reportResults: reportResults + }; + })(); - """ + """ static let probeFunc = "Probe.probe" static let suffixCode = """ - Probe.reportResults(); + Probe.reportResults(); - """ + """ } diff --git a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift index 17fba9d87..9b2448dbb 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptRuntimeAssistedMutatorLifting.swift @@ -15,577 +15,577 @@ /// This file contains the JavaScript specific implementation of common runtime-assisted logic, such as the JS struct JavaScriptRuntimeAssistedMutatorLifting { static let commonCode = """ - // Note: runtime instrumentation code must generally assume that any operation performed on any object coming from the "outside", may raise an exception, for example due to triggering a Proxy trap. - // Further, it must also assume that the environment has been modified arbitrarily. For example, the Array.prototype[@@iterator] may have been set to an invalid value, so using `for...of` syntax could trigger an exception. - - // Load all necessary routines and objects into local variables as they may be overwritten by the program. - // We generally want to avoid triggerring observable side-effects, such as storing or loading - // properties. For that reason, we prefer to use builtins like Object.defineProperty. - - const ProxyConstructor = Proxy; - const BigIntConstructor = BigInt; - const SetConstructor = Set; - - const ObjectPrototype = Object.prototype; - - const getOwnPropertyNames = Object.getOwnPropertyNames; - const getPrototypeOf = Object.getPrototypeOf; - const setPrototypeOf = Object.setPrototypeOf; - const stringify = JSON.stringify; - const hasOwnProperty = Object.hasOwn; - const defineProperty = Object.defineProperty; - const propertyValues = Object.values; - const parseInteger = parseInt; - const NumberIsInteger = Number.isInteger; - const isNaN = Number.isNaN; - const isFinite = Number.isFinite; - const truncate = Math.trunc; - const apply = Reflect.apply; - const construct = Reflect.construct; - const ReflectGet = Reflect.get; - const ReflectSet = Reflect.set; - const ReflectHas = Reflect.has; - - // Bind methods to local variables. These all expect the 'this' object as first parameter. - const concat = Function.prototype.call.bind(Array.prototype.concat); - const findIndex = Function.prototype.call.bind(Array.prototype.findIndex); - const includes = Function.prototype.call.bind(Array.prototype.includes); - const shift = Function.prototype.call.bind(Array.prototype.shift); - const pop = Function.prototype.call.bind(Array.prototype.pop); - const push = Function.prototype.call.bind(Array.prototype.push); - const filter = Function.prototype.call.bind(Array.prototype.filter); - const execRegExp = Function.prototype.call.bind(RegExp.prototype.exec); - const stringSlice = Function.prototype.call.bind(String.prototype.slice); - const toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase); - const numberToString = Function.prototype.call.bind(Number.prototype.toString); - const bigintToString = Function.prototype.call.bind(BigInt.prototype.toString); - const stringStartsWith = Function.prototype.call.bind(String.prototype.startsWith); - const setAdd = Function.prototype.call.bind(Set.prototype.add); - const setHas = Function.prototype.call.bind(Set.prototype.has); - - const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER; - const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; - - // Simple, seedable PRNG based on a LCG. - class RNG { - m = 2 ** 32; - a = 1664525; - c = 1013904223; - x; - - constructor(seed) { - this.x = seed; - } - randomInt() { - this.x = (this.x * this.a + this.c) % this.m; - if (!isInteger(this.x)) throw "RNG state is not an Integer!" - return this.x; - } - randomFloat() { - return this.randomInt() / this.m; - } - probability(p) { - return this.randomFloat() < p; - } - reseed(seed) { - this.x = seed; - } - } - - // When creating empty arrays to which elements are later added, use a custom array type that has a null prototype. This way, the arrays are not - // affected by changes to the Array.prototype that could interfere with array builtins (e.g. indexed setters or a modified .constructor property). - function EmptyArray() { - let array = []; - setPrototypeOf(array, null); - return array; - } - - // - // Misc. helper functions. - // - // Type check helpers. These are less error-prone than manually using typeof and comparing against a string. - function isObject(v) { - return typeof v === 'object'; - } - function isFunction(v) { - return typeof v === 'function'; - } - function isString(v) { - return typeof v === 'string'; - } - function isNumber(v) { - return typeof v === 'number'; - } - function isBigint(v) { - return typeof v === 'bigint'; - } - function isSymbol(v) { - return typeof v === 'symbol'; - } - function isBoolean(v) { - return typeof v === 'boolean'; - } - function isUndefined(v) { - return typeof v === 'undefined'; - } - - // Helper function to determine if a value is an integer, and within [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER]. - function isInteger(n) { - return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; - } - - // Helper function to determine if a string is short. - function isShortString(s) { - if (!isString(s)) throw "Non-string argument to isShortString: " + s; - return s.length < 50; - } - - // Helper function to determine if a string is numeric and its numeric value representable as an integer. - function isNumericString(s) { - if (!isString(s)) return false; - let number = parseInteger(s); - return number >= MIN_SAFE_INTEGER && number <= MAX_SAFE_INTEGER && numberToString(number) === s; - } - - // Helper function to determine whether a property can be accessed without raising an exception. - function tryAccessProperty(prop, obj) { - try { - obj[prop]; - return true; - } catch (e) { - return false; - } - } - - // Helper function to determine if a property exists on an object or one of its prototypes. If an exception is raised, false is returned. - function tryHasProperty(prop, obj) { - try { - return prop in obj; - } catch (e) { - return false; - } - } - - // Helper function to load a property from an object. If an exception is raised, undefined is returned. - function tryGetProperty(prop, obj) { - try { - return obj[prop]; - } catch (e) { - return undefined; - } - } - - // Helper function to obtain the own properties of an object. If that raises an exception (e.g. on a Proxy object), an empty array is returned. - function tryGetOwnPropertyNames(obj) { - try { - return getOwnPropertyNames(obj); - } catch (e) { - return new Array(); - } - } - - // Helper function to fetch the prototype of an object. If that raises an exception (e.g. on a Proxy object), null is returned. - function tryGetPrototypeOf(obj) { - try { - return getPrototypeOf(obj); - } catch (e) { - return null; - } - } - - // Helper function to that creates a wrapper function for the given function which will call it in a try-catch and return false on exception. - function wrapInTryCatch(f) { - return function() { + // Note: runtime instrumentation code must generally assume that any operation performed on any object coming from the "outside", may raise an exception, for example due to triggering a Proxy trap. + // Further, it must also assume that the environment has been modified arbitrarily. For example, the Array.prototype[@@iterator] may have been set to an invalid value, so using `for...of` syntax could trigger an exception. + + // Load all necessary routines and objects into local variables as they may be overwritten by the program. + // We generally want to avoid triggerring observable side-effects, such as storing or loading + // properties. For that reason, we prefer to use builtins like Object.defineProperty. + + const ProxyConstructor = Proxy; + const BigIntConstructor = BigInt; + const SetConstructor = Set; + + const ObjectPrototype = Object.prototype; + + const getOwnPropertyNames = Object.getOwnPropertyNames; + const getPrototypeOf = Object.getPrototypeOf; + const setPrototypeOf = Object.setPrototypeOf; + const stringify = JSON.stringify; + const hasOwnProperty = Object.hasOwn; + const defineProperty = Object.defineProperty; + const propertyValues = Object.values; + const parseInteger = parseInt; + const NumberIsInteger = Number.isInteger; + const isNaN = Number.isNaN; + const isFinite = Number.isFinite; + const truncate = Math.trunc; + const apply = Reflect.apply; + const construct = Reflect.construct; + const ReflectGet = Reflect.get; + const ReflectSet = Reflect.set; + const ReflectHas = Reflect.has; + + // Bind methods to local variables. These all expect the 'this' object as first parameter. + const concat = Function.prototype.call.bind(Array.prototype.concat); + const findIndex = Function.prototype.call.bind(Array.prototype.findIndex); + const includes = Function.prototype.call.bind(Array.prototype.includes); + const shift = Function.prototype.call.bind(Array.prototype.shift); + const pop = Function.prototype.call.bind(Array.prototype.pop); + const push = Function.prototype.call.bind(Array.prototype.push); + const filter = Function.prototype.call.bind(Array.prototype.filter); + const execRegExp = Function.prototype.call.bind(RegExp.prototype.exec); + const stringSlice = Function.prototype.call.bind(String.prototype.slice); + const toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase); + const numberToString = Function.prototype.call.bind(Number.prototype.toString); + const bigintToString = Function.prototype.call.bind(BigInt.prototype.toString); + const stringStartsWith = Function.prototype.call.bind(String.prototype.startsWith); + const setAdd = Function.prototype.call.bind(Set.prototype.add); + const setHas = Function.prototype.call.bind(Set.prototype.has); + + const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER; + const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; + + // Simple, seedable PRNG based on a LCG. + class RNG { + m = 2 ** 32; + a = 1664525; + c = 1013904223; + x; + + constructor(seed) { + this.x = seed; + } + randomInt() { + this.x = (this.x * this.a + this.c) % this.m; + if (!isInteger(this.x)) throw "RNG state is not an Integer!" + return this.x; + } + randomFloat() { + return this.randomInt() / this.m; + } + probability(p) { + return this.randomFloat() < p; + } + reseed(seed) { + this.x = seed; + } + } + + // When creating empty arrays to which elements are later added, use a custom array type that has a null prototype. This way, the arrays are not + // affected by changes to the Array.prototype that could interfere with array builtins (e.g. indexed setters or a modified .constructor property). + function EmptyArray() { + let array = []; + setPrototypeOf(array, null); + return array; + } + + // + // Misc. helper functions. + // + // Type check helpers. These are less error-prone than manually using typeof and comparing against a string. + function isObject(v) { + return typeof v === 'object'; + } + function isFunction(v) { + return typeof v === 'function'; + } + function isString(v) { + return typeof v === 'string'; + } + function isNumber(v) { + return typeof v === 'number'; + } + function isBigint(v) { + return typeof v === 'bigint'; + } + function isSymbol(v) { + return typeof v === 'symbol'; + } + function isBoolean(v) { + return typeof v === 'boolean'; + } + function isUndefined(v) { + return typeof v === 'undefined'; + } + + // Helper function to determine if a value is an integer, and within [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER]. + function isInteger(n) { + return isNumber(n) && NumberIsInteger(n) && n>= MIN_SAFE_INTEGER && n <= MAX_SAFE_INTEGER; + } + + // Helper function to determine if a string is short. + function isShortString(s) { + if (!isString(s)) throw "Non-string argument to isShortString: " + s; + return s.length < 50; + } + + // Helper function to determine if a string is numeric and its numeric value representable as an integer. + function isNumericString(s) { + if (!isString(s)) return false; + let number = parseInteger(s); + return number >= MIN_SAFE_INTEGER && number <= MAX_SAFE_INTEGER && numberToString(number) === s; + } + + // Helper function to determine whether a property can be accessed without raising an exception. + function tryAccessProperty(prop, obj) { try { - return apply(f, this, arguments); + obj[prop]; + return true; } catch (e) { return false; } - }; - } - - // - // Basic random number generation utility functions. - // - - // Initially the rng is seeded randomly, specific mutators can reseed() the rng if they need deterministic behavior. - // See the explore operation in JsOperations.swift for an example. - let rng = new RNG(truncate(Math.random() * 2**32)); - - function probability(p) { - if (p < 0 || p > 1) throw "Argument to probability must be a number between zero and one"; - return rng.probability(p); - } - - function randomIntBetween(start, end) { - if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; - return (rng.randomInt() % (end - start)) + start; - } - - function randomFloat() { - return rng.randomFloat(); - } - - function randomBigintBetween(start, end) { - if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; - if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular intergers"; - return BigIntConstructor(randomIntBetween(Number(start), Number(end))); - } - - function randomIntBelow(n) { - if (!isInteger(n)) throw "Argument to randomIntBelow must be an integer"; - return rng.randomInt() % n; - } - - function randomElement(array) { - return array[randomIntBelow(array.length)]; - } - """ + } - static let introspectionCode = """ - // Note: this code assumes that the common code from above has been included before. - - // - // Object introspection. - // - - // - // Enumerate all properties on the given object and its prototypes. - // - // These include elements and methods (callable properties). Each property is assigned a "weight" which expresses roughly how "important"/"interesting" a property is: - // a property that exists on a prototype is considered less interesting as it can probably be reached through other objects as well, so we prefer properties closer to the start object. - // - // The result is returned in an array like the following: - // [ - // length: - // totalWeight: - // 0, 1, ..., length - 1: { name: , weight: } - // ] - function enumeratePropertiesOf(o) { - // Collect all properties, including those from prototypes, in this array. - let properties = EmptyArray(); - - // Give properties from prototypes a lower weight. Currently, the weight is halved for every new level of the prototype chain. - let currentWeight = 1.0; - properties.totalWeight = 0.0; - function recordProperty(p) { - push(properties, {name: p, weight: currentWeight}); - properties.totalWeight += currentWeight; - } - - // Iterate over the prototype chain and record all properties. - let obj = o; - while (obj !== null) { - // Special handling for array-like things: if the array is too large, skip this level and just include a couple random indices. - // We need to be careful when accessing the length though: for TypedArrays, the length property is defined on the prototype but - // must be accessed with the TypedArray as |this| value (not the prototype). - let maybeLength = tryGetProperty('length', obj); - if (isInteger(maybeLength) && maybeLength > 100) { - for (let i = 0; i < 10; i++) { - let randomElement = randomIntBelow(maybeLength); - recordProperty(randomElement); + // Helper function to determine if a property exists on an object or one of its prototypes. If an exception is raised, false is returned. + function tryHasProperty(prop, obj) { + try { + return prop in obj; + } catch (e) { + return false; + } + } + + // Helper function to load a property from an object. If an exception is raised, undefined is returned. + function tryGetProperty(prop, obj) { + try { + return obj[prop]; + } catch (e) { + return undefined; + } + } + + // Helper function to obtain the own properties of an object. If that raises an exception (e.g. on a Proxy object), an empty array is returned. + function tryGetOwnPropertyNames(obj) { + try { + return getOwnPropertyNames(obj); + } catch (e) { + return new Array(); + } + } + + // Helper function to fetch the prototype of an object. If that raises an exception (e.g. on a Proxy object), null is returned. + function tryGetPrototypeOf(obj) { + try { + return getPrototypeOf(obj); + } catch (e) { + return null; + } + } + + // Helper function to that creates a wrapper function for the given function which will call it in a try-catch and return false on exception. + function wrapInTryCatch(f) { + return function() { + try { + return apply(f, this, arguments); + } catch (e) { + return false; } - } else { - // TODO do we want to also enumerate symbol properties here (using Object.getOwnPropertySymbols)? If we do, we should probable also add IL-level support for Symbols (i.e. a `LoadSymbol` instruction that ensures the symbol is in the global Symbol registry). - let allOwnPropertyNames = tryGetOwnPropertyNames(obj); - let allOwnElements = EmptyArray(); - for (let i = 0; i < allOwnPropertyNames.length; i++) { - let p = allOwnPropertyNames[i]; - let index = parseInteger(p); - // TODO should we allow negative indices here as well? - if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { - push(allOwnElements, index); - } else if (isShortString(p) && tryAccessProperty(p, o)) { - // Only include properties with short names and only if they can be accessed on the original object without raising an exception. - recordProperty(p); + }; + } + + // + // Basic random number generation utility functions. + // + + // Initially the rng is seeded randomly, specific mutators can reseed() the rng if they need deterministic behavior. + // See the explore operation in JsOperations.swift for an example. + let rng = new RNG(truncate(Math.random() * 2**32)); + + function probability(p) { + if (p < 0 || p > 1) throw "Argument to probability must be a number between zero and one"; + return rng.probability(p); + } + + function randomIntBetween(start, end) { + if (!isInteger(start) || !isInteger(end)) throw "Arguments to randomIntBetween must be integers"; + return (rng.randomInt() % (end - start)) + start; + } + + function randomFloat() { + return rng.randomFloat(); + } + + function randomBigintBetween(start, end) { + if (!isBigint(start) || !isBigint(end)) throw "Arguments to randomBigintBetween must be bigints"; + if (!isInteger(Number(start)) || !isInteger(Number(end))) throw "Arguments to randomBigintBetween must be representable as regular intergers"; + return BigIntConstructor(randomIntBetween(Number(start), Number(end))); + } + + function randomIntBelow(n) { + if (!isInteger(n)) throw "Argument to randomIntBelow must be an integer"; + return rng.randomInt() % n; + } + + function randomElement(array) { + return array[randomIntBelow(array.length)]; + } + """ + + static let introspectionCode = """ + // Note: this code assumes that the common code from above has been included before. + + // + // Object introspection. + // + + // + // Enumerate all properties on the given object and its prototypes. + // + // These include elements and methods (callable properties). Each property is assigned a "weight" which expresses roughly how "important"/"interesting" a property is: + // a property that exists on a prototype is considered less interesting as it can probably be reached through other objects as well, so we prefer properties closer to the start object. + // + // The result is returned in an array like the following: + // [ + // length: + // totalWeight: + // 0, 1, ..., length - 1: { name: , weight: } + // ] + function enumeratePropertiesOf(o) { + // Collect all properties, including those from prototypes, in this array. + let properties = EmptyArray(); + + // Give properties from prototypes a lower weight. Currently, the weight is halved for every new level of the prototype chain. + let currentWeight = 1.0; + properties.totalWeight = 0.0; + function recordProperty(p) { + push(properties, {name: p, weight: currentWeight}); + properties.totalWeight += currentWeight; + } + + // Iterate over the prototype chain and record all properties. + let obj = o; + while (obj !== null) { + // Special handling for array-like things: if the array is too large, skip this level and just include a couple random indices. + // We need to be careful when accessing the length though: for TypedArrays, the length property is defined on the prototype but + // must be accessed with the TypedArray as |this| value (not the prototype). + let maybeLength = tryGetProperty('length', obj); + if (isInteger(maybeLength) && maybeLength > 100) { + for (let i = 0; i < 10; i++) { + let randomElement = randomIntBelow(maybeLength); + recordProperty(randomElement); + } + } else { + // TODO do we want to also enumerate symbol properties here (using Object.getOwnPropertySymbols)? If we do, we should probable also add IL-level support for Symbols (i.e. a `LoadSymbol` instruction that ensures the symbol is in the global Symbol registry). + let allOwnPropertyNames = tryGetOwnPropertyNames(obj); + let allOwnElements = EmptyArray(); + for (let i = 0; i < allOwnPropertyNames.length; i++) { + let p = allOwnPropertyNames[i]; + let index = parseInteger(p); + // TODO should we allow negative indices here as well? + if (index >= 0 && index <= MAX_SAFE_INTEGER && numberToString(index) === p) { + push(allOwnElements, index); + } else if (isShortString(p) && tryAccessProperty(p, o)) { + // Only include properties with short names and only if they can be accessed on the original object without raising an exception. + recordProperty(p); + } } - } - // Limit array-like objects to at most 10 random elements. - for (let i = 0; i < 10 && allOwnElements.length > 0; i++) { - let index = randomIntBelow(allOwnElements.length); - recordProperty(allOwnElements[index]); - allOwnElements[index] = pop(allOwnElements); + // Limit array-like objects to at most 10 random elements. + for (let i = 0; i < 10 && allOwnElements.length > 0; i++) { + let index = randomIntBelow(allOwnElements.length); + recordProperty(allOwnElements[index]); + allOwnElements[index] = pop(allOwnElements); + } } - } - obj = tryGetPrototypeOf(obj); - currentWeight /= 2.0; + obj = tryGetPrototypeOf(obj); + currentWeight /= 2.0; - // Greatly reduce the property weights for the Object.prototype. These methods are always available and we can use more targeted mechanisms like CodeGenerators to call them if we want to. - if (obj === ObjectPrototype) { - // Somewhat arbitrarily reduce the weight as if there were another 3 levels. - currentWeight /= 8.0; + // Greatly reduce the property weights for the Object.prototype. These methods are always available and we can use more targeted mechanisms like CodeGenerators to call them if we want to. + if (obj === ObjectPrototype) { + // Somewhat arbitrarily reduce the weight as if there were another 3 levels. + currentWeight /= 8.0; - // However, if we've reached the Object prototype without any other properties (i.e. are inspecting an empty, plain object), then always return an empty list since these properties are not very intersting. - if (properties.length == 0) { - return properties; + // However, if we've reached the Object prototype without any other properties (i.e. are inspecting an empty, plain object), then always return an empty list since these properties are not very intersting. + if (properties.length == 0) { + return properties; + } } } + + return properties; } - return properties; - } - - // - // Returns a random property available on the given object or one of its prototypes. - // - // This will return more "interesting" properties with a higher probability. In general, properties closer to the start object - // are preferred over properties on prototypes (as these are likely shared with other objects). - // - // If no (interesting) property exists, null is returned. Otherwise, the key of the property is returned. - function randomPropertyOf(o) { - let properties = enumeratePropertiesOf(o); - - // We need at least one property to chose from. - if (properties.length === 0) { - return null; - } - - // Now choose a random property. If a property has weight 2W, it will be selected with twice the probability of a property with weight W. - let selectedProperty; - let remainingWeight = randomFloat() * properties.totalWeight; - for (let i = 0; i < properties.length; i++) { - let candidate = properties[i]; - remainingWeight -= candidate.weight; - if (remainingWeight < 0) { - selectedProperty = candidate.name; - break; + // + // Returns a random property available on the given object or one of its prototypes. + // + // This will return more "interesting" properties with a higher probability. In general, properties closer to the start object + // are preferred over properties on prototypes (as these are likely shared with other objects). + // + // If no (interesting) property exists, null is returned. Otherwise, the key of the property is returned. + function randomPropertyOf(o) { + let properties = enumeratePropertiesOf(o); + + // We need at least one property to chose from. + if (properties.length === 0) { + return null; + } + + // Now choose a random property. If a property has weight 2W, it will be selected with twice the probability of a property with weight W. + let selectedProperty; + let remainingWeight = randomFloat() * properties.totalWeight; + for (let i = 0; i < properties.length; i++) { + let candidate = properties[i]; + remainingWeight -= candidate.weight; + if (remainingWeight < 0) { + selectedProperty = candidate.name; + break; + } } - } - // Sanity checking. This may fail for example if Proxies are involved. In that case, just fail here. - if (!tryHasProperty(selectedProperty, o)) return null; + // Sanity checking. This may fail for example if Proxies are involved. In that case, just fail here. + if (!tryHasProperty(selectedProperty, o)) return null; - return selectedProperty; - } - """ + return selectedProperty; + } + """ static let actionCode = """ - // Note: this code assumes that the common code from above has been included before. - - // - // List of all supported operations. Must be kept in sync with the ActionOperation enum. - // - const OP_CALL_FUNCTION = 'CALL_FUNCTION'; - const OP_CONSTRUCT = 'CONSTRUCT'; - const OP_CALL_METHOD = 'CALL_METHOD'; - const OP_CONSTRUCT_METHOD = 'CONSTRUCT_METHOD'; - const OP_GET_PROPERTY = 'GET_PROPERTY'; - const OP_SET_PROPERTY = 'SET_PROPERTY'; - const OP_DELETE_PROPERTY = 'DELETE_PROPERTY'; - - const OP_ADD = 'ADD'; - const OP_SUB = 'SUB'; - const OP_MUL = 'MUL'; - const OP_DIV = 'DIV'; - const OP_MOD = 'MOD'; - const OP_INC = 'INC'; - const OP_DEC = 'DEC'; - const OP_NEG = 'NEG'; - - const OP_LOGICAL_AND = 'LOGICAL_AND'; - const OP_LOGICAL_OR = 'LOGICAL_OR'; - const OP_LOGICAL_NOT = 'LOGICAL_NOT'; - const OP_NULL_COALESCE = 'NULL_COALESCE'; - - const OP_BITWISE_AND = 'BITWISE_AND'; - const OP_BITWISE_OR = 'BITWISE_OR'; - const OP_BITWISE_XOR = 'BITWISE_XOR'; - const OP_LEFT_SHIFT = 'LEFT_SHIFT'; - const OP_SIGNED_RIGHT_SHIFT = 'SIGNED_RIGHT_SHIFT'; - const OP_UNSIGNED_RIGHT_SHIFT = 'UNSIGNED_RIGHT_SHIFT'; - const OP_BITWISE_NOT = 'BITWISE_NOT'; - - const OP_COMPARE_EQUAL = 'COMPARE_EQUAL'; - const OP_COMPARE_STRICT_EQUAL = 'COMPARE_STRICT_EQUAL'; - const OP_COMPARE_NOT_EQUAL = 'COMPARE_NOT_EQUAL'; - const OP_COMPARE_STRICT_NOT_EQUAL = 'COMPARE_STRICT_NOT_EQUAL'; - const OP_COMPARE_GREATER_THAN = 'COMPARE_GREATER_THAN'; - const OP_COMPARE_LESS_THAN = 'COMPARE_LESS_THAN'; - const OP_COMPARE_GREATER_THAN_OR_EQUAL = 'COMPARE_GREATER_THAN_OR_EQUAL'; - const OP_COMPARE_LESS_THAN_OR_EQUAL = 'COMPARE_LESS_THAN_OR_EQUAL'; - const OP_TEST_IS_NAN = 'TEST_IS_NAN'; - const OP_TEST_IS_FINITE = 'TEST_IS_FINITE'; - - const OP_SYMBOL_REGISTRATION = 'SYMBOL_REGISTRATION'; - - // - // Action constructors. - // - function Action(operation, inputs) { - this.operation = operation; - this.inputs = inputs; - this.isGuarded = false; - } - - // A guarded action is an action that is allowed to raise an exception. - // - // These are for example used for by the ExplorationMutator for function/method call - // which may throw an exception if they aren't given the right arguments. In that case, - // we may still want to keep the function call so that it can be mutated further to - // hopefully eventually find the correct arguments. This is especially true if finding - // the right arguments reqires the ProbingMutator to install the right properties on an - // argument object, in which case the ExplorationMutator on its own would (likely) never - // be able to generate a valid call, and so the function/method may be missed entirely. - // - // If a guarded action succeeds (doesn't raise an exception), it will be converted to - // a regular action to limit the number of generated try-catch blocks. - function GuardedAction(operation, inputs) { - this.operation = operation; - this.inputs = inputs; - this.isGuarded = true; - } - - // Special value to indicate that no action should be performed. - const NO_ACTION = null; - - // - // Action Input constructors. - // - // The inputs for actions are encoded as objects that specify both the type and the value of the input. They are basically enum values with associated values. - // These must be kept compatible with the Action.Input enum in RuntimeAssistedMutator.swift as they have to be encodable to/decodable from that enum. - // - function ArgumentInput(index) { - if (!isInteger(index)) throw "ArgumentInput index is not an integer: " + index; - return { argument: { index } }; - } - function SpecialInput(name) { - if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; - return { special: { name } }; - } - function IntInput(value) { - if (!isInteger(value)) throw "IntInput value is not an integer: " + value; - return { int: { value } }; - } - function FloatInput(value) { - if (!isNumber(value) || !isFinite(value)) throw "FloatInput value is not a (finite) number: " + value; - return { float: { value } }; - } - function BigintInput(value) { - if (!isBigint(value)) throw "BigintInput value is not a bigint: " + value; - // Bigints can't be serialized by JSON.stringify, so store them as strings instead. - return { bigint: { value: bigintToString(value) } }; - } - function StringInput(value) { - if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; - return { string: { value } }; - } - - // Type checkers for Input objects. We use these instead of for example 'instanceof' since we allow Input - // objects to be decoded from JSON, in which case they will not have the right .constructor property. - function isArgumentInput(input) { return hasOwnProperty(input, 'argument'); } - function isSpecialInput(input) { return hasOwnProperty(input, 'special'); } - function isIntInput(input) { return hasOwnProperty(input, 'int'); } - function isFloatInput(input) { return hasOwnProperty(input, 'float'); } - function isBigintInput(input) { return hasOwnProperty(input, 'bigint'); } - function isStringInput(input) { return hasOwnProperty(input, 'string'); } - - // Helper routines to extract the associated values from Input objects. - function getArgumentInputIndex(input) { return input.argument.index; } - function getSpecialInputName(input) { return input.special.name; } - function getIntInputValue(input) { return input.int.value; } - function getFloatInputValue(input) { return input.float.value; } - function getBigintInputValue(input) { return BigIntConstructor(input.bigint.value); } - function getStringInputValue(input) { return input.string.value; } - - // Handlers for executing actions. - // These will receive the array of concrete inputs (i.e. JavaScript values) as first parameter and the current value of |this| as second parameter (which can be ignored if not needed). - const ACTION_HANDLERS = { - [OP_CALL_FUNCTION]: (inputs, currentThis) => { let f = shift(inputs); return apply(f, currentThis, inputs); }, - [OP_CONSTRUCT]: (inputs) => { let c = shift(inputs); return construct(c, inputs); }, - [OP_CALL_METHOD]: (inputs) => { let o = shift(inputs); let m = shift(inputs); return apply(o[m], o, inputs); }, - [OP_CONSTRUCT_METHOD]: (v, inputs) => { let o = shift(inputs); let m = shift(inputs); return construct(o[m], inputs); }, - [OP_GET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return o[p]; }, - [OP_SET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; let v = inputs[2]; o[p] = v; }, - [OP_DELETE_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return delete o[p]; }, - [OP_ADD]: (inputs) => inputs[0] + inputs[1], - [OP_SUB]: (inputs) => inputs[0] - inputs[1], - [OP_MUL]: (inputs) => inputs[0] * inputs[1], - [OP_DIV]: (inputs) => inputs[0] / inputs[1], - [OP_MOD]: (inputs) => inputs[0] % inputs[1], - [OP_INC]: (inputs) => inputs[0]++, - [OP_DEC]: (inputs) => inputs[0]--, - [OP_NEG]: (inputs) => -inputs[0], - [OP_LOGICAL_AND]: (inputs) => inputs[0] && inputs[1], - [OP_LOGICAL_OR]: (inputs) => inputs[0] || inputs[1], - [OP_LOGICAL_NOT]: (inputs) => !inputs[0], - [OP_NULL_COALESCE]: (inputs) => inputs[0] ?? inputs[1], - [OP_BITWISE_AND]: (inputs) => inputs[0] & inputs[1], - [OP_BITWISE_OR]: (inputs) => inputs[0] | inputs[1], - [OP_BITWISE_XOR]: (inputs) => inputs[0] ^ inputs[1], - [OP_LEFT_SHIFT]: (inputs) => inputs[0] << inputs[1], - [OP_SIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >> inputs[1], - [OP_UNSIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >>> inputs[1], - [OP_BITWISE_NOT]: (inputs) => ~inputs[0], - [OP_COMPARE_EQUAL]: (inputs) => inputs[0] == inputs[1], - [OP_COMPARE_STRICT_EQUAL]: (inputs) => inputs[0] === inputs[1], - [OP_COMPARE_NOT_EQUAL]: (inputs) => inputs[0] != inputs[1], - [OP_COMPARE_STRICT_NOT_EQUAL]: (inputs) => inputs[0] !== inputs[1], - [OP_COMPARE_GREATER_THAN]: (inputs) => inputs[0] > inputs[1], - [OP_COMPARE_LESS_THAN]: (inputs) => inputs[0] < inputs[1], - [OP_COMPARE_GREATER_THAN_OR_EQUAL]: (inputs) => inputs[0] >= inputs[1], - [OP_COMPARE_LESS_THAN_OR_EQUAL]: (inputs) => inputs[0] <= inputs[1], - [OP_TEST_IS_NAN]: (inputs) => Number.isNaN(inputs[0]), - [OP_TEST_IS_FINITE]: (inputs) => Number.isFinite(inputs[0]), - [OP_SYMBOL_REGISTRATION]: (inputs) => Symbol.for(inputs[0].description), - }; - - // Executes the given action. - // - // This will convert the inputs to concrete JavaScript values, then execute the operation with these inputs. - // Executing an action may change its guarding state: if a guarded action executes without raising an exception, - // it will be converted to an unguarded operation (as the guarding apears to not be needed). This way, we will - // ultimately end up emitting fewer try-catch (or equivalent) constructs in the final JavaScript code generated - // from these actions. - // - // Returns true if either the action succeeded without raising an exception or if the action is guarded, false otherwise. - // The output of the action is stored in |context.output| upon successful execution. - function execute(action, context) { - if (action === NO_ACTION) { - return true; + // Note: this code assumes that the common code from above has been included before. + + // + // List of all supported operations. Must be kept in sync with the ActionOperation enum. + // + const OP_CALL_FUNCTION = 'CALL_FUNCTION'; + const OP_CONSTRUCT = 'CONSTRUCT'; + const OP_CALL_METHOD = 'CALL_METHOD'; + const OP_CONSTRUCT_METHOD = 'CONSTRUCT_METHOD'; + const OP_GET_PROPERTY = 'GET_PROPERTY'; + const OP_SET_PROPERTY = 'SET_PROPERTY'; + const OP_DELETE_PROPERTY = 'DELETE_PROPERTY'; + + const OP_ADD = 'ADD'; + const OP_SUB = 'SUB'; + const OP_MUL = 'MUL'; + const OP_DIV = 'DIV'; + const OP_MOD = 'MOD'; + const OP_INC = 'INC'; + const OP_DEC = 'DEC'; + const OP_NEG = 'NEG'; + + const OP_LOGICAL_AND = 'LOGICAL_AND'; + const OP_LOGICAL_OR = 'LOGICAL_OR'; + const OP_LOGICAL_NOT = 'LOGICAL_NOT'; + const OP_NULL_COALESCE = 'NULL_COALESCE'; + + const OP_BITWISE_AND = 'BITWISE_AND'; + const OP_BITWISE_OR = 'BITWISE_OR'; + const OP_BITWISE_XOR = 'BITWISE_XOR'; + const OP_LEFT_SHIFT = 'LEFT_SHIFT'; + const OP_SIGNED_RIGHT_SHIFT = 'SIGNED_RIGHT_SHIFT'; + const OP_UNSIGNED_RIGHT_SHIFT = 'UNSIGNED_RIGHT_SHIFT'; + const OP_BITWISE_NOT = 'BITWISE_NOT'; + + const OP_COMPARE_EQUAL = 'COMPARE_EQUAL'; + const OP_COMPARE_STRICT_EQUAL = 'COMPARE_STRICT_EQUAL'; + const OP_COMPARE_NOT_EQUAL = 'COMPARE_NOT_EQUAL'; + const OP_COMPARE_STRICT_NOT_EQUAL = 'COMPARE_STRICT_NOT_EQUAL'; + const OP_COMPARE_GREATER_THAN = 'COMPARE_GREATER_THAN'; + const OP_COMPARE_LESS_THAN = 'COMPARE_LESS_THAN'; + const OP_COMPARE_GREATER_THAN_OR_EQUAL = 'COMPARE_GREATER_THAN_OR_EQUAL'; + const OP_COMPARE_LESS_THAN_OR_EQUAL = 'COMPARE_LESS_THAN_OR_EQUAL'; + const OP_TEST_IS_NAN = 'TEST_IS_NAN'; + const OP_TEST_IS_FINITE = 'TEST_IS_FINITE'; + + const OP_SYMBOL_REGISTRATION = 'SYMBOL_REGISTRATION'; + + // + // Action constructors. + // + function Action(operation, inputs) { + this.operation = operation; + this.inputs = inputs; + this.isGuarded = false; } - // Convert the action's inputs to the concrete JS values to use for executing the action. - let concreteInputs = EmptyArray(); - for (let i = 0; i < action.inputs.length; i++) { - let input = action.inputs[i]; - if (isArgumentInput(input)) { - let index = getArgumentInputIndex(input); - if (index >= context.arguments.length) throw "Invalid argument index: " + index; - push(concreteInputs, context.arguments[index]); - } else if (isSpecialInput(input)) { - let name = getSpecialInputName(input); - if (!hasOwnProperty(context.specialValues, name)) throw "Unknown special value: " + name; - push(concreteInputs, context.specialValues[name]); - } else if (isIntInput(input)) { - push(concreteInputs, getIntInputValue(input)); - } else if (isFloatInput(input)) { - push(concreteInputs, getFloatInputValue(input)); - } else if (isBigintInput(input)) { - // These need special handling because BigInts cannot be serialized into JSON, so are stored as strings. - push(concreteInputs, getBigintInputValue(input)); - } else if (isStringInput(input)) { - push(concreteInputs, getStringInputValue(input)); - } else { - throw "Unknown action input: " + stringify(input); - } + // A guarded action is an action that is allowed to raise an exception. + // + // These are for example used for by the ExplorationMutator for function/method call + // which may throw an exception if they aren't given the right arguments. In that case, + // we may still want to keep the function call so that it can be mutated further to + // hopefully eventually find the correct arguments. This is especially true if finding + // the right arguments reqires the ProbingMutator to install the right properties on an + // argument object, in which case the ExplorationMutator on its own would (likely) never + // be able to generate a valid call, and so the function/method may be missed entirely. + // + // If a guarded action succeeds (doesn't raise an exception), it will be converted to + // a regular action to limit the number of generated try-catch blocks. + function GuardedAction(operation, inputs) { + this.operation = operation; + this.inputs = inputs; + this.isGuarded = true; } - let handler = ACTION_HANDLERS[action.operation]; - if (isUndefined(handler)) throw "Unhandled operation " + action.operation; - - try { - context.output = handler(concreteInputs, context.currentThis); - // If the action succeeded, mark it as non-guarded so that we don't emit try-catch blocks for it later on. - // We could alternatively only do that if all executions succeeded, but it's probably fine to do it if at least one execution succeeded. - if (action.isGuarded) action.isGuarded = false; - } catch (e) { - return action.isGuarded; + // Special value to indicate that no action should be performed. + const NO_ACTION = null; + + // + // Action Input constructors. + // + // The inputs for actions are encoded as objects that specify both the type and the value of the input. They are basically enum values with associated values. + // These must be kept compatible with the Action.Input enum in RuntimeAssistedMutator.swift as they have to be encodable to/decodable from that enum. + // + function ArgumentInput(index) { + if (!isInteger(index)) throw "ArgumentInput index is not an integer: " + index; + return { argument: { index } }; + } + function SpecialInput(name) { + if (!isString(name) || !isShortString(name)) throw "SpecialInput name is not a (short) string: " + name; + return { special: { name } }; } + function IntInput(value) { + if (!isInteger(value)) throw "IntInput value is not an integer: " + value; + return { int: { value } }; + } + function FloatInput(value) { + if (!isNumber(value) || !isFinite(value)) throw "FloatInput value is not a (finite) number: " + value; + return { float: { value } }; + } + function BigintInput(value) { + if (!isBigint(value)) throw "BigintInput value is not a bigint: " + value; + // Bigints can't be serialized by JSON.stringify, so store them as strings instead. + return { bigint: { value: bigintToString(value) } }; + } + function StringInput(value) { + if (!isString(value) || !isShortString(value)) throw "StringInput value is not a (short) string: " + value; + return { string: { value } }; + } + + // Type checkers for Input objects. We use these instead of for example 'instanceof' since we allow Input + // objects to be decoded from JSON, in which case they will not have the right .constructor property. + function isArgumentInput(input) { return hasOwnProperty(input, 'argument'); } + function isSpecialInput(input) { return hasOwnProperty(input, 'special'); } + function isIntInput(input) { return hasOwnProperty(input, 'int'); } + function isFloatInput(input) { return hasOwnProperty(input, 'float'); } + function isBigintInput(input) { return hasOwnProperty(input, 'bigint'); } + function isStringInput(input) { return hasOwnProperty(input, 'string'); } + + // Helper routines to extract the associated values from Input objects. + function getArgumentInputIndex(input) { return input.argument.index; } + function getSpecialInputName(input) { return input.special.name; } + function getIntInputValue(input) { return input.int.value; } + function getFloatInputValue(input) { return input.float.value; } + function getBigintInputValue(input) { return BigIntConstructor(input.bigint.value); } + function getStringInputValue(input) { return input.string.value; } + + // Handlers for executing actions. + // These will receive the array of concrete inputs (i.e. JavaScript values) as first parameter and the current value of |this| as second parameter (which can be ignored if not needed). + const ACTION_HANDLERS = { + [OP_CALL_FUNCTION]: (inputs, currentThis) => { let f = shift(inputs); return apply(f, currentThis, inputs); }, + [OP_CONSTRUCT]: (inputs) => { let c = shift(inputs); return construct(c, inputs); }, + [OP_CALL_METHOD]: (inputs) => { let o = shift(inputs); let m = shift(inputs); return apply(o[m], o, inputs); }, + [OP_CONSTRUCT_METHOD]: (v, inputs) => { let o = shift(inputs); let m = shift(inputs); return construct(o[m], inputs); }, + [OP_GET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return o[p]; }, + [OP_SET_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; let v = inputs[2]; o[p] = v; }, + [OP_DELETE_PROPERTY]: (inputs) => { let o = inputs[0]; let p = inputs[1]; return delete o[p]; }, + [OP_ADD]: (inputs) => inputs[0] + inputs[1], + [OP_SUB]: (inputs) => inputs[0] - inputs[1], + [OP_MUL]: (inputs) => inputs[0] * inputs[1], + [OP_DIV]: (inputs) => inputs[0] / inputs[1], + [OP_MOD]: (inputs) => inputs[0] % inputs[1], + [OP_INC]: (inputs) => inputs[0]++, + [OP_DEC]: (inputs) => inputs[0]--, + [OP_NEG]: (inputs) => -inputs[0], + [OP_LOGICAL_AND]: (inputs) => inputs[0] && inputs[1], + [OP_LOGICAL_OR]: (inputs) => inputs[0] || inputs[1], + [OP_LOGICAL_NOT]: (inputs) => !inputs[0], + [OP_NULL_COALESCE]: (inputs) => inputs[0] ?? inputs[1], + [OP_BITWISE_AND]: (inputs) => inputs[0] & inputs[1], + [OP_BITWISE_OR]: (inputs) => inputs[0] | inputs[1], + [OP_BITWISE_XOR]: (inputs) => inputs[0] ^ inputs[1], + [OP_LEFT_SHIFT]: (inputs) => inputs[0] << inputs[1], + [OP_SIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >> inputs[1], + [OP_UNSIGNED_RIGHT_SHIFT]: (inputs) => inputs[0] >>> inputs[1], + [OP_BITWISE_NOT]: (inputs) => ~inputs[0], + [OP_COMPARE_EQUAL]: (inputs) => inputs[0] == inputs[1], + [OP_COMPARE_STRICT_EQUAL]: (inputs) => inputs[0] === inputs[1], + [OP_COMPARE_NOT_EQUAL]: (inputs) => inputs[0] != inputs[1], + [OP_COMPARE_STRICT_NOT_EQUAL]: (inputs) => inputs[0] !== inputs[1], + [OP_COMPARE_GREATER_THAN]: (inputs) => inputs[0] > inputs[1], + [OP_COMPARE_LESS_THAN]: (inputs) => inputs[0] < inputs[1], + [OP_COMPARE_GREATER_THAN_OR_EQUAL]: (inputs) => inputs[0] >= inputs[1], + [OP_COMPARE_LESS_THAN_OR_EQUAL]: (inputs) => inputs[0] <= inputs[1], + [OP_TEST_IS_NAN]: (inputs) => Number.isNaN(inputs[0]), + [OP_TEST_IS_FINITE]: (inputs) => Number.isFinite(inputs[0]), + [OP_SYMBOL_REGISTRATION]: (inputs) => Symbol.for(inputs[0].description), + }; - return true; - } - """ + // Executes the given action. + // + // This will convert the inputs to concrete JavaScript values, then execute the operation with these inputs. + // Executing an action may change its guarding state: if a guarded action executes without raising an exception, + // it will be converted to an unguarded operation (as the guarding apears to not be needed). This way, we will + // ultimately end up emitting fewer try-catch (or equivalent) constructs in the final JavaScript code generated + // from these actions. + // + // Returns true if either the action succeeded without raising an exception or if the action is guarded, false otherwise. + // The output of the action is stored in |context.output| upon successful execution. + function execute(action, context) { + if (action === NO_ACTION) { + return true; + } + + // Convert the action's inputs to the concrete JS values to use for executing the action. + let concreteInputs = EmptyArray(); + for (let i = 0; i < action.inputs.length; i++) { + let input = action.inputs[i]; + if (isArgumentInput(input)) { + let index = getArgumentInputIndex(input); + if (index >= context.arguments.length) throw "Invalid argument index: " + index; + push(concreteInputs, context.arguments[index]); + } else if (isSpecialInput(input)) { + let name = getSpecialInputName(input); + if (!hasOwnProperty(context.specialValues, name)) throw "Unknown special value: " + name; + push(concreteInputs, context.specialValues[name]); + } else if (isIntInput(input)) { + push(concreteInputs, getIntInputValue(input)); + } else if (isFloatInput(input)) { + push(concreteInputs, getFloatInputValue(input)); + } else if (isBigintInput(input)) { + // These need special handling because BigInts cannot be serialized into JSON, so are stored as strings. + push(concreteInputs, getBigintInputValue(input)); + } else if (isStringInput(input)) { + push(concreteInputs, getStringInputValue(input)); + } else { + throw "Unknown action input: " + stringify(input); + } + } + + let handler = ACTION_HANDLERS[action.operation]; + if (isUndefined(handler)) throw "Unhandled operation " + action.operation; + + try { + context.output = handler(concreteInputs, context.currentThis); + // If the action succeeded, mark it as non-guarded so that we don't emit try-catch blocks for it later on. + // We could alternatively only do that if all executions succeeded, but it's probably fine to do it if at least one execution succeeded. + if (action.isGuarded) action.isGuarded = false; + } catch (e) { + return action.isGuarded; + } + + return true; + } + """ } diff --git a/Sources/Fuzzilli/Lifting/ScriptWriter.swift b/Sources/Fuzzilli/Lifting/ScriptWriter.swift index 8b53a9075..f9c029856 100644 --- a/Sources/Fuzzilli/Lifting/ScriptWriter.swift +++ b/Sources/Fuzzilli/Lifting/ScriptWriter.swift @@ -36,7 +36,10 @@ struct ScriptWriter { /// Current line, used when including line numbers in the output. public private(set) var currentLineNumber = 0 - public init (stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, initialIndentionLevel: Int = 0, maxLineLength: Int = Int.max) { + public init( + stripComments: Bool = false, includeLineNumbers: Bool = false, indent: Int = 4, + initialIndentionLevel: Int = 0, maxLineLength: Int = Int.max + ) { self.indent = String(repeating: " ", count: indent) self.currentIndention = String(repeating: " ", count: indent * initialIndentionLevel) self.stripComments = stripComments @@ -59,7 +62,8 @@ struct ScriptWriter { while line.count > splitAt { var lineToPrint = line.prefix(splitAt + 1) if let spaceIndex = lineToPrint.lastIndex(of: " "), - spaceIndex != lineToPrint.startIndex { + spaceIndex != lineToPrint.startIndex + { // Only print the line if it contains non-space characters trimming all trailing // spaces. lineToPrint = lineToPrint.prefix(upTo: spaceIndex) @@ -71,7 +75,7 @@ struct ScriptWriter { emitImpl(line.prefix(splitAt)) line = line.suffix(line.count - splitAt) } - line = line.suffix(from: line.firstIndex {$0 != " "} ?? line.endIndex) + line = line.suffix(from: line.firstIndex { $0 != " " } ?? line.endIndex) } if !line.isEmpty { emitImpl(line) @@ -94,7 +98,9 @@ struct ScriptWriter { for line in block.split(separator: "\n", omittingEmptySubsequences: false) { if stripComments { let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines) - if trimmedLine.hasPrefix("//") || (trimmedLine.hasPrefix("/*") && trimmedLine.hasSuffix("*/")) { + if trimmedLine.hasPrefix("//") + || (trimmedLine.hasPrefix("/*") && trimmedLine.hasSuffix("*/")) + { continue } } diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index d57adaf38..13f91758d 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - import Foundation /// Represents the type identifiers for each code section according to the wasm @@ -43,18 +42,18 @@ private enum Prefix: UInt8 { // This maps ILTypes to their respective binary encoding. private let ILTypeMapping: [ILType: Data] = [ - .wasmi32 : Data([0x7F]), - .wasmi64 : Data([0x7E]), - .wasmf32 : Data([0x7D]), - .wasmf64 : Data([0x7C]), + .wasmi32: Data([0x7F]), + .wasmi64: Data([0x7E]), + .wasmf32: Data([0x7D]), + .wasmf64: Data([0x7C]), .wasmSimd128: Data([0x7B]), .wasmPackedI8: Data([0x78]), .wasmPackedI16: Data([0x77]), - .bigint : Data([0x7E]), // Maps to .wasmi64 - .jsAnything: Data([0x6F]), // Maps to .wasmExternRef - .integer: Data([0x7F]), // Maps to .wasmi32 - .number: Data([0x7D]) // Maps to .wasmf32 + .bigint: Data([0x7E]), // Maps to .wasmi64 + .jsAnything: Data([0x6F]), // Maps to .wasmExternRef + .integer: Data([0x7F]), // Maps to .wasmi32 + .number: Data([0x7D]), // Maps to .wasmf32 ] /// This is the main compiler for Wasm instructions. @@ -118,7 +117,7 @@ public class WasmLifter { // This can further be filtered for only e.g. tag imports by doing this. // `exports.compactMap({$0.getImport()}).filter({$0.type.isFunction})` - var isFunction : Bool { + var isFunction: Bool { if case .function(_) = self { return true } else { @@ -126,7 +125,7 @@ public class WasmLifter { } } - var isTable : Bool { + var isTable: Bool { if case .table(_) = self { return true } else { @@ -134,7 +133,7 @@ public class WasmLifter { } } - var isMemory : Bool { + var isMemory: Bool { if case .memory(_) = self { return true } else { @@ -142,7 +141,7 @@ public class WasmLifter { } } - var isGlobal : Bool { + var isGlobal: Bool { if case .global(_) = self { return true } else { @@ -150,7 +149,7 @@ public class WasmLifter { } } - var isTag : Bool { + var isTag: Bool { if case .tag(_) = self { return true } else { @@ -158,7 +157,7 @@ public class WasmLifter { } } - var isSuspendingObject : Bool { + var isSuspendingObject: Bool { if case .suspendingObject = self { return true } else { @@ -167,7 +166,7 @@ public class WasmLifter { } func getImport() -> (type: Self, variable: Variable, signature: WasmSignature?)? { - if case let .import(export, variable, signature) = self { + if case .import(let export, let variable, let signature) = self { return (export, variable, signature) } return nil @@ -176,13 +175,13 @@ public class WasmLifter { func getDefInstr() -> Instruction? { switch self { case .function(_), - .import(_, _, _), - .suspendingObject: + .import(_, _, _), + .suspendingObject: return nil case .global(let instr), - .table(let instr), - .memory(let instr), - .tag(let instr): + .table(let instr), + .memory(let instr), + .tag(let instr): return instr! } } @@ -190,8 +189,8 @@ public class WasmLifter { func groupName() -> String { switch self { case .function, - .import, - .suspendingObject: + .import, + .suspendingObject: // Functions and imports don't have group names, this is used for getting imports of that type. fatalError("unreachable") case .table: @@ -208,7 +207,7 @@ public class WasmLifter { func exportName(forIdx idx: Int) -> String { return switch self { case .function, - .suspendingObject: + .suspendingObject: WasmLifter.nameOfFunction(idx) case .table: WasmLifter.nameOfTable(idx) @@ -226,7 +225,7 @@ public class WasmLifter { func exportTypeByte() -> Int { switch self { case .function, - .suspendingObject: + .suspendingObject: return 0x0 case .table: return 0x1 @@ -290,20 +289,20 @@ public class WasmLifter { private var dataSegments: [Instruction] = [] private var elementSegments: [Instruction] = [] -// // The tags associated with this module. -// private var tags: VariableMap<[ILType]> = VariableMap() + // // The tags associated with this module. + // private var tags: VariableMap<[ILType]> = VariableMap() private var typeGroups: Set = [] - private var typeDescToIndex : [WasmTypeDescription:Int] = [:] + private var typeDescToIndex: [WasmTypeDescription: Int] = [:] private var userDefinedTypesCount = 0 // The function index space private var functionIdxBase = 0 // The signature index space. - private var signatures : [WasmSignature] = [] - private var signatureIndexMap : [WasmSignature: Int] = [:] + private var signatures: [WasmSignature] = [] + private var signatureIndexMap: [WasmSignature: Int] = [:] // This tracks in which order we have seen globals, this can probably be unified with the .globals and .imports properties, as they should match in their keys. private var globalOrder: [Variable] = [] @@ -342,9 +341,7 @@ public class WasmLifter { private var writer = WasmExprWriter() var isEmpty: Bool { - return instructionBuffer.isEmpty && - self.bytecode.isEmpty && - self.exports.isEmpty + return instructionBuffer.isEmpty && self.bytecode.isEmpty && self.exports.isEmpty } // TODO: maybe we can do some analysis based on blocks. @@ -374,7 +371,10 @@ public class WasmLifter { public var labelBranchDepthMapping: VariableMap = VariableMap() // Expects the withArguments array to contain the variables of the innerOutputs, they should map directly to the local indices. - init(_ signature: WasmSignature, _ code: Data, for lifter: WasmLifter, withArguments arguments: [Variable]) { + init( + _ signature: WasmSignature, _ code: Data, for lifter: WasmLifter, + withArguments arguments: [Variable] + ) { // Infer the first few locals from this signature. self.signature = signature self.code = code @@ -385,7 +385,9 @@ public class WasmLifter { for (idx, argVar) in arguments.dropFirst().enumerated() { self.localsInfo.append((argVar, signature.parameterTypes[idx])) // Emit the expressions for the parameters such that we can accesss them if we need them. - self.lifter!.writer.addExpr(for: argVar, bytecode: Data([0x20]) + Leb128.unsignedEncode(self.localsInfo.count - 1)) + self.lifter!.writer.addExpr( + for: argVar, + bytecode: Data([0x20]) + Leb128.unsignedEncode(self.localsInfo.count - 1)) } } @@ -402,7 +404,7 @@ public class WasmLifter { } func isLocal(_ variable: Variable) -> Bool { - self.localsInfo.contains(where: {$0.0 == variable}) + self.localsInfo.contains(where: { $0.0 == variable }) } func getStackSlot(for variable: Variable) -> Int? { @@ -469,14 +471,13 @@ public class WasmLifter { // All functions should have associated byte code at this point. // - // // Step 3: Lift the whole module and put everything together. // if verbose { print("Got the following functions") - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { print("\(String(describing: functionInfo))") } } @@ -532,19 +533,19 @@ public class WasmLifter { // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/wasm/wasm-constants.h?q=symbol:ValueTypeCode let sharedFlagPrefix: [UInt8] = heapTypeInfo.shared ? [0x65] : [] let opCode: UInt8 = - switch (heapTypeInfo.heapType) { - case .WasmExtern: 0x6F - case .WasmFunc: 0x70 - case .WasmAny: 0x6E - case .WasmEq: 0x6D - case .WasmI31: 0x6C - case .WasmStruct: 0x6B - case .WasmArray: 0x6A - case .WasmExn: 0x69 - case .WasmNone: 0x71 - case .WasmNoExtern: 0x72 - case .WasmNoFunc: 0x73 - case .WasmNoExn: 0x74 + switch heapTypeInfo.heapType { + case .WasmExtern: 0x6F + case .WasmFunc: 0x70 + case .WasmAny: 0x6E + case .WasmEq: 0x6D + case .WasmI31: 0x6C + case .WasmStruct: 0x6B + case .WasmArray: 0x6A + case .WasmExn: 0x69 + case .WasmNone: 0x71 + case .WasmNoExtern: 0x72 + case .WasmNoFunc: 0x73 + case .WasmNoExn: 0x74 } return Data(sharedFlagPrefix + [opCode]) } @@ -585,7 +586,9 @@ public class WasmLifter { } // Helper method in cases we have either abstract type represented by ILType or an index type Variable - private func encodeReferenceType(_ refType: WasmReferenceType, instr: Instruction, typeInput: Int) throws -> Data { + private func encodeReferenceType( + _ refType: WasmReferenceType, instr: Instruction, typeInput: Int + ) throws -> Data { switch refType.kind { case .Abstract(let heapTypeInfo): return encodeAbstractHeapType(heapTypeInfo) @@ -629,7 +632,7 @@ public class WasmLifter { } // Special handling for defined functions - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { registerSignature(functionInfo!.signature) } @@ -711,14 +714,16 @@ public class WasmLifter { temp += Leb128.unsignedEncode(self.exports.count { $0.getImport() != nil }) // Build the import components of this vector that consist of mod:name, nm:name, and d:importdesc - for (idx, (_, importVariable, signature)) in self.exports.compactMap({ $0.getImport() }).enumerated() { + for (idx, (_, importVariable, signature)) in self.exports.compactMap({ $0.getImport() }) + .enumerated() + { if verbose { print(importVariable) } // Append the name as a vector temp += Leb128.unsignedEncode("imports".count) temp += "imports".data(using: .utf8)! - var importName : String + var importName: String importName = "import_\(idx)_\(importVariable)" temp += Leb128.unsignedEncode(importName.count) temp += importName.data(using: .utf8)! @@ -739,7 +744,9 @@ public class WasmLifter { temp += Data([0x2]) let mem = type.wasmMemoryType! - let limits_byte: UInt8 = (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0); + let limits_byte: UInt8 = + (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) + | (mem.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(mem.limits.min)) @@ -755,7 +762,8 @@ public class WasmLifter { let table = type.wasmTableType! temp += try encodeType(table.elementType) - let limits_byte: UInt8 = (table.isTable64 ? 4 : 0) | (table.limits.max != nil ? 1 : 0) + let limits_byte: UInt8 = + (table.isTable64 ? 4 : 0) | (table.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(table.limits.min)) @@ -772,7 +780,7 @@ public class WasmLifter { temp += mutability ? [0x1] : [0x0] continue } - if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { + if type.Is(.object(ofGroup: "WasmTag")) && signature != nil { temp += [0x4, 0x0] + Leb128.unsignedEncode(try getSignatureIndex(signature!)) continue } @@ -803,7 +811,7 @@ public class WasmLifter { // TODO(cffsmith): functions can share type indices. This could be an optimization later on. var temp = Leb128.unsignedEncode(functionCount) - for case let .function(functionInfo) in self.exports { + for case .function(let functionInfo) in self.exports { temp.append(Leb128.unsignedEncode(try getSignatureIndex(functionInfo!.signature))) } @@ -829,7 +837,7 @@ public class WasmLifter { var temp = Leb128.unsignedEncode(tableCount) - for case let .table(instruction) in self.exports { + for case .table(let instruction) in self.exports { let op = instruction!.op as! WasmDefineTable let elementType = op.elementType let minSize = op.limits.min @@ -865,20 +873,20 @@ public class WasmLifter { // - constant starting index. private func buildElementSection() throws { let numDefinedTablesWithEntries = self.exports.count { - if case let .table(instruction) = $0 { + if case .table(let instruction) = $0 { return !(instruction!.op as! WasmDefineTable).definedEntries.isEmpty } else { return false } } - if numDefinedTablesWithEntries == 0 && elementSegments.count == 0 { return } + if numDefinedTablesWithEntries == 0 && elementSegments.count == 0 { return } self.bytecode += [WasmSection.element.rawValue] - var temp = Data(); + var temp = Data() // Element segment count. - temp += Leb128.unsignedEncode(numDefinedTablesWithEntries + elementSegments.count); + temp += Leb128.unsignedEncode(numDefinedTablesWithEntries + elementSegments.count) // Passive element segments. They go first so that their indexes start with 0. for instruction in self.elementSegments { @@ -897,7 +905,7 @@ public class WasmLifter { } // Active element segments - for case let .table(instruction) in self.exports { + for case .table(let instruction) in self.exports { let table = instruction!.op as! WasmDefineTable let definedEntries = table.definedEntries assert(definedEntries.count == instruction!.inputs.count) @@ -945,7 +953,7 @@ public class WasmLifter { let functions = self.exports.filter({ $0.isFunction }) - let importedFunctionCount = self.exports.compactMap({$0.getImport()}).count { + let importedFunctionCount = self.exports.compactMap({ $0.getImport() }).count { $0.type.isFunction } @@ -965,8 +973,11 @@ public class WasmLifter { var funcTemp = Data() // TODO: this should be encapsulated more nicely. There should be an interface that gets the locals without the parameters. As this is currently mainly used to get the slots info. // Encode number of locals - funcTemp += Leb128.unsignedEncode(functionInfo!.localsInfo.count - functionInfo!.signature.parameterTypes.count) - for (_, type) in functionInfo!.localsInfo[functionInfo!.signature.parameterTypes.count...] { + funcTemp += Leb128.unsignedEncode( + functionInfo!.localsInfo.count - functionInfo!.signature.parameterTypes.count) + for (_, type) in functionInfo!.localsInfo[ + functionInfo!.signature.parameterTypes.count...] + { // Encode the locals funcTemp += Leb128.unsignedEncode(1) funcTemp += try encodeType(type) @@ -985,7 +996,8 @@ public class WasmLifter { // The function entry is the function index, followed by the counts of branch hints // for this function and then the bytes containing the actual branch hints. let functionIndex = defIndex + importedFunctionCount - let hintsEncoded = Leb128.unsignedEncode(functionIndex) + let hintsEncoded = + Leb128.unsignedEncode(functionIndex) + Leb128.unsignedEncode(functionInfo!.branchHints.count) + functionInfo!.branchHints.map { // Each branch hint is the instruction offset starting from the locals @@ -1001,7 +1013,8 @@ public class WasmLifter { if !functionBranchHints.isEmpty { self.bytecode += [WasmSection.custom.rawValue] let name = "metadata.code.branch_hint" - let sectionContent = Leb128.unsignedEncode(name.count) + Data(name.data(using: .ascii)!) + let sectionContent = + Leb128.unsignedEncode(name.count) + Data(name.data(using: .ascii)!) + Leb128.unsignedEncode(functionBranchHints.count) + functionBranchHints.joined() self.bytecode.append(Leb128.unsignedEncode(sectionContent.count)) self.bytecode.append(sectionContent) @@ -1032,7 +1045,7 @@ public class WasmLifter { for instruction in self.dataSegments { let segment = (instruction.op as! WasmDefineDataSegment).segment - temp += Data([0x01]) // mode = passive + temp += Data([0x01]) // mode = passive temp += Leb128.unsignedEncode(segment.count) temp += Data(segment) } @@ -1076,7 +1089,7 @@ public class WasmLifter { var temp = Leb128.unsignedEncode(globalCount) // TODO: in the future this should maybe be a context that allows instructions? Such that we can fuzz this expression as well? - for case let .global(instruction) in self.exports { + for case .global(let instruction) in self.exports { let definition = instruction!.op as! WasmDefineGlobal let global = definition.wasmGlobal @@ -1104,7 +1117,7 @@ public class WasmLifter { temp += try! Data([0xD0]) + encodeHeapType(.wasmI31Ref()) + Data([0x0B]) continue case .refFunc(_), - .imported(_): + .imported(_): fatalError("unreachable") } temp += try lift(temporaryInstruction!) @@ -1132,12 +1145,13 @@ public class WasmLifter { self.bytecode += [WasmSection.memory.rawValue] var temp = Leb128.unsignedEncode(memoryCount) - for case let .memory(instruction) in self.exports { + for case .memory(let instruction) in self.exports { let type = typer.type(of: instruction!.output) assert(type.isWasmMemoryType) let mem = type.wasmMemoryType! - let limits_byte: UInt8 = (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0); + let limits_byte: UInt8 = + (mem.isMemory64 ? 4 : 0) | (mem.isShared ? 2 : 0) | (mem.limits.max != nil ? 1 : 0) temp += Data([limits_byte]) temp += Data(Leb128.unsignedEncode(mem.limits.min)) @@ -1159,7 +1173,7 @@ public class WasmLifter { private func buildTagSection() throws { if self.exports.count(where: { $0.isTag }) == 0 { - return // Skip the whole section. + return // Skip the whole section. } self.bytecode.append(WasmSection.tag.rawValue) @@ -1167,7 +1181,7 @@ public class WasmLifter { section += Leb128.unsignedEncode(self.exports.count { $0.isTag }) - for case let .tag(instr) in self.exports { + for case .tag(let instr) in self.exports { let signatureDesc = typer.getTypeDescription(of: instr!.input(0)) section.append(0) section.append(Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!)) @@ -1204,11 +1218,12 @@ public class WasmLifter { temp += Leb128.unsignedEncode(name.count) temp += name.data(using: .utf8)! // Add the base, as our exports start after the imports. This variable needs to be incremented in the `buildImportSection` function. - temp += Leb128.unsignedEncode(export.exportTypeByte()) + Leb128.unsignedEncode(idx + offset) + temp += + Leb128.unsignedEncode(export.exportTypeByte()) + Leb128.unsignedEncode(idx + offset) } // The predicate is used to filter for only a specific type of import. - let reexportAndExport: ((Export) -> Bool) -> () = { predicate in + let reexportAndExport: ((Export) -> Bool) -> Void = { predicate in let imported = self.exports.filter({ $0.getImport() != nil && predicate($0.getImport()!.type) }) @@ -1266,41 +1281,51 @@ public class WasmLifter { switch instr.op.opcode { case .wasmBeginBlock(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginIf(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginElse(_): // Note: We need to subtract one because the begin else block closes the if block before opening the else block! - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmBeginTryTable(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginTry(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginTryDelegate(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginLoop(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth // Needs typer analysis return true case .wasmBeginCatch(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(1)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(1)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmBeginCatchAll(_): - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth - 1 // Needs typer analysis return true case .wasmCallIndirect(let op): @@ -1315,26 +1340,31 @@ public class WasmLifter { break case .beginWasmFunction(_): let signature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature - let functionInfo = FunctionInfo(signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) + let functionInfo = FunctionInfo( + signature, Data(), for: self, withArguments: Array(instr.innerOutputs)) self.exports.append(.function(functionInfo)) // Set the current active function as we are *actively* in it. currentFunction = functionInfo - self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = self.currentFunction!.variableAnalyzer.wasmBranchDepth + self.currentFunction!.labelBranchDepthMapping[instr.innerOutput(0)] = + self.currentFunction!.variableAnalyzer.wasmBranchDepth case .endWasmFunction(_): currentFunction!.outputVariable = instr.output return true case .wasmDefineGlobal(_): - assert(self.exports.contains(where: { - $0.isGlobal && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isGlobal && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineTable(_): - assert(self.exports.contains(where: { - $0.isTable && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isTable && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineMemory(_): - assert(self.exports.contains(where: { - $0.isMemory && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + $0.isMemory && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineDataSegment(_): self.dataSegments.append(instr) case .wasmDefineElementSegment(_): @@ -1344,16 +1374,18 @@ public class WasmLifter { case .wasmThrow(_): return true case .wasmDefineTag(_): - assert(self.exports.contains(where: { - if case .tag(let i) = $0 { - return i!.output == instr.output - } else { - return false - } - })) - assert(self.exports.contains(where: { - $0.isTag && $0.getDefInstr()!.output == instr.output - })) + assert( + self.exports.contains(where: { + if case .tag(let i) = $0 { + return i!.output == instr.output + } else { + return false + } + })) + assert( + self.exports.contains(where: { + $0.isTag && $0.getDefInstr()!.output == instr.output + })) case .wasmDefineAdHocModuleSignatureType(_): break default: @@ -1404,18 +1436,23 @@ public class WasmLifter { // reassigns. Similarly, the end of a function doesn't spill anything. // WasmDefineAdHocSignatureType isn't a wasm instruction and therefore also doesn't have any // Wasm stack inputs. - if instr.op is WasmReassign || instr.op is EndWasmFunction || instr.op is WasmDefineAdHocSignatureType { + if instr.op is WasmReassign || instr.op is EndWasmFunction + || instr.op is WasmDefineAdHocSignatureType + { return } // If we have an output, make sure we store it on the stack as this is a "complex" instruction, i.e. has inputs and outputs. if instr.numOutputs > 0 { - assert(instr.outputs.allSatisfy {!typer.type(of: $0).Is(.anyLabel)}) + assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyLabel) }) for output in instr.outputs.reversed() { // Also spill the instruction currentFunction!.spillLocal(forVariable: output) // Add the corresponding stack load as an expression, this adds the number of arguments, as output vars always live after the function arguments. - self.writer.addExpr(for: output, bytecode: Data([0x20]) + Leb128.unsignedEncode(currentFunction!.localsInfo.count - 1)) + self.writer.addExpr( + for: output, + bytecode: Data([0x20]) + + Leb128.unsignedEncode(currentFunction!.localsInfo.count - 1)) } } @@ -1460,7 +1497,6 @@ public class WasmLifter { return } - // Now check for generic imports that we can just import as is without using a signature. if !imports.contains(where: { // if we have a signature, we need to make sure that create a new import with that signature. @@ -1486,7 +1522,8 @@ public class WasmLifter { } // Add typegroups and their dependencies. if typeGroups.insert(typeDesc.typeGroupIndex).inserted { - typeGroups.formUnion(typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) + typeGroups.formUnion( + typer.getTypeGroupDependencies(typeGroupIndex: typeDesc.typeGroupIndex)) } } @@ -1504,19 +1541,28 @@ public class WasmLifter { throw WasmLifter.CompileError.missingTypeInformation } // TODO: This now uses the typer here but the op also carries this information? - importIfNeeded(.import(type: .tag(nil), variable: input, signature: inputType.wasmTagType!.parameters => [])) + importIfNeeded( + .import( + type: .tag(nil), variable: input, + signature: inputType.wasmTagType!.parameters => [])) } // Special handling for functions, we only expect them in WasmJSCalls, and WasmDefineTable instructions right now. // We can treat the suspendingObjects as function imports. - if inputType.Is(.function()) || inputType.Is(.object(ofGroup: "WasmSuspendingObject")) { + if inputType.Is(.function()) + || inputType.Is(.object(ofGroup: "WasmSuspendingObject")) + { if case .wasmJsCall(_) = instr.op.opcode { - let wasmSignature = typer.type(of: instr.input(0)).wasmFunctionSignatureDefSignature - importIfNeeded(.import(type: .function(nil), variable: input, signature: wasmSignature)) + let wasmSignature = typer.type(of: instr.input(0)) + .wasmFunctionSignatureDefSignature + importIfNeeded( + .import(type: .function(nil), variable: input, signature: wasmSignature) + ) } else if case .wasmDefineTable(let op) = instr.op.opcode { // Find the signature in the defined entries let sig = op.definedEntries[idx].signature - importIfNeeded(.import(type: .function(nil), variable: input, signature: sig)) + importIfNeeded( + .import(type: .function(nil), variable: input, signature: sig)) } else { // This instruction has likely expected some .object() of a specific group, as this variable can originate from outside wasm, it might have been reassigned to. Which means we will enter this path. // Therefore we need to bail. @@ -1536,7 +1582,10 @@ public class WasmLifter { for (value, definedEntry) in zip(instr.inputs, tableDef.definedEntries) { if !typer.type(of: value).Is(.wasmFunctionDef()) { // Check if we need to import the inputs. - importIfNeeded(.import(type: .function(nil), variable: value, signature: definedEntry.signature)) + importIfNeeded( + .import( + type: .function(nil), variable: value, + signature: definedEntry.signature)) } } } @@ -1600,7 +1649,7 @@ public class WasmLifter { }) // Now get the index in this "import space" - if let idx = imports.firstIndex(where: { + if let idx = imports.firstIndex(where: { $0.variable == input }) { return idx @@ -1624,11 +1673,11 @@ public class WasmLifter { } func resolveDataSegmentIdx(for input: Variable) -> Int { - dataSegments.firstIndex {$0.output == input}! + dataSegments.firstIndex { $0.output == input }! } func resolveElementSegmentIdx(for input: Variable) -> Int { - elementSegments.firstIndex {$0.output == input}! + elementSegments.firstIndex { $0.output == input }! } // The memory immediate argument, which encodes the alignment and memory index. @@ -1637,12 +1686,13 @@ public class WasmLifter { // Memory zero: `[align]`. // Multi-memory: `[align | 0x40] + [mem_idx]`. private func alignmentAndMemoryBytes(_ memory: Variable, alignment: Int64 = 1) throws -> Data { - assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be a power of two") + assert( + alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be a power of two") let memoryIdx = try resolveIdx(ofType: .memory, for: memory) - let alignmentLog2 = alignment.trailingZeroBitCount - assert(alignmentLog2 < 0x40, "Alignment \(alignment) is too large for multi-memory encoding") + assert( + alignmentLog2 < 0x40, "Alignment \(alignment) is too large for multi-memory encoding") if memoryIdx == 0 { return Leb128.unsignedEncode(alignmentLog2) @@ -1832,57 +1882,71 @@ public class WasmLifter { return Data([0x24]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: input)) case .wasmTableGet(_): let tableRef = wasmInstruction.input(0) - return Data([0x25]) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x25]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableSet(_): let tableRef = wasmInstruction.input(0) - return Data([0x26]) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x26]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableSize(_): let tableRef = wasmInstruction.input(0) // Value 0x10 is table.size opcode - return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x10) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x10) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmTableGrow(_): let tableRef = wasmInstruction.input(0) // Value 0x0f is table.grow opcode - return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x0f) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([Prefix.Numeric.rawValue]) + Leb128.unsignedEncode(0x0f) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmCallIndirect(let op): let tableRef = wasmInstruction.input(0) let sigIndex = try getSignatureIndex(op.signature) - return Data([0x11]) + Leb128.unsignedEncode(sigIndex) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x11]) + Leb128.unsignedEncode(sigIndex) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmCallDirect(_): let functionRef = wasmInstruction.input(0) - return Data([0x10]) + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) + return Data([0x10]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) case .wasmReturnCallDirect(_): let functionRef = wasmInstruction.input(0) - return Data([0x12]) + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) + return Data([0x12]) + + Leb128.unsignedEncode(try resolveIdx(ofType: .function, for: functionRef)) case .wasmReturnCallIndirect(let op): let tableRef = wasmInstruction.input(0) let sigIndex = try getSignatureIndex(op.signature) - return Data([0x13]) + Leb128.unsignedEncode(sigIndex) + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) + return Data([0x13]) + Leb128.unsignedEncode(sigIndex) + + Leb128.unsignedEncode(try resolveIdx(ofType: .table, for: tableRef)) case .wasmMemoryLoad(let op): let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - return Data([op.loadType.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + return Data([op.loadType.rawValue]) + alignAndMemory + + Leb128.signedEncode(Int(op.staticOffset)) case .wasmMemoryStore(let op): let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - let opCode = Data(op.storeType != .S128StoreMem - ? [op.storeType.rawValue] - : [Prefix.Simd.rawValue, op.storeType.rawValue]) + let opCode = Data( + op.storeType != .S128StoreMem + ? [op.storeType.rawValue] + : [Prefix.Simd.rawValue, op.storeType.rawValue]) return opCode + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) case .wasmAtomicLoad(let op): let opcode = [Prefix.Atomic.rawValue, op.loadType.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.loadType.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.loadType.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicStore(let op): let opcode = [Prefix.Atomic.rawValue, op.storeType.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.storeType.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.storeType.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicRMW(let op): let opcode = [Prefix.Atomic.rawValue, op.op.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.op.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.op.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmAtomicCmpxchg(let op): let opcode = [Prefix.Atomic.rawValue, op.op.rawValue] - let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.op.naturalAlignment()) + let alignAndMemory = try alignmentAndMemoryBytes( + wasmInstruction.input(0), alignment: op.op.naturalAlignment()) return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset)) case .wasmMemorySize(_): let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) @@ -1893,14 +1957,16 @@ public class WasmLifter { case .wasmMemoryCopy(_): let dstMemIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) let srcMemIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0A]) + Leb128.unsignedEncode(dstMemIdx) + Leb128.unsignedEncode(srcMemIdx) + return Data([0xFC, 0x0A]) + Leb128.unsignedEncode(dstMemIdx) + + Leb128.unsignedEncode(srcMemIdx) case .wasmMemoryFill(_): let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0)) return Data([0xFC, 0x0B]) + Leb128.unsignedEncode(memoryIdx) case .wasmMemoryInit(_): let dataSegmentIdx = resolveDataSegmentIdx(for: wasmInstruction.input(0)) let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(1)) - return Data([0xFC, 0x08]) + Leb128.unsignedEncode(dataSegmentIdx) + Leb128.unsignedEncode(memoryIdx) + return Data([0xFC, 0x08]) + Leb128.unsignedEncode(dataSegmentIdx) + + Leb128.unsignedEncode(memoryIdx) case .wasmDropDataSegment(_): let dataSegmentIdx = resolveDataSegmentIdx(for: wasmInstruction.input(0)) return Data([0xFC, 0x09]) + Leb128.unsignedEncode(dataSegmentIdx) @@ -1910,14 +1976,17 @@ public class WasmLifter { case .wasmTableInit(_): let elementSegmentIdx = resolveElementSegmentIdx(for: wasmInstruction.input(0)) let tableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0c]) + Leb128.unsignedEncode(elementSegmentIdx) + Leb128.unsignedEncode(tableIdx) + return Data([0xFC, 0x0c]) + Leb128.unsignedEncode(elementSegmentIdx) + + Leb128.unsignedEncode(tableIdx) case .wasmTableCopy(_): let dstTableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(0)) let srcTableIdx = try resolveIdx(ofType: .table, for: wasmInstruction.input(1)) - return Data([0xFC, 0x0e]) + Leb128.unsignedEncode(dstTableIdx) + Leb128.unsignedEncode(srcTableIdx) + return Data([0xFC, 0x0e]) + Leb128.unsignedEncode(dstTableIdx) + + Leb128.unsignedEncode(srcTableIdx) case .wasmJsCall(_): // We filter first, such that we get the index of functions only. - let wasmSignature = typer.type(of: wasmInstruction.input(0)).wasmFunctionSignatureDefSignature + let wasmSignature = typer.type(of: wasmInstruction.input(0)) + .wasmFunctionSignatureDefSignature // This has somewhat special handling as we might have multiple imports for this variable, we also need to get the right index that matches that signature that we expect here. // TODO(cffsmith): consider adding that signature matching feature to resolveIdx. @@ -1928,7 +1997,8 @@ public class WasmLifter { return false } }).firstIndex(where: { - wasmInstruction.input(1) == $0.getImport()!.variable && wasmSignature == $0.getImport()!.signature + wasmInstruction.input(1) == $0.getImport()!.variable + && wasmSignature == $0.getImport()!.signature }) { return Data([0x10]) + Leb128.unsignedEncode(index) } else { @@ -1946,19 +2016,21 @@ public class WasmLifter { let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) var inputIndex = 1 + op.parameterCount let catchTable: Data = try op.catches.map { - switch $0 { - case .Ref, .NoRef: - let tag = try resolveIdx(ofType: .tag, for: wasmInstruction.input(inputIndex)) - let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex + 1)) - 1 - let result = Data([$0.rawValue]) + Leb128.unsignedEncode(tag) + Leb128.unsignedEncode(depth) - inputIndex += 2 - return result - case .AllRef, .AllNoRef: - let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex)) - 1 - inputIndex += 1 - return Data([$0.rawValue]) + Leb128.unsignedEncode(depth) - } - }.reduce(Data(), +) + switch $0 { + case .Ref, .NoRef: + let tag = try resolveIdx(ofType: .tag, for: wasmInstruction.input(inputIndex)) + let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex + 1)) - 1 + let result = + Data([$0.rawValue]) + Leb128.unsignedEncode(tag) + + Leb128.unsignedEncode(depth) + inputIndex += 2 + return result + case .AllRef, .AllNoRef: + let depth = try branchDepthFor(label: wasmInstruction.input(inputIndex)) - 1 + inputIndex += 1 + return Data([$0.rawValue]) + Leb128.unsignedEncode(depth) + } + }.reduce(Data(), +) return [0x1F] + Leb128.unsignedEncode(typeDescToIndex[signatureDesc]!) + Leb128.unsignedEncode(op.catches.count) @@ -1972,12 +2044,15 @@ public class WasmLifter { case .wasmBeginCatchAll(_): return Data([0x19]) case .wasmBeginCatch(_): - return Data([0x07] + Leb128.unsignedEncode(try resolveIdx(ofType: .tag, for: wasmInstruction.input(1)))) + return Data( + [0x07] + + Leb128.unsignedEncode( + try resolveIdx(ofType: .tag, for: wasmInstruction.input(1)))) case .wasmEndLoop(_), - .wasmEndIf(_), - .wasmEndTryTable(_), - .wasmEndTry(_), - .wasmEndBlock(_): + .wasmEndIf(_), + .wasmEndTryTable(_), + .wasmEndTry(_), + .wasmEndBlock(_): // Basically the same as EndBlock, just an explicit instruction. return Data([0x0B]) case .wasmEndTryDelegate(_): @@ -1988,7 +2063,10 @@ public class WasmLifter { } return Data([0x18]) + Leb128.unsignedEncode(branchDepth) case .wasmThrow(_): - return Data([0x08] + Leb128.unsignedEncode(try resolveIdx(ofType: .tag, for: wasmInstruction.input(0)))) + return Data( + [0x08] + + Leb128.unsignedEncode( + try resolveIdx(ofType: .tag, for: wasmInstruction.input(0)))) case .wasmThrowRef(_): return Data([0x0A]) case .wasmRethrow(_): @@ -1996,16 +2074,19 @@ public class WasmLifter { return Data([0x09] + Leb128.unsignedEncode(blockDepth)) case .wasmBranch(let op): let branchDepth = try branchDepthFor(label: wasmInstruction.input(0)) - return Data([0x0C]) + Leb128.unsignedEncode(branchDepth) + Array(repeating: 0x1a, count: op.parameterCount) + return Data([0x0C]) + Leb128.unsignedEncode(branchDepth) + + Array(repeating: 0x1a, count: op.parameterCount) case .wasmBranchIf(let op): currentFunction!.addBranchHint(op.hint) let branchDepth = try branchDepthFor(label: wasmInstruction.input(0)) - return Data([0x0D]) + Leb128.unsignedEncode(branchDepth) + Array(repeating: 0x1a, count: op.parameterCount) + return Data([0x0D]) + Leb128.unsignedEncode(branchDepth) + + Array(repeating: 0x1a, count: op.parameterCount) case .wasmBranchTable(let op): let depths = try (0...op.valueCount).map { try branchDepthFor(label: wasmInstruction.input($0)) } - return Data([0x0E]) + Leb128.unsignedEncode(op.valueCount) + depths.map(Leb128.unsignedEncode).joined() + return Data([0x0E]) + Leb128.unsignedEncode(op.valueCount) + + depths.map(Leb128.unsignedEncode).joined() case .wasmBeginIf(let op): currentFunction!.addBranchHint(op.hint) let signatureDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) @@ -2029,7 +2110,10 @@ public class WasmLifter { storeInstruction = Data([0x21]) + Leb128.unsignedEncode(stackSlot) } else { // It has to be global then. Do what StoreGlobal does. - storeInstruction = Data([0x24]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: wasmInstruction.input(0))) + storeInstruction = + Data([0x24]) + + Leb128.unsignedEncode( + try resolveIdx(ofType: .global, for: wasmInstruction.input(0))) } // Load the input now. For "internal" variables, we should not have an expression. @@ -2039,7 +2123,10 @@ public class WasmLifter { out += Data([0x20]) + Leb128.unsignedEncode(stackSlot) } else { // Has to be a global then. Do what LoadGlobal does. - out += Data([0x23]) + Leb128.unsignedEncode(try resolveIdx(ofType: .global, for: wasmInstruction.input(1))) + out += + Data([0x23]) + + Leb128.unsignedEncode( + try resolveIdx(ofType: .global, for: wasmInstruction.input(1))) } return out + storeInstruction @@ -2052,58 +2139,78 @@ public class WasmLifter { case .constSimd128(let op): return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(12) + Data(op.value) case .wasmSimd128IntegerUnOp(let op): - assert(WasmSimd128IntegerUnOpKind.allCases.count == 17, "New WasmSimd128IntegerUnOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerUnOpKind.allCases.count == 17, + "New WasmSimd128IntegerUnOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .i8x16: 0x5C case .i16x8: 0x7C case .i32x4: 0x9C case .i64x2: 0xBC default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") - } - var encoding = Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.unOpKind.rawValue) + } + var encoding = + Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.unOpKind.rawValue) // For most of the instructions we have to add another 0x01 byte add the end of the encoding. switch op.shape { - case .i8x16: + case .i8x16: + break + case .i16x8, .i32x4, .i64x2: + switch op.unOpKind { + case .extadd_pairwise_i8x16_s, + .extadd_pairwise_i8x16_u: break - case .i16x8, .i32x4, .i64x2: switch op.unOpKind { - case .extadd_pairwise_i8x16_s, - .extadd_pairwise_i8x16_u: - break - default: - encoding += Leb128.unsignedEncode(0x01) + default: + encoding += Leb128.unsignedEncode(0x01) } - default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") + default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerUnOp") } return encoding case .wasmSimd128IntegerBinOp(let op): - assert(WasmSimd128IntegerBinOpKind.allCases.count == 26, "New WasmSimd128IntegerBinOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerBinOpKind.allCases.count == 26, + "New WasmSimd128IntegerBinOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .i8x16: 0x5C case .i16x8: 0x7C case .i32x4: 0x9C case .i64x2: 0xBC default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerBinOp") - } - var encoding = Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.binOpKind.rawValue) + } + var encoding = + Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.binOpKind.rawValue) // Apart from .i8x16 shape, the encoding has another 0x01 byte at the end of the encoding. - if (op.shape != .i8x16) { + if op.shape != .i8x16 { encoding += Leb128.unsignedEncode(0x01) } return encoding case .wasmSimd128IntegerTernaryOp(let op): - assert(WasmSimd128IntegerTernaryOpKind.allCases.count == 2, "New WasmSimd128IntegerTernaryOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128IntegerTernaryOpKind.allCases.count == 2, + "New WasmSimd128IntegerTernaryOpKind added: check if the encoding is still correct!" + ) + let base = + switch op.shape { case .i8x16: 0x100 case .i16x8: 0x101 case .i32x4: 0x102 case .i64x2: 0x103 - default: fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerTernaryOp") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + Leb128.unsignedEncode(0x01) + default: + fatalError("Shape \(op.shape) not supported for WasmSimd128IntegerTernaryOp") + } + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + + Leb128.unsignedEncode(0x01) case .wasmSimd128FloatUnOp(let op): - assert(WasmSimd128FloatUnOpKind.allCases.count == 7, "New WasmSimd128FloatUnOpKind added: check if the encoding is still correct!") - let encoding = switch op.shape { - case .f32x4: switch op.unOpKind { + assert( + WasmSimd128FloatUnOpKind.allCases.count == 7, + "New WasmSimd128FloatUnOpKind added: check if the encoding is still correct!") + let encoding = + switch op.shape { + case .f32x4: + switch op.unOpKind { case .ceil: Leb128.unsignedEncode(0x67) case .floor: Leb128.unsignedEncode(0x68) case .trunc: Leb128.unsignedEncode(0x69) @@ -2111,8 +2218,9 @@ public class WasmLifter { case .abs: Leb128.unsignedEncode(0xE0) + Leb128.unsignedEncode(0x01) case .neg: Leb128.unsignedEncode(0xE1) + Leb128.unsignedEncode(0x01) case .sqrt: Leb128.unsignedEncode(0xE3) + Leb128.unsignedEncode(0x01) - } - case .f64x2: switch op.unOpKind { + } + case .f64x2: + switch op.unOpKind { case .ceil: Leb128.unsignedEncode(0x74) case .floor: Leb128.unsignedEncode(0x75) case .trunc: Leb128.unsignedEncode(0x7A) @@ -2120,49 +2228,70 @@ public class WasmLifter { case .abs: Leb128.unsignedEncode(0xEC) + Leb128.unsignedEncode(0x01) case .neg: Leb128.unsignedEncode(0xED) + Leb128.unsignedEncode(0x01) case .sqrt: Leb128.unsignedEncode(0xEF) + Leb128.unsignedEncode(0x01) - } + } default: fatalError("Shape \(op.shape) not supported for WasmSimd128FloatUnOp") - } + } return Data([Prefix.Simd.rawValue]) + encoding case .wasmSimd128FloatBinOp(let op): - assert(WasmSimd128FloatBinOpKind.allCases.count == 10, "New WasmSimd128FloatBinOpKind added: check if the encoding is still correct!") - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(op.getOpcode()) + Leb128.unsignedEncode(0x01) + assert( + WasmSimd128FloatBinOpKind.allCases.count == 10, + "New WasmSimd128FloatBinOpKind added: check if the encoding is still correct!") + return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(op.getOpcode()) + + Leb128.unsignedEncode(0x01) case .wasmSimd128FloatTernaryOp(let op): - assert(WasmSimd128FloatTernaryOpKind.allCases.count == 2, "New WasmSimd128FloatTernaryOpKind added: check if the encoding is still correct!") - let base = switch op.shape { + assert( + WasmSimd128FloatTernaryOpKind.allCases.count == 2, + "New WasmSimd128FloatTernaryOpKind added: check if the encoding is still correct!") + let base = + switch op.shape { case .f32x4: 0x100 case .f64x2: 0x102 default: fatalError("Shape \(op.shape) not supported for WasmSimd128FloatTernaryOp") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + Leb128.unsignedEncode(0x01) + } + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(base + op.ternaryOpKind.rawValue) + + Leb128.unsignedEncode(0x01) case .wasmSimd128Compare(let op): - assert(WasmIntegerCompareOpKind.allCases.count == 10, "New WasmIntegerCompareOpKind added: check if the encoding is still correct!") - assert(WasmFloatCompareOpKind.allCases.count == 6, "New WasmFloatCompareOpKind added: check if the encoding is still correct!") + assert( + WasmIntegerCompareOpKind.allCases.count == 10, + "New WasmIntegerCompareOpKind added: check if the encoding is still correct!") + assert( + WasmFloatCompareOpKind.allCases.count == 6, + "New WasmFloatCompareOpKind added: check if the encoding is still correct!") switch op.shape { case .i8x16: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x23 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x23 + op.compareOpKind.toInt()) case .i16x8: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x2D + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x2D + op.compareOpKind.toInt()) case .i32x4: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x37 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x37 + op.compareOpKind.toInt()) case .i64x2: if case .iKind(let value) = op.compareOpKind { - let temp = switch value { + let temp = + switch value { case .Eq: 0 case .Ne: 1 case .Lt_s: 2 case .Gt_s: 3 case .Le_s: 4 case .Ge_s: 5 - default: fatalError("Shape \(op.shape) does not have \(op.compareOpKind) instruction") - } - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0xD6 + temp) + Leb128.unsignedEncode(0x01) + default: + fatalError( + "Shape \(op.shape) does not have \(op.compareOpKind) instruction") + } + return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0xD6 + temp) + + Leb128.unsignedEncode(0x01) } fatalError("unreachable") case .f32x4: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x41 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x41 + op.compareOpKind.toInt()) case .f64x2: - return Data([Prefix.Simd.rawValue]) + Leb128.unsignedEncode(0x47 + op.compareOpKind.toInt()) + return Data([Prefix.Simd.rawValue]) + + Leb128.unsignedEncode(0x47 + op.compareOpKind.toInt()) } case .wasmSimdSplat(let op): return Data([Prefix.Simd.rawValue, op.kind.rawValue]) @@ -2178,10 +2307,11 @@ public class WasmLifter { let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + Leb128.unsignedEncode(op.lane) - case .wasmSimdLoad(let op): + case .wasmSimdLoad(let op): // The memory immediate is {staticOffset, align} where align is 0 by default. Use signed encoding for potential bad (i.e. negative) offsets. let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0)) - return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + Leb128.signedEncode(Int(op.staticOffset)) + return Data([Prefix.Simd.rawValue, op.kind.rawValue]) + alignAndMemory + + Leb128.signedEncode(Int(op.staticOffset)) case .wasmArrayNewFixed(let op): let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) let arrayIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) @@ -2193,7 +2323,8 @@ public class WasmLifter { case .wasmArrayLen(_): return Data([Prefix.GC.rawValue, 0x0F]) case .wasmArrayGet(let op): - let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmArrayTypeDescription + let typeDesc = + typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmArrayTypeDescription let opCode: UInt8 = typeDesc.elementType.isPacked() ? (op.isSigned ? 0x0C : 0x0D) : 0x0B let arrayIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) return Data([Prefix.GC.rawValue, opCode]) + arrayIndex @@ -2210,8 +2341,10 @@ public class WasmLifter { let structIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) return Data([Prefix.GC.rawValue, 0x01]) + structIndex case .wasmStructGet(let op): - let typeDesc = typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmStructTypeDescription - let opCode: UInt8 = typeDesc.fields[op.fieldIndex].type.isPacked() ? (op.isSigned ? 0x03 : 0x04) : 0x02 + let typeDesc = + typer.getTypeDescription(of: wasmInstruction.input(0)) as! WasmStructTypeDescription + let opCode: UInt8 = + typeDesc.fields[op.fieldIndex].type.isPacked() ? (op.isSigned ? 0x03 : 0x04) : 0x02 let structIndex = Leb128.unsignedEncode(typeDescToIndex[typeDesc]!) let fieldIndex = Leb128.unsignedEncode(op.fieldIndex) return Data([Prefix.GC.rawValue, opCode]) + structIndex + fieldIndex @@ -2251,7 +2384,7 @@ public class WasmLifter { return Data() default: - fatalError("unreachable") + fatalError("unreachable") } } } diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index ddc493bc7..39f27e327 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -27,11 +27,11 @@ struct BlockReducer: Reducer { reduceObjectLiteral(group.block(0), with: helper) case .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter: + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter: assert(group.numBlocks == 1) reduceFunctionInObjectLiteral(group.block(0), with: helper) @@ -39,22 +39,22 @@ struct BlockReducer: Reducer { reduceClassDefinition(group.block(0), with: helper) case .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassStaticInitializer, .beginClassPrivateMethod: + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: reduceFunctionInClassDefinition(group.block(0), with: helper) case .beginWhileLoopHeader, - .beginDoWhileLoopBody, - .beginForLoopInitializer, - .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct, - .beginRepeatLoop: + .beginDoWhileLoopBody, + .beginForLoopInitializer, + .beginForInLoop, + .beginForOfLoop, + .beginForOfLoopWithDestruct, + .beginRepeatLoop: reduceLoop(group, with: helper) case .beginIf: @@ -67,41 +67,41 @@ struct BlockReducer: Reducer { reduceBeginSwitch(group, with: helper) case .beginSwitchCase, - .beginSwitchDefaultCase: - // These instructions are handled in reduceBeginSwitch. - break + .beginSwitchDefaultCase: + // These instructions are handled in reduceBeginSwitch. + break case .beginWith: reduceGenericBlockGroup(group, with: helper) case .beginPlainFunction, - .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor: + .beginArrowFunction, + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor: reduceFunctionOrConstructor(group, with: helper) case .beginCodeString: reduceCodeString(group, with: helper) case .beginBlockStatement, - .beginWasmFunction, - .beginWasmModule, - .wasmBeginTryDelegate, - .wasmBeginTryTable: + .beginWasmFunction, + .beginWasmModule, + .wasmBeginTryDelegate, + .wasmBeginTryTable: reduceGenericBlockGroup(group, with: helper) case .wasmBeginBlock, - .wasmBeginLoop: + .wasmBeginLoop: let rewroteProgram = reduceGenericWasmBlockGroup(group, with: helper) if rewroteProgram { return } case .wasmBeginCatchAll, - .wasmBeginCatch: + .wasmBeginCatch: // These instructions are handled in the reduceWasmTryCatch. break case .wasmBeginTry: @@ -209,7 +209,8 @@ struct BlockReducer: Reducer { helper.tryReplacements(replacements, renumberVariables: true, expectCodeToBeValid: false) } - private func reduceFunctionInClassDefinition(_ function: Block, with helper: MinimizationHelper) { + private func reduceFunctionInClassDefinition(_ function: Block, with helper: MinimizationHelper) + { // Similar to the object literal case, the instructions inside the function body aren't valid inside // the surrounding class definition, so we can only try to temove the entire function. helper.tryNopping(function.allInstructions) @@ -224,7 +225,7 @@ struct BlockReducer: Reducer { for block in loop.blocks { for instr in helper.code.body(of: block) { if instr.isBlockEnd { - inNestedLoop = nestedBlocks.pop() + inNestedLoop = nestedBlocks.pop() } if instr.isBlockStart { let isLoop = instr.op.contextOpened.contains(.loop) @@ -256,7 +257,7 @@ struct BlockReducer: Reducer { if group.numBlocks == 2 { // First try to remove the else block. let elseBlock = group.block(1) - let rangeToNop = Array(elseBlock.head ..< elseBlock.tail) + let rangeToNop = Array(elseBlock.head.. Bool { + private func reduceGenericWasmBlockGroup(_ group: BlockGroup, with helper: MinimizationHelper) + -> Bool + { // Try to remove just the block. var candidates = group.blockInstructionIndices if helper.tryNopping(candidates) { @@ -337,12 +344,13 @@ struct BlockReducer: Reducer { let endInstrInputs = endInstr.inputs.dropFirst() var varReplacements = Dictionary( uniqueKeysWithValues: zip(beginInstr.innerOutputs.dropFirst(), blockInputs)) - varReplacements.merge(zip(endInstr.outputs, endInstrInputs.map {varReplacements[$0] ?? $0}), - uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) + varReplacements.merge( + zip(endInstr.outputs, endInstrInputs.map { varReplacements[$0] ?? $0 }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) var newCode = Code() for (i, instr) in helper.code.enumerated() { if i == group.head || i == group.tail { - continue // Skip the block begin and end. + continue // Skip the block begin and end. } let newInouts = instr.inouts.map({ varReplacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -375,7 +383,9 @@ struct BlockReducer: Reducer { // Start iterating over the switch case statements. var instructionIdx = group.head + 1 while instructionIdx < group.tail { - if helper.code[instructionIdx].op is BeginSwitchCase || helper.code[instructionIdx].op is BeginSwitchDefaultCase { + if helper.code[instructionIdx].op is BeginSwitchCase + || helper.code[instructionIdx].op is BeginSwitchDefaultCase + { let block = helper.code.block(startingAt: instructionIdx) blocks.append(block) candidates.append(block.head) @@ -423,7 +433,9 @@ struct BlockReducer: Reducer { // Start iterating over the try catch statements. var instructionIdx = group.head + 1 while instructionIdx < group.tail { - if helper.code[instructionIdx].op is WasmBeginCatch || helper.code[instructionIdx].op is WasmBeginCatchAll { + if helper.code[instructionIdx].op is WasmBeginCatch + || helper.code[instructionIdx].op is WasmBeginCatchAll + { let block = helper.code.block(startingAt: instructionIdx) blocks.append(block) candidates.append(block.head) @@ -446,14 +458,14 @@ struct BlockReducer: Reducer { // Skip the last instruction as it is both the .endBlock as well as the .startBlock for // the next catch (or the overall end of the try). let allInstructions = block.allInstructions - helper.tryNopping(Array(allInstructions[0.. Bool { let label = helper.code[group.head].innerOutputs.first! - return ((group.head + 1)..= elseBlock.head && i <= elseBlock.tail) { - continue // Skip the WasmBeginIf and the else block. + continue // Skip the WasmBeginIf and the else block. } - let newInouts = instr.inouts.map {varReplacements[$0] ?? $0} + let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) } newCode.renumberVariables() @@ -535,22 +556,26 @@ struct BlockReducer: Reducer { return true } } - do { // Try to replace the if-else with the else body. + do { // Try to replace the if-else with the else body. let beginElseInstr = helper.code[elseBlock.head] // "Shortcut" bypassing the WasmBeginElse by directly using the inputs into the // WasmBeginIf. var varReplacements = Dictionary( - uniqueKeysWithValues: zip(beginElseInstr.innerOutputs.dropFirst(), beginIfInstr.inputs.dropFirst())) + uniqueKeysWithValues: zip( + beginElseInstr.innerOutputs.dropFirst(), beginIfInstr.inputs.dropFirst())) // Replace all usages of the WasmEndIf outputs with the results of the else block // which are the inputs into the WasmEndIf block. varReplacements.merge( - zip(helper.code[elseBlock.tail].outputs, - helper.code[elseBlock.tail].inputs.dropFirst().map {varReplacements[$0] ?? $0}), - uniquingKeysWith: {_, _ in fatalError("duplicate variables")}) + zip( + helper.code[elseBlock.tail].outputs, + helper.code[elseBlock.tail].inputs.dropFirst().map { + varReplacements[$0] ?? $0 + }), + uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) var newCode = Code() for (i, instr) in helper.code.enumerated() { if i == elseBlock.tail || (i >= ifBlock.head && i <= ifBlock.tail) { - continue // Skip the WasmBeginIf and the if true block. + continue // Skip the WasmBeginIf and the if true block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -565,7 +590,9 @@ struct BlockReducer: Reducer { return false } - private func reduceFunctionOrConstructor(_ function: BlockGroup, with helper: MinimizationHelper) { + private func reduceFunctionOrConstructor( + _ function: BlockGroup, with helper: MinimizationHelper + ) { assert(helper.code[function.head].op is BeginAnySubroutine) assert(helper.code[function.tail].op is EndAnySubroutine) @@ -597,7 +624,11 @@ struct BlockReducer: Reducer { // This avoids the need to find the `eval` call that use the CodeString. // Indices stay valid throughout this reduction. var replacements = [(Int, Instruction)]() - replacements.append((codestring.head, Instruction(LoadString(value: ""), output: helper.code[codestring.head].output))) + replacements.append( + ( + codestring.head, + Instruction(LoadString(value: ""), output: helper.code[codestring.head].output) + )) replacements.append((codestring.tail, Instruction(Nop()))) if helper.tryReplacements(replacements) { // Success! diff --git a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift index 43820e996..c1a4357c4 100644 --- a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift @@ -41,7 +41,7 @@ struct DataFlowSimplifier: Reducer { } // For now, we only consider simple instructions as candidates. - guard instr.isSimple else { continue } + guard instr.isSimple else { continue } // The instruction must have at least one output and one input, // otherwise it wouldn't be an intermediate node. guard instr.numOutputs > 0 else { continue } @@ -54,7 +54,9 @@ struct DataFlowSimplifier: Reducer { } // Remove those candidates whose outputs aren't used. - candidates = candidates.filter({ helper.code[$0].allOutputs.map({ uses[$0]! }).reduce(0, +) > 0 }) + candidates = candidates.filter({ + helper.code[$0].allOutputs.map({ uses[$0]! }).reduce(0, +) > 0 + }) // Filter out Wasm instructions where the types would be invalid if we replaced them. candidates = candidates.filter({ @@ -69,7 +71,9 @@ struct DataFlowSimplifier: Reducer { if operation is WasmOperation { guard operation.numOutputs == 1 else { return false } let outputType = typer.type(of: helper.code[$0].output) - let filteredOutputs = helper.code[$0].inputs.map(typer.type).filter {$0.Is(outputType)} + let filteredOutputs = helper.code[$0].inputs.map(typer.type).filter { + $0.Is(outputType) + } // If we have outputs, we can actually try to replace this. return !filteredOutputs.isEmpty } else { @@ -90,10 +94,13 @@ struct DataFlowSimplifier: Reducer { // if the candidate is a Wasm operation we need to preserve types. if instr.op is WasmOperation { let outputType = typer.type(of: instr.output) - let filteredOutputs = instr.inputs.map(typer.type).enumerated().filter {$0.element.Is(outputType)} + let filteredOutputs = instr.inputs.map(typer.type).enumerated().filter { + $0.element.Is(outputType) + } if !filteredOutputs.isEmpty { // Now pick a random index and choose that input as a replacement. - replacement = instr.inputs[chooseUniform(from: filteredOutputs.map { $0.offset })] + replacement = + instr.inputs[chooseUniform(from: filteredOutputs.map { $0.offset })] } } else { // Pick a random input as replacement. Here we could attempt to be smarter and @@ -125,4 +132,3 @@ struct DataFlowSimplifier: Reducer { } } } - diff --git a/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift b/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift index 2e5746a39..c6ea5a438 100644 --- a/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift +++ b/Sources/Fuzzilli/Minimization/DeduplicatingReducer.swift @@ -36,7 +36,8 @@ struct DeduplicatingReducer: Reducer { let oldInouts = Array(instr.inouts) let newInouts = oldInouts.map({ deduplicatedVariables[$0] ?? $0 }) if oldInouts != newInouts { - replacements.append((instr.index, Instruction(instr.op, inouts: newInouts, flags: instr.flags))) + replacements.append( + (instr.index, Instruction(instr.op, inouts: newInouts, flags: instr.flags))) } // Scope management. @@ -57,7 +58,10 @@ struct DeduplicatingReducer: Reducer { deduplicatedVariables[instr.output] = replacement } else { // Each builtin must only be present once (all other instances are replaced with the first one). - assert(visibleBuiltins.elementsStartingAtBottom().allSatisfy({ !$0.contains(op.variableName) })) + assert( + visibleBuiltins.elementsStartingAtBottom().allSatisfy({ + !$0.contains(op.variableName) + })) visibleBuiltins.top.append(op.variableName) variableForName[op.variableName] = instr.output } diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index dcb039c1f..731478c45 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -44,54 +44,54 @@ struct InliningReducer: Reducer { for instr in code { // Identify candidates. switch instr.op.opcode { - // Currently we only inline plain functions as that guarantees that the resulting code is always valid. - // Otherwise, we might for example attempt to inline an async function containing an 'await', which would not be valid. - // This works fine because the ReplaceReducer will attempt to turn "special" functions into plain functions. + // Currently we only inline plain functions as that guarantees that the resulting code is always valid. + // Otherwise, we might for example attempt to inline an async function containing an 'await', which would not be valid. + // This works fine because the ReplaceReducer will attempt to turn "special" functions into plain functions. case .beginPlainFunction: candidates[instr.output] = (callCount: 0, index: instr.index) fallthrough case .beginArrowFunction, - .beginGeneratorFunction, - .beginAsyncFunction, - .beginAsyncArrowFunction, - .beginAsyncGeneratorFunction, - .beginConstructor, - .beginObjectLiteralMethod, - .beginObjectLiteralComputedMethod, - .beginObjectLiteralGetter, - .beginObjectLiteralComputedGetter, - .beginObjectLiteralSetter, - .beginObjectLiteralComputedSetter, - .beginClassConstructor, - .beginClassMethod, - .beginClassComputedMethod, - .beginClassGetter, - .beginClassComputedGetter, - .beginClassSetter, - .beginClassComputedSetter, - .beginClassStaticInitializer, .beginClassPrivateMethod: + .beginGeneratorFunction, + .beginAsyncFunction, + .beginAsyncArrowFunction, + .beginAsyncGeneratorFunction, + .beginConstructor, + .beginObjectLiteralMethod, + .beginObjectLiteralComputedMethod, + .beginObjectLiteralGetter, + .beginObjectLiteralComputedGetter, + .beginObjectLiteralSetter, + .beginObjectLiteralComputedSetter, + .beginClassConstructor, + .beginClassMethod, + .beginClassComputedMethod, + .beginClassGetter, + .beginClassComputedGetter, + .beginClassSetter, + .beginClassComputedSetter, + .beginClassStaticInitializer, .beginClassPrivateMethod: activeSubroutineDefinitions.append(instr.hasOneOutput ? instr.output : nil) case .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endConstructor, - .endObjectLiteralMethod, - .endObjectLiteralComputedMethod, - .endObjectLiteralGetter, - .endObjectLiteralComputedGetter, - .endObjectLiteralSetter, - .endObjectLiteralComputedSetter, - .endClassConstructor, - .endClassMethod, - .endClassComputedMethod, - .endClassGetter, - .endClassComputedGetter, - .endClassSetter, - .endClassComputedSetter, - .endClassStaticInitializer, .endClassPrivateMethod: + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endConstructor, + .endObjectLiteralMethod, + .endObjectLiteralComputedMethod, + .endObjectLiteralGetter, + .endObjectLiteralComputedGetter, + .endObjectLiteralSetter, + .endObjectLiteralComputedSetter, + .endClassConstructor, + .endClassMethod, + .endClassComputedMethod, + .endClassGetter, + .endClassComputedGetter, + .endClassSetter, + .endClassComputedSetter, + .endClassStaticInitializer, .endClassPrivateMethod: activeSubroutineDefinitions.removeLast() default: assert(!instr.op.contextOpened.contains(.subroutine)) @@ -115,14 +115,14 @@ struct InliningReducer: Reducer { // Can't inline functions that are passed as arguments to other functions. deleteCandidates(instr.inputs.dropFirst()) case .loadDisposableVariable, - .createNamedDisposableVariable, - .loadAsyncDisposableVariable, - .createNamedAsyncDisposableVariable: + .createNamedDisposableVariable, + .loadAsyncDisposableVariable, + .createNamedAsyncDisposableVariable: // Can't inline functions that are also used as a disposable variable. deleteCandidates(instr.inputs) fallthrough case .loadNewTarget, - .loadArguments: + .loadArguments: // Can't inline functions if they access their arguments or new.target. // Or if they create a disposable variable. if let function = activeSubroutineDefinitions.last! { @@ -136,7 +136,7 @@ struct InliningReducer: Reducer { } } - return candidates.values.filter({ $0.callCount == 1}).map({ $0.index }) + return candidates.values.filter({ $0.callCount == 1 }).map({ $0.index }) } /// Returns a new Code object with the specified function inlined into its callsite. diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 858b39003..da9d32ad3 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -30,11 +30,14 @@ struct InstructionSimplifier: Reducer { if begin is BeginPlainFunction { continue } let functionName = (begin as? BeginAnyNamedFunction)?.functionName ?? nil - let newBegin = Instruction(BeginPlainFunction(parameters: begin.parameters, functionName: functionName), inouts: helper.code[group.head].inouts, flags: .empty) + let newBegin = Instruction( + BeginPlainFunction(parameters: begin.parameters, functionName: functionName), + inouts: helper.code[group.head].inouts, flags: .empty) let newEnd = Instruction(EndPlainFunction()) // The resulting code may be invalid as we may be changing the context inside the body (e.g. turning an async function into a plain one). - helper.tryReplacements([(group.head, newBegin), (group.tail, newEnd)], expectCodeToBeValid: false) + helper.tryReplacements( + [(group.head, newBegin), (group.tail, newEnd)], expectCodeToBeValid: false) } } @@ -56,7 +59,9 @@ struct InstructionSimplifier: Reducer { } if let op = newOp { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(op, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(op, inouts: instr.inouts, flags: .empty)) } } } @@ -78,7 +83,9 @@ struct InstructionSimplifier: Reducer { case .constructWithSpread(let op): newOp = Construct(numArguments: op.numArguments, isGuarded: op.isGuarded) case .callMethodWithSpread(let op): - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments, + isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): newOp = CallComputedMethod(numArguments: op.numArguments, isGuarded: op.isGuarded) @@ -91,7 +98,9 @@ struct InstructionSimplifier: Reducer { } if let op = newOp { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(op, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(op, inouts: instr.inouts, flags: .empty)) } } } @@ -103,7 +112,9 @@ struct InstructionSimplifier: Reducer { guard let op = instr.op as? GuardableOperation else { continue } let newOp = GuardableOperation.disableGuard(of: op) if newOp !== op { - helper.tryReplacing(instructionAt: instr.index, with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) + helper.tryReplacing( + instructionAt: instr.index, + with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) } } } @@ -129,10 +140,16 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, propertyName) in op.properties.enumerated() { - newCode.append(Instruction(GetProperty(propertyName: propertyName, isGuarded: false), output: outputs[i], inputs: [instr.input(0)])) + newCode.append( + Instruction( + GetProperty(propertyName: propertyName, isGuarded: false), + output: outputs[i], inputs: [instr.input(0)])) } if op.hasRestElement { - newCode.append(Instruction(DestructObject(properties: [], hasRestElement: true), output: outputs.last!, inputs: [instr.input(0)])) + newCode.append( + Instruction( + DestructObject(properties: [], hasRestElement: true), + output: outputs.last!, inputs: [instr.input(0)])) } keepInstruction = false case .destructArray(let op): @@ -144,9 +161,15 @@ struct InstructionSimplifier: Reducer { let outputs = Array(instr.outputs) for (i, idx) in op.indices.enumerated() { if i == op.indices.count - 1 && op.lastIsRest { - newCode.append(Instruction(DestructArray(indices: [idx], lastIsRest: true), output: outputs.last!, inputs: [instr.input(0)])) + newCode.append( + Instruction( + DestructArray(indices: [idx], lastIsRest: true), + output: outputs.last!, inputs: [instr.input(0)])) } else { - newCode.append(Instruction(GetElement(index: idx, isGuarded: false), output: outputs[i], inputs: [instr.input(0)])) + newCode.append( + Instruction( + GetElement(index: idx, isGuarded: false), output: outputs[i], + inputs: [instr.input(0)])) } } keepInstruction = false diff --git a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index 11169adb2..edf76df0c 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -41,12 +41,15 @@ struct LoopSimplifier: Reducer { case .beginRepeatLoop: tryReduceRepeatLoopIterationCount(group, with: helper) case .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct: + .beginForOfLoop, + .beginForOfLoopWithDestruct: // These loops are (usually) guaranteed to terminate, and should probably anyway not be replaced by repeat-loops. break default: - assert(group.blocks.allSatisfy({ !helper.code[$0.head].op.contextOpened.contains(.loop) })) + assert( + group.blocks.allSatisfy({ + !helper.code[$0.head].op.contextOpened.contains(.loop) + })) } } @@ -54,7 +57,9 @@ struct LoopSimplifier: Reducer { findAndMergeNestedRepeatLoops(with: helper) } - private func tryReplaceForLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceForLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginForLoopInitializer @@ -93,10 +98,14 @@ struct LoopSimplifier: Reducer { let headerIndex = newCode.count let needLoopVariable = beginConditionBlock.numInnerOutputs > 0 let loopVar = needLoopVariable ? beginConditionBlock.innerOutput(0) : nil - newCode.append(Instruction(BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) + newCode.append( + Instruction( + BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), + inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) // Append condition, body, and afterthought code - var replacements = Dictionary(uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) + var replacements = [Variable: Variable]( + uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: conditionBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -104,7 +113,8 @@ struct LoopSimplifier: Reducer { let bodyBlock = group.block(3) assert(helper.code[bodyBlock.head].op is BeginForLoopBody) - replacements = Dictionary(uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) + replacements = [Variable: Variable]( + uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: bodyBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -112,7 +122,10 @@ struct LoopSimplifier: Reducer { let afterthoughtBlock = group.block(2) assert(helper.code[afterthoughtBlock.head].op is BeginForLoopAfterthought) - replacements = Dictionary(uniqueKeysWithValues: helper.code[afterthoughtBlock.head].innerOutputs.map({ ($0, loopVar!) })) + replacements = [Variable: Variable]( + uniqueKeysWithValues: helper.code[afterthoughtBlock.head].innerOutputs.map({ + ($0, loopVar!) + })) for instr in helper.code.body(of: afterthoughtBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) @@ -121,10 +134,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: headerIndex, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: headerIndex, + using: helper) } - private func tryReplaceWhileLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceWhileLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginWhileLoopHeader @@ -161,10 +178,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, + using: helper) } - private func tryReplaceDoWhileLoopWithRepeatLoop(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReplaceDoWhileLoopWithRepeatLoop( + _ group: BlockGroup, with helper: MinimizationHelper + ) { // Turn // // BeginDoWhileLoopBody @@ -201,10 +222,14 @@ struct LoopSimplifier: Reducer { // Append loop footer newCode.append(Instruction(EndRepeatLoop())) - tryReplacingWithShortestPossibleRepeatLoop(range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, using: helper) + tryReplacingWithShortestPossibleRepeatLoop( + range: group.head...group.tail, with: newCode, loopHeaderIndexInNewCode: 0, + using: helper) } - private func tryReduceRepeatLoopIterationCount(_ group: BlockGroup, with helper: MinimizationHelper) { + private func tryReduceRepeatLoopIterationCount( + _ group: BlockGroup, with helper: MinimizationHelper + ) { let originalLoopHeader = helper.code[group.head].op as! BeginRepeatLoop guard originalLoopHeader.iterations > commonLoopIterationCounts[0] else { // Loop already has the minimum number of iterations. @@ -217,27 +242,41 @@ struct LoopSimplifier: Reducer { } let replacement: Instruction if originalLoopHeader.exposesLoopCounter { - replacement = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), inouts: helper.code[group.head].inouts, flags: .empty) + replacement = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), + inouts: helper.code[group.head].inouts, flags: .empty) } else { - replacement = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) + replacement = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) } - if helper.tryReplacing(instructionAt: group.head, with: replacement, numExecutions: numTestExecutions) { + if helper.tryReplacing( + instructionAt: group.head, with: replacement, numExecutions: numTestExecutions) + { return } } } - private func tryReplacingWithShortestPossibleRepeatLoop(range: ClosedRange, with newCode: [Instruction], loopHeaderIndexInNewCode headerIndex: Int, using helper: MinimizationHelper) { + private func tryReplacingWithShortestPossibleRepeatLoop( + range: ClosedRange, with newCode: [Instruction], + loopHeaderIndexInNewCode headerIndex: Int, using helper: MinimizationHelper + ) { var newCode = newCode assert(newCode[headerIndex].op is BeginRepeatLoop) for numIterations in commonLoopIterationCounts { if newCode[headerIndex].numInnerOutputs > 0 { - newCode[headerIndex] = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), inouts: newCode[headerIndex].inouts, flags: .empty) + newCode[headerIndex] = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), + inouts: newCode[headerIndex].inouts, flags: .empty) } else { - newCode[headerIndex] = Instruction(BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) + newCode[headerIndex] = Instruction( + BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) } // After this change, the variable numbers may no longer be sequential as we may have removed instructions with inner outputs. So we need to also renumber the variables. - if helper.tryReplacing(range: range, with: newCode, renumberVariables: true, numExecutions: numTestExecutions) { + if helper.tryReplacing( + range: range, with: newCode, renumberVariables: true, + numExecutions: numTestExecutions) + { return } } @@ -268,7 +307,8 @@ struct LoopSimplifier: Reducer { // // Would. var loops = [Block]() - for group in helper.code.findAllBlockGroups() where helper.code[group.head].op is BeginRepeatLoop { + for group in helper.code.findAllBlockGroups() + where helper.code[group.head].op is BeginRepeatLoop { assert(group.numBlocks == 1) loops.append(group.block(0)) } @@ -276,9 +316,11 @@ struct LoopSimplifier: Reducer { var nestedLoops = [(outerHead: Int, innerHead: Int, innerTail: Int, outerTail: Int)]() for (i, outerLoop) in loops.dropLast().enumerated() { let innerLoop = loops[i + 1] - let instructionsBeforeInnerLoop = helper.code[helper.code.index(after: outerLoop.head).. Bool { + func testAndCommit( + _ newCode: Code, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions, allowRemoving: Instruction.Flags = .empty + ) -> Bool { assert(!self.finalized) assert(numExecutions > 0) assert(!expectCodeToBeValid || newCode.isStaticallyValid()) @@ -144,7 +150,9 @@ class MinimizationHelper { var stillHasAspects = false performOnFuzzerQueue { for _ in 0.. Bool { + func tryReplacing( + instructionAt index: Int, with newInstr: Instruction, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var newCode = self.code assert(newCode[index].allOutputs == newInstr.allOutputs) newCode[index] = newInstr - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } @discardableResult - func tryInserting(_ newInstr: Instruction, at index: Int, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions) -> Bool { + func tryInserting( + _ newInstr: Instruction, at index: Int, expectCodeToBeValid: Bool = true, + numExecutions: Int = defaultNumExecutions + ) -> Bool { // Right now we don't expect to see any flags here on the new instruction. assert(newInstr.flags.isEmpty) @@ -187,18 +203,28 @@ class MinimizationHelper { newCode.append(instr) } - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions) } /// Remove the instruction at the given index if it does not negatively influence the programs previous behaviour. @discardableResult - func tryNopping(instructionAt index: Int, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { - return tryReplacing(instructionAt: index, with: nop(for: code[index]), expectCodeToBeValid: false, numExecutions: numExecutions, allowRemoving: flags) + func tryNopping( + instructionAt index: Int, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { + return tryReplacing( + instructionAt: index, with: nop(for: code[index]), expectCodeToBeValid: false, + numExecutions: numExecutions, allowRemoving: flags) } /// Attempt multiple replacements at once. @discardableResult - func tryReplacements(_ replacements: [(Int, Instruction)], renumberVariables: Bool = false, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryReplacements( + _ replacements: [(Int, Instruction)], renumberVariables: Bool = false, + expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var newCode = self.code for (index, newInstr) in replacements { @@ -210,11 +236,17 @@ class MinimizationHelper { } assert(newCode.variablesAreNumberedContinuously()) - return testAndCommit(newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return testAndCommit( + newCode, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } @discardableResult - func tryReplacing(range: ClosedRange, with newCode: [Instruction], renumberVariables: Bool = false, expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryReplacing( + range: ClosedRange, with newCode: [Instruction], renumberVariables: Bool = false, + expectCodeToBeValid: Bool = true, numExecutions: Int = defaultNumExecutions, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { assert(range.count >= newCode.count) var replacements = [(Int, Instruction)]() @@ -230,12 +262,18 @@ class MinimizationHelper { replacements.append((indexOfInstructionToReplace, replacement)) } - return tryReplacements(replacements, renumberVariables: renumberVariables, expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, allowRemoving: flags) + return tryReplacements( + replacements, renumberVariables: renumberVariables, + expectCodeToBeValid: expectCodeToBeValid, numExecutions: numExecutions, + allowRemoving: flags) } /// Attempt the removal of multiple instructions at once. @discardableResult - func tryNopping(_ indices: [Int], expectCodeToBeValid: Bool = false, allowRemoving flags: Instruction.Flags = .empty) -> Bool { + func tryNopping( + _ indices: [Int], expectCodeToBeValid: Bool = false, + allowRemoving flags: Instruction.Flags = .empty + ) -> Bool { var replacements = [(Int, Instruction)]() for index in indices { replacements.append((index, nop(for: code[index]))) @@ -246,7 +284,9 @@ class MinimizationHelper { /// Create a Nop instruction for replacing the given instruction with. func nop(for instr: Instruction) -> Instruction { // We must preserve outputs here to keep variable number contiguous. - return Instruction(Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, flags: .empty) + return Instruction( + Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, + flags: .empty) } } diff --git a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift index 6254e0971..45180278c 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift @@ -38,39 +38,58 @@ struct MinimizationPostProcessor { var replacementInstruction: Instruction? = nil switch instr.op.opcode { case .endPlainFunction, - .endArrowFunction, - .endGeneratorFunction, - .endAsyncFunction, - .endAsyncArrowFunction, - .endAsyncGeneratorFunction, - .endObjectLiteralMethod, - .endObjectLiteralGetter: + .endArrowFunction, + .endGeneratorFunction, + .endAsyncFunction, + .endAsyncArrowFunction, + .endAsyncGeneratorFunction, + .endObjectLiteralMethod, + .endObjectLiteralGetter: // Insert return statements at the end of functions, but only if there is not one already. if lastInstr.op is Return || !b.hasVisibleJsVariables { break } - addedInstruction = Instruction(Return(hasReturnValue: true), inputs: [b.randomJsVariable()]) + addedInstruction = Instruction( + Return(hasReturnValue: true), inputs: [b.randomJsVariable()]) case .callFunction(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } let args = b.randomArguments(forCalling: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(CallFunction(numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + CallFunction(numArguments: args.count, isGuarded: op.isGuarded), + output: instr.output, inputs: [instr.input(0)] + args) case .callMethod(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } - let args = b.randomArguments(forCallingMethod: op.methodName, on: instr.input(0)) + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } + let args = b.randomArguments( + forCallingMethod: op.methodName, on: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(CallMethod(methodName: op.methodName, numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + CallMethod( + methodName: op.methodName, numArguments: args.count, + isGuarded: op.isGuarded), output: instr.output, + inputs: [instr.input(0)] + args) case .construct(let op): // (Sometimes) insert random arguments, but only if there are none currently. - if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { break } + if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables || probability(0.5) { + break + } let args = b.randomArguments(forCalling: instr.input(0)) guard args.count > 0 else { break } - replacementInstruction = Instruction(Construct(numArguments: args.count, isGuarded: op.isGuarded), output: instr.output, inputs: [instr.input(0)] + args) + replacementInstruction = Instruction( + Construct(numArguments: args.count, isGuarded: op.isGuarded), + output: instr.output, inputs: [instr.input(0)] + args) case .createArray: // Add initial values, but only if there are none currently. if instr.hasAnyVariadicInputs || !b.hasVisibleJsVariables { break } - let initialValues = Array(repeating: b.randomJsVariable(), count: Int.random(in: 1...5)) - replacementInstruction = Instruction(CreateArray(numInitialValues: initialValues.count), output: instr.output, inputs: initialValues) + let initialValues = [Variable]( + repeating: b.randomJsVariable(), count: Int.random(in: 1...5)) + replacementInstruction = Instruction( + CreateArray(numInitialValues: initialValues.count), output: instr.output, + inputs: initialValues) default: assert(!(instr.op is EndAnyFunction)) break @@ -98,8 +117,11 @@ struct MinimizationPostProcessor { // Step 2: Try to apply each change from step 1 on its own and verify that the change doesn't alter the program's behaviour. for change in changes { // Either we're adding a new instruction (in which case we're replacing a nop inserted in step 1), or changing the number of inputs of an existing instruction. - assert((helper.code[change.index].op is Nop && !(change.newInstruction.op is Nop)) || - (helper.code[change.index].op.name == change.newInstruction.op.name && helper.code[change.index].numInputs < change.newInstruction.numInputs)) + assert( + (helper.code[change.index].op is Nop && !(change.newInstruction.op is Nop)) + || (helper.code[change.index].op.name == change.newInstruction.op.name + && helper.code[change.index].numInputs < change.newInstruction.numInputs) + ) helper.tryReplacing(instructionAt: change.index, with: change.newInstruction) } diff --git a/Sources/Fuzzilli/Minimization/Minimizer.swift b/Sources/Fuzzilli/Minimization/Minimizer.swift index 2b59ce1b5..6bdf91ce4 100644 --- a/Sources/Fuzzilli/Minimization/Minimizer.swift +++ b/Sources/Fuzzilli/Minimization/Minimizer.swift @@ -42,16 +42,23 @@ public class Minimizer: ComponentBase { /// /// Minimization will not modify the given program. Instead, it produce a new Program instance. /// Once minimization is finished, the passed block will be invoked on the fuzzer's queue with the minimized program. - func withMinimizedCopy(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double = 0.0, block: @escaping (Program) -> ()) { + func withMinimizedCopy( + _ program: Program, withAspects aspects: ProgramAspects, + limit minimizationLimit: Double = 0.0, block: @escaping (Program) -> Void + ) { minimizationQueue.async { - let minimizedCode = self.internalMinimize(program, withAspects: aspects, limit: minimizationLimit, performPostprocessing: true, runningSynchronously: false) + let minimizedCode = self.internalMinimize( + program, withAspects: aspects, limit: minimizationLimit, + performPostprocessing: true, runningSynchronously: false) self.fuzzer.async { let minimizedProgram: Program if self.fuzzer.config.enableInspection { - minimizedProgram = Program(code: minimizedCode, parent: program, contributors: program.contributors) + minimizedProgram = Program( + code: minimizedCode, parent: program, contributors: program.contributors) minimizedProgram.comments.add("Minimizing \(program.id)", at: .header) } else { - minimizedProgram = Program(code: minimizedCode, contributors: program.contributors) + minimizedProgram = Program( + code: minimizedCode, contributors: program.contributors) } block(minimizedProgram) } @@ -59,15 +66,25 @@ public class Minimizer: ComponentBase { } /// Synchronous version of withMinimizedCopy. Should only be used for tests since it otherwise blocks the fuzzer queue. - func minimize(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double = 0.0, performPostprocessing: Bool = true) -> Program { - let minimizedCode = internalMinimize(program, withAspects: aspects, limit: minimizationLimit, performPostprocessing: performPostprocessing, runningSynchronously: true) + func minimize( + _ program: Program, withAspects aspects: ProgramAspects, + limit minimizationLimit: Double = 0.0, performPostprocessing: Bool = true + ) -> Program { + let minimizedCode = internalMinimize( + program, withAspects: aspects, limit: minimizationLimit, + performPostprocessing: performPostprocessing, runningSynchronously: true) return Program(code: minimizedCode, parent: program, contributors: program.contributors) } - private func internalMinimize(_ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double, performPostprocessing: Bool, runningSynchronously: Bool) -> Code { + private func internalMinimize( + _ program: Program, withAspects aspects: ProgramAspects, limit minimizationLimit: Double, + performPostprocessing: Bool, runningSynchronously: Bool + ) -> Code { assert(program.code.countIntructionsWith(flags: .notRemovable) == 0) - let helper = MinimizationHelper(for: aspects, forCode: program.code, of: fuzzer, runningOnFuzzerQueue: runningSynchronously) + let helper = MinimizationHelper( + for: aspects, forCode: program.code, of: fuzzer, + runningOnFuzzerQueue: runningSynchronously) helper.applyMinimizationLimit(limit: minimizationLimit) @@ -91,20 +108,24 @@ public class Minimizer: ComponentBase { DataFlowSimplifier(), VariadicInputReducer(), DeduplicatingReducer(), - WasmTypeGroupReducer() + WasmTypeGroupReducer(), ] for reducer in reducers { reducer.reduce(with: helper) // The reducers should not remove any instructions that we want to keep unconditionally. // The code might have more non-removable instructions due to other analyzers marking them as non-removable // but it should be at least more than we have seen at the start. - assert(helper.code.countIntructionsWith(flags: .notRemovable) >= helper.numKeptInstructions) + assert( + helper.code.countIntructionsWith(flags: .notRemovable) + >= helper.numKeptInstructions) assert(helper.code.isStaticallyValid()) } iterations += 1 guard iterations < 100 else { // This can happen if a reducer performs a no-op change in every iteration, e.g. replacing one instruction with the same instruction. This is considered a bug since it leads to this kind of issue. - logger.error("Fixpoint iteration for program minimization did not converge after 100 iterations for program:\n\(FuzzILLifter().lift(helper.code)). Aborting minimization.") + logger.error( + "Fixpoint iteration for program minimization did not converge after 100 iterations for program:\n\(FuzzILLifter().lift(helper.code)). Aborting minimization." + ) break } } while helper.didReduce diff --git a/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift b/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift index f641216ea..8b33138ab 100644 --- a/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift +++ b/Sources/Fuzzilli/Minimization/VariadicInputReducer.swift @@ -37,7 +37,9 @@ struct VariadicInputReducer: Reducer { if op.numArguments == 1 { newOp = CallFunction(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallFunctionWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallFunctionWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .construct(let op): newOp = Construct(numArguments: op.numArguments - 1, isGuarded: op.isGuarded) @@ -45,30 +47,42 @@ struct VariadicInputReducer: Reducer { if op.numArguments == 1 { newOp = Construct(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = ConstructWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = ConstructWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .callMethod(let op): - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments - 1, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments - 1, + isGuarded: op.isGuarded) case .callMethodWithSpread(let op): if op.numArguments == 1 { - newOp = CallMethod(methodName: op.methodName, numArguments: 0, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments - 1, + spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) } case .callComputedMethod(let op): - newOp = CallComputedMethod(numArguments: op.numArguments - 1, isGuarded: op.isGuarded) + newOp = CallComputedMethod( + numArguments: op.numArguments - 1, isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): if op.numArguments == 1 { newOp = CallComputedMethod(numArguments: 0, isGuarded: op.isGuarded) } else { - newOp = CallComputedMethodWithSpread(numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), isGuarded: op.isGuarded) + newOp = CallComputedMethodWithSpread( + numArguments: op.numArguments - 1, spreads: op.spreads.dropLast(), + isGuarded: op.isGuarded) } case .callSuperConstructor(let op): newOp = CallSuperConstructor(numArguments: op.numArguments - 1) case .callPrivateMethod(let op): - newOp = CallPrivateMethod(methodName: op.methodName, numArguments: op.numArguments - 1) + newOp = CallPrivateMethod( + methodName: op.methodName, numArguments: op.numArguments - 1) case .callSuperMethod(let op): - newOp = CallSuperMethod(methodName: op.methodName, numArguments: op.numArguments - 1) + newOp = CallSuperMethod( + methodName: op.methodName, numArguments: op.numArguments - 1) case .bindFunction(let op): newOp = BindFunction(numInputs: op.numInputs - 1) case .createTemplateString(let op): diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index df6c149db..76b991b43 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -22,7 +22,6 @@ struct WasmTypeGroupReducer: Reducer { uses[input]? += 1 } - guard instr.op is WasmTypeOperation else { continue } // Define the usages for all WasmTypeOperation so that we also count usages of a type // inside a type group (i.e. by other type operations). @@ -31,7 +30,7 @@ struct WasmTypeGroupReducer: Reducer { } // For now, we only consider EndTypeGroup instructions. - guard case .wasmEndTypeGroup = instr.op.opcode else { continue } + guard case .wasmEndTypeGroup = instr.op.opcode else { continue } candidates.append(instr.index) for (input, output) in zip(instr.inputs, instr.outputs) { @@ -44,7 +43,9 @@ struct WasmTypeGroupReducer: Reducer { } // Remove those candidates whose outputs are all used. - candidates = candidates.filter {helper.code[$0].allOutputs.map({ uses[$0]! }).contains {$0 == 0}} + candidates = candidates.filter { + helper.code[$0].allOutputs.map({ uses[$0]! }).contains { $0 == 0 } + } if candidates.isEmpty { return @@ -56,9 +57,10 @@ struct WasmTypeGroupReducer: Reducer { let instr = helper.code[candidate] assert(instr.op is WasmEndTypeGroup) assert(instr.inputs.count == instr.outputs.count) - let newInoutsMap = zip(instr.inputs, instr.outputs).filter {uses[$0.1]! > 0} - let newInouts = newInoutsMap.map {$0.0} + newInoutsMap.map {$0.1} - let newInstr = Instruction(WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) + let newInoutsMap = zip(instr.inputs, instr.outputs).filter { uses[$0.1]! > 0 } + let newInouts = newInoutsMap.map { $0.0 } + newInoutsMap.map { $0.1 } + let newInstr = Instruction( + WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) replacements.append((candidate, newInstr)) } helper.tryReplacements(replacements, renumberVariables: true) diff --git a/Sources/Fuzzilli/Modules/NetworkSync.swift b/Sources/Fuzzilli/Modules/NetworkSync.swift index 807a11e21..49045cb04 100644 --- a/Sources/Fuzzilli/Modules/NetworkSync.swift +++ b/Sources/Fuzzilli/Modules/NetworkSync.swift @@ -14,6 +14,7 @@ import Foundation import libsocket + // Explicitly import `Foundation.UUID` to avoid the conflict with `WinSDK.UUID` import struct Foundation.UUID @@ -34,11 +35,11 @@ import struct Foundation.UUID // | 4 byte little endian | 4 byte little endian | length - 8 bytes | | // +----------------------+----------------------+------------------+-----------+ -fileprivate let messageHeaderSize = 8 -fileprivate let maxMessageSize = 1024 * 1024 * 1024 +private let messageHeaderSize = 8 +private let maxMessageSize = 1024 * 1024 * 1024 /// Protocol for an object capable of receiving messages. -fileprivate protocol MessageHandler { +private protocol MessageHandler { func handleMessage(_ payload: Data, ofType type: MessageType, from connection: Connection) func handleError(_ err: String, on connection: Connection) // The fuzzer instance on which to schedule the handler calls @@ -46,7 +47,7 @@ fileprivate protocol MessageHandler { } /// A connection to a network peer that speaks the above protocol. -fileprivate class Connection { +private class Connection { /// The file descriptor on POSIX or SOCKET handle on Windows of the socket. let socket: libsocket.libsocket_t @@ -73,7 +74,7 @@ fileprivate class Connection { private var currentMessageData = Data() /// Buffer to receive incoming data into. Must only be accessed on this connection's dispatch queue. - private var receiveBuffer = UnsafeMutableBufferPointer.allocate(capacity: 1024*1024) + private var receiveBuffer = UnsafeMutableBufferPointer.allocate(capacity: 1024 * 1024) /// Pending outgoing data. Must only be accessed on this connection's dispatch queue. private var sendQueue: [Data] = [] @@ -86,11 +87,13 @@ fileprivate class Connection { guard performHandshake() else { return nil } -#if os(Windows) - self.readSource = DispatchSource.makeReadSource(handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) -#else - self.readSource = DispatchSource.makeReadSource(fileDescriptor: socket, queue: self.queue) -#endif + #if os(Windows) + self.readSource = DispatchSource.makeReadSource( + handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) + #else + self.readSource = DispatchSource.makeReadSource( + fileDescriptor: socket, queue: self.queue) + #endif self.readSource?.setEventHandler { [weak self] in self?.handleDataAvailable() } @@ -119,7 +122,8 @@ fileprivate class Connection { // Send our id. let message = localId.uuidData let rv = message.withUnsafeBytes { data in - return libsocket.socket_send(socket, data.bindMemory(to: UInt8.self).baseAddress, message.count) + return libsocket.socket_send( + socket, data.bindMemory(to: UInt8.self).baseAddress, message.count) } guard rv == message.count else { return false } @@ -202,7 +206,8 @@ fileprivate class Connection { let startIndex = chunk.startIndex let rv = chunk.withUnsafeBytes { content -> Int in - return libsocket.socket_send(socket, content.bindMemory(to: UInt8.self).baseAddress, length) + return libsocket.socket_send( + socket, content.bindMemory(to: UInt8.self).baseAddress, length) } if rv < 0 { @@ -227,11 +232,13 @@ fileprivate class Connection { writeSource = nil } else if writeSource == nil { // Otherwise ensure we have an active write source to notify us when the next chunk can be sent -#if os(Windows) - writeSource = DispatchSource.makeWriteSource(handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) -#else - writeSource = DispatchSource.makeWriteSource(fileDescriptor: socket, queue: self.queue) -#endif + #if os(Windows) + writeSource = DispatchSource.makeWriteSource( + handle: HANDLE(bitPattern: UInt(socket))!, queue: self.queue) + #else + writeSource = DispatchSource.makeWriteSource( + fileDescriptor: socket, queue: self.queue) + #endif writeSource?.setEventHandler { [weak self] in self?.sendPendingData() } @@ -279,7 +286,8 @@ fileprivate class Connection { let message = Data(currentMessageData.prefix(length)) // Explicitely make a copy of the data here so the discarded data is also freed from memory - currentMessageData = currentMessageData.subdata(in: totalMessageLength..= 1.0 else { - return // This can happen due to delays in queue processing + return // This can happen due to delays in queue processing } let execsPerSecond = self.currentExecs / interval @@ -217,17 +217,25 @@ public class Statistics: Module { fuzzer.timers.scheduleTask(every: 15 * Minutes) { self.logger.info("Mutator Statistics:") let nameMaxLength = fuzzer.mutators.map({ $0.name.count }).max()! - let maxSamplesGeneratedStringLength = fuzzer.mutators.map({ String($0.totalSamples).count }).max()! + let maxSamplesGeneratedStringLength = fuzzer.mutators.map({ + String($0.totalSamples).count + }).max()! for mutator in fuzzer.mutators { let name = mutator.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Self.percentageOrNa(mutator.correctnessRate, 7) let failureRate = Self.percentageOrNa(mutator.failureRate, 7) let timeoutRate = Self.percentageOrNa(mutator.timeoutRate, 6) - let interestingSamplesRate = Self.percentageOrNa(mutator.interestingSamplesRate, 7) - let avgInstructionsAdded = String(format: "%.2f", mutator.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) - let samplesGenerated = String(mutator.totalSamples).leftPadded(toLength: maxSamplesGeneratedStringLength) + let interestingSamplesRate = Self.percentageOrNa( + mutator.interestingSamplesRate, 7) + let avgInstructionsAdded = String( + format: "%.2f", mutator.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) + let samplesGenerated = String(mutator.totalSamples).leftPadded( + toLength: maxSamplesGeneratedStringLength) let crashesFound = mutator.crashesFound - self.logger.info(" \(name) : Correctness rate: \(correctnessRate), Failure rate: \(failureRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated), Total # of crashes found: \(crashesFound)") + self.logger.info( + " \(name) : Correctness rate: \(correctnessRate), Failure rate: \(failureRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated), Total # of crashes found: \(crashesFound)" + ) } } @@ -241,12 +249,18 @@ public class Statistics: Module { for stub in generator.parts { let name = stub.name.rightPadded(toLength: nameMaxLength) let correctnessRate = Self.percentageOrNa(stub.correctnessRate, 7) - let interestingSamplesRate = Self.percentageOrNa(stub.interestingSamplesRate, 7) + let interestingSamplesRate = Self.percentageOrNa( + stub.interestingSamplesRate, 7) let timeoutRate = Self.percentageOrNa(stub.timeoutRate, 6) - let avgInstructionsAdded = String(format: "%.2f", stub.avgNumberOfInstructionsGenerated).leftPadded(toLength: 5) - let invocationSuccessRate = Self.percentageOrNa(stub.invocationSuccessRate, 6) + let avgInstructionsAdded = String( + format: "%.2f", stub.avgNumberOfInstructionsGenerated + ).leftPadded(toLength: 5) + let invocationSuccessRate = Self.percentageOrNa( + stub.invocationSuccessRate, 6) let samplesGenerated = stub.totalSamples - self.logger.verbose(" \(name) : Invocation Success: \(invocationSuccessRate), Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)") + self.logger.verbose( + " \(name) : Invocation Success: \(invocationSuccessRate), Correctness rate: \(correctnessRate), Interesting sample rate: \(interestingSamplesRate), Timeout rate: \(timeoutRate), Avg. # of instructions added: \(avgInstructionsAdded), Total # of generated samples: \(samplesGenerated)" + ) } } } diff --git a/Sources/Fuzzilli/Modules/Storage.swift b/Sources/Fuzzilli/Modules/Storage.swift index 72c5ad49f..9d3d08afa 100644 --- a/Sources/Fuzzilli/Modules/Storage.swift +++ b/Sources/Fuzzilli/Modules/Storage.swift @@ -56,22 +56,34 @@ public class Storage: Module { public func initialize(with fuzzer: Fuzzer) { do { - try FileManager.default.createDirectory(atPath: crashesDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: duplicateCrashesDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: differentialsDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: corpusDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: statisticsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: crashesDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: duplicateCrashesDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: differentialsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: corpusDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: statisticsDir, withIntermediateDirectories: true) if fuzzer.config.enableDiagnostics { - try FileManager.default.createDirectory(atPath: failedDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: timeOutDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: diagnosticsDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: failedDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: timeOutDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: diagnosticsDir, withIntermediateDirectories: true) } if fuzzer.isDifferentialFuzzing { - try FileManager.default.createDirectory(atPath: optimizedDumpDir, withIntermediateDirectories: true) - try FileManager.default.createDirectory(atPath: unoptimizedDumpDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: optimizedDumpDir, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + atPath: unoptimizedDumpDir, withIntermediateDirectories: true) } } catch { - logger.fatal("Failed to create storage directories. Is \(storageDir) writable by the current user?") + logger.fatal( + "Failed to create storage directories. Is \(storageDir) writable by the current user?" + ) } struct Settings: Codable { @@ -80,7 +92,8 @@ public class Storage: Module { } // Write the current settings to disk. - let settings = Settings(processArguments: Array(fuzzer.runner.processArguments[1...]), tag: fuzzer.config.tag) + let settings = Settings( + processArguments: Array(fuzzer.runner.processArguments[1...]), tag: fuzzer.config.tag) var settingsData: Data? do { let encoder = JSONEncoder() @@ -94,7 +107,8 @@ public class Storage: Module { let settingsUrl = URL(fileURLWithPath: "\(self.storageDir)/settings.json") try settingsData!.write(to: settingsUrl) } catch { - logger.fatal("Failed to write settings to disk. Is \(storageDir) writable by the current user?") + logger.fatal( + "Failed to write settings to disk. Is \(storageDir) writable by the current user?") } fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in @@ -140,7 +154,9 @@ public class Storage: Module { logger.fatal("Requested stats export but no Statistics module is active") } fuzzer.timers.scheduleTask(every: interval) { self.saveStatistics(stats) } - fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in self.saveStatistics(stats) } + fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in + self.saveStatistics(stats) + } } } @@ -209,7 +225,8 @@ public class Storage: Module { let date = formatDate() let statsUrl = URL(fileURLWithPath: "\(self.statisticsDir)/\(date).json") try statsData.write(to: statsUrl) - let evaluatorStateUrl = URL(fileURLWithPath: "\(self.statisticsDir)/\(date)_evaluator_state.bin") + let evaluatorStateUrl = URL( + fileURLWithPath: "\(self.statisticsDir)/\(date)_evaluator_state.bin") try evaluatorStateData.write(to: evaluatorStateUrl) } catch { diff --git a/Sources/Fuzzilli/Modules/Sync.swift b/Sources/Fuzzilli/Modules/Sync.swift index f09db6bd1..d21b68d8c 100644 --- a/Sources/Fuzzilli/Modules/Sync.swift +++ b/Sources/Fuzzilli/Modules/Sync.swift @@ -59,30 +59,30 @@ import Foundation /// The different messages supported by the distributed fuzzing protocol. enum MessageType: UInt32 { // Informs the other side that the sender is terminating. - case shutdown = 0 + case shutdown = 0 // A synchronization packet sent by a parent to a newly connected child. // Contains the exported state of the parent so the child can // synchronize itself with that. - case sync = 1 + case sync = 1 // A program from a corpus import. Send from parents to children. // Children are expected to add this program to their corpus // even if it does not trigger new coverage and without minimization. - case importedProgram = 2 + case importedProgram = 2 // A program that triggered interesting behaviour and which should // therefore be imported by the receiver. - case interestingProgram = 3 + case interestingProgram = 3 // A program that caused a crash. Only sent from a children to their parent. - case crashingProgram = 4 + case crashingProgram = 4 // A statistics package send by a child to a parent node. - case statistics = 5 + case statistics = 5 // Log messages are forwarded from child to parent nides. - case log = 6 + case log = 6 } /// Distributed fuzzing nodes can be configured to only share their corpus in one direction in the tree. @@ -161,7 +161,9 @@ public class DistributedFuzzingNode { // If the wasm enablement is different, we can't safely import the corpus. let parentState = fuzzer.config.isWasmEnabled ? "enabled" : "disabled" let selfState = state.isWasmEnabled ? "enabled" : "disabled" - throw FuzzilliError.corpusImportError("Inconsistent state between distributed nodes: The parent has wasm \(parentState) while the current fuzzer has wasm \(selfState)!") + throw FuzzilliError.corpusImportError( + "Inconsistent state between distributed nodes: The parent has wasm \(parentState) while the current fuzzer has wasm \(selfState)!" + ) } try fuzzer.corpus.importState(state.corpus) @@ -191,7 +193,10 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { /// List of all child nodes connected to us. They are identified by their UUID. private var children = Set() - init(for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, transport: DistributedFuzzingParentNodeTransport) { + init( + for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, + transport: DistributedFuzzingParentNodeTransport + ) { self.transport = transport super.init(for: fuzzer, name: name, corpusSynchronizationMode: corpusSynchronizationMode) transport.setOnMessageCallback(onMessageReceived) @@ -205,7 +210,8 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { fuzzer.registerEventListener(for: fuzzer.events.Shutdown) { _ in let shutdownGroup = DispatchGroup() for child in self.children { - self.transport.send(.shutdown, to: child, contents: Data(), synchronizeWith: shutdownGroup) + self.transport.send( + .shutdown, to: child, contents: Data(), synchronizeWith: shutdownGroup) } // Attempt to make sure that the shutdown messages have been sent before continuing. let _ = shutdownGroup.wait(timeout: .now() + .seconds(5)) @@ -254,7 +260,9 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { case .interestingProgram: guard shouldAcceptCorpusSamplesFromChildren() else { - logger.warning("Received corpus sample from child node but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message.") + logger.warning( + "Received corpus sample from child node but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message." + ) return } @@ -277,15 +285,19 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { case .log: if let proto = try? Fuzzilli_Protobuf_LogMessage(serializedBytes: data), - let origin = UUID(uuidString: proto.origin), - let level = LogLevel(rawValue: Int(clamping: proto.level)) { - fuzzer.dispatchEvent(fuzzer.events.Log, data: (origin: origin, level: level, label: proto.label, message: proto.content)) + let origin = UUID(uuidString: proto.origin), + let level = LogLevel(rawValue: Int(clamping: proto.level)) + { + fuzzer.dispatchEvent( + fuzzer.events.Log, + data: (origin: origin, level: level, label: proto.label, message: proto.content) + ) } else { logger.warning("Received malformed log message from child node") } case .importedProgram, - .sync: + .sync: logger.error("Received unexpected message: \(messageType)") } @@ -316,7 +328,9 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { } let (state, duration) = measureTime { exportState() } - logger.info("Encoding fuzzer state took \((String(format: "%.2f", duration)))s. Data size: \(ByteCountFormatter.string(fromByteCount: Int64(state.count), countStyle: .memory))") + logger.info( + "Encoding fuzzer state took \((String(format: "%.2f", duration)))s. Data size: \(ByteCountFormatter.string(fromByteCount: Int64(state.count), countStyle: .memory))" + ) transport.send(.sync, to: child, contents: state) } @@ -333,14 +347,15 @@ public class DistributedFuzzingParentNode: DistributedFuzzingNode, Module { protocol DistributedFuzzingParentNodeTransport { func initialize() func send(_ messageType: MessageType, to child: UUID, contents: Data) - func send(_ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith: DispatchGroup) + func send( + _ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith: DispatchGroup) func disconnect(_ child: UUID) - typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data, _ child: UUID) -> () + typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data, _ child: UUID) -> Void func setOnMessageCallback(_ callback: @escaping OnMessageCallback) - typealias OnChildConnectedCallback = (_ child: UUID) -> () + typealias OnChildConnectedCallback = (_ child: UUID) -> Void func setOnChildConnectedCallback(_ callback: @escaping OnChildConnectedCallback) - typealias OnChildDisconnectedCallback = (_ child: UUID) -> () + typealias OnChildDisconnectedCallback = (_ child: UUID) -> Void func setOnChildDisconnectedCallback(_ callback: @escaping OnChildDisconnectedCallback) } @@ -353,7 +368,10 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { private let transport: DistributedFuzzingChildNodeTransport private var parentIsShuttingDown = false - init(for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, transport: DistributedFuzzingChildNodeTransport) { + init( + for fuzzer: Fuzzer, name: String, corpusSynchronizationMode: CorpusSynchronizationMode, + transport: DistributedFuzzingChildNodeTransport + ) { self.transport = transport super.init(for: fuzzer, name: name, corpusSynchronizationMode: corpusSynchronizationMode) transport.setOnMessageCallback(onMessageReceived) @@ -427,14 +445,18 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { guard shouldAcceptCorpusSamplesFromParent() else { return } guard !data.isEmpty else { - return logger.warning("Received empty synchronization message. Is the parent node configured to synchronize its corpus with its children?") + return logger.warning( + "Received empty synchronization message. Is the parent node configured to synchronize its corpus with its children?" + ) } guard fuzzer.state == .waiting else { // While child nodes will remain in the .waiting state until we've received a sync message, this can // still legitimately happen, for example if we imported our own corpus, or if we've lost the connection // to our parent node and are reconnecting to it. - return logger.info("Not synchronizing our state with that of our parent as we already have a corpus") + return logger.info( + "Not synchronizing our state with that of our parent as we already have a corpus" + ) } let start = Date() @@ -444,12 +466,16 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { logger.error("Failed to synchronize state: \(error)") } let end = Date() - logger.info("Synchronized with parent node (took \((String(format: "%.2f", end.timeIntervalSince(start))))s). Corpus now contains \(fuzzer.corpus.size) programs") + logger.info( + "Synchronized with parent node (took \((String(format: "%.2f", end.timeIntervalSince(start))))s). Corpus now contains \(fuzzer.corpus.size) programs" + ) case .importedProgram, - .interestingProgram: + .interestingProgram: guard shouldAcceptCorpusSamplesFromParent() else { - return logger.warning("Received corpus sample but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message.") + return logger.warning( + "Received corpus sample but not configured to accept them (corpus synchronization mode is \(corpusSynchronizationMode)). Ignoring message." + ) } do { @@ -460,7 +486,8 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { // Regardless of the corpus import mode used by the parent node, as a child node we // always add the program to our corpus without further checks or minimization as // that will, if necessary, already have been performed by our parent node. - fuzzer.importProgram(program, origin: .corpusImport(mode: .full), enableDropout: true) + fuzzer.importProgram( + program, origin: .corpusImport(mode: .full), enableDropout: true) } else { assert(messageType == .interestingProgram) fuzzer.importProgram(program, origin: .parent, enableDropout: true) @@ -470,8 +497,8 @@ public class DistributedFuzzingChildNode: DistributedFuzzingNode, Module { } case .crashingProgram, - .statistics, - .log: + .statistics, + .log: logger.error("Received unexpected message: \(messageType)") } } @@ -508,6 +535,6 @@ protocol DistributedFuzzingChildNodeTransport { func send(_ messageType: MessageType, contents: Data) func send(_ messageType: MessageType, contents: Data, synchronizeWith: DispatchGroup) - typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data) -> () + typealias OnMessageCallback = (_ messageType: MessageType, _ data: Data) -> Void func setOnMessageCallback(_ callback: @escaping OnMessageCallback) } diff --git a/Sources/Fuzzilli/Modules/ThreadSync.swift b/Sources/Fuzzilli/Modules/ThreadSync.swift index fd2c226d4..f77fb967b 100644 --- a/Sources/Fuzzilli/Modules/ThreadSync.swift +++ b/Sources/Fuzzilli/Modules/ThreadSync.swift @@ -23,7 +23,9 @@ public class ThreadParent: DistributedFuzzingParentNode { public init(for fuzzer: Fuzzer) { self.transport = Transport(for: fuzzer) - super.init(for: fuzzer, name: "ThreadParent", corpusSynchronizationMode: .full, transport: transport) + super.init( + for: fuzzer, name: "ThreadParent", corpusSynchronizationMode: .full, + transport: transport) } fileprivate class Transport: DistributedFuzzingParentNodeTransport { @@ -70,12 +72,17 @@ public class ThreadParent: DistributedFuzzingParentNode { fatalError("Unknown child node \(child)") } client.async { - guard let module = ThreadChild.instance(for: client) else { fatalError("No active ThreadChild module on client instance") } + guard let module = ThreadChild.instance(for: client) else { + fatalError("No active ThreadChild module on client instance") + } module.transport.onMessageCallback?(messageType, contents) } } - func send(_ messageType: MessageType, to child: UUID, contents: Data, synchronizeWith synchronizationGroup: DispatchGroup) { + func send( + _ messageType: MessageType, to child: UUID, contents: Data, + synchronizeWith synchronizationGroup: DispatchGroup + ) { send(messageType, to: child, contents: contents) } @@ -106,7 +113,9 @@ public class ThreadChild: DistributedFuzzingChildNode { public init(for fuzzer: Fuzzer, parent: Fuzzer) { self.transport = Transport(child: fuzzer, parent: parent) - super.init(for: fuzzer, name: "ThreadChild", corpusSynchronizationMode: .full, transport: transport) + super.init( + for: fuzzer, name: "ThreadChild", corpusSynchronizationMode: .full, transport: transport + ) } fileprivate class Transport: DistributedFuzzingChildNodeTransport { diff --git a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift index 4ad73bccb..4cd2d2543 100644 --- a/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift +++ b/Sources/Fuzzilli/Mutators/BaseInstructionMutator.swift @@ -21,7 +21,9 @@ public class BaseInstructionMutator: Mutator { super.init(name: name) } - override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { beginMutation(of: program) var candidates = [Int]() @@ -40,7 +42,7 @@ public class BaseInstructionMutator: Mutator { toMutate.insert(chooseUniform(from: candidates)) } - b.adopting() { + b.adopting { for instr in program.code { if toMutate.contains(instr.index) { mutate(instr, b) @@ -68,4 +70,3 @@ public class BaseInstructionMutator: Mutator { fatalError("This method must be overridden") } } - diff --git a/Sources/Fuzzilli/Mutators/CodeGenMutator.swift b/Sources/Fuzzilli/Mutators/CodeGenMutator.swift index 0536540f3..4326e4fa3 100644 --- a/Sources/Fuzzilli/Mutators/CodeGenMutator.swift +++ b/Sources/Fuzzilli/Mutators/CodeGenMutator.swift @@ -36,11 +36,14 @@ public class CodeGenMutator: BaseInstructionMutator { // Don't CodeGen on Type definition instructions, with this line they are not available as candidates which effectively compresses the program and avoids useless CodeGeneration. // (As any emitted type would not be an input to the EndTypeGroup instruction). - if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) || (instr.op is WasmBeginTypeGroup) { + if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) + || (instr.op is WasmBeginTypeGroup) + { return false } - return variableAnalyzer.visibleVariables.count >= minVisibleVariables && !deadCodeAnalyzer.currentlyInDeadCode + return variableAnalyzer.visibleVariables.count >= minVisibleVariables + && !deadCodeAnalyzer.currentlyInDeadCode } public override func mutate(_ instr: Instruction, _ b: ProgramBuilder) { diff --git a/Sources/Fuzzilli/Mutators/ConcatMutator.swift b/Sources/Fuzzilli/Mutators/ConcatMutator.swift index 00a8f6fb9..0958eb38d 100644 --- a/Sources/Fuzzilli/Mutators/ConcatMutator.swift +++ b/Sources/Fuzzilli/Mutators/ConcatMutator.swift @@ -14,7 +14,9 @@ /// A mutator that concatenates two programs together. public class ConcatMutator: Mutator { - override func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { let suffix = b.fuzzer.corpus.randomElementForSplicing() b.append(program) diff --git a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift index 24e6a9551..048ed446e 100644 --- a/Sources/Fuzzilli/Mutators/ExplorationMutator.swift +++ b/Sources/Fuzzilli/Mutators/ExplorationMutator.swift @@ -83,7 +83,8 @@ public class ExplorationMutator: RuntimeAssistedMutator { let numUntypedVariablesToExplore = Int((Double(untypedVariables.count) * 0.5).rounded(.up)) // TODO probably we only rarely want to explore known variables (e.g. only 10% of them or even fewer). But currently, the JSTyper and JavaScriptEnvironment still often set the type to something like .object() or so, which isn't very useful (it's basically a "unknownObject" type). We should maybe stop doing that... let numTypedVariablesToExplore = Int((Double(typedVariables.count) * 0.25).rounded(.up)) - let untypedVariablesToExplore = untypedVariables.shuffled().prefix(numUntypedVariablesToExplore) + let untypedVariablesToExplore = untypedVariables.shuffled().prefix( + numUntypedVariablesToExplore) let typedVariablesToExplore = typedVariables.shuffled().prefix(numTypedVariablesToExplore) let variablesToExplore = VariableSet(untypedVariablesToExplore + typedVariablesToExplore) guard !variablesToExplore.isEmpty else { @@ -106,7 +107,7 @@ public class ExplorationMutator: RuntimeAssistedMutator { // For that reason, we keep a stack of variables that still need to be explored. A variable in that stack is explored // when its entry is popped from the stack, which happens when the block end instruction is emitted. var pendingExploreStack = Stack() - b.adopting() { + b.adopting { for instr in program.code { b.adopt(instr) @@ -145,7 +146,10 @@ public class ExplorationMutator: RuntimeAssistedMutator { return instrumentedProgram } - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { // Initialize the actions dictionary that will contain the processed results. // This way, we can detect if something went wrong on the JS side: if we get results for IDs // for which there is no Explore operation, then there's probably a bug in the JS code. @@ -205,20 +209,25 @@ public class ExplorationMutator: RuntimeAssistedMutator { } // Now build the real program by replacing every Explore operation with the operation(s) that it actually performed at runtime. - b.adopting() { + b.adopting { for instr in instrumentedProgram.code { if let op = instr.op as? Explore { if let entry = actions[op.id], let action = entry { if verbose { actionUsageCounts[action.operation]! += 1 } let exploredValue = b.adopt(instr.input(0)) let args = instr.inputs.suffix(from: 1).map(b.adopt) - guard case .special(let name) = action.inputs.first, name == "exploredValue" else { - logger.error("Unexpected first input, expected the explored value, got \(String(describing: action.inputs.first)) for operation \(action.operation)") + guard case .special(let name) = action.inputs.first, name == "exploredValue" + else { + logger.error( + "Unexpected first input, expected the explored value, got \(String(describing: action.inputs.first)) for operation \(action.operation)" + ) continue } b.trace("Exploring value \(exploredValue)") do { - let context = (arguments: args, specialValues: ["exploredValue": exploredValue]) + let context = ( + arguments: args, specialValues: ["exploredValue": exploredValue] + ) try action.translateToFuzzIL(withContext: context, using: b) } catch ActionError.actionTranslationError(let msg) { logger.error("Failed to process action: \(msg)") @@ -238,12 +247,16 @@ public class ExplorationMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average number of inserted explore operations: \(String(format: "%.2f", averageNumberOfInsertedExploreOps.currentValue))") + logger.verbose( + "Average number of inserted explore operations: \(String(format: "%.2f", averageNumberOfInsertedExploreOps.currentValue))" + ) let totalHandlerInvocations = actionUsageCounts.values.reduce(0, +) logger.verbose("Frequencies of generated operations:") for (op, count) in actionUsageCounts { let frequency = (Double(count) / Double(totalHandlerInvocations)) * 100.0 - logger.verbose(" \(op.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f", frequency))%") + logger.verbose( + " \(op.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f", frequency))%" + ) } } } diff --git a/Sources/Fuzzilli/Mutators/FixupMutator.swift b/Sources/Fuzzilli/Mutators/FixupMutator.swift index fc9865bed..42da2a1f2 100644 --- a/Sources/Fuzzilli/Mutators/FixupMutator.swift +++ b/Sources/Fuzzilli/Mutators/FixupMutator.swift @@ -64,10 +64,20 @@ public class FixupMutator: RuntimeAssistedMutator { // Helper functions to emit the Fixup operations. var numInstrumentedInstructions = 0 let actionEncoder = JSONEncoder() - func fixup(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func fixup( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { assert(instr.numOutputs == 0 || instr.numOutputs == 1) assert(instr.numInnerOutputs == 0) - assert(inputs.allSatisfy({ if case .argument(let index) = $0 { return index < instr.numInputs } else { return true }})) + assert( + inputs.allSatisfy({ + if case .argument(let index) = $0 { + return index < instr.numInputs + } else { + return true + } + })) numInstrumentedInstructions += 1 @@ -75,19 +85,26 @@ public class FixupMutator: RuntimeAssistedMutator { let action = Action(id: id, operation: op, inputs: inputs, isGuarded: guarded) let encodedData = try! actionEncoder.encode(action) let encodedAction = String(data: encodedData, encoding: .utf8)! - let maybeOutput = b.fixup(id: id, action: encodedAction, originalOperation: instr.op.name, arguments: Array(instr.inputs), hasOutput: instr.hasOneOutput) + let maybeOutput = b.fixup( + id: id, action: encodedAction, originalOperation: instr.op.name, + arguments: Array(instr.inputs), hasOutput: instr.hasOneOutput) // The fixup instruction must create the same output variable, as that may be used by subsequent code. assert(!instr.hasOutputs || instr.output == maybeOutput) if verbose { - instrumentedOperations[instr.op.name] = (instrumentedOperations[instr.op.name] ?? 0) + 1 + instrumentedOperations[instr.op.name] = + (instrumentedOperations[instr.op.name] ?? 0) + 1 if instr.isGuarded { - instrumentedGuardedOperations[instr.op.name] = (instrumentedGuardedOperations[instr.op.name] ?? 0) + 1 + instrumentedGuardedOperations[instr.op.name] = + (instrumentedGuardedOperations[instr.op.name] ?? 0) + 1 } } } - func maybeFixup(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func maybeFixup( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { // Only instrument some percentage of unguarded instructions but do still instrument all guarded instructions (to attempt to remove the guards). if !guarded { if !probability(probabilityOfFixingUnguardedInstruction) { @@ -99,7 +116,10 @@ public class FixupMutator: RuntimeAssistedMutator { fixup(instr, performing: op, guarded: guarded, withInputs: inputs, with: b) } - func fixupIfGuarded(_ instr: Instruction, performing op: ActionOperation, guarded: Bool, withInputs inputs: [Action.Input], with b: ProgramBuilder) { + func fixupIfGuarded( + _ instr: Instruction, performing op: ActionOperation, guarded: Bool, + withInputs inputs: [Action.Input], with b: ProgramBuilder + ) { guard guarded else { b.append(instr) return @@ -116,55 +136,80 @@ public class FixupMutator: RuntimeAssistedMutator { // exception would be raised. case .callFunction(let op): let inputs = (0.. (Program?, RuntimeAssistedMutator.Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, RuntimeAssistedMutator.Outcome) { // For each Fixup operation (identified by its Id), this dict contains the (potentially modified) action that was performed by it. var actions = [String: Action]() @@ -191,7 +239,10 @@ public class FixupMutator: RuntimeAssistedMutator { // Populate the actions map with the original actions. This way, we can verify that the received (updated) actions all belong to a Fixup operation. for instr in instrumentedProgram.code { if let op = instr.op as? Fixup { - guard let originalAction = try? actionDecoder.decode(Action.self, from: op.action.data(using: .utf8)!) else { + guard + let originalAction = try? actionDecoder.decode( + Action.self, from: op.action.data(using: .utf8)!) + else { logger.error("Failed to decode original action \"\(op.action)\"") return (nil, .unexpectedError) } @@ -233,7 +284,9 @@ public class FixupMutator: RuntimeAssistedMutator { } seenFailures.insert(id) // We could also drop this action or replace it with a different one, but for now, simply add the guard back if we observe a failure. - actions[id] = Action(id: action.id, operation: action.operation, inputs: action.inputs, isGuarded: true) + actions[id] = Action( + id: action.id, operation: action.operation, inputs: action.inputs, + isGuarded: true) } else if line.hasPrefix(actionMarker) { let payload = Data(line.dropFirst(actionMarker.count).utf8) guard let action = try? actionDecoder.decode(Action.self, from: payload) else { @@ -283,9 +336,10 @@ public class FixupMutator: RuntimeAssistedMutator { let args = Array(instr.inputs) b.trace("Fixing next instruction") do { - try action.translateToFuzzIL(withContext: (arguments: args, specialValues: [:]), using: b) + try action.translateToFuzzIL( + withContext: (arguments: args, specialValues: [:]), using: b) assert(!op.hasOutput || b.visibleVariables.last == instr.output) - assert(op.originalOperation == b.lastInstruction().op.name) // We expect the old and new operations to be the same (but potentially performed on different inputs) + assert(op.originalOperation == b.lastInstruction().op.name) // We expect the old and new operations to be the same (but potentially performed on different inputs) } catch ActionError.actionTranslationError(let msg) { // In case of an error we won't have emitted an instruction. As such, we need // to abort the mutation here (unfortunately), as we might now have an @@ -302,7 +356,8 @@ public class FixupMutator: RuntimeAssistedMutator { } b.trace("Fixup done") if verbose && modifiedActions.contains(action.id) { - modifiedOperations[op.originalOperation] = (modifiedOperations[op.originalOperation] ?? 0) + 1 + modifiedOperations[op.originalOperation] = + (modifiedOperations[op.originalOperation] ?? 0) + 1 } } else { b.append(instr) @@ -314,13 +369,19 @@ public class FixupMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average success rate (percentage of removed guards) during recent mutations: \(String(format: "%.2f", averageSuccesRate.currentValue * 100))%") - logger.verbose("Average percentage of instrumented instructions: \(String(format: "%.2f", averageInstrumentationRatio.currentValue * 100))%") + logger.verbose( + "Average success rate (percentage of removed guards) during recent mutations: \(String(format: "%.2f", averageSuccesRate.currentValue * 100))%" + ) + logger.verbose( + "Average percentage of instrumented instructions: \(String(format: "%.2f", averageInstrumentationRatio.currentValue * 100))%" + ) logger.verbose("Per-operation statistics:") for (opName, count) in instrumentedOperations { let guardedRatio = Double(instrumentedGuardedOperations[opName] ?? 0) / Double(count) let modificationRate = Double(modifiedOperations[opName] ?? 0) / Double(count) - logger.verbose(" \(opName.rightPadded(toLength: 30)): instrumented \(count) times (of which \(String(format: "%.2f", guardedRatio * 100))% were guarded), modification rate: \(String(format: "%.2f", modificationRate * 100))%") + logger.verbose( + " \(opName.rightPadded(toLength: 30)): instrumented \(count) times (of which \(String(format: "%.2f", guardedRatio * 100))% were guarded), modification rate: \(String(format: "%.2f", modificationRate * 100))%" + ) } } } diff --git a/Sources/Fuzzilli/Mutators/InputMutator.swift b/Sources/Fuzzilli/Mutators/InputMutator.swift index 7f03a9ffc..01c214a89 100644 --- a/Sources/Fuzzilli/Mutators/InputMutator.swift +++ b/Sources/Fuzzilli/Mutators/InputMutator.swift @@ -34,11 +34,13 @@ public class InputMutator: BaseInstructionMutator { // the mutator correctness rates, it can very roughly be twice as aggressive. switch self.typeAwareness { case .aware: - maxSimultaneousMutations *= 2 + maxSimultaneousMutations *= 2 default: break } - super.init(name: "InputMutator (\(String(describing: self.typeAwareness)))", maxSimultaneousMutations: maxSimultaneousMutations) + super.init( + name: "InputMutator (\(String(describing: self.typeAwareness)))", + maxSimultaneousMutations: maxSimultaneousMutations) } public override func canMutate(_ instr: Instruction) -> Bool { @@ -62,14 +64,15 @@ public class InputMutator: BaseInstructionMutator { let replacement: Variable? // In wasm we need strict typing, so there is no notion of loose or aware. - if b.context.contains(.wasm) || - b.context.contains(.wasmFunction) || - b.context.contains(.wasmTypeGroup) { + if b.context.contains(.wasm) || b.context.contains(.wasmFunction) + || b.context.contains(.wasmTypeGroup) + { let type = b.type(of: inouts[selectedInput]) // TODO(mliedtke): For type definitions we need a lot of consistency. E.g. the signature // flowing into the block begin operation and the block end operation need to be in // sync. - replacement = type.Is(.wasmTypeDef()) ? inouts[selectedInput] : b.randomVariable(ofType: type) + replacement = + type.Is(.wasmTypeDef()) ? inouts[selectedInput] : b.randomVariable(ofType: type) } else { switch self.typeAwareness { case .loose: @@ -81,7 +84,8 @@ public class InputMutator: BaseInstructionMutator { } if let replacement = replacement { - b.trace("Replacing input \(selectedInput) (\(inouts[selectedInput])) with \(replacement)") + b.trace( + "Replacing input \(selectedInput) (\(inouts[selectedInput])) with \(replacement)") inouts[selectedInput] = replacement // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. diff --git a/Sources/Fuzzilli/Mutators/MutatorSettings.swift b/Sources/Fuzzilli/Mutators/MutatorSettings.swift index f080de7d8..b08983493 100644 --- a/Sources/Fuzzilli/Mutators/MutatorSettings.swift +++ b/Sources/Fuzzilli/Mutators/MutatorSettings.swift @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. - // The settings here strive to achieve a correctness rate of around 75%. Empirically, this appears to be roughly optimal: // higher than that, and samples are too similar to each other, lower than that, and too many samples are invalid. // TODO evaluate this independently for every mutator. let defaultMaxSimultaneousMutations = 7 let defaultMaxSimultaneousCodeGenerations = 3 -let defaultCodeGenerationAmount = 5 // This must be at least ProgramBuilder.minBudgetForRecursiveCodeGeneration +let defaultCodeGenerationAmount = 5 // This must be at least ProgramBuilder.minBudgetForRecursiveCodeGeneration diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 4d7903629..c7614ff25 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -30,7 +30,8 @@ public class OperationMutator: BaseInstructionMutator { let newInstr: Instruction if instr.isOperationMutable && instr.isVariadic { - newInstr = probability(0.5) ? mutateOperation(instr, b) : extendVariadicOperation(instr, b) + newInstr = + probability(0.5) ? mutateOperation(instr, b) : extendVariadicOperation(instr, b) } else if instr.isOperationMutable { newInstr = mutateOperation(instr, b) } else { @@ -55,19 +56,24 @@ public class OperationMutator: BaseInstructionMutator { // Half the time we want to just hit the regular path if Bool.random() { if let type = b.fuzzer.environment.getEnum(ofName: customName) { - newOp = LoadString(value: chooseUniform(from: type.enumValues), customName: customName) + newOp = LoadString( + value: chooseUniform(from: type.enumValues), customName: customName) break - } else if let gen = b.fuzzer.environment.getNamedStringGenerator(ofName: customName) { + } else if let gen = b.fuzzer.environment.getNamedStringGenerator( + ofName: customName) + { newOp = LoadString(value: gen(), customName: customName) break } } } - let charSetAlNum = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + let charSetAlNum = Array( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") // TODO(mliedtke): Should we also use some more esoteric characters in initial string // creation, e.g. ProgramBuilder.randomString? - let charSetExtended = charSetAlNum + Array("-_.,!?<>()[]{}`´^\\/|+#*=;:'~^²\t°ß¿ 🤯🙌🏿\u{202D}") - let randomIndex = {(s: String) in + let charSetExtended = + charSetAlNum + Array("-_.,!?<>()[]{}`´^\\/|+#*=;:'~^²\t°ß¿ 🤯🙌🏿\u{202D}") + let randomIndex = { (s: String) in s.index(s.startIndex, offsetBy: Int.random(in: 0.. Instruction { + private func extendVariadicOperationByOneInput(_ instr: Instruction, _ b: ProgramBuilder) + -> Instruction + { // Without visible variables, we can't add a new input to this instruction. // This should happen rarely, so just skip this mutation. guard b.hasVisibleVariables else { return instr } @@ -777,28 +873,35 @@ public class OperationMutator: BaseInstructionMutator { case .callFunctionWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallFunctionWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallFunctionWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .construct(let op): inputs.append(b.randomJsVariable()) newOp = Construct(numArguments: op.numArguments + 1, isGuarded: op.isGuarded) case .constructWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = ConstructWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = ConstructWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .callMethod(let op): inputs.append(b.randomJsVariable()) - newOp = CallMethod(methodName: op.methodName, numArguments: op.numArguments + 1, isGuarded: op.isGuarded) + newOp = CallMethod( + methodName: op.methodName, numArguments: op.numArguments + 1, + isGuarded: op.isGuarded) case .callMethodWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallMethodWithSpread(methodName: op.methodName, numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallMethodWithSpread( + methodName: op.methodName, numArguments: op.numArguments + 1, spreads: spreads, + isGuarded: op.isGuarded) case .callComputedMethod(let op): inputs.append(b.randomJsVariable()) newOp = CallComputedMethod(numArguments: op.numArguments + 1, isGuarded: op.isGuarded) case .callComputedMethodWithSpread(let op): let spreads = op.spreads + [Bool.random()] inputs.append(b.randomJsVariable()) - newOp = CallComputedMethodWithSpread(numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) + newOp = CallComputedMethodWithSpread( + numArguments: op.numArguments + 1, spreads: spreads, isGuarded: op.isGuarded) case .callSuperConstructor(let op): inputs.append(b.randomJsVariable()) newOp = CallSuperConstructor(numArguments: op.numArguments + 1) @@ -834,7 +937,9 @@ public class OperationMutator: BaseInstructionMutator { return Instruction(newOp, inouts: inouts, flags: .empty) } - private func replaceRandomElement(in elements: inout Array, generatingRandomValuesWith generator: () -> T) { + private func replaceRandomElement( + in elements: inout [T], generatingRandomValuesWith generator: () -> T + ) { // Pick a random index to replace. guard let index = elements.indices.randomElement() else { return } diff --git a/Sources/Fuzzilli/Mutators/ProbingMutator.swift b/Sources/Fuzzilli/Mutators/ProbingMutator.swift index de3aaba09..f7c29f2ed 100644 --- a/Sources/Fuzzilli/Mutators/ProbingMutator.swift +++ b/Sources/Fuzzilli/Mutators/ProbingMutator.swift @@ -75,7 +75,7 @@ public class ProbingMutator: RuntimeAssistedMutator { // the block that they are the output of is closed. var pendingProbesStack = Stack() let b = fuzzer.makeBuilder() - b.adopting() { + b.adopting { for instr in program.code { b.adopt(instr) @@ -106,7 +106,10 @@ public class ProbingMutator: RuntimeAssistedMutator { return instrumentedProgram } - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, RuntimeAssistedMutator.Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, RuntimeAssistedMutator.Outcome) { assert(instrumentedProgram.code.contains(where: { $0.op is Probe })) // Parse the output: look for either "PROBING_ERROR" or "PROBING_RESULTS" and process the content. @@ -130,7 +133,8 @@ public class ProbingMutator: RuntimeAssistedMutator { let decoder = JSONDecoder() let payload = Data(line.dropFirst(resultsMarker.count).utf8) - guard let decodedResults = try? decoder.decode([String: Result].self, from: payload) else { + guard let decodedResults = try? decoder.decode([String: Result].self, from: payload) + else { logger.error("Failed to decode JSON payload in \"\(line)\"") return (nil, .unexpectedError) } @@ -143,7 +147,7 @@ public class ProbingMutator: RuntimeAssistedMutator { // Now build the final program by parsing the results and replacing the Probe operations // with FuzzIL operations that install one of the non-existent properties (if any). - b.adopting() { + b.adopting { for instr in instrumentedProgram.code { if let op = instr.op as? Probe { if let results = results[op.id] { @@ -162,10 +166,13 @@ public class ProbingMutator: RuntimeAssistedMutator { } override func logAdditionalStatistics() { - logger.verbose("Average number of inserted probes: \(String(format: "%.2f", averageNumberOfInsertedProbes.currentValue))") - logger.verbose("Properties installed during recent mutations (in total: \(installedPropertyCounter)):") + logger.verbose( + "Average number of inserted probes: \(String(format: "%.2f", averageNumberOfInsertedProbes.currentValue))" + ) + logger.verbose( + "Properties installed during recent mutations (in total: \(installedPropertyCounter)):") var statsAsList = installedPropertiesForGetAccess.map({ (key: $0, count: $1, op: "get") }) - statsAsList += installedPropertiesForSetAccess.map({ (key: $0, count: $1, op: "set") }) + statsAsList += installedPropertiesForSetAccess.map({ (key: $0, count: $1, op: "set") }) for (key, count, op) in statsAsList.sorted(by: { $0.count > $1.count }) { let type = isCallableProperty(key) ? "function" : "anything" logger.verbose(" \(count)x \(key.description) (access: \(op), type: \(type))") @@ -178,7 +185,10 @@ public class ProbingMutator: RuntimeAssistedMutator { private func processProbeResults(_ result: Result, on obj: Variable, using b: ProgramBuilder) { // Extract all candidates: properties that are accessed but not present (or explicitly marked as overwritable). - let loadCandidates = result.loads.filter({ $0.value == .notFound || ($0.value == .found && propertiesOnPrototypeToOverwrite.contains($0.key)) }).map({ $0.key }) + let loadCandidates = result.loads.filter({ + $0.value == .notFound + || ($0.value == .found && propertiesOnPrototypeToOverwrite.contains($0.key)) + }).map({ $0.key }) // For stores we only care about properties that don't exist anywhere on the prototype chain. let storeCandidates = result.stores.filter({ $0.value == .notFound }).map({ $0.key }) let candidates = Set(loadCandidates).union(storeCandidates) @@ -194,20 +204,26 @@ public class ProbingMutator: RuntimeAssistedMutator { if probability(0.8) { installRegularProperty(property, on: obj, using: b) } else { - installPropertyAccessor(for: property, on: obj, using: b, shouldHaveGetter: propertyIsLoaded, shouldHaveSetter: propertyIsStored) + installPropertyAccessor( + for: property, on: obj, using: b, shouldHaveGetter: propertyIsLoaded, + shouldHaveSetter: propertyIsStored) } // Update our statistics. if verbose && propertyIsLoaded { - installedPropertiesForGetAccess[property] = (installedPropertiesForGetAccess[property] ?? 0) + 1 + installedPropertiesForGetAccess[property] = + (installedPropertiesForGetAccess[property] ?? 0) + 1 } if verbose && propertyIsStored { - installedPropertiesForSetAccess[property] = (installedPropertiesForSetAccess[property] ?? 0) + 1 + installedPropertiesForSetAccess[property] = + (installedPropertiesForSetAccess[property] ?? 0) + 1 } installedPropertyCounter += 1 } - private func installRegularProperty(_ property: Property, on obj: Variable, using b: ProgramBuilder) { + private func installRegularProperty( + _ property: Property, on obj: Variable, using b: ProgramBuilder + ) { let value = selectValue(for: property, using: b) switch property { @@ -222,7 +238,10 @@ public class ProbingMutator: RuntimeAssistedMutator { } } - private func installPropertyAccessor(for property: Property, on obj: Variable, using b: ProgramBuilder, shouldHaveGetter: Bool, shouldHaveSetter: Bool) { + private func installPropertyAccessor( + for property: Property, on obj: Variable, using b: ProgramBuilder, shouldHaveGetter: Bool, + shouldHaveSetter: Bool + ) { assert(shouldHaveGetter || shouldHaveSetter) let installAsValue = probability(0.5) let installGetter = !installAsValue && (shouldHaveGetter || probability(0.5)) @@ -262,7 +281,8 @@ public class ProbingMutator: RuntimeAssistedMutator { case .symbol(let desc): let Symbol = b.createNamedVariable(forBuiltin: "Symbol") let symbol = b.getProperty(extractSymbolNameFromDescription(desc), of: Symbol) - b.configureComputedProperty(symbol, of: obj, usingFlags: PropertyFlags.random(), as: config) + b.configureComputedProperty( + symbol, of: obj, usingFlags: PropertyFlags.random(), as: config) } } @@ -277,8 +297,12 @@ public class ProbingMutator: RuntimeAssistedMutator { } private func isCallableProperty(_ property: Property) -> Bool { - let knownFunctionPropertyNames = ["valueOf", "toString", "constructor", "then", "next", "get", "set"] - let knownNonFunctionSymbolNames = ["Symbol.isConcatSpreadable", "Symbol.unscopables", "Symbol.toStringTag"] + let knownFunctionPropertyNames = [ + "valueOf", "toString", "constructor", "then", "next", "get", "set", + ] + let knownNonFunctionSymbolNames = [ + "Symbol.isConcatSpreadable", "Symbol.unscopables", "Symbol.toStringTag", + ] // Check if the property should be a function. switch property { @@ -295,11 +319,13 @@ public class ProbingMutator: RuntimeAssistedMutator { if isCallableProperty(property) { // Either create a new function or reuse an existing one let probabilityOfReusingExistingFunction = 2.0 / 3.0 - if let f = b.randomVariable(ofType: .function()), probability(probabilityOfReusingExistingFunction) { + if let f = b.randomVariable(ofType: .function()), + probability(probabilityOfReusingExistingFunction) + { return f } else { let f = b.buildPlainFunction(with: .parameters(n: Int.random(in: 0..<3))) { args in - b.build(n: 2) // TODO maybe forbid generating any nested blocks here? + b.build(n: 2) // TODO maybe forbid generating any nested blocks here? b.doReturn(b.randomJsVariable()) } return f diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 4e43be6e0..89845ff39 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -60,13 +60,18 @@ public class RuntimeAssistedMutator: Mutator { } // Process the runtime output of the instrumented program and build the final program from that. - func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { fatalError("Must be overwritten by child classes") } // Helper function for use by child classes. This detects known types of runtime errors that are expected to some degree (e.g. stack exhaustion or OOM). func isKnownRuntimeError(_ message: Substring) -> Bool { - let ignoredErrors = ["maximum call stack size exceeded", "out of memory", "too much recursion"] + let ignoredErrors = [ + "maximum call stack size exceeded", "out of memory", "too much recursion", + ] for error in ignoredErrors { if message.lowercased().contains(error) { return true @@ -80,7 +85,9 @@ public class RuntimeAssistedMutator: Mutator { // May be overwritten by child classes } - override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) + -> Program? + { // Build the instrumented program. guard let instrumentedProgram = instrument(program, for: fuzzer) else { return failure(.cannotInstrument) @@ -90,7 +97,9 @@ public class RuntimeAssistedMutator: Mutator { assert(instrumentedProgram.code.contains(where: { $0.op is JsInternalOperation })) // Execute the instrumented program (with a higher timeout) and collect the output. - let execution = fuzzer.execute(instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, purpose: .runtimeAssistedMutation) + let execution = fuzzer.execute( + instrumentedProgram, withTimeout: fuzzer.config.timeout * 4, + purpose: .runtimeAssistedMutation) // We need to cache these because they're invalidated the next time we call execute(). let oldStdout = execution.stdout let oldStderr = execution.stderr @@ -118,20 +127,30 @@ public class RuntimeAssistedMutator: Mutator { let stdout = oldFuzzout + "\n" + oldStdout // We log the crash here in case something goes wrong. - let crashInfoText = fuzzer.collectCrashInfo(for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, withExectime: execution.execTime) - logger.error("Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))") + let crashInfoText = fuzzer.collectCrashInfo( + for: program, withSignal: signal, withStderr: oldStderr, withStdout: oldStdout, + withExectime: execution.execTime) + logger.error( + "Instrumented program crashed: \(fuzzer.lifter.lift(program))\n\(crashInfoText.joined(separator: "\n"))" + ) // Check if the process()'d program also crashes. If yes, we report that crash instead. // This allows to use Fuzzilli's input minimization, which wouldn't work for the instrumented program. - let (mutatedProgram, outcome) = process(execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (mutatedProgram, outcome) = process( + execution.fuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) if let mutatedProgram { assert(outcome == .success) - let execution = fuzzer.execute(mutatedProgram, withTimeout: fuzzer.config.timeout , purpose: .runtimeAssistedMutation) + let execution = fuzzer.execute( + mutatedProgram, withTimeout: fuzzer.config.timeout, + purpose: .runtimeAssistedMutation) if case .crashed(let signal) = execution.outcome { - logger.warning("Mutated program crashed as well, reporting mutated program instead") + logger.warning( + "Mutated program crashed as well, reporting mutated program instead") let stdout = execution.fuzzout + "\n" + execution.stdout - fuzzer.processCrash(mutatedProgram, withSignal: signal, withStderr: execution.stderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + fuzzer.processCrash( + mutatedProgram, withSignal: signal, withStderr: execution.stderr, + withStdout: stdout, origin: .local, withExectime: execution.execTime) return failure(.instrumentedProgramCrashed) } } @@ -141,26 +160,35 @@ public class RuntimeAssistedMutator: Mutator { // We need this because instrumentation adds boilerplate JS code. let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) var maybeProgramToMinimize: Program? = nil - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".js") - if let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]), - let parser = JavaScriptParser(executor: nodejs) { - do { - try instrumentedJavaScriptProgram.write(to: tempFile, atomically: true, encoding: .utf8) - let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") - } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") - } - try? FileManager.default.removeItem(at: tempFile) + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( + UUID().uuidString + ".js") + if let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]), + let parser = JavaScriptParser(executor: nodejs) + { + do { + try instrumentedJavaScriptProgram.write( + to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") } - else { - logger.warning("Unable to compile instrumented JS program to FuzzIL because node.js is not available") - } - + try? FileManager.default.removeItem(at: tempFile) + } else { + logger.warning( + "Unable to compile instrumented JS program to FuzzIL because node.js is not available" + ) + } - logger.warning("Mutated program did not crash, reporting original crash of the instrumented program") - fuzzer.processCrash(maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) + logger.warning( + "Mutated program did not crash, reporting original crash of the instrumented program" + ) + fuzzer.processCrash( + maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, + withStderr: oldStderr, withStdout: stdout, origin: .local, + withExectime: execution.execTime) case .succeeded: // The expected case. break @@ -169,7 +197,8 @@ public class RuntimeAssistedMutator: Mutator { } // Process the output to build the mutated program. - let (maybeMutatedProgram, outcome) = process(oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) + let (maybeMutatedProgram, outcome) = process( + oldFuzzout, ofInstrumentedProgram: instrumentedProgram, using: b) guard let mutatedProgram = maybeMutatedProgram else { assert(outcome != .success) return failure(outcome) @@ -184,7 +213,9 @@ public class RuntimeAssistedMutator: Mutator { for outcome in Outcome.allCases { let count = outcomeCounts[outcome]! let frequency = (Double(count) / Double(totalOutcomes)) * 100.0 - logger.verbose(" \(outcome.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f%%", frequency))") + logger.verbose( + " \(outcome.rawValue.rightPadded(toLength: 30)): \(String(format: "%.2f%%", frequency))" + ) } logAdditionalStatistics() @@ -282,11 +313,15 @@ public class RuntimeAssistedMutator: Mutator { } extension RuntimeAssistedMutator.Action.Input { - func translateToFuzzIL(withContext context: (arguments: [Variable], specialValues: [String: Variable]), using b: ProgramBuilder) throws -> Variable { + func translateToFuzzIL( + withContext context: (arguments: [Variable], specialValues: [String: Variable]), + using b: ProgramBuilder + ) throws -> Variable { switch self { case .argument(let index): guard context.arguments.indices.contains(index) else { - throw RuntimeAssistedMutator.ActionError.actionTranslationError("Invalid argument index: \(index), have \(context.arguments.count) arguments") + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Invalid argument index: \(index), have \(context.arguments.count) arguments") } return context.arguments[index] case .int(let value): @@ -295,7 +330,8 @@ extension RuntimeAssistedMutator.Action.Input { return b.loadFloat(value) case .bigint(let value): guard value.allSatisfy({ $0.isNumber || $0 == "-" }) else { - throw RuntimeAssistedMutator.ActionError.actionTranslationError("Malformed bigint value: \(value)") + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Malformed bigint value: \(value)") } if let intValue = Int64(value) { return b.loadBigInt(intValue) @@ -308,17 +344,26 @@ extension RuntimeAssistedMutator.Action.Input { case .string(let value): return b.loadString(value) case .special(let name): - guard let v = context.specialValues[name] else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Unknown special input value \(name)") } + guard let v = context.specialValues[name] else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Unknown special input value \(name)") + } return v } } } extension RuntimeAssistedMutator.Action { - func translateToFuzzIL(withContext context: (arguments: [Variable], specialValues: [String: Variable]), using b: ProgramBuilder) throws { + func translateToFuzzIL( + withContext context: (arguments: [Variable], specialValues: [String: Variable]), + using b: ProgramBuilder + ) throws { // Helper function to fetch an input of this Action. func getInput(_ i: Int) throws -> Input { - guard inputs.indices.contains(i) else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Missing input \(i) for operation \(operation)") } + guard inputs.indices.contains(i) else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Missing input \(i) for operation \(operation)") + } return inputs[i] } // Helper function to fetch an input of this Action and translate it to a FuzzIL variable. @@ -327,7 +372,10 @@ extension RuntimeAssistedMutator.Action { } // Helper function to translate a range of inputs of this Action into FuzzIL variables. func translateInputs(_ r: PartialRangeFrom) throws -> [Variable] { - guard inputs.indices.upperBound >= r.lowerBound else { throw RuntimeAssistedMutator.ActionError.actionTranslationError("Missing inputs in range \(r) for operation \(operation)") } + guard inputs.indices.upperBound >= r.lowerBound else { + throw RuntimeAssistedMutator.ActionError.actionTranslationError( + "Missing inputs in range \(r) for operation \(operation)") + } return try inputs[r].map({ try $0.translateToFuzzIL(withContext: context, using: b) }) } // Helper functions to translate actions to binary/unary operations or comparisons. diff --git a/Sources/Fuzzilli/Mutators/SpliceMutator.swift b/Sources/Fuzzilli/Mutators/SpliceMutator.swift index 1b264063b..8d19a6644 100644 --- a/Sources/Fuzzilli/Mutators/SpliceMutator.swift +++ b/Sources/Fuzzilli/Mutators/SpliceMutator.swift @@ -35,7 +35,8 @@ public class SpliceMutator: BaseInstructionMutator { // actually update that instruction to make spliced type definitions // available. if (instr.op.requiredContext.contains(.wasmTypeGroup) && !(instr.op is WasmEndTypeGroup)) - || (instr.op is WasmBeginTypeGroup) { + || (instr.op is WasmBeginTypeGroup) + { return false } // It only makes sense to copy code if we're not currently in dead code. diff --git a/Sources/Fuzzilli/Profiles/DuktapeProfile.swift b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift index 0611eb8ed..b22ddef87 100644 --- a/Sources/Fuzzilli/Profiles/DuktapeProfile.swift +++ b/Sources/Fuzzilli/Profiles/DuktapeProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let duktapeProfile = Profile( processArgs: { randomize in ["--reprl"] @@ -27,10 +26,10 @@ let duktapeProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -52,13 +51,13 @@ let duktapeProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "CBOR.encode" : .function([.jsAnything] => .object()), - "CBOR.decode" : .function([.object()] => .object()), - "Duktape.fin" : .function([.object(), .opt(.function())] => .undefined), - "Duktape.act" : .function([.number] => .object()), - "Duktape.gc" : .function([] => .undefined), - "Duktape.compact" : .function([.object()] => .undefined), - "placeholder" : .function([] => .undefined), + "CBOR.encode": .function([.jsAnything] => .object()), + "CBOR.decode": .function([.object()] => .object()), + "Duktape.fin": .function([.object(), .opt(.function())] => .undefined), + "Duktape.act": .function([.number] => .object()), + "Duktape.gc": .function([] => .undefined), + "Duktape.compact": .function([.object()] => .undefined), + "placeholder": .function([] => .undefined), ], diff --git a/Sources/Fuzzilli/Profiles/JSCProfile.swift b/Sources/Fuzzilli/Profiles/JSCProfile.swift index 214a2f9d2..85b906036 100644 --- a/Sources/Fuzzilli/Profiles/JSCProfile.swift +++ b/Sources/Fuzzilli/Profiles/JSCProfile.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let ForceDFGCompilationGenerator = CodeGenerator("ForceDFGCompilationGenerator", inputs: .required(.function())) { b, f in +private let ForceDFGCompilationGenerator = CodeGenerator( + "ForceDFGCompilationGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -22,7 +23,9 @@ fileprivate let ForceDFGCompilationGenerator = CodeGenerator("ForceDFGCompilatio } } -fileprivate let ForceFTLCompilationGenerator = CodeGenerator("ForceFTLCompilationGenerator", inputs: .required(.function())) { b, f in +private let ForceFTLCompilationGenerator = CodeGenerator( + "ForceFTLCompilationGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -31,7 +34,7 @@ fileprivate let ForceFTLCompilationGenerator = CodeGenerator("ForceFTLCompilatio } } -fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in +private let GcGenerator = CodeGenerator("GcGenerator") { b in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) } @@ -49,7 +52,8 @@ let jscProfile = Profile( "--thresholdForFTLOptimizeSoon=1000", // Enable bounds check elimination validation "--validateBCE=true", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -70,18 +74,18 @@ let jscProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -100,7 +104,7 @@ let jscProfile = Profile( additionalCodeGenerators: [ (ForceDFGCompilationGenerator, 5), (ForceFTLCompilationGenerator, 5), - (GcGenerator, 5), + (GcGenerator, 5), ], additionalProgramTemplates: WeightedList([]), @@ -110,20 +114,20 @@ let jscProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "transferArrayBuffer" : .function([.object(ofGroup: "ArrayBuffer")] => .undefined), - "noInline" : .function([.function()] => .undefined), - "noFTL" : .function([.function()] => .undefined), - "createGlobalObject" : .function([] => .object()), - "OSRExit" : .function([] => .jsAnything), - "drainMicrotasks" : .function([] => .jsAnything), - "runString" : .function([.string] => .jsAnything), - "makeMasquerader" : .function([] => .jsAnything), - "fullGC" : .function([] => .undefined), - "edenGC" : .function([] => .undefined), - "fiatInt52" : .function([.number] => .number), - "forceGCSlowPaths" : .function([] => .jsAnything), - "ensureArrayStorage" : .function([] => .jsAnything), + "gc": .function([] => .undefined), + "transferArrayBuffer": .function([.object(ofGroup: "ArrayBuffer")] => .undefined), + "noInline": .function([.function()] => .undefined), + "noFTL": .function([.function()] => .undefined), + "createGlobalObject": .function([] => .object()), + "OSRExit": .function([] => .jsAnything), + "drainMicrotasks": .function([] => .jsAnything), + "runString": .function([.string] => .jsAnything), + "makeMasquerader": .function([] => .jsAnything), + "fullGC": .function([] => .undefined), + "edenGC": .function([] => .undefined), + "fiatInt52": .function([.number] => .number), + "forceGCSlowPaths": .function([] => .jsAnything), + "ensureArrayStorage": .function([] => .jsAnything), ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift index 912aa5b97..65f160296 100644 --- a/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift +++ b/Sources/Fuzzilli/Profiles/JerryscriptProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let jerryscriptProfile = Profile( processArgs: { randomize in ["--reprl-fuzzilli"] @@ -20,17 +19,17 @@ let jerryscriptProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es5, @@ -52,10 +51,10 @@ let jerryscriptProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "print" : .function([] => .undefined), - "resourceName" : .function([] => .undefined), - "placeholder" : .function([] => .undefined), + "gc": .function([] => .undefined), + "print": .function([] => .undefined), + "resourceName": .function([] => .undefined), + "placeholder": .function([] => .undefined), ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/NjsProfile.swift b/Sources/Fuzzilli/Profiles/NjsProfile.swift index 6dc3408c1..42b01cd29 100644 --- a/Sources/Fuzzilli/Profiles/NjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/NjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let njsProfile = Profile( processArgs: { randomize in ["fuzz"] @@ -27,10 +26,10 @@ let njsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, diff --git a/Sources/Fuzzilli/Profiles/Profile.swift b/Sources/Fuzzilli/Profiles/Profile.swift index aca59b0e7..b8d0fc063 100644 --- a/Sources/Fuzzilli/Profiles/Profile.swift +++ b/Sources/Fuzzilli/Profiles/Profile.swift @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. - public struct Profile { public let processArgs: (_ randomize: Bool) -> [String] // if not nil, then this is profile for differential fuzzing public let processArgsReference: [String]? - public let processEnv: [String : String] + public let processEnv: [String: String] public let maxExecsBeforeRespawn: Int // Timeout either by value or interval in milliseconds. public let timeout: Timeout diff --git a/Sources/Fuzzilli/Profiles/QjsProfile.swift b/Sources/Fuzzilli/Profiles/QjsProfile.swift index a5e3e8b62..5a344b4f5 100644 --- a/Sources/Fuzzilli/Profiles/QjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QjsProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let qjsProfile = Profile( processArgs: { randomize in ["--reprl"] @@ -27,10 +26,10 @@ let qjsProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -53,7 +52,7 @@ let qjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "placeholder" : .function([] => .undefined) + "placeholder": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/QtjsProfile.swift b/Sources/Fuzzilli/Profiles/QtjsProfile.swift index 5c743062a..fddd2a071 100644 --- a/Sources/Fuzzilli/Profiles/QtjsProfile.swift +++ b/Sources/Fuzzilli/Profiles/QtjsProfile.swift @@ -13,10 +13,12 @@ // limitations under the License. // QV4 is the Execution Engine behind QTJS -fileprivate let ForceQV4JITGenerator = CodeGenerator("ForceQV4JITGenerator", inputs: .required(.function())) { b, f in +private let ForceQV4JITGenerator = CodeGenerator( + "ForceQV4JITGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) - b.buildRepeatLoop(n: 100){ _ in + b.buildRepeatLoop(n: 100) { _ in b.callFunction(f, withArgs: arguments) } } @@ -28,17 +30,17 @@ let qtjsProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0"], + processEnv: ["UBSAN_OPTIONS": "handle_segv=0"], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -51,7 +53,7 @@ let qtjsProfile = Profile( ], additionalCodeGenerators: [ - (ForceQV4JITGenerator, 20), + (ForceQV4JITGenerator, 20) ], additionalProgramTemplates: WeightedList([]), @@ -61,7 +63,7 @@ let qtjsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), + "gc": .function([] => .undefined) ], additionalObjectGroups: [], diff --git a/Sources/Fuzzilli/Profiles/Serenity.swift b/Sources/Fuzzilli/Profiles/Serenity.swift index 12fbd404f..134cb875a 100644 --- a/Sources/Fuzzilli/Profiles/Serenity.swift +++ b/Sources/Fuzzilli/Profiles/Serenity.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let serenityProfile = Profile( processArgs: { randomize in return [""] }, processArgsReference: nil, @@ -23,12 +22,12 @@ let serenityProfile = Profile( maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - function main() { - """, - codeSuffix: """ - } - main(); - """, + function main() { + """, + codeSuffix: """ + } + main(); + """, ecmaVersion: ECMAScriptVersion.es6, startupTests: [ diff --git a/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift index bd857368d..4e4a1110b 100644 --- a/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift +++ b/Sources/Fuzzilli/Profiles/SpidermonkeyProfile.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let ForceSpidermonkeyIonGenerator = CodeGenerator("ForceSpidermonkeyIonGenerator", inputs: .required(.function())) { b, f in +private let ForceSpidermonkeyIonGenerator = CodeGenerator( + "ForceSpidermonkeyIonGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -22,7 +23,7 @@ fileprivate let ForceSpidermonkeyIonGenerator = CodeGenerator("ForceSpidermonkey } } -fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in +private let GcGenerator = CodeGenerator("GcGenerator") { b in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) } @@ -35,7 +36,8 @@ let spidermonkeyProfile = Profile( "--ion-extra-checks", "--fuzzing-safe", "--disable-oom-functions", - "--reprl"] + "--reprl", + ] guard randomize else { return args } @@ -60,12 +62,15 @@ let spidermonkeyProfile = Profile( args.append("--ion-licm=\(probability(0.9) ? "on": "off")") args.append("--ion-instruction-reordering=\(probability(0.9) ? "on": "off")") args.append("--cache-ir-stubs=\(probability(0.9) ? "on": "off")") - args.append(chooseUniform(from: ["--no-sse3", "--no-ssse3", "--no-sse41", "--no-sse42", "--enable-avx"])) + args.append( + chooseUniform(from: [ + "--no-sse3", "--no-ssse3", "--no-sse41", "--no-sse42", "--enable-avx", + ])) if probability(0.1) { args.append("--ion-regalloc=testbed") } args.append(probability(0.9) ? "--enable-watchtower" : "--disable-watchtower") - args.append("--ion-sink=\(probability(0.0) ? "on": "off")") // disabled + args.append("--ion-sink=\(probability(0.0) ? "on": "off")") // disabled return args }, @@ -78,11 +83,11 @@ let spidermonkeyProfile = Profile( timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -100,7 +105,7 @@ let spidermonkeyProfile = Profile( additionalCodeGenerators: [ (ForceSpidermonkeyIonGenerator, 10), - (GcGenerator, 10), + (GcGenerator, 10), ], additionalProgramTemplates: WeightedList([]), @@ -110,10 +115,10 @@ let spidermonkeyProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "enqueueJob" : .function([.function()] => .undefined), - "drainJobQueue" : .function([] => .undefined), - "bailout" : .function([] => .undefined), + "gc": .function([] => .undefined), + "enqueueJob": .function([.function()] => .undefined), + "drainJobQueue": .function([] => .undefined), + "bailout": .function([] => .undefined), ], diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 6fb2fe379..59ec66b44 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -12,33 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. +extension ILType { + public static let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) -public extension ILType { - static let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) + public static let jsD8Test = ILType.object( + ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) - static let jsD8Test = ILType.object(ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) + public static let jsD8FastCAPI = ILType.object( + ofGroup: "D8FastCAPI", withProperties: [], + withMethods: ["throw_no_fallback", "add_32bit_int"]) - static let jsD8FastCAPI = ILType.object(ofGroup: "D8FastCAPI", withProperties: [], withMethods: ["throw_no_fallback", "add_32bit_int"]) + public static let jsD8FastCAPIConstructor = ILType.constructor([] => .jsD8FastCAPI) - static let jsD8FastCAPIConstructor = ILType.constructor([] => .jsD8FastCAPI) + public static let gcTypeEnum = ILType.enumeration( + ofName: "gcType", withValues: ["minor", "major"]) + public static let gcExecutionEnum = ILType.enumeration( + ofName: "gcExecution", withValues: ["async", "sync"]) - static let gcTypeEnum = ILType.enumeration(ofName: "gcType", withValues: ["minor", "major"]) - static let gcExecutionEnum = ILType.enumeration(ofName: "gcExecution", withValues: ["async", "sync"]) - - static let jsWorker = object(ofGroup: "Worker", withMethods: ["postMessage","getMessage", "terminate", "terminateAndWait"]) - static let jsWorkerConstructor = constructor([.jsAnything, .object()] => jsWorker) + public static let jsWorker = object( + ofGroup: "Worker", + withMethods: ["postMessage", "getMessage", "terminate", "terminateAndWait"]) + public static let jsWorkerConstructor = + constructor([.jsAnything, .object()] => jsWorker) + object(ofGroup: "WorkerConstructor", withProperties: ["prototype"]) } public let gcOptions = ObjectGroup( name: "GCOptions", - instanceType: .object(ofGroup: "GCOptions", withProperties: ["type", "execution"], withMethods: []), - properties: ["type": .gcTypeEnum, - "execution": .gcExecutionEnum], + instanceType: .object( + ofGroup: "GCOptions", withProperties: ["type", "execution"], withMethods: []), + properties: [ + "type": .gcTypeEnum, + "execution": .gcExecutionEnum, + ], methods: [:]) -public extension ObjectGroup { - static let jsWorkers = ObjectGroup( +extension ObjectGroup { + public static let jsWorkers = ObjectGroup( name: "Worker", instanceType: .jsWorker, properties: [:], @@ -46,25 +56,25 @@ public extension ObjectGroup { "postMessage": [.jsAnything] => .undefined, "getMessage": [] => .jsAnything, "terminate": [] => .undefined, - "terminateAndWait": [] => .undefined + "terminateAndWait": [] => .undefined, ] ) - static let jsWorkerPrototype = + public static let jsWorkerPrototype = ObjectGroup.createPrototypeObjectGroup(jsWorkers, constructor: .jsWorkerConstructor) - static let jsWorkerConstructors = ObjectGroup( - name: "WorkerConstructor", - constructorPath: "Worker", - instanceType: .jsWorkerConstructor, - properties: [ - "prototype" : jsWorkerPrototype.instanceType, - ], - methods: [:] - ) + public static let jsWorkerConstructors = ObjectGroup( + name: "WorkerConstructor", + constructorPath: "Worker", + instanceType: .jsWorkerConstructor, + properties: [ + "prototype": jsWorkerPrototype.instanceType + ], + methods: [:] + ) } -public let fastCallables : [(group: ILType, method: String)] = [ +public let fastCallables: [(group: ILType, method: String)] = [ (group: .jsD8FastCAPI, method: "throw_no_fallback"), (group: .jsD8FastCAPI, method: "add_32bit_int"), ] @@ -78,14 +88,17 @@ public let V8GcGenerator = CodeGenerator("GcGenerator") { b in // return of gc to .undefined | .jsPromise. One could either chain a .then // or create two wrapper functions that are differently typed such that // fuzzilli always knows what the type of the return value is. - b.callFunction(gc, withArgs: b.findOrGenerateArguments(forSignature: b.fuzzer.environment.type(ofBuiltin: "gc").signature!)) + b.callFunction( + gc, + withArgs: b.findOrGenerateArguments( + forSignature: b.fuzzer.environment.type(ofBuiltin: "gc").signature!)) } public let V8AllocationTimeoutGenerator = CodeGenerator("AllocationTimeoutGenerator") { b in // Repeated GCs are expensive, so only rarely use an interval. let interval = probability(0.1) ? Int64.random(in: 100...10000) : -1 - let timeout = Int64.random(in: 0...(Bool.random() ? 10 : 100)) // prefer small values - b.eval("%SetAllocationTimeout(%@, %@)", with: [b.loadInt(interval), b.loadInt(timeout)]); + let timeout = Int64.random(in: 0...(Bool.random() ? 10 : 100)) // prefer small values + b.eval("%SetAllocationTimeout(%@, %@)", with: [b.loadInt(interval), b.loadInt(timeout)]) } public let V8MajorGcGenerator = CodeGenerator("MajorGcGenerator") { b in @@ -94,7 +107,9 @@ public let V8MajorGcGenerator = CodeGenerator("MajorGcGenerator") { b in b.eval("%MajorGCForCompilerTesting()") } -public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITCompilationThroughLoopGenerator", inputs: .required(.function())) { b, f in +public let ForceJITCompilationThroughLoopGenerator = CodeGenerator( + "ForceJITCompilationThroughLoopGenerator", inputs: .required(.function()) +) { b, f in assert(b.type(of: f).Is(.function())) let arguments = b.randomArguments(forCalling: f) @@ -105,7 +120,9 @@ public let ForceJITCompilationThroughLoopGenerator = CodeGenerator("ForceJITComp // Choose argument lists for four function calls of the same function with // interesting optimization patterns. -func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Variable], [Variable], [Variable], [Variable]) { +func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ( + [Variable], [Variable], [Variable], [Variable] +) { var reusePool: [[Variable]] = [b.randomArguments(forCalling: f)] let reuseProbabilities = [1.0, 0.9, 0.9, 0.5] @@ -122,7 +139,9 @@ func chooseArgumentLists(_ b: ProgramBuilder, forCalling f: Variable) -> ([Varia return (argumentLists[0], argumentLists[1], argumentLists[2], argumentLists[3]) } -private func forceCompilationGenerator(_ generatorName: String, optimizeName: String) -> CodeGenerator { +private func forceCompilationGenerator(_ generatorName: String, optimizeName: String) + -> CodeGenerator +{ return CodeGenerator(generatorName, inputs: .required(.function())) { b, f in assert(b.type(of: f).Is(.function())) let (args1, args2, args3, args4) = chooseArgumentLists(b, forCalling: f) @@ -131,12 +150,12 @@ private func forceCompilationGenerator(_ generatorName: String, optimizeName: St b.callFunction(f, withArgs: args1, guard: guardCalls) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]) b.callFunction(f, withArgs: args2, guard: guardCalls) b.callFunction(f, withArgs: args3, guard: guardCalls) - b.eval("%\(optimizeName)(%@)", with: [f]); + b.eval("%\(optimizeName)(%@)", with: [f]) b.callFunction(f, withArgs: args4, guard: guardCalls) } @@ -149,34 +168,37 @@ public let ForceMaglevCompilationGenerator = forceCompilationGenerator( "ForceMaglevCompilationGenerator", optimizeName: "OptimizeMaglevOnNextCall") // Create a loop and force OSR in one of the iterations. -public let ForceOsrGenerator = CodeGenerator("ForceOsrGenerator", [ - GeneratorStub( - "ForceOsrBeginGenerator", - inContext: .single(.javascript), - provides: [.javascript] - ) { b in - let numIterations = Int.random(in: 2...50) - let loopVar = b.emit(BeginRepeatLoop(iterations: numIterations)).innerOutput - let condition = b.compare( - loopVar, with: b.loadInt(Int64.random(in: 0..([ - (primitiveCodeGenerator, 2), - (createObjectGenerator, 1), - (objectMakerGenerator, 1), - (objectConstructorGenerator, 1), - (objectClassGenerator, 1), - - (propertyStoreGenerator, 10), - (propertyLoadGenerator, 10), - (propertyConfigureGenerator, 5), - (functionDefinitionGenerator, 2), - (functionCallGenerator, 3), - (constructorCallGenerator, 2), - (functionJitCallGenerator, 2) - ])) + b.fuzzer.setCodeGenerators( + WeightedList([ + (primitiveCodeGenerator, 2), + (createObjectGenerator, 1), + (objectMakerGenerator, 1), + (objectConstructorGenerator, 1), + (objectClassGenerator, 1), + + (propertyStoreGenerator, 10), + (propertyLoadGenerator, 10), + (propertyConfigureGenerator, 5), + (functionDefinitionGenerator, 2), + (functionCallGenerator, 3), + (constructorCallGenerator, 2), + (functionJitCallGenerator, 2), + ])) // ... run some of the CodeGenerators to create some initial objects ... b.buildPrefix() @@ -482,21 +525,21 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let twoByteSubjectString = "f\\uD83D\\uDCA9ba\\u2603" let replacementCandidates = [ - "'X'", - "'$1$2$3'", - "'$$$&$`$\\'$1'", - "() => 'X'", - "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", - "() => 42" + "'X'", + "'$1$2$3'", + "'$$$&$`$\\'$1'", + "() => 'X'", + "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", + "() => 42", ] let lastIndices = [ - "undefined", "-1", "0", - "1", "2", "3", - "4", "5", "6", - "7", "8", "9", - "50", "4294967296", "2147483647", - "2147483648", "NaN", "Not a Number" + "undefined", "-1", "0", + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", + "50", "4294967296", "2147483647", + "2147483648", "NaN", "Not a Number", ] let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -518,59 +561,74 @@ public let V8RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let resultVar = b.loadNull() - b.buildTryCatchFinally(tryBody: { - let symbol = b.createNamedVariable(forBuiltin: "Symbol") - withEqualProbability({ - let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("replace", of: symbol) - let replacement = withEqualProbability({ - b.loadString(b.randomString()) - }, { - b.loadString(chooseUniform(from: replacementCandidates)) - }) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("split", of: symbol) - let randomSplitLimit = withEqualProbability({ - "undefined" - }, { - "'not a number'" - }, { - String(b.randomInt()) - }) - let limit = b.loadString(randomSplitLimit) - let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(variable: resultVar, value: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) + b.buildTryCatchFinally( + tryBody: { + let symbol = b.createNamedVariable(forBuiltin: "Symbol") + withEqualProbability( + { + let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("match", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("replace", of: symbol) + let replacement = withEqualProbability( + { + b.loadString(b.randomString()) + }, + { + b.loadString(chooseUniform(from: replacementCandidates)) + }) + let res = b.callComputedMethod( + prop, on: regExpVar, withArgs: [subjectVar, replacement]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("search", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("split", of: symbol) + let randomSplitLimit = withEqualProbability( + { + "undefined" + }, + { + "'not a number'" + }, + { + String(b.randomInt()) + }) + let limit = b.loadString(randomSplitLimit) + let res = b.callComputedMethod( + symbol, on: regExpVar, withArgs: [subjectVar, limit]) + b.reassign(variable: resultVar, value: res) + }, + { + let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }) + }, + catchBody: { _ in }) - }, catchBody: { _ in - }) b.build(n: 7) b.doReturn(resultVar) } - b.eval("%SetForceSlowPath(false)"); + b.eval("%SetForceSlowPath(false)") // compile the regexp once b.callFunction(f) let resFast = b.callFunction(f) - b.eval("%SetForceSlowPath(true)"); + b.eval("%SetForceSlowPath(true)") let resSlow = b.callFunction(f) - b.eval("%SetForceSlowPath(false)"); + b.eval("%SetForceSlowPath(false)") b.build(n: 15) } @@ -595,7 +653,7 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in } // Mark the function for deoptimization. Due to the recursive pattern above, on the outer // stack frames this should trigger a lazy deoptimization. - b.eval("%DeoptimizeNow();"); + b.eval("%DeoptimizeNow();") b.build(n: 30) b.doReturn(b.randomJsVariable()) } @@ -604,9 +662,9 @@ public let LazyDeoptFuzzer = ProgramTemplate("LazyDeoptFuzzer") { b in b.reassign(variable: dummyFct, value: realFct) let args = b.randomArguments(forCalling: realFct) let guardCalls = probability(0.5) - b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [realFct]) b.callFunction(realFct, withArgs: args, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]); + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [realFct]) // Call the function. b.callFunction(realFct, withArgs: args, guard: guardCalls) } @@ -620,12 +678,13 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in // after the other. let mainSignatureBase = b.randomWasmSignature() let useTable64 = Bool.random() - let mainSignature = [useTable64 ? .wasmi64 : .wasmi32] + mainSignatureBase.parameterTypes + let mainSignature = + [useTable64 ? .wasmi64 : .wasmi32] + mainSignatureBase.parameterTypes => mainSignatureBase.outputTypes let numCallees = Int.random(in: 2...5) // Emit a TypeGroup to increase the chance for interesting wasm-gc cases. - b.wasmDefineTypeGroup() { + b.wasmDefineTypeGroup { b.build(n: 10) } @@ -642,14 +701,18 @@ public let WasmDeoptFuzzer = WasmProgramTemplate("WasmDeoptFuzzer") { b in let table = wasmModule.addTable( elementType: .wasmFuncRef(), minSize: numCallees, - definedEntries: (0.. .integer, - "add_32bit_int": [.integer, .integer] => .integer +public let jsD8FastCAPI = ObjectGroup( + name: "D8FastCAPI", instanceType: .jsD8FastCAPI, properties: [:], + methods: [ + "throw_no_fallback": [] => .integer, + "add_32bit_int": [.integer, .integer] => .integer, ]) public let WasmFastCallFuzzer = WasmProgramTemplate("WasmFastCallFuzzer") { b in @@ -723,14 +791,19 @@ public let WasmFastCallFuzzer = WasmProgramTemplate("WasmFastCallFuzzer") { b in let wrappedSig = [.plain(b.type(of: apiObj))] + functionSig.parameters => functionSig.outputType let m = b.buildWasmModule { m in - let allWasmTypes: WeightedList = WeightedList([(.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), (.wasmFuncRef(), 1)]) - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(wrappedSig, availableTypes: allWasmTypes) - m.addWasmFunction(with: wasmSignature) {fbuilder, _, _ in + let allWasmTypes: WeightedList = WeightedList([ + (.wasmi32, 1), (.wasmi64, 1), (.wasmf32, 1), (.wasmf64, 1), (.wasmExternRef(), 1), + (.wasmFuncRef(), 1), + ]) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + wrappedSig, availableTypes: allWasmTypes) + m.addWasmFunction(with: wasmSignature) { fbuilder, _, _ in let args = b.randomWasmArguments(forWasmSignature: wasmSignature) if let args { - let maybeRet = fbuilder.wasmJsCall(function: wrapped, withArgs: args, withWasmSignature: wasmSignature) + let maybeRet = fbuilder.wasmJsCall( + function: wrapped, withArgs: args, withWasmSignature: wasmSignature) if let ret = maybeRet { - return [ret] + return [ret] } } else { Logger(withLabel: "V8CommonProfile").error("Arguments should have been generated") @@ -758,8 +831,11 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in b.build(n: 10) let target = fastCallables.randomElement()! let apiObj = b.findOrGenerateType(target.group) - let functionSig = chooseUniform(from: b.methodSignatures(of: target.method, on: target.group)) - let apiCall = b.callMethod(target.method, on: apiObj, withArgs: b.findOrGenerateArguments(forSignature: functionSig), guard: true) + let functionSig = chooseUniform( + from: b.methodSignatures(of: target.method, on: target.group)) + let apiCall = b.callMethod( + target.method, on: apiObj, + withArgs: b.findOrGenerateArguments(forSignature: functionSig), guard: true) b.doReturn(apiCall) } @@ -767,12 +843,12 @@ public let FastApiCallFuzzer = ProgramTemplate("FastApiCallFuzzer") { b in let guardCalls = probability(0.5) b.callFunction(f, withArgs: args, guard: guardCalls) - b.eval("%PrepareFunctionForOptimization(%@)", with: [f]); + b.eval("%PrepareFunctionForOptimization(%@)", with: [f]) b.callFunction(f, withArgs: args, guard: guardCalls) b.callFunction(f, withArgs: args, guard: guardCalls) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]); + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [f]) b.callFunction(f, withArgs: args, guard: guardCalls) @@ -785,19 +861,21 @@ public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") let containingFct = b.buildPlainFunction(with: b.randomParameters()) { args in // The function to install the prototypes on. let params = b.randomParameters() - let body = {(args: [Variable]) in + let body = { (args: [Variable]) in b.build(n: 20) b.doReturn(b.randomVariable(forUseAs: .object())) } let fct = withEqualProbability( - {b.buildPlainFunction(with: params, body)}, - {b.buildArrowFunction(with: params, body)}, - {b.buildGeneratorFunction(with: params, body)}, // not a valid constructor - {b.buildAsyncFunction(with: params, body)}, // not a valid constructor - {b.buildConstructor(with: params, body)}, - {b.buildClassDefinition(withSuperclass: b.randomVariable(forUseAs: .object())) { _ in - b.build(n: 30) - }} + { b.buildPlainFunction(with: params, body) }, + { b.buildArrowFunction(with: params, body) }, + { b.buildGeneratorFunction(with: params, body) }, // not a valid constructor + { b.buildAsyncFunction(with: params, body) }, // not a valid constructor + { b.buildConstructor(with: params, body) }, + { + b.buildClassDefinition(withSuperclass: b.randomVariable(forUseAs: .object())) { _ in + b.build(n: 30) + } + } ) // Explicitly expose the prototype property to make modifications of it more likely. b.getProperty("prototype", of: fct) @@ -827,34 +905,36 @@ public let ProtoAssignSeqOptFuzzer = ProgramTemplate("ProtoAssignSeqOptFuzzer") public let TurbofanTierUpNonInlinedCallFuzzer = ProgramTemplate("TurbofanTierUpNonInlinedCallFuzzer") { b in - b.buildPrefix() - b.build(n: 50) - // Find a function (or generate a new one) to be marked as "never optimize". - let unoptimizedFunction = b.randomVariable(ofType: .function()) - ?? b.buildPlainFunction(with: .parameters(n: 2)) { _ in - b.build(n: 20) - b.doReturn(b.randomJsVariable()) + b.buildPrefix() + b.build(n: 50) + // Find a function (or generate a new one) to be marked as "never optimize". + let unoptimizedFunction = + b.randomVariable(ofType: .function()) + ?? b.buildPlainFunction(with: .parameters(n: 2)) { _ in + b.build(n: 20) + b.doReturn(b.randomJsVariable()) + } + b.eval("%NeverOptimizeFunction(%@)", with: [unoptimizedFunction]) + // Create another function that calls the unoptimized function. This will always create a real + // call instead of inlining it. + let optimizedFunction = b.buildPlainFunction(with: .parameters(n: 0)) { _ in + // This should be able to generate interesting things including calls to the unoptimized + // function in all kinds of control flow. + b.build(n: 30) + // Also explicitly emit a call to the unoptimized function. + b.callFunction( + unoptimizedFunction, withArgs: b.randomArguments(forCalling: unoptimizedFunction)) + b.build(n: 10) } - b.eval("%NeverOptimizeFunction(%@)", with: [unoptimizedFunction]) - // Create another function that calls the unoptimized function. This will always create a real - // call instead of inlining it. - let optimizedFunction = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - // This should be able to generate interesting things including calls to the unoptimized - // function in all kinds of control flow. - b.build(n: 30) - // Also explicitly emit a call to the unoptimized function. - b.callFunction(unoptimizedFunction, withArgs: b.randomArguments(forCalling: unoptimizedFunction)) - b.build(n: 10) + // Collect feedback and optimize the function. + // Guard all calls. The path where they throw is still interesting as there are + // optimizations that affect the unwinding logic which we'd like to get coverage for as well. + b.eval("%PrepareFunctionForOptimization(%@)", with: [optimizedFunction]) + b.callFunction(optimizedFunction, guard: true) + b.callFunction(optimizedFunction, guard: true) + b.eval("%OptimizeFunctionOnNextCall(%@)", with: [optimizedFunction]) + b.callFunction(optimizedFunction, guard: true) } - // Collect feedback and optimize the function. - // Guard all calls. The path where they throw is still interesting as there are - // optimizations that affect the unwinding logic which we'd like to get coverage for as well. - b.eval("%PrepareFunctionForOptimization(%@)", with: [optimizedFunction]); - b.callFunction(optimizedFunction, guard: true) - b.callFunction(optimizedFunction, guard: true) - b.eval("%OptimizeFunctionOnNextCall(%@)", with: [optimizedFunction]); - b.callFunction(optimizedFunction, guard: true) -} // Configure V8 invocation arguments. `forSandbox` is used by the V8SandboxProfile. As the sandbox // fuzzer does not crash on regular assertions, most validation flags do not make sense in that @@ -873,7 +953,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { "--wasm-staging", "--wasm-fast-api", "--expose-fast-api", - "--wasm-test-streaming", // WebAssembly.compileStreaming & WebAssembly.instantiateStreaming() + "--wasm-test-streaming", // WebAssembly.compileStreaming & WebAssembly.instantiateStreaming() ] if forSandbox { args.append("--sandbox-fuzzing") @@ -892,9 +972,10 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--maglev-as-top-tier") } } else if probability(0.1) { - args.append(probability(0.5) - ? "--turbo-instruction-scheduling" - : "--turbo-stress-instruction-scheduling") + args.append( + probability(0.5) + ? "--turbo-instruction-scheduling" + : "--turbo-stress-instruction-scheduling") } if probability(0.1) { @@ -963,7 +1044,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } if probability(0.2) { args.append("--maglev-non-eager-inlining") - if probability(0.4) { // TODO: @tacet decrease this probability to max 0.2 + if probability(0.4) { // TODO: @tacet decrease this probability to max 0.2 args.append("--max-maglev-inlined-bytecode-size-small=0") } } @@ -977,7 +1058,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--turbolev") if probability(0.82) { args.append("--turbolev-future") - if probability(0.3) { // TODO: @tacet change to 0.15 + if probability(0.3) { // TODO: @tacet change to 0.15 args.append("--max-inlined-bytecode-size-small=0") } } @@ -1021,14 +1102,14 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { // Temporarily enable the three flags below with high probability to // stress-test JSPI. // Lower the probabilities once we have enough coverage. - if (probability(0.5)) { + if probability(0.5) { let stackSwitchingSize = Int.random(in: 1...300) args.append("--wasm-stack-switching-stack-size=\(stackSwitchingSize)") } - if (probability(0.5)) { + if probability(0.5) { args.append("--experimental-wasm-growable-stacks") } - if (probability(0.5)) { + if probability(0.5) { args.append("--stress-wasm-stack-switching") } @@ -1060,7 +1141,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--assert-types") } if (!args.contains("--no-maglev") || args.contains("--turbolev")) && probability(0.1) { - // TODO(tacet): update the Turbolev conditions to !args.contains("--no-turbolev") after Turbolev trial + // TODO(tacet): update the Turbolev conditions to !args.contains("--no-turbolev") after Turbolev trial args.append("--maglev-assert-types") } if probability(0.1) { @@ -1078,7 +1159,9 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } if probability(0.1) { - args.append("--deopt-every-n-times=\(chooseUniform(from: [100, 250, 500, 1000, 2500, 5000, 10000]))") + args.append( + "--deopt-every-n-times=\(chooseUniform(from: [100, 250, 500, 1000, 2500, 5000, 10000]))" + ) } if probability(0.1) { args.append("--stress-ic") @@ -1109,17 +1192,21 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--stress-wasm-memory-moving") } if probability(0.4) { - args.append(chooseUniform( - from: ["--gc-interval=\(Int.random(in: 100...10000))", - "--random-gc-interval=\(Int.random(in: 1000...10000))"])) + args.append( + chooseUniform( + from: [ + "--gc-interval=\(Int.random(in: 100...10000))", + "--random-gc-interval=\(Int.random(in: 1000...10000))", + ])) } if probability(0.4) { args.append("--concurrent-recompilation-queue-length=\(Int.random(in: 4...64))") args.append("--concurrent-recompilation-delay=\(Int.random(in: 1...500))") } if probability(0.6) { - args.append(chooseUniform( - from: ["--stress-compaction", "--stress-compaction-random"])) + args.append( + chooseUniform( + from: ["--stress-compaction", "--stress-compaction-random"])) } } @@ -1160,7 +1247,7 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { // Compiler related flags chooseBooleanFlag("turbo-move-optimization") - chooseBooleanFlag("turbo-jt") // jump threading + chooseBooleanFlag("turbo-jt") // jump threading chooseBooleanFlag("turbo-loop-peeling") chooseBooleanFlag("turbo-loop-variable") chooseBooleanFlag("turbo-loop-rotation") @@ -1175,7 +1262,11 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { chooseBooleanFlag("turbo-load-elimination") chooseBooleanFlag("turbo-inlining") chooseBooleanFlag("turbo-splitting") - args.append(chooseUniform(from: ["--no-enable-sse3", "--no-enable-ssse3", "--no-enable-sse4-1", "--no-enable-sse4-2", "--no-enable-avx", "--no-enable-avx2"])) + args.append( + chooseUniform(from: [ + "--no-enable-sse3", "--no-enable-ssse3", "--no-enable-sse4-1", "--no-enable-sse4-2", + "--no-enable-avx", "--no-enable-avx2", + ])) chooseBooleanFlag("turboshaft-loop-unrolling") chooseBooleanFlag("turboshaft-load-elimination") diff --git a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift index 2f8aa988b..8c404a79f 100644 --- a/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8DumplingProfile.swift @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - let v8DumplingProfile = Profile( processArgs: { randomize in var args = [ @@ -55,7 +54,7 @@ let v8DumplingProfile = Profile( "--experimental-fuzzing", "--js-staging", "--expose-fast-api", - "--predictable" + "--predictable", ], processEnv: [:], @@ -65,56 +64,56 @@ let v8DumplingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - // --- Determinism Shim --- - (function() { - const originalDate = Date; - const FIXED_TIME = 1767225600000; - const FIXED_STRING = new originalDate(FIXED_TIME).toString(); - - Date.now = function() { return FIXED_TIME; }; - globalThis.Date = new Proxy(originalDate, { - construct(target, args) { - if (args.length === 0) return new target(FIXED_TIME); - return new target(...args); - }, - apply(target, thisArg, args) { return FIXED_STRING; } - }); - globalThis.Date.prototype = originalDate.prototype; - - // Math.random shim - const rng = function() { - let s = 0x12345678; - return function() { - s ^= s << 13; s ^= s >> 17; s ^= s << 5; - return (s >>> 0) / 4294967296; - }; - }(); - Math.random = rng; - - if (typeof Temporal !== 'undefined' && Temporal.Now) { - const fixedInstant = Temporal.Instant.fromEpochMilliseconds(FIXED_TIME); - - Temporal.Now.instant = () => fixedInstant; - - // Shim Zoned/Plain methods to use the fixed instant - Temporal.Now.zonedDateTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()); - - Temporal.Now.plainDateTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDateTime(); - - Temporal.Now.plainDateISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDate(); - - Temporal.Now.plainTimeISO = (tzLike) => - fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainTime(); - } - })(); - // --- End Determinism Shim --- - """, + // --- Determinism Shim --- + (function() { + const originalDate = Date; + const FIXED_TIME = 1767225600000; + const FIXED_STRING = new originalDate(FIXED_TIME).toString(); + + Date.now = function() { return FIXED_TIME; }; + globalThis.Date = new Proxy(originalDate, { + construct(target, args) { + if (args.length === 0) return new target(FIXED_TIME); + return new target(...args); + }, + apply(target, thisArg, args) { return FIXED_STRING; } + }); + globalThis.Date.prototype = originalDate.prototype; + + // Math.random shim + const rng = function() { + let s = 0x12345678; + return function() { + s ^= s << 13; s ^= s >> 17; s ^= s << 5; + return (s >>> 0) / 4294967296; + }; + }(); + Math.random = rng; + + if (typeof Temporal !== 'undefined' && Temporal.Now) { + const fixedInstant = Temporal.Instant.fromEpochMilliseconds(FIXED_TIME); + + Temporal.Now.instant = () => fixedInstant; + + // Shim Zoned/Plain methods to use the fixed instant + Temporal.Now.zonedDateTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()); + + Temporal.Now.plainDateTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDateTime(); + + Temporal.Now.plainDateISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainDate(); + + Temporal.Now.plainTimeISO = (tzLike) => + fixedInstant.toZonedDateTimeISO(tzLike || Temporal.Now.timeZoneId()).toPlainTime(); + } + })(); + // --- End Determinism Shim --- + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -123,21 +122,21 @@ let v8DumplingProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), - (V8GcGenerator, 10), + (V8GcGenerator, 10), ], additionalProgramTemplates: WeightedList([ - (MapTransitionFuzzer, 1), - (ValueSerializerFuzzer, 1), - (V8RegExpFuzzer, 1), - (FastApiCallFuzzer, 1), - (LazyDeoptFuzzer, 1), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), ]), disabledCodeGenerators: [], @@ -145,9 +144,10 @@ let v8DumplingProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .jsD8, - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .jsD8, + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], diff --git a/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift index 6bcafe668..a3985adbb 100644 --- a/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8HoleFuzzingProfile.swift @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. - // This value generator inserts Hole leaks into the program. Use this if you // want to fuzz for Memory Corruption using holes, this should be used in // conjunction with the --hole-fuzzing runtime flag. -fileprivate let HoleLeakGenerator = CodeGenerator("HoleLeakGenerator", produces: [.jsAnything]) { b in +private let HoleLeakGenerator = CodeGenerator("HoleLeakGenerator", produces: [.jsAnything]) { b in b.eval("%LeakHole()", hasOutput: true) } @@ -44,10 +43,10 @@ let v8HoleFuzzingProfile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -68,25 +67,25 @@ let v8HoleFuzzingProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (V8GcGenerator, 10), - (HoleLeakGenerator, 25), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (V8GcGenerator, 10), + (HoleLeakGenerator, 25), ], - additionalProgramTemplates: WeightedList([ - ]), + additionalProgramTemplates: WeightedList([]), disabledCodeGenerators: [], disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .object(), - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .object(), + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], diff --git a/Sources/Fuzzilli/Profiles/V8Profile.swift b/Sources/Fuzzilli/Profiles/V8Profile.swift index 6d1960729..3ffb35672 100644 --- a/Sources/Fuzzilli/Profiles/V8Profile.swift +++ b/Sources/Fuzzilli/Profiles/V8Profile.swift @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. - public let v8Profile = Profile( - processArgs: {randomize in - v8ProcessArgs(randomize: randomize, forSandbox: false) + processArgs: { randomize in + v8ProcessArgs(randomize: randomize, forSandbox: false) }, processArgsReference: nil, @@ -28,10 +27,10 @@ public let v8Profile = Profile( timeout: Timeout.interval(300, 900), codePrefix: """ - """, + """, codeSuffix: """ - """, + """, ecmaVersion: ECMAScriptVersion.es6, @@ -57,37 +56,37 @@ public let v8Profile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (TurbofanVerifyTypeGenerator, 10), - - (WorkerGenerator, 10), - (V8GcGenerator, 5), - (V8AllocationTimeoutGenerator, 5), - (V8MajorGcGenerator, 5), - - (WasmStructGenerator, 15), - (WasmArrayGenerator, 15), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 5), - (HoleNanGenerator, 5), - (UndefinedNanGenerator, 5), - (StringShapeGenerator, 5), - (HeapNumberGenerator, 5), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (TurbofanVerifyTypeGenerator, 10), + + (WorkerGenerator, 10), + (V8GcGenerator, 5), + (V8AllocationTimeoutGenerator, 5), + (V8MajorGcGenerator, 5), + + (WasmStructGenerator, 15), + (WasmArrayGenerator, 15), + (SharedObjectGenerator, 5), + (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), + (HeapNumberGenerator, 5), ], additionalProgramTemplates: WeightedList([ - (MapTransitionFuzzer, 1), - (ValueSerializerFuzzer, 1), - (V8RegExpFuzzer, 1), - (WasmFastCallFuzzer, 1), - (FastApiCallFuzzer, 1), - (LazyDeoptFuzzer, 1), - (WasmDeoptFuzzer, 1), - (WasmTurbofanFuzzer, 1), - (ProtoAssignSeqOptFuzzer, 1), + (MapTransitionFuzzer, 1), + (ValueSerializerFuzzer, 1), + (V8RegExpFuzzer, 1), + (WasmFastCallFuzzer, 1), + (FastApiCallFuzzer, 1), + (LazyDeoptFuzzer, 1), + (WasmDeoptFuzzer, 1), + (WasmTurbofanFuzzer, 1), + (ProtoAssignSeqOptFuzzer, 1), (TurbofanTierUpNonInlinedCallFuzzer, 1), ]), @@ -96,8 +95,8 @@ public let v8Profile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .jsD8, + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .jsD8, "Worker": .jsWorkerConstructor, // via --expose-externalize-string: "externalizeString": .function([.plain(.jsString)] => .jsString), @@ -106,7 +105,10 @@ public let v8Profile = Profile( "createExternalizableTwoByteString": .function([.plain(.jsString)] => .jsString), ], - additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions, .jsWorkers, .jsWorkerPrototype, .jsWorkerConstructors], + additionalObjectGroups: [ + jsD8, jsD8Test, jsD8FastCAPI, gcOptions, .jsWorkers, .jsWorkerPrototype, + .jsWorkerConstructors, + ], additionalEnumerations: [.gcTypeEnum, .gcExecutionEnum], diff --git a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift index 38744e23b..7f4c4f0ef 100644 --- a/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8SandboxProfile.swift @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. - // A post-processor that inserts calls to the sandbox corruption functions (defined in the codeSuffix below) into the generated samples. -fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { +private struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { func process(_ program: Program, for fuzzer: Fuzzer) throws -> Program { // We don't instrument every generated program since we still want the fuzzer to make progress towards // discovering more interestesting programs and adding them to the corpus. Corrupting objects in every @@ -31,9 +30,11 @@ fileprivate struct SandboxFuzzingPostProcessor: FuzzingPostProcessor { func corruptSomething() { // TODO: Currently, Fuzzilli wraps sandbox corruptions inside `b.eval(...)`. Because Fuzzilli treats `eval` strings as opaque, the mutation engine cannot genetically evolve the `pathArray` tuples or seeds. Implementing native Instruction classes (e.g. `.corruptDataWithBitflip(...)`) would allow Fuzzilli to structurally mutate these corruption paths. // Make sure that we get a JS variable that is not a primitive. - guard let target = b.findVariable(satisfying: { v in - !b.type(of: v).Is(.primitive) && b.type(of: v).Is(.jsAnything) - }) else { return } + guard + let target = b.findVariable(satisfying: { v in + !b.type(of: v).Is(.primitive) && b.type(of: v).Is(.jsAnything) + }) + else { return } let numCorruptions = Int.random(in: 1...3) for _ in 0..> 1 - let randomMagnitudeValue = lower == upper ? lower : UInt64.random(in: lower.. 1s), which may cause crashing samples to time out before the stack trace has been captured (in which case Fuzzilli will discard the sample) // - redzone=128: This value is used by Clusterfuzz for reproducing testcases so we should use the same value - processEnv: ["ASAN_OPTIONS" : "abort_on_error=1:handle_sigill=1:symbolize=false:redzone=128", "UBSAN_OPTIONS" : "abort_on_error=1:symbolize=false:redzone=128"], + processEnv: [ + "ASAN_OPTIONS": "abort_on_error=1:handle_sigill=1:symbolize=false:redzone=128", + "UBSAN_OPTIONS": "abort_on_error=1:symbolize=false:redzone=128", + ], maxExecsBeforeRespawn: 1000, @@ -168,336 +175,336 @@ let v8SandboxProfile = Profile( timeout: Timeout.interval(500, 1200), codePrefix: """ - // - // BEGIN FUZZER GENERATED CODE - // + // + // BEGIN FUZZER GENERATED CODE + // - """, + """, codeSuffix: """ - // - // BEGIN FUZZER HELPER CODE - // - - // The following functions corrupt a given object in a deterministic fashion (based on the provided seed and path) and log the steps being performed. + // + // BEGIN FUZZER HELPER CODE + // - function getSandboxCorruptionHelpers() { - // In general, memory contents are represented as (unsigned) BigInts, everything else (addresses, offsets, etc.) are Numbers. + // The following functions corrupt a given object in a deterministic fashion (based on the provided seed and path) and log the steps being performed. - function assert(c) { - if (!c) { - throw new Error("Assertion in the in-sandbox-corruption API failed!"); - } - } + function getSandboxCorruptionHelpers() { + // In general, memory contents are represented as (unsigned) BigInts, everything else (addresses, offsets, etc.) are Numbers. - const kHeapObjectTag = 0x1n; - // V8 uses the two lowest bits as tag bits: 0x1 to indicate HeapObject vs Smi and 0x2 to indicate a weak reference. - const kHeapObjectTagMask = 0x3n; - // Offsets should be a multiple of 4, as that's the typical field size. - const kOffsetAlignmentMask = ~0x3; - - const builtins = Sandbox.getBuiltinNames(); - assert(builtins.length > 0); - - const Step = { - NEIGHBOR: 0, - POINTER: 1, - }; - - // Helper class for accessing in-sandbox memory. - class Memory { - constructor() { - let buffer = new Sandbox.MemoryView(0, 0x100000000); - this.dataView = new DataView(buffer); - this.taggedView = new Uint32Array(buffer); - } - - read(addr, numBits) { - switch (numBits) { - case 8: return BigInt(this.dataView.getUint8(addr)); - case 16: return BigInt(this.dataView.getUint16(addr, true)); - case 32: return BigInt(this.dataView.getUint32(addr, true)); - } - } + function assert(c) { + if (!c) { + throw new Error("Assertion in the in-sandbox-corruption API failed!"); + } + } - write(addr, value, numBits) { - switch (numBits) { - case 8: this.dataView.setUint8(addr, Number(value)); break; - case 16: this.dataView.setUint16(addr, Number(value), true); break; - case 32: this.dataView.setUint32(addr, Number(value), true); break; - } - } + const kHeapObjectTag = 0x1n; + // V8 uses the two lowest bits as tag bits: 0x1 to indicate HeapObject vs Smi and 0x2 to indicate a weak reference. + const kHeapObjectTagMask = 0x3n; + // Offsets should be a multiple of 4, as that's the typical field size. + const kOffsetAlignmentMask = ~0x3; + + const builtins = Sandbox.getBuiltinNames(); + assert(builtins.length > 0); + + const Step = { + NEIGHBOR: 0, + POINTER: 1, + }; + + // Helper class for accessing in-sandbox memory. + class Memory { + constructor() { + let buffer = new Sandbox.MemoryView(0, 0x100000000); + this.dataView = new DataView(buffer); + this.taggedView = new Uint32Array(buffer); + } - copyTagged(source, destination, size) { - assert(size % 4 == 0); - let toIndex = destination / 4; - let startIndex = source / 4; - let endIndex = (source + size) / 4; - this.taggedView.copyWithin(toIndex, startIndex, endIndex); - } + read(addr, numBits) { + switch (numBits) { + case 8: return BigInt(this.dataView.getUint8(addr)); + case 16: return BigInt(this.dataView.getUint16(addr, true)); + case 32: return BigInt(this.dataView.getUint32(addr, true)); } - let memory = new Memory; - - // A worker thread that corrupts memory from the background. - // - // The main thread can post messages to this worker which contain - // effectively (address, valueA, valueB) triples. This worker - // will then permanently flip all the given addresses between - // valueA and valueB. This for example makes it possible to find - // double-fetch issues and similar bugs. - function workerFunc() { - let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); - let work = []; - let iteration = 0; - - onmessage = function(e) { - if (work.length == 0) { - // Time to start working. - setTimeout(doWork); - } - work.push(e.data); - } + } - function corrupt(address, value, size) { - switch (size) { - case 8: - memory.setUint8(address, value); - break; - case 16: - memory.setUint16(address, value, true); - break; - case 32: - memory.setUint32(address, value, true); - break; - } - } + write(addr, value, numBits) { + switch (numBits) { + case 8: this.dataView.setUint8(addr, Number(value)); break; + case 16: this.dataView.setUint16(addr, Number(value), true); break; + case 32: this.dataView.setUint32(addr, Number(value), true); break; + } + } - function doWork() { - iteration++; - for (let item of work) { - let value = (iteration % 2) == 0 ? item.valueA : item.valueB; - corrupt(item.address, value, item.size); - } - // Schedule the next round of work. - setTimeout(doWork); - } + copyTagged(source, destination, size) { + assert(size % 4 == 0); + let toIndex = destination / 4; + let startIndex = source / 4; + let endIndex = (source + size) / 4; + this.taggedView.copyWithin(toIndex, startIndex, endIndex); + } + } + let memory = new Memory; + + // A worker thread that corrupts memory from the background. + // + // The main thread can post messages to this worker which contain + // effectively (address, valueA, valueB) triples. This worker + // will then permanently flip all the given addresses between + // valueA and valueB. This for example makes it possible to find + // double-fetch issues and similar bugs. + function workerFunc() { + let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); + let work = []; + let iteration = 0; + + onmessage = function(e) { + if (work.length == 0) { + // Time to start working. + setTimeout(doWork); } - if (typeof globalThis.memory_corruption_worker === 'undefined') { - // Define as non-configurable and non-enumerable property. - let worker = new Worker(workerFunc, {type: 'function'}); - Object.defineProperty(globalThis, 'memory_corruption_worker', {value: worker}); + work.push(e.data); + } + + function corrupt(address, value, size) { + switch (size) { + case 8: + memory.setUint8(address, value); + break; + case 16: + memory.setUint16(address, value, true); + break; + case 32: + memory.setUint32(address, value, true); + break; } + } + function doWork() { + iteration++; + for (let item of work) { + let value = (iteration % 2) == 0 ? item.valueA : item.valueB; + corrupt(item.address, value, item.size); + } + // Schedule the next round of work. + setTimeout(doWork); + } + } + if (typeof globalThis.memory_corruption_worker === 'undefined') { + // Define as non-configurable and non-enumerable property. + let worker = new Worker(workerFunc, {type: 'function'}); + Object.defineProperty(globalThis, 'memory_corruption_worker', {value: worker}); + } - // Helper function to deterministically find a random neighbor object. - // - // This logic is designed to deal with a (somewhat) non-deterministic heap layout to ensure that test cases are reproducible. - // In practice, it should most of the time find the same neighbor object if (a) that object is always allocated after the - // start object, (b) is within the first N (currently 100) objects, and (c) is always the first neighbor of its instance type. - // - // This is achieved by iterating over the heap starting from the start object and computing a simple 16-bit hash value for each - // object. At the end, we select the first object whose hash is closest to a random 16-bit hash query. - // Note that we always take the first object if there are multiple objects with the same instance type. - // For finding later neighbors, we rely on the traversal path containing multiple Step.NEIGHBOR entries. - function findRandomNeighborObject(addr, hashQuery) { - const N = 100; - const kUint16Max = 0xffff; - const kUnknownInstanceId = kUint16Max; - - // Simple hash function for 16-bit unsigned integers. See https://github.com/skeeto/hash-prospector - function hash16(x) { - assert(x >= 0 && x <= kUint16Max); - x ^= x >> 8; - x = (x * 0x88B5) & 0xffff; - x ^= x >> 7; - x = (x * 0xdB2d) & 0xffff; - x ^= x >> 9; - return x; - } - hashQuery = hashQuery & 0xffff; - let currentWinner = addr; - let currentBest = kUint16Max; + // Helper function to deterministically find a random neighbor object. + // + // This logic is designed to deal with a (somewhat) non-deterministic heap layout to ensure that test cases are reproducible. + // In practice, it should most of the time find the same neighbor object if (a) that object is always allocated after the + // start object, (b) is within the first N (currently 100) objects, and (c) is always the first neighbor of its instance type. + // + // This is achieved by iterating over the heap starting from the start object and computing a simple 16-bit hash value for each + // object. At the end, we select the first object whose hash is closest to a random 16-bit hash query. + // Note that we always take the first object if there are multiple objects with the same instance type. + // For finding later neighbors, we rely on the traversal path containing multiple Step.NEIGHBOR entries. + function findRandomNeighborObject(addr, hashQuery) { + const N = 100; + const kUint16Max = 0xffff; + const kUnknownInstanceId = kUint16Max; + + // Simple hash function for 16-bit unsigned integers. See https://github.com/skeeto/hash-prospector + function hash16(x) { + assert(x >= 0 && x <= kUint16Max); + x ^= x >> 8; + x = (x * 0x88B5) & 0xffff; + x ^= x >> 7; + x = (x * 0xdB2d) & 0xffff; + x ^= x >> 9; + return x; + } - for (let i = 0; i < N; i++) { - addr += Sandbox.getSizeOfObjectAt(addr); - let typeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); - if (typeId == kUnknownInstanceId) { - break; - } - let hash = hash16(typeId); - let score = Math.abs(hash - hashQuery); - if (score < currentBest) { - currentBest = score; - currentWinner = addr; - } - } + hashQuery = hashQuery & 0xffff; + let currentWinner = addr; + let currentBest = kUint16Max; - return currentWinner; + for (let i = 0; i < N; i++) { + addr += Sandbox.getSizeOfObjectAt(addr); + let typeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); + if (typeId == kUnknownInstanceId) { + break; } - - // Helper function to create a copy of the object at the given address and return the address of the copy. - // This is for example useful when we would like to corrupt a read-only object: in that case, we can then instead - // create a copy of the read-only object, install that into whichever object references is, then corrupt the copy. - function copyObjectAt(source) { - let objectSize = Sandbox.getSizeOfObjectAt(source); - // Simple way to get a placeholder object that's large enough: create a sequential string. - // TODO(saelo): maybe add a method to the sandbox api to construct an object of the appropriate size. - let placeholder = Array(objectSize).fill("a").join(""); - let destination = Sandbox.getAddressOf(placeholder); - memory.copyTagged(source, destination, objectSize); - return destination; + let hash = hash16(typeId); + let score = Math.abs(hash - hashQuery); + if (score < currentBest) { + currentBest = score; + currentWinner = addr; } + } - function getRandomAlignedOffset(addr, offsetSeed) { - let objectSize = Sandbox.getSizeOfObjectAt(addr); - return (offsetSeed % objectSize) & kOffsetAlignmentMask; - } + return currentWinner; + } - function getBaseAddress(obj) { - try { - if (!Sandbox.isWritable(obj)) return null; - return Sandbox.getAddressOf(obj); - } catch (e) { - // Presumably, |obj| is a Smi, not a HeapObject. - return null; - } - } + // Helper function to create a copy of the object at the given address and return the address of the copy. + // This is for example useful when we would like to corrupt a read-only object: in that case, we can then instead + // create a copy of the read-only object, install that into whichever object references is, then corrupt the copy. + function copyObjectAt(source) { + let objectSize = Sandbox.getSizeOfObjectAt(source); + // Simple way to get a placeholder object that's large enough: create a sequential string. + // TODO(saelo): maybe add a method to the sandbox api to construct an object of the appropriate size. + let placeholder = Array(objectSize).fill("a").join(""); + let destination = Sandbox.getAddressOf(placeholder); + memory.copyTagged(source, destination, objectSize); + return destination; + } + + function getRandomAlignedOffset(addr, offsetSeed) { + let objectSize = Sandbox.getSizeOfObjectAt(addr); + return (offsetSeed % objectSize) & kOffsetAlignmentMask; + } - function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { - let baseAddr = getBaseAddress(obj); - if (!baseAddr) return null; + function getBaseAddress(obj) { + try { + if (!Sandbox.isWritable(obj)) return null; + return Sandbox.getAddressOf(obj); + } catch (e) { + // Presumably, |obj| is a Smi, not a HeapObject. + return null; + } + } - let addr = evaluateTraversalPath(baseAddr, path); - if (!addr) return null; + function prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) { + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return null; - let offset = getRandomAlignedOffset(addr, offsetSeed); - offset += subFieldOffset; + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return null; - let oldValue = memory.read(addr + offset, numBitsToCorrupt); - return { addr, offset, oldValue, finalizeDataCorruption }; - } + let offset = getRandomAlignedOffset(addr, offsetSeed); + offset += subFieldOffset; + + let oldValue = memory.read(addr + offset, numBitsToCorrupt); + return { addr, offset, oldValue, finalizeDataCorruption }; + } - function finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, typeString) { - assert(oldValue >= 0 && oldValue < (1n << BigInt(numBitsToCorrupt))); - assert(newValue >= 0 && newValue < (1n << BigInt(numBitsToCorrupt))); + function finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, typeString) { + assert(oldValue >= 0 && oldValue < (1n << BigInt(numBitsToCorrupt))); + assert(newValue >= 0 && newValue < (1n << BigInt(numBitsToCorrupt))); - memory.write(addr + offset, newValue, numBitsToCorrupt); - print(" Corrupted " + numBitsToCorrupt + "-bit field (" + typeString + ") at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + memory.write(addr + offset, newValue, numBitsToCorrupt); + print(" Corrupted " + numBitsToCorrupt + "-bit field (" + typeString + ") at offset " + offset + ". Old value: 0x" + oldValue.toString(16) + ", new value: 0x" + newValue.toString(16)); + } + + // The path argument is an array of [Step, Value] tuples. + // If Step === Step.NEIGHBOR, Value is the exact 16-bit hash query. + // If Step === Step.POINTER, Value is a random UInt32 seed used to calculate an aligned offset. + function evaluateTraversalPath(addr, path) { + let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); + print("Corrupting memory starting from object at 0x" + addr.toString(16) + " of type " + instanceType); + + for (let [stepType, seedValue] of path) { + if (!Sandbox.isWritableObjectAt(addr)) { + print(" Not corrupting read-only object. Bailing out."); + return null; } - // The path argument is an array of [Step, Value] tuples. - // If Step === Step.NEIGHBOR, Value is the exact 16-bit hash query. - // If Step === Step.POINTER, Value is a random UInt32 seed used to calculate an aligned offset. - function evaluateTraversalPath(addr, path) { - let instanceType = Sandbox.getInstanceTypeOfObjectAt(addr); - print("Corrupting memory starting from object at 0x" + addr.toString(16) + " of type " + instanceType); - - for (let [stepType, seedValue] of path) { - if (!Sandbox.isWritableObjectAt(addr)) { - print(" Not corrupting read-only object. Bailing out."); - return null; + switch (stepType) { + case Step.NEIGHBOR: { + let oldAddr = addr; + addr = findRandomNeighborObject(addr, seedValue); + print(" Jumping to neighboring object at offset " + (addr - oldAddr)); + break; + } + case Step.POINTER: { + let offset = getRandomAlignedOffset(addr, seedValue); + let oldValue = memory.read(addr + offset, 32); + + // If the selected offset doesn't contain a valid pointer, we break out + // of the traversal loop but still corrupt the current (valid) object. + let isLikelyPointer = (oldValue & kHeapObjectTag) == kHeapObjectTag; + if (!isLikelyPointer) { + break; + } + + let newAddr = Number(oldValue & ~kHeapObjectTagMask); + if (!Sandbox.isValidObjectAt(newAddr)) { + break; } - switch (stepType) { - case Step.NEIGHBOR: { - let oldAddr = addr; - addr = findRandomNeighborObject(addr, seedValue); - print(" Jumping to neighboring object at offset " + (addr - oldAddr)); - break; - } - case Step.POINTER: { - let offset = getRandomAlignedOffset(addr, seedValue); - let oldValue = memory.read(addr + offset, 32); - - // If the selected offset doesn't contain a valid pointer, we break out - // of the traversal loop but still corrupt the current (valid) object. - let isLikelyPointer = (oldValue & kHeapObjectTag) == kHeapObjectTag; - if (!isLikelyPointer) { - break; - } - - let newAddr = Number(oldValue & ~kHeapObjectTagMask); - if (!Sandbox.isValidObjectAt(newAddr)) { - break; - } - - print(" Following pointer at offset " + offset + " to object at 0x" + newAddr.toString(16)); - - if (!Sandbox.isWritableObjectAt(newAddr)) { - newAddr = copyObjectAt(newAddr); - memory.write(addr + offset, BigInt(newAddr) | kHeapObjectTag, 32); - print(" Referenced object is in read-only memory. Created and linked a writable copy at 0x" + newAddr.toString(16)); - } - addr = newAddr; - break; - } + print(" Following pointer at offset " + offset + " to object at 0x" + newAddr.toString(16)); + + if (!Sandbox.isWritableObjectAt(newAddr)) { + newAddr = copyObjectAt(newAddr); + memory.write(addr + offset, BigInt(newAddr) | kHeapObjectTag, 32); + print(" Referenced object is in read-only memory. Created and linked a writable copy at 0x" + newAddr.toString(16)); } + addr = newAddr; + break; } - return Sandbox.isWritableObjectAt(addr) ? addr : null; } - - return { - builtins, getBaseAddress, evaluateTraversalPath, prepareDataCorruptionContext - }; } + return Sandbox.isWritableObjectAt(addr) ? addr : null; + } - function corruptDataWithBitflip(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + return { + builtins, getBaseAddress, evaluateTraversalPath, prepareDataCorruptionContext + }; + } - let newValue = oldValue ^ (1n << BigInt(bitPosition)); - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Bitflip"); - } + function corruptDataWithBitflip(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - function corruptDataWithIncrement(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, incrementValue) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + let newValue = oldValue ^ (1n << BigInt(bitPosition)); + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Bitflip"); + } - let newValue = (oldValue + incrementValue) & ((1n << BigInt(numBitsToCorrupt)) - 1n); - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Increment"); - } + function corruptDataWithIncrement(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, incrementValue) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; + + let newValue = (oldValue + incrementValue) & ((1n << BigInt(numBitsToCorrupt)) - 1n); + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Increment"); + } - function corruptDataWithReplace(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, replaceValue) { - let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + function corruptDataWithReplace(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, replaceValue) { + let { addr, offset, oldValue, finalizeDataCorruption } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - let newValue = replaceValue; - finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Replace"); - } + let newValue = replaceValue; + finalizeDataCorruption(addr, offset, oldValue, newValue, numBitsToCorrupt, "Replace"); + } - function corruptWithWorker(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { - let { addr, offset, oldValue } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; - if (!addr) return; + function corruptWithWorker(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset, bitPosition) { + let { addr, offset, oldValue } = getSandboxCorruptionHelpers().prepareDataCorruptionContext(obj, path, offsetSeed, numBitsToCorrupt, subFieldOffset) || {}; + if (!addr) return; - let newValue = oldValue ^ (1n << BigInt(bitPosition)); + let newValue = oldValue ^ (1n << BigInt(bitPosition)); - globalThis.memory_corruption_worker.postMessage({ - address: addr + offset, valueA: Number(oldValue), valueB: Number(newValue), size: numBitsToCorrupt - }); + globalThis.memory_corruption_worker.postMessage({ + address: addr + offset, valueA: Number(oldValue), valueB: Number(newValue), size: numBitsToCorrupt + }); - print(" Started background worker to continuously flip " + numBitsToCorrupt + "-bit field at offset " + offset + " between 0x" + oldValue.toString(16) + " and 0x" + newValue.toString(16)); - } + print(" Started background worker to continuously flip " + numBitsToCorrupt + "-bit field at offset " + offset + " between 0x" + oldValue.toString(16) + " and 0x" + newValue.toString(16)); + } - function corruptFunction(obj, path, builtinSeed) { - let { builtins, getBaseAddress, evaluateTraversalPath } = getSandboxCorruptionHelpers(); - let baseAddr = getBaseAddress(obj); - if (!baseAddr) return; - let addr = evaluateTraversalPath(baseAddr, path); - if (!addr) return; - - let instanceTypeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); - if (instanceTypeId === Sandbox.getInstanceTypeIdFor("JS_FUNCTION_TYPE")) { - let targetObj = Sandbox.getObjectAt(addr); - let builtinId = builtinSeed % builtins.length; - try { - Sandbox.setFunctionCodeToBuiltin(targetObj, builtinId); - print(" Hijacked JSFunction code pointer! Swapped with builtin: " + builtins[builtinId]); - } catch(e) {} - } - } - """, + function corruptFunction(obj, path, builtinSeed) { + let { builtins, getBaseAddress, evaluateTraversalPath } = getSandboxCorruptionHelpers(); + let baseAddr = getBaseAddress(obj); + if (!baseAddr) return; + let addr = evaluateTraversalPath(baseAddr, path); + if (!addr) return; + + let instanceTypeId = Sandbox.getInstanceTypeIdOfObjectAt(addr); + if (instanceTypeId === Sandbox.getInstanceTypeIdFor("JS_FUNCTION_TYPE")) { + let targetObj = Sandbox.getObjectAt(addr); + let builtinId = builtinSeed % builtins.length; + try { + Sandbox.setFunctionCodeToBuiltin(targetObj, builtinId); + print(" Hijacked JSFunction code pointer! Swapped with builtin: " + builtins[builtinId]); + } catch(e) {} + } + } + """, ecmaVersion: ECMAScriptVersion.es6, @@ -543,18 +550,18 @@ let v8SandboxProfile = Profile( ], additionalCodeGenerators: [ - (ForceJITCompilationThroughLoopGenerator, 5), - (ForceTurboFanCompilationGenerator, 5), - (ForceMaglevCompilationGenerator, 5), - (ForceOsrGenerator, 5), - (V8GcGenerator, 10), - (WasmStructGenerator, 5), - (WasmArrayGenerator, 5), - (SharedObjectGenerator, 5), - (PretenureAllocationSiteGenerator, 5), - (HoleNanGenerator, 5), - (UndefinedNanGenerator, 5), - (StringShapeGenerator, 5), + (ForceJITCompilationThroughLoopGenerator, 5), + (ForceTurboFanCompilationGenerator, 5), + (ForceMaglevCompilationGenerator, 5), + (ForceOsrGenerator, 5), + (V8GcGenerator, 10), + (WasmStructGenerator, 5), + (WasmArrayGenerator, 5), + (SharedObjectGenerator, 5), + (PretenureAllocationSiteGenerator, 5), + (HoleNanGenerator, 5), + (UndefinedNanGenerator, 5), + (StringShapeGenerator, 5), ], additionalProgramTemplates: WeightedList([ @@ -566,9 +573,10 @@ let v8SandboxProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), - "d8" : .object(), - "Worker" : .constructor([.jsAnything, .object()] => .object(withMethods: ["postMessage","getMessage"])), + "gc": .function([.opt(gcOptions.instanceType)] => (.undefined | .jsPromise)), + "d8": .object(), + "Worker": .constructor( + [.jsAnything, .object()] => .object(withMethods: ["postMessage", "getMessage"])), ], additionalObjectGroups: [jsD8, jsD8Test, jsD8FastCAPI, gcOptions], @@ -577,4 +585,3 @@ let v8SandboxProfile = Profile( optionalPostProcessor: SandboxFuzzingPostProcessor() ) - diff --git a/Sources/Fuzzilli/Profiles/XSProfile.swift b/Sources/Fuzzilli/Profiles/XSProfile.swift index 8037aca28..c7407040d 100644 --- a/Sources/Fuzzilli/Profiles/XSProfile.swift +++ b/Sources/Fuzzilli/Profiles/XSProfile.swift @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. - -fileprivate let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.function())) { b, f in +private let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.function())) { b, f in let arguments = b.randomArguments(forCalling: f) let index = b.loadInt(1) let end = b.loadInt(128) let gc = b.createNamedVariable(forBuiltin: "gc") b.callFunction(gc, withArgs: [index]) - b.buildWhileLoop({b.compare(index, with: end, using: .lessThan)}) { + b.buildWhileLoop({ b.compare(index, with: end, using: .lessThan) }) { b.callFunction(f, withArgs: arguments) b.unary(.PostInc, index) let result = b.callFunction(gc, withArgs: [index]) @@ -30,24 +29,26 @@ fileprivate let StressXSGC = CodeGenerator("StressXSGC", inputs: .required(.func } } -fileprivate let StressXSMemoryFail = CodeGenerator("StressXSMemoryFail", inputs: .required(.function())) { b, f in +private let StressXSMemoryFail = CodeGenerator("StressXSMemoryFail", inputs: .required(.function())) +{ b, f in let arguments = b.randomArguments(forCalling: f) let index = b.loadInt(1) - let max = b.loadInt(1000000) + let max = b.loadInt(1_000_000) let memoryFail = b.createNamedVariable(forBuiltin: "memoryFail") - b.callFunction(memoryFail, withArgs: [max]) // count how many allocations this function makes + b.callFunction(memoryFail, withArgs: [max]) // count how many allocations this function makes b.callFunction(f, withArgs: arguments) var end = b.callFunction(memoryFail, withArgs: [index]) end = b.binary(max, end, with: .Sub) - b.buildWhileLoop({b.compare(index, with: end, using: .lessThan)}) { + b.buildWhileLoop({ b.compare(index, with: end, using: .lessThan) }) { b.callFunction(f, withArgs: arguments) b.unary(.PostInc, index) b.callFunction(memoryFail, withArgs: [index]) } } -fileprivate let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { b, obj in +private let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .required(.object())) { + b, obj in let harden = b.createNamedVariable(forBuiltin: "harden") if probability(0.05) { @@ -57,20 +58,20 @@ fileprivate let HardenGenerator = CodeGenerator("HardenGenerator", inputs: .requ b.callFunction(harden, withArgs: [obj]) } -fileprivate let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in +private let ModuleSourceGenerator = CodeGenerator("ModuleSourceGenerator") { b in let moduleSourceConstructor = b.createNamedVariable(forBuiltin: "ModuleSource") - let code = b.buildCodeString() { + let code = b.buildCodeString { b.build(n: 5) } b.construct(moduleSourceConstructor, withArgs: [code]) } -fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b in +private let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b in let compartmentConstructor = b.createNamedVariable(forBuiltin: "Compartment") - var endowments = [String: Variable]() // may be used as endowments argument or globalLexicals + var endowments = [String: Variable]() // may be used as endowments argument or globalLexicals var moduleMap = [String: Variable]() var options = [String: Variable]() @@ -80,7 +81,7 @@ fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b } var endowmentsObject = b.createObject(with: endowments) - // to do: populate moduleMap + // to do: populate moduleMap let moduleMapObject = b.createObject(with: moduleMap) let resolveHook = b.buildPlainFunction(with: .parameters(n: 2)) { _ in b.build(n: 5) @@ -106,17 +107,18 @@ fileprivate let CompartmentGenerator = CodeGenerator("CompartmentGenerator") { b } let optionsObject = b.createObject(with: options) - let compartment = b.construct(compartmentConstructor, withArgs: [endowmentsObject, moduleMapObject, optionsObject]) + let compartment = b.construct( + compartmentConstructor, withArgs: [endowmentsObject, moduleMapObject, optionsObject]) if probability(0.5) { - let code = b.buildCodeString() { + let code = b.buildCodeString { b.build(n: 5) } b.callMethod("evaluate", on: compartment, withArgs: [code]) } } -fileprivate let UnicodeStringGenerator = CodeGenerator("UnicodeStringGenerator") { b in +private let UnicodeStringGenerator = CodeGenerator("UnicodeStringGenerator") { b in var s = "" for _ in 0.. 'X'", - "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", - "() => 42" + "'X'", + "'$1$2$3'", + "'$$$&$`$\\'$1'", + "() => 'X'", + "(arg0, arg1, arg2, arg3, arg4) => arg0 + arg1 + arg2 + arg3 + arg4", + "() => 42", ] let lastIndices = [ - "undefined", "-1", "0", - "1", "2", "3", - "4", "5", "6", - "7", "8", "9", - "50", "4294967296", "2147483647", - "2147483648", "NaN", "Not a Number" + "undefined", "-1", "0", + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", + "50", "4294967296", "2147483647", + "2147483648", "NaN", "Not a Number", ] let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -177,46 +181,61 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in let resultVar = b.loadNull() - b.buildTryCatchFinally(tryBody: { - let symbol = b.createNamedVariable(forBuiltin: "Symbol") - withEqualProbability({ - let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("match", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("replace", of: symbol) - let replacement = withEqualProbability({ - b.loadString(b.randomString()) - }, { - b.loadString(chooseUniform(from: replacementCandidates)) - }) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar, replacement]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("search", of: symbol) - let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) - }, { - let prop = b.getProperty("split", of: symbol) - let randomSplitLimit = withEqualProbability({ - "undefined" - }, { - "'not a number'" - }, { - String(b.randomInt()) - }) - let limit = b.loadString(randomSplitLimit) - let res = b.callComputedMethod(symbol, on: regExpVar, withArgs: [subjectVar, limit]) - b.reassign(variable: resultVar, value: res) - }, { - let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) - b.reassign(variable: resultVar, value: res) + b.buildTryCatchFinally( + tryBody: { + let symbol = b.createNamedVariable(forBuiltin: "Symbol") + withEqualProbability( + { + let res = b.callMethod("exec", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("match", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("replace", of: symbol) + let replacement = withEqualProbability( + { + b.loadString(b.randomString()) + }, + { + b.loadString(chooseUniform(from: replacementCandidates)) + }) + let res = b.callComputedMethod( + prop, on: regExpVar, withArgs: [subjectVar, replacement]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("search", of: symbol) + let res = b.callComputedMethod(prop, on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }, + { + let prop = b.getProperty("split", of: symbol) + let randomSplitLimit = withEqualProbability( + { + "undefined" + }, + { + "'not a number'" + }, + { + String(b.randomInt()) + }) + let limit = b.loadString(randomSplitLimit) + let res = b.callComputedMethod( + symbol, on: regExpVar, withArgs: [subjectVar, limit]) + b.reassign(variable: resultVar, value: res) + }, + { + let res = b.callMethod("test", on: regExpVar, withArgs: [subjectVar]) + b.reassign(variable: resultVar, value: res) + }) + }, + catchBody: { _ in }) - }, catchBody: { _ in - }) b.build(n: 7) @@ -228,15 +247,23 @@ fileprivate let RegExpFuzzer = ProgramTemplate("RegExpFuzzer") { b in b.build(n: 15) } -public extension ILType { +extension ILType { /// Type of a JavaScript Compartment object. - static let jsCompartment = ILType.object(ofGroup: "Compartment", withProperties: ["globalThis"], withMethods: ["evaluate", "import", "importNow" /* , "module" */]) + public static let jsCompartment = ILType.object( + ofGroup: "Compartment", withProperties: ["globalThis"], + withMethods: ["evaluate", "import", "importNow" /* , "module" */]) - static let jsCompartmentConstructor = ILType.constructor([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartment) + .object(ofGroup: "CompartmentConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsCompartmentConstructor = + ILType.constructor([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartment) + + .object(ofGroup: "CompartmentConstructor", withProperties: ["prototype"], withMethods: []) - static let jsModuleSource = ILType.object(ofGroup: "ModuleSource", withProperties: ["bindings", "needsImport", "needsImportMeta"]) + public static let jsModuleSource = ILType.object( + ofGroup: "ModuleSource", withProperties: ["bindings", "needsImport", "needsImportMeta"]) - static let jsModuleSourceConstructor = ILType.constructor([.opt(.string)] => .jsModuleSource) + .object(ofGroup: "ModuleSourceConstructor", withProperties: ["prototype"], withMethods: []) + public static let jsModuleSourceConstructor = + ILType.constructor([.opt(.string)] => .jsModuleSource) + + .object( + ofGroup: "ModuleSourceConstructor", withProperties: ["prototype"], withMethods: []) } /// Object group modelling JavaScript compartments. @@ -244,13 +271,13 @@ let jsCompartments = ObjectGroup( name: "Compartment", instanceType: .jsCompartment, properties: [ - "globalThis" : .object() + "globalThis": .object() ], methods: [ //@@ import/importNow can accept more than strings - "import" : [.string] => .jsPromise, - "importNow" : [.string] => .jsAnything, + "import": [.string] => .jsPromise, + "importNow": [.string] => .jsAnything, // "module" : [.opt(.string)] => .object(), (currently unavailable) - "evaluate" : [.string] => .jsAnything, + "evaluate": [.string] => .jsAnything, ] ) @@ -258,7 +285,7 @@ let jsCompartmentConstructor = ObjectGroup( name: "CompartmentConstructor", instanceType: .jsCompartmentConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) @@ -268,9 +295,9 @@ let jsModuleSources = ObjectGroup( name: "ModuleSource", instanceType: .jsModuleSource, properties: [ - "bindings" : .object(), - "needsImport" : .object(), - "needsImportMeta" : .object(), + "bindings": .object(), + "needsImport": .object(), + "needsImportMeta": .object(), ], methods: [:] ) @@ -279,7 +306,7 @@ let jsModuleSourceConstructor = ObjectGroup( name: "ModuleSourceConstructor", instanceType: .jsModuleSourceConstructor, properties: [ - "prototype" : .object() + "prototype": .object() ], methods: [:] ) @@ -291,21 +318,23 @@ let xsProfile = Profile( processArgsReference: nil, - processEnv: ["UBSAN_OPTIONS":"handle_segv=0:symbolize=1:print_stacktrace=1:silence_unsigned_overflow=1", - "ASAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", - "MSAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", - "MSAN_SYMBOLIZER_PATH": "/usr/bin/llvm-symbolizer"], + processEnv: [ + "UBSAN_OPTIONS": "handle_segv=0:symbolize=1:print_stacktrace=1:silence_unsigned_overflow=1", + "ASAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", + "MSAN_OPTIONS": "handle_segv=0:abort_on_error=1:symbolize=1", + "MSAN_SYMBOLIZER_PATH": "/usr/bin/llvm-symbolizer", + ], maxExecsBeforeRespawn: 1000, timeout: Timeout.value(250), codePrefix: """ - """, + """, codeSuffix: """ - gc(); - """, + gc(); + """, ecmaVersion: ECMAScriptVersion.es6, @@ -320,17 +349,17 @@ let xsProfile = Profile( ], additionalCodeGenerators: [ - (StressXSMemoryFail, 5), - (StressXSGC, 5), - (HardenGenerator, 5), - (CompartmentGenerator, 5), - (CompartmentEvaluateGenerator, 5), - (UnicodeStringGenerator, 2), - (ModuleSourceGenerator, 3), + (StressXSMemoryFail, 5), + (StressXSGC, 5), + (HardenGenerator, 5), + (CompartmentGenerator, 5), + (CompartmentEvaluateGenerator, 5), + (UnicodeStringGenerator, 2), + (ModuleSourceGenerator, 3), ], additionalProgramTemplates: WeightedList([ - (RegExpFuzzer, 1), + (RegExpFuzzer, 1) ]), disabledCodeGenerators: [], @@ -338,20 +367,23 @@ let xsProfile = Profile( disabledMutators: [], additionalBuiltins: [ - "gc" : .function([] => .undefined), - "memoryFail" : .function([.number] => .number), - "print" : .function([.string] => .undefined), + "gc": .function([] => .undefined), + "memoryFail": .function([.number] => .number), + "print": .function([.string] => .undefined), // hardened javascript - "Compartment" : .function([.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartmentConstructor), - "ModuleSource" : .function([.opt(.string)] => .jsModuleSourceConstructor), - "harden" : .function([.object()] => .object()), - "lockdown" : .function([] => .undefined) , - "petrify" : .function([.jsAnything] => .jsAnything), - "mutabilities" : .function([.object()] => .object()) + "Compartment": .function( + [.opt(.object()), .opt(.object()), .opt(.object())] => .jsCompartmentConstructor), + "ModuleSource": .function([.opt(.string)] => .jsModuleSourceConstructor), + "harden": .function([.object()] => .object()), + "lockdown": .function([] => .undefined), + "petrify": .function([.jsAnything] => .jsAnything), + "mutabilities": .function([.object()] => .object()), ], - additionalObjectGroups: [jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor], + additionalObjectGroups: [ + jsCompartments, jsCompartmentConstructor, jsModuleSources, jsModuleSourceConstructor, + ], additionalEnumerations: [], diff --git a/Sources/Fuzzilli/Protobuf/ProtoUtils.swift b/Sources/Fuzzilli/Protobuf/ProtoUtils.swift index 488e43639..0852e154f 100644 --- a/Sources/Fuzzilli/Protobuf/ProtoUtils.swift +++ b/Sources/Fuzzilli/Protobuf/ProtoUtils.swift @@ -71,7 +71,8 @@ class ProtoCache { typealias OperationCache = ProtoCache -public func encodeProtobufCorpus(_ programs: T) throws -> Data where T.Element == Program { +public func encodeProtobufCorpus(_ programs: T) throws -> Data +where T.Element == Program { // This does streaming serialization to keep memory usage as low as possible. // Also, this uses the operation compression feature of our protobuf representation: // when the same operation occurs multiple times in the corpus, every subsequent @@ -99,19 +100,21 @@ public func encodeProtobufCorpus(_ programs: T) throws -> Data wh return buf } -public func decodeProtobufCorpus(_ buffer: Data) throws -> [Program]{ +public func decodeProtobufCorpus(_ buffer: Data) throws -> [Program] { let opCache = OperationCache.forDecoding() var offset = buffer.startIndex var newPrograms = [Program]() while offset + 4 <= buffer.endIndex { - let value = buffer.withUnsafeBytes { $0.load(fromByteOffset: offset - buffer.startIndex, as: UInt32.self) } + let value = buffer.withUnsafeBytes { + $0.load(fromByteOffset: offset - buffer.startIndex, as: UInt32.self) + } let size = Int(UInt32(littleEndian: value)) offset += 4 guard offset + size <= buffer.endIndex else { throw FuzzilliError.corpusImportError("Serialized corpus appears to be corrupted") } - let data = buffer.subdata(in: offset.. UnsafeMutablePointer?> { let buffer = UnsafeMutablePointer?>.allocate(capacity: array.count + 1) for (i, str) in array.enumerated() { -#if os(Windows) - buffer[i] = UnsafePointer(str.withCString(_strdup)) -#else - buffer[i] = UnsafePointer(str.withCString(strdup)) -#endif + #if os(Windows) + buffer[i] = UnsafePointer(str.withCString(_strdup)) + #else + buffer[i] = UnsafePointer(str.withCString(strdup)) + #endif } buffer[array.count] = nil return buffer } func freeCArray(_ array: UnsafeMutablePointer?>, numElems: Int) { - for arg in array ..< array + numElems { + for arg in array.. Result { - return try execute(executablePath, withInput: prefix + script.data(using: .utf8)!, withArguments: self.arguments, withEnv: self.env, timeout: timeout) + public func executeScript(_ script: String, withTimeout timeout: TimeInterval? = nil) throws + -> Result + { + return try execute( + executablePath, withInput: prefix + script.data(using: .utf8)!, + withArguments: self.arguments, withEnv: self.env, timeout: timeout) } /// Executes the JavaScript script at the specified path using the configured engine and returns the stdout. - public func executeScript(at url: URL, withTimeout timeout: TimeInterval? = nil) throws -> Result { + public func executeScript(at url: URL, withTimeout timeout: TimeInterval? = nil) throws + -> Result + { let script = try Data(contentsOf: url) - return try execute(executablePath, withInput: prefix + script, withArguments: self.arguments, withEnv: self.env, timeout: timeout) + return try execute( + executablePath, withInput: prefix + script, withArguments: self.arguments, + withEnv: self.env, timeout: timeout) } - func execute(_ path: String, withInput input: Data = Data(), withArguments arguments: [String] = [], withEnv env: [(String, String)] = [], timeout maybeTimeout: TimeInterval? = nil) throws -> Result { + func execute( + _ path: String, withInput input: Data = Data(), withArguments arguments: [String] = [], + withEnv env: [(String, String)] = [], timeout maybeTimeout: TimeInterval? = nil + ) throws -> Result { let inputPipe = Pipe() let outputPipe = Pipe() let errorPipe = Pipe() @@ -115,14 +133,15 @@ public class JavaScriptExecutor { // Write input into file. let url = FileManager.default.temporaryDirectory - .appendingPathComponent(UUID().uuidString) - .appendingPathExtension("js") + .appendingPathComponent(UUID().uuidString) + .appendingPathExtension("js") try input.write(to: url) // Close stdin try inputPipe.fileHandleForWriting.close() - let environment = ProcessInfo.processInfo.environment.merging(env, uniquingKeysWith: { _, new in new }) + let environment = ProcessInfo.processInfo.environment.merging( + env, uniquingKeysWith: { _, new in new }) // Execute the subprocess. let task = Process() @@ -145,19 +164,22 @@ public class JavaScriptExecutor { } runningCheck: if task.isRunning { timedOut = true -#if os(Windows) - guard let processHandle = OpenProcess(DWORD(PROCESS_TERMINATE), false, DWORD(task.processIdentifier)) else { - // Fall back to built-in termination - task.terminate() - break runningCheck - } - defer { CloseHandle(processHandle) } - TerminateProcess(processHandle, 1) -#else - // Properly kill the task now with SIGKILL as it might be stuck - // in Wasm, where SIGTERM is not enough. - kill(task.processIdentifier, SIGKILL) -#endif /* os(Windows) */ + #if os(Windows) + guard + let processHandle = OpenProcess( + DWORD(PROCESS_TERMINATE), false, DWORD(task.processIdentifier)) + else { + // Fall back to built-in termination + task.terminate() + break runningCheck + } + defer { CloseHandle(processHandle) } + TerminateProcess(processHandle, 1) + #else + // Properly kill the task now with SIGKILL as it might be stuck + // in Wasm, where SIGTERM is not enough. + kill(task.processIdentifier, SIGKILL) + #endif /* os(Windows) */ } } @@ -167,9 +189,11 @@ public class JavaScriptExecutor { try FileManager.default.removeItem(at: url) // Fetch and return the output. - var output = String(data: outputData.currentData, encoding: .utf8) + var output = + String(data: outputData.currentData, encoding: .utf8) ?? "Process output is not valid UTF-8" - let error = String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) + let error = + String(data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? "Process stderr is not valid UTF-8" let outcome: Result.Outcome if timedOut { diff --git a/Sources/Fuzzilli/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift index bd524bcf2..91d118707 100644 --- a/Sources/Fuzzilli/Util/MockFuzzer.swift +++ b/Sources/Fuzzilli/Util/MockFuzzer.swift @@ -29,11 +29,12 @@ class MockScriptRunner: ScriptRunner { var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { - return MockExecution(outcome: .succeeded, - stdout: "", - stderr: "", - fuzzout: "", - execTime: TimeInterval(0.1)) + return MockExecution( + outcome: .succeeded, + stdout: "", + stderr: "", + fuzzout: "", + execTime: TimeInterval(0.1)) } func setEnvironmentVariable(_ key: String, to value: String) {} @@ -74,7 +75,9 @@ class MockEvaluator: ProgramEvaluator { func importState(_ state: Data) {} - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { return nil } @@ -82,7 +85,14 @@ class MockEvaluator: ProgramEvaluator { } /// Create a fuzzer instance usable for testing. -public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engine maybeEngine: FuzzEngine? = nil, runner maybeRunner: ScriptRunner? = nil, environment maybeEnvironment: JavaScriptEnvironment? = nil, evaluator maybeEvaluator: ProgramEvaluator? = nil, corpus maybeCorpus: Corpus? = nil, codeGenerators additionalCodeGenerators : [(CodeGenerator, Int)] = [], queue: DispatchQueue? = nil, overwriteGenerators: WeightedList? = nil) -> Fuzzer { +public func makeMockFuzzer( + config maybeConfiguration: Configuration? = nil, engine maybeEngine: FuzzEngine? = nil, + runner maybeRunner: ScriptRunner? = nil, + environment maybeEnvironment: JavaScriptEnvironment? = nil, + evaluator maybeEvaluator: ProgramEvaluator? = nil, corpus maybeCorpus: Corpus? = nil, + codeGenerators additionalCodeGenerators: [(CodeGenerator, Int)] = [], + queue: DispatchQueue? = nil, overwriteGenerators: WeightedList? = nil +) -> Fuzzer { // The configuration of this fuzzer. let configuration = maybeConfiguration ?? Configuration(logLevel: .warning) @@ -91,10 +101,10 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // the mutators to use for this fuzzing engine. let mutators = WeightedList([ - (CodeGenMutator(), 1), - (OperationMutator(), 1), + (CodeGenMutator(), 1), + (OperationMutator(), 1), (InputMutator(typeAwareness: .loose), 1), - (CombineMutator(), 1), + (CombineMutator(), 1), ]) let engine = maybeEngine ?? MutationEngine(numConsecutiveMutations: 5) @@ -106,7 +116,9 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi let environment = maybeEnvironment ?? JavaScriptEnvironment() // A lifter to translate FuzzIL programs to JavaScript. - let lifter = JavaScriptLifter(prefix: "", suffix: "", ecmaVersion: .es6, environment: environment, alwaysEmitVariables: configuration.forDifferentialFuzzing) + let lifter = JavaScriptLifter( + prefix: "", suffix: "", ecmaVersion: .es6, environment: environment, + alwaysEmitVariables: configuration.forDifferentialFuzzing) // Corpus managing interesting programs that have been found during fuzzing. let corpus = maybeCorpus ?? BasicCorpus(minSize: 1000, maxSize: 2000, minMutationsPerSample: 5) @@ -115,33 +127,38 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi let minimizer = Minimizer() // Use all builtin CodeGenerators - let codeGenerators = overwriteGenerators ?? WeightedList( - (CodeGenerators + WasmCodeGenerators).map { - guard let weight = codeGeneratorWeights[$0.name] else { - fatalError("Missing weight for CodeGenerator \($0.name) in CodeGeneratorWeights.swift") - } - return ($0, weight) - } + additionalCodeGenerators) + let codeGenerators = + overwriteGenerators + ?? WeightedList( + (CodeGenerators + WasmCodeGenerators).map { + guard let weight = codeGeneratorWeights[$0.name] else { + fatalError( + "Missing weight for CodeGenerator \($0.name) in CodeGeneratorWeights.swift") + } + return ($0, weight) + } + additionalCodeGenerators) // Use all builtin ProgramTemplates - let programTemplates = WeightedList(ProgramTemplates.map { return ($0, programTemplateWeights[$0.name]!) }) + let programTemplates = WeightedList( + ProgramTemplates.map { return ($0, programTemplateWeights[$0.name]!) }) // Construct the fuzzer instance. - let fuzzer = Fuzzer(configuration: configuration, - scriptRunner: runner, - referenceScriptRunner: nil, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, - programTemplates: programTemplates, - evaluator: evaluator, - environment: environment, - lifter: lifter, - corpus: corpus, - minimizer: minimizer, - queue: queue ?? DispatchQueue.main) - - let initializeFuzzer = { + let fuzzer = Fuzzer( + configuration: configuration, + scriptRunner: runner, + referenceScriptRunner: nil, + engine: engine, + mutators: mutators, + codeGenerators: codeGenerators, + programTemplates: programTemplates, + evaluator: evaluator, + environment: environment, + lifter: lifter, + corpus: corpus, + minimizer: minimizer, + queue: queue ?? DispatchQueue.main) + + let initializeFuzzer = { fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in print("[\(ev.label)] \(ev.message)") } @@ -151,7 +168,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // If a DispatchQueue was provided by the caller, initialize the fuzzer // there. Otherwise initialize it directly. if let queue { - queue.sync {initializeFuzzer()} + queue.sync { initializeFuzzer() } } else { dispatchPrecondition(condition: .onQueue(DispatchQueue.main)) initializeFuzzer() diff --git a/Sources/Fuzzilli/Util/Random.swift b/Sources/Fuzzilli/Util/Random.swift index 9b0a7eae6..097790d6f 100644 --- a/Sources/Fuzzilli/Util/Random.swift +++ b/Sources/Fuzzilli/Util/Random.swift @@ -43,9 +43,11 @@ extension Int { extension String { // Returns a random string of the specified length. - public static func random(ofLength length: Int, - withCharSet charSet: [Character] = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - ) -> String { + public static func random( + ofLength length: Int, + withCharSet charSet: [Character] = Array( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + ) -> String { var s = "" for _ in 0..: Sequence { } public func hasHoles() -> Bool { - return elements.contains(where: {$0 == nil}) + return elements.contains(where: { $0 == nil }) } public mutating func removeValue(forKey variable: Variable) { diff --git a/Sources/Fuzzilli/Util/VariableSet.swift b/Sources/Fuzzilli/Util/VariableSet.swift index aae322ef4..98131404a 100644 --- a/Sources/Fuzzilli/Util/VariableSet.swift +++ b/Sources/Fuzzilli/Util/VariableSet.swift @@ -222,7 +222,7 @@ public struct VariableSet: Hashable, Codable, Sequence { } /// Returns true if the two given sets are equal. - public static func ==(lhs: VariableSet, rhs: VariableSet) -> Bool { + public static func == (lhs: VariableSet, rhs: VariableSet) -> Bool { return lhs.words == rhs.words } diff --git a/Sources/FuzzilliCli/TerminalUI.swift b/Sources/FuzzilliCli/TerminalUI.swift index 7d8682088..a3c7e9fb0 100644 --- a/Sources/FuzzilliCli/TerminalUI.swift +++ b/Sources/FuzzilliCli/TerminalUI.swift @@ -17,8 +17,8 @@ import Fuzzilli let Seconds = 1.0 let Minutes = 60.0 * Seconds -let Hours = 60.0 * Minutes -let Days = 24.0 * Hours +let Hours = 60.0 * Minutes +let Days = 24.0 * Hours // A very basic terminal UI. class TerminalUI { @@ -44,11 +44,15 @@ class TerminalUI { fuzzer.registerEventListener(for: fuzzer.events.Log) { ev in let color = self.colorForLevel[ev.level]! if ev.origin == fuzzer.id { - print("\u{001B}[0;\(color.rawValue)m[\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m") + print( + "\u{001B}[0;\(color.rawValue)m[\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m" + ) } else { // Mark message as coming from a worker by including its id let shortId = ev.origin.uuidString.split(separator: "-")[0] - print("\u{001B}[0;\(color.rawValue)m[\(shortId):\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m") + print( + "\u{001B}[0;\(color.rawValue)m[\(shortId):\(ev.label)] \(ev.message)\u{001B}[0;\(Color.reset.rawValue)m" + ) } } @@ -74,7 +78,8 @@ class TerminalUI { } } - fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { program, origin in + fuzzer.registerEventListener(for: fuzzer.events.InterestingProgramFound) { + program, origin in self.lastInterestingProgramFound = Date() if self.printNextInterestingProgram { print("--------- Randomly Sampled Interesting Program -----------") @@ -125,40 +130,43 @@ class TerminalUI { let timeSinceLastInterestingProgram = -lastInterestingProgramFound.timeIntervalSinceNow - let maybeAvgCorpusSize = stats.numChildNodes > 0 ? " (global average: \(Int(stats.avgCorpusSize)))" : "" + let maybeAvgCorpusSize = + stats.numChildNodes > 0 ? " (global average: \(Int(stats.avgCorpusSize)))" : "" if let tag = fuzzer.config.tag { print("Fuzzer Statistics (tag: \(tag))") } else { print("Fuzzer Statistics") } - let differentialsLine = fuzzer.isDifferentialFuzzing + let differentialsLine = + fuzzer.isDifferentialFuzzing ? "\nDifferentials Found: \(stats.differentialSamples)" : "" - print(""" - ----------------- - Fuzzer state: \(state) - Uptime: \(formatTimeInterval(fuzzer.uptime())) - Total Samples: \(stats.totalSamples) - Interesting Samples Found: \(stats.interestingSamples) - Last Interesting Sample: \(formatTimeInterval(timeSinceLastInterestingProgram)) - Valid Samples Found: \(stats.validSamples) - Corpus Size: \(fuzzer.corpus.size)\(maybeAvgCorpusSize) - Correctness Rate: \(String(format: "%.2f%%", stats.correctnessRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallCorrectnessRate * 100))) - Timeout Rate: \(String(format: "%.2f%%", stats.timeoutRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallTimeoutRate * 100))) - Crashes Found: \(stats.crashingSamples)\(differentialsLine) - Timeouts Hit: \(stats.timedOutSamples) - Coverage: \(String(format: "%.2f%%", stats.coverage * 100)) - Avg. program size: \(String(format: "%.2f", stats.avgProgramSize)) - Avg. corpus program size: \(String(format: "%.2f", stats.avgCorpusProgramSize)) - Avg. program execution time: \(Int(stats.avgExecutionTime * 1000))ms - Connected nodes: \(stats.numChildNodes) - Execs / Second: \(String(format: "%.2f", stats.execsPerSecond)) - Fuzzer Overhead: \(String(format: "%.2f", stats.fuzzerOverhead * 100))% - Minimization Overhead: \(String(format: "%.2f", stats.minimizationOverhead * 100))% - Total Execs: \(stats.totalExecs) - """) + print( + """ + ----------------- + Fuzzer state: \(state) + Uptime: \(formatTimeInterval(fuzzer.uptime())) + Total Samples: \(stats.totalSamples) + Interesting Samples Found: \(stats.interestingSamples) + Last Interesting Sample: \(formatTimeInterval(timeSinceLastInterestingProgram)) + Valid Samples Found: \(stats.validSamples) + Corpus Size: \(fuzzer.corpus.size)\(maybeAvgCorpusSize) + Correctness Rate: \(String(format: "%.2f%%", stats.correctnessRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallCorrectnessRate * 100))) + Timeout Rate: \(String(format: "%.2f%%", stats.timeoutRate * 100)) (overall: \(String(format: "%.2f%%", stats.overallTimeoutRate * 100))) + Crashes Found: \(stats.crashingSamples)\(differentialsLine) + Timeouts Hit: \(stats.timedOutSamples) + Coverage: \(String(format: "%.2f%%", stats.coverage * 100)) + Avg. program size: \(String(format: "%.2f", stats.avgProgramSize)) + Avg. corpus program size: \(String(format: "%.2f", stats.avgCorpusProgramSize)) + Avg. program execution time: \(Int(stats.avgExecutionTime * 1000))ms + Connected nodes: \(stats.numChildNodes) + Execs / Second: \(String(format: "%.2f", stats.execsPerSecond)) + Fuzzer Overhead: \(String(format: "%.2f", stats.fuzzerOverhead * 100))% + Minimization Overhead: \(String(format: "%.2f", stats.minimizationOverhead * 100))% + Total Execs: \(stats.totalExecs) + """) } private func formatTimeInterval(_ interval: TimeInterval) -> String { @@ -170,23 +178,23 @@ class TerminalUI { } private enum Color: Int { - case reset = 0 - case black = 30 - case red = 31 - case green = 32 - case yellow = 33 - case blue = 34 + case reset = 0 + case black = 30 + case red = 31 + case green = 32 + case yellow = 33 + case blue = 34 case magenta = 35 - case cyan = 36 - case white = 37 + case cyan = 36 + case white = 37 } // The color with which to print log entries. private let colorForLevel: [LogLevel: Color] = [ .verbose: .cyan, - .info: .white, + .info: .white, .warning: .yellow, - .error: .red, - .fatal: .magenta + .error: .red, + .fatal: .magenta, ] } diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index f49dde3b6..8a95f081a 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -21,88 +21,89 @@ import Fuzzilli let args = Arguments.parse(from: CommandLine.arguments) if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != 1 { - print(""" -Usage: -\(args.programName) [options] --profile= /path/to/jsshell - -Options: - --profile=name : Select one of several preconfigured profiles. - Available profiles: \(profiles.keys). - --jobs=n : Total number of fuzzing jobs. This will start a main instance and n-1 worker instances. - --engine=name : The fuzzing engine to use. Available engines: "mutation" (default), "hybrid", "multi". - Only the mutation engine should be regarded stable at this point. - --corpus=name : The corpus scheduler to use. Available schedulers: "basic" (default), "markov" - --logLevel=level : The log level to use. Valid values: "verbose", "info", "warning", "error", "fatal" (default: "info"). - --maxIterations=n : Run for the specified number of iterations (default: unlimited). - --maxRuntimeInHours=n : Run for the specified number of hours (default: unlimited). - --timeout=n : Timeout in ms after which to interrupt execution of programs (default depends - on the profile). Or provide an interval like --timeout=200,400. The actual - timeout in this interval will be determined by the start-up tests. - --minMutationsPerSample=n : Discard samples from the corpus only after they have been mutated at least this many times (default: 25). - --minCorpusSize=n : Keep at least this many samples in the corpus regardless of the number of times - they have been mutated (default: 1000). - --maxCorpusSize=n : Only allow the corpus to grow to this many samples. Otherwise the oldest samples - will be discarded (default: unlimited). - --markovDropoutRate=p : Rate at which low edge samples are not selected, in the Markov Corpus Scheduler, - per round of sample selection. Used to ensure diversity between fuzzer instances - (default: 0.10) - --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). - --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions - regardless of whether they are needed to trigger the interesting behaviour or not. - See Minimizer.swift for an overview of this feature (default: 0.0). - --storagePath=path : Path at which to store output files (crashes, corpus, etc.) to. - --resume : If storage path exists, import the programs from the corpus/ subdirectory - --overwrite : If storage path exists, delete all data in it and start a fresh fuzzing session - --staticCorpus : In this mode, we will just mutate the existing corpus and look for crashes. - No new samples are added to the corpus, regardless of their coverage. - This can be used to find different manifestations of bugs and - also to try and reproduce a flaky crash or turn it into a deterministic one. - --exportStatistics : If enabled, fuzzing statistics will be collected and saved to disk in regular intervals. - Requires --storagePath. - --statisticsExportInterval=n : Interval in minutes for saving fuzzing statistics to disk (default: 10). - Requires --exportStatistics. - --importCorpus=path : Imports an existing corpus of FuzzIL programs to build the initial corpus for fuzzing. - The provided path must point to a directory, and all .fzil files in that directory will be imported. - --corpusImportMode=mode : The corpus import mode. Possible values: - default : Keep samples that are interesting (e.g. those that increase code coverage) and minimize them (default). - full : Keep all samples that execute successfully without minimization. - unminimized : Keep samples that are interesting but do not minimize them. - - --instanceType=type : Specifies the instance type for distributed fuzzing over a network. - In distributed fuzzing, instances form a tree hierarchy, so the possible values are: - root: Accept connections from other instances. - leaf: Connect to a parent instance and synchronize with it. - intermediate: Connect to a parent instance and synchronize with it but also accept incoming connections. - standalone: Don't participate in distributed fuzzing (default). - Note: it is *highly* recommended to run distributed fuzzing in an isolated network! - --bindTo=host:port : When running as a root or intermediate node, bind to this address (default: 127.0.0.1:1337). - --connectTo=host:port : When running as a leaf or intermediate node, connect to the parent instance at this address (default: 127.0.0.1:1337). - --corpusSyncMode=mode : How the corpus is synchronized during distributed fuzzing. Possible values: - up: newly discovered corpus samples are only sent to parent nodes but - not to chjild nodes. This way, the child nodes are forced to generate their - own corpus, which may lead to more diverse samples overall. However, parent - instances will still have the full corpus. - down: newly discovered corpus samples are only sent to child nodes but not to - parent nodes. This may make sense when importing a corpus in the parent. - full (default): newly discovered corpus samples are sent in both direction. This is the - default behaviour and will generally cause all instances in the network - to have very roughly the same corpus. - none : corpus samples are not shared with any other instances in the network. - Note: thread workers (--jobs=X) always fully synchronize their corpus. - --diagnostics : Enable saving of programs that failed or timed-out during execution. Also tracks - executions on the current REPRL instance. - --swarmTesting : Enable Swarm Testing mode. The fuzzer will choose random weights for the code generators per process. - --inspect : Enable inspection for generated programs. When enabled, additional .fuzzil.history files are written - to disk for every interesting or crashing program. These describe in detail how the program was generated - through mutations, code generation, and minimization. - --argumentRandomization : Enable JS engine argument randomization - --additionalArguments=args : Pass additional arguments to the JS engine. If multiple arguments are passed, they should be separated by a comma. - --tag=tag : Optional string tag associated with this instance which will be stored in the settings.json file as well as in crashing samples. - This can for example be used to remember the target revision that is being fuzzed. - --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). - --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. - -""") + print( + """ + Usage: + \(args.programName) [options] --profile= /path/to/jsshell + + Options: + --profile=name : Select one of several preconfigured profiles. + Available profiles: \(profiles.keys). + --jobs=n : Total number of fuzzing jobs. This will start a main instance and n-1 worker instances. + --engine=name : The fuzzing engine to use. Available engines: "mutation" (default), "hybrid", "multi". + Only the mutation engine should be regarded stable at this point. + --corpus=name : The corpus scheduler to use. Available schedulers: "basic" (default), "markov" + --logLevel=level : The log level to use. Valid values: "verbose", "info", "warning", "error", "fatal" (default: "info"). + --maxIterations=n : Run for the specified number of iterations (default: unlimited). + --maxRuntimeInHours=n : Run for the specified number of hours (default: unlimited). + --timeout=n : Timeout in ms after which to interrupt execution of programs (default depends + on the profile). Or provide an interval like --timeout=200,400. The actual + timeout in this interval will be determined by the start-up tests. + --minMutationsPerSample=n : Discard samples from the corpus only after they have been mutated at least this many times (default: 25). + --minCorpusSize=n : Keep at least this many samples in the corpus regardless of the number of times + they have been mutated (default: 1000). + --maxCorpusSize=n : Only allow the corpus to grow to this many samples. Otherwise the oldest samples + will be discarded (default: unlimited). + --markovDropoutRate=p : Rate at which low edge samples are not selected, in the Markov Corpus Scheduler, + per round of sample selection. Used to ensure diversity between fuzzer instances + (default: 0.10) + --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). + --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions + regardless of whether they are needed to trigger the interesting behaviour or not. + See Minimizer.swift for an overview of this feature (default: 0.0). + --storagePath=path : Path at which to store output files (crashes, corpus, etc.) to. + --resume : If storage path exists, import the programs from the corpus/ subdirectory + --overwrite : If storage path exists, delete all data in it and start a fresh fuzzing session + --staticCorpus : In this mode, we will just mutate the existing corpus and look for crashes. + No new samples are added to the corpus, regardless of their coverage. + This can be used to find different manifestations of bugs and + also to try and reproduce a flaky crash or turn it into a deterministic one. + --exportStatistics : If enabled, fuzzing statistics will be collected and saved to disk in regular intervals. + Requires --storagePath. + --statisticsExportInterval=n : Interval in minutes for saving fuzzing statistics to disk (default: 10). + Requires --exportStatistics. + --importCorpus=path : Imports an existing corpus of FuzzIL programs to build the initial corpus for fuzzing. + The provided path must point to a directory, and all .fzil files in that directory will be imported. + --corpusImportMode=mode : The corpus import mode. Possible values: + default : Keep samples that are interesting (e.g. those that increase code coverage) and minimize them (default). + full : Keep all samples that execute successfully without minimization. + unminimized : Keep samples that are interesting but do not minimize them. + + --instanceType=type : Specifies the instance type for distributed fuzzing over a network. + In distributed fuzzing, instances form a tree hierarchy, so the possible values are: + root: Accept connections from other instances. + leaf: Connect to a parent instance and synchronize with it. + intermediate: Connect to a parent instance and synchronize with it but also accept incoming connections. + standalone: Don't participate in distributed fuzzing (default). + Note: it is *highly* recommended to run distributed fuzzing in an isolated network! + --bindTo=host:port : When running as a root or intermediate node, bind to this address (default: 127.0.0.1:1337). + --connectTo=host:port : When running as a leaf or intermediate node, connect to the parent instance at this address (default: 127.0.0.1:1337). + --corpusSyncMode=mode : How the corpus is synchronized during distributed fuzzing. Possible values: + up: newly discovered corpus samples are only sent to parent nodes but + not to chjild nodes. This way, the child nodes are forced to generate their + own corpus, which may lead to more diverse samples overall. However, parent + instances will still have the full corpus. + down: newly discovered corpus samples are only sent to child nodes but not to + parent nodes. This may make sense when importing a corpus in the parent. + full (default): newly discovered corpus samples are sent in both direction. This is the + default behaviour and will generally cause all instances in the network + to have very roughly the same corpus. + none : corpus samples are not shared with any other instances in the network. + Note: thread workers (--jobs=X) always fully synchronize their corpus. + --diagnostics : Enable saving of programs that failed or timed-out during execution. Also tracks + executions on the current REPRL instance. + --swarmTesting : Enable Swarm Testing mode. The fuzzer will choose random weights for the code generators per process. + --inspect : Enable inspection for generated programs. When enabled, additional .fuzzil.history files are written + to disk for every interesting or crashing program. These describe in detail how the program was generated + through mutations, code generation, and minimization. + --argumentRandomization : Enable JS engine argument randomization + --additionalArguments=args : Pass additional arguments to the JS engine. If multiple arguments are passed, they should be separated by a comma. + --tag=tag : Optional string tag associated with this instance which will be stored in the settings.json file as well as in crashing samples. + This can for example be used to remember the target revision that is being fuzzed. + --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). + --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + + """) exit(0) } @@ -125,7 +126,9 @@ if let val = args["--profile"], let p = profiles[val] { profileName = val } if profile == nil || profileName == nil { - configError("Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)") + configError( + "Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)" + ) } let numJobs = args.int(for: "--jobs") ?? 1 @@ -159,12 +162,13 @@ let tag = args["--tag"] let enableWasm = args.has("--wasm") let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") -var timeout : Timeout +var timeout: Timeout if let raw_timeout = args.string(for: "--timeout") { if raw_timeout.contains(",") { let parts = raw_timeout.split(separator: ",") guard parts.count == 2 else { - configError("Timeout intervals must be specified by two boundaries, e.g. --timeout=200,400") + configError( + "Timeout intervals must be specified by two boundaries, e.g. --timeout=200,400") } guard let lower = UInt32(parts[0]) else { configError("The lower bound for --timeout must be an integer") @@ -200,7 +204,9 @@ if maxIterations != -1 { exitCondition = .timeFuzzed(Double(maxRuntimeInHours) * Hours) } -let logLevelByName: [String: LogLevel] = ["verbose": .verbose, "info": .info, "warning": .warning, "error": .error, "fatal": .fatal] +let logLevelByName: [String: LogLevel] = [ + "verbose": .verbose, "info": .info, "warning": .warning, "error": .error, "fatal": .fatal, +] guard let logLevel = logLevelByName[logLevelName] else { configError("Invalid log level \(logLevelName)") } @@ -223,9 +229,13 @@ if markovDropoutRate < 0 || markovDropoutRate > 1 { print("The markovDropoutRate must be between 0 and 1") } -if corpusName == "markov" && (args.int(for: "--maxCorpusSize") != nil || args.int(for: "--minCorpusSize") != nil - || args.int(for: "--minMutationsPerSample") != nil ) { - configError("--maxCorpusSize, --minCorpusSize, --minMutationsPerSample are not compatible with the Markov corpus") +if corpusName == "markov" + && (args.int(for: "--maxCorpusSize") != nil || args.int(for: "--minCorpusSize") != nil + || args.int(for: "--minMutationsPerSample") != nil) +{ + configError( + "--maxCorpusSize, --minCorpusSize, --minMutationsPerSample are not compatible with the Markov corpus" + ) } if (resume || overwrite) && storagePath == nil { @@ -239,7 +249,9 @@ if corpusName == "markov" && staticCorpus { if let path = storagePath { let directory = (try? FileManager.default.contentsOfDirectory(atPath: path)) ?? [] if !directory.isEmpty && !resume && !overwrite { - configError("Storage path \(path) exists and is not empty. Please specify either --resume or --overwrite or delete the directory manually") + configError( + "Storage path \(path) exists and is not empty. Please specify either --resume or --overwrite or delete the directory manually" + ) } } @@ -255,7 +267,7 @@ if statisticsExportInterval <= 0 { configError("statisticsExportInterval needs to be > 0") } -if args.has("--statisticsExportInterval") && !exportStatistics { +if args.has("--statisticsExportInterval") && !exportStatistics { configError("statisticsExportInterval requires --exportStatistics") } @@ -271,7 +283,10 @@ if minimizationLimit < 0 || minimizationLimit > 1 { configError("--minimizationLimit must be between 0 and 1") } -let corpusImportModeByName: [String: CorpusImportMode] = ["default": .interestingOnly(shouldMinimize: true), "full": .full, "unminimized": .interestingOnly(shouldMinimize: false)] +let corpusImportModeByName: [String: CorpusImportMode] = [ + "default": .interestingOnly(shouldMinimize: true), "full": .full, + "unminimized": .interestingOnly(shouldMinimize: false), +] guard let corpusImportMode = corpusImportModeByName[corpusImportModeName] else { configError("Invalid corpus import mode \(corpusImportModeName)") } @@ -314,13 +329,17 @@ func parseAddress(_ argName: String) -> (String, UInt16) { var addressToBindTo: (ip: String, port: UInt16) = parseAddress("--bindTo") var addressToConnectTo: (ip: String, port: UInt16) = parseAddress("--connectTo") -let corpusSyncModeByName: [String: CorpusSynchronizationMode] = ["up": .up, "down": .down, "full": .full, "none": .none] +let corpusSyncModeByName: [String: CorpusSynchronizationMode] = [ + "up": .up, "down": .down, "full": .full, "none": .none, +] guard let corpusSyncMode = corpusSyncModeByName[corpusSyncMode] else { configError("Invalid corpus synchronization mode \(corpusSyncMode)") } if staticCorpus && !(resume || isNetworkChildNode || corpusImportPath != nil) { - configError("Static corpus requires this instance to import a corpus or to participate in distributed fuzzing as a child node") + configError( + "Static corpus requires this instance to import a corpus or to participate in distributed fuzzing as a child node" + ) } // Make it easy to detect typos etc. in command line arguments @@ -347,12 +366,12 @@ if swarmTesting { let disableCodeGenerators = Set(profile.disabledCodeGenerators) let additionalCodeGenerators = profile.additionalCodeGenerators -let codeGeneratorsToUse = if enableWasm { - CodeGenerators + WasmCodeGenerators -} else { - CodeGenerators -} - +let codeGeneratorsToUse = + if enableWasm { + CodeGenerators + WasmCodeGenerators + } else { + CodeGenerators + } let standardCodeGenerators: [(CodeGenerator, Int)] = codeGeneratorsToUse.map { guard let weight = codeGeneratorWeights[$0.name] else { @@ -381,7 +400,8 @@ for (generator, var weight) in (additionalCodeGenerators + standardCodeGenerator func loadCorpus(from dirPath: String) -> [Program] { var isDir: ObjCBool = false - guard FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) && isDir.boolValue else { + guard FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir) && isDir.boolValue + else { logger.fatal("Cannot import programs from \(dirPath), it is not a directory!") } @@ -408,12 +428,16 @@ func loadCorpus(from dirPath: String) -> [Program] { // When using multiple jobs, all Fuzzilli instances should use the same arguments for the JS shell, even if // argument randomization is enabled. This way, their corpora are "compatible" and crashes that require // (a subset of) the randomly chosen flags can be reproduced on the main instance. -let jsShellArguments = profile.processArgs(argumentRandomization) + additionalArguments.split(separator: ",").map(String.init) +let jsShellArguments = + profile.processArgs(argumentRandomization) + + additionalArguments.split(separator: ",").map(String.init) logger.info("Using the following arguments for the target engine: \(jsShellArguments)") func makeFuzzer(with configuration: Configuration) -> Fuzzer { let createRunner = { (baseArgs: [String], forReferenceRunner: Bool) -> REPRL in - let finalArgs = baseArgs + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) + let finalArgs = + baseArgs + + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) return REPRL( executable: jsShellPath, processArguments: finalArgs, @@ -436,29 +460,32 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { /// The mutation fuzzer responsible for mutating programs from the corpus and evaluating the outcome. let disabledMutators = Set(profile.disabledMutators) var mutators = WeightedList([ - (ExplorationMutator(), 3), - (CodeGenMutator(), 2), - (SpliceMutator(), 2), - (ProbingMutator(), 2), - (InputMutator(typeAwareness: .loose), 2), - (InputMutator(typeAwareness: .aware), 1), + (ExplorationMutator(), 3), + (CodeGenMutator(), 2), + (SpliceMutator(), 2), + (ProbingMutator(), 2), + (InputMutator(typeAwareness: .loose), 2), + (InputMutator(typeAwareness: .aware), 1), // Can be enabled for experimental use, ConcatMutator is a limited version of CombineMutator // (ConcatMutator(), 1), - (OperationMutator(), 1), - (CombineMutator(), 1), + (OperationMutator(), 1), + (CombineMutator(), 1), // Include this once it does more than just remove unneeded try-catch // (FixupMutator()), 1), ]) let mutatorsSet = Set(mutators.map { $0.name }) if !disabledMutators.isSubset(of: mutatorsSet) { - configError("The following mutators in \(profileName!) profile's disabledMutators do not exist: \(disabledMutators.subtracting(mutatorsSet)). Please check and remove them from your profile configuration.") + configError( + "The following mutators in \(profileName!) profile's disabledMutators do not exist: \(disabledMutators.subtracting(mutatorsSet)). Please check and remove them from your profile configuration." + ) } if !disabledMutators.isEmpty { mutators = mutators.filter({ !disabledMutators.contains($0.name) }) } logger.info("Enabled mutators: \(mutators.map { $0.name })") if mutators.isEmpty { - configError("List of enabled mutators is empty. There needs to be at least one mutator available.") + configError( + "List of enabled mutators is empty. There needs to be at least one mutator available.") } // Engines to execute programs. @@ -479,7 +506,8 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { // to minimize, making the fuzzer less efficient. // For the same reason, we also use a relatively larger iterationsPerEngine value, so that // the MutationEngine can already find most "low-hanging fruits" in its first run. - engine = MultiEngine(engines: engines, initialActive: mutationEngine, iterationsPerEngine: 10000) + engine = MultiEngine( + engines: engines, initialActive: mutationEngine, iterationsPerEngine: 10000) default: engine = MutationEngine(numConsecutiveMutations: consecutiveMutations) } @@ -494,7 +522,9 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { for template in ProgramTemplates { guard let weight = programTemplateWeights[template.name] else { - print("Missing weight for program template \(template.name) in ProgramTemplateWeights.swift") + print( + "Missing weight for program template \(template.name) in ProgramTemplateWeights.swift" + ) exit(-1) } @@ -509,23 +539,32 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { } // The environment containing available builtins, property names, and method names. - let environment = JavaScriptEnvironment(additionalBuiltins: profile.additionalBuiltins, additionalObjectGroups: profile.additionalObjectGroups, additionalEnumerations: profile.additionalEnumerations) + let environment = JavaScriptEnvironment( + additionalBuiltins: profile.additionalBuiltins, + additionalObjectGroups: profile.additionalObjectGroups, + additionalEnumerations: profile.additionalEnumerations) if !profile.additionalBuiltins.isEmpty { - logger.verbose("Loaded additional builtins from profile: \(profile.additionalBuiltins.map { $0.key })") + logger.verbose( + "Loaded additional builtins from profile: \(profile.additionalBuiltins.map { $0.key })") } if !profile.additionalObjectGroups.isEmpty { - logger.verbose("Loaded additional ObjectGroups from profile: \(profile.additionalObjectGroups.map { $0.name })") + logger.verbose( + "Loaded additional ObjectGroups from profile: \(profile.additionalObjectGroups.map { $0.name })" + ) } if !profile.additionalEnumerations.isEmpty { - logger.verbose("Loaded additional Enumerations from profile: \(profile.additionalEnumerations.map { $0.group! })") + logger.verbose( + "Loaded additional Enumerations from profile: \(profile.additionalEnumerations.map { $0.group! })" + ) } // A lifter to translate FuzzIL programs to JavaScript. - let lifter = JavaScriptLifter(prefix: profile.codePrefix, - suffix: profile.codeSuffix, - ecmaVersion: profile.ecmaVersion, - environment: environment, - alwaysEmitVariables: configuration.forDifferentialFuzzing) + let lifter = JavaScriptLifter( + prefix: profile.codePrefix, + suffix: profile.codeSuffix, + ecmaVersion: profile.ecmaVersion, + environment: environment, + alwaysEmitVariables: configuration.forDifferentialFuzzing) // The evaluator to score produced samples. let evaluator = ProgramCoverageEvaluator(runner: runner) @@ -534,9 +573,12 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let corpus: Corpus switch corpusName { case "basic": - corpus = BasicCorpus(minSize: minCorpusSize, maxSize: maxCorpusSize, minMutationsPerSample: minMutationsPerSample) + corpus = BasicCorpus( + minSize: minCorpusSize, maxSize: maxCorpusSize, + minMutationsPerSample: minMutationsPerSample) case "markov": - corpus = MarkovCorpus(covEvaluator: evaluator as ProgramCoverageEvaluator, dropoutRate: markovDropoutRate) + corpus = MarkovCorpus( + covEvaluator: evaluator as ProgramCoverageEvaluator, dropoutRate: markovDropoutRate) default: logger.fatal("Invalid corpus name provided") } @@ -545,35 +587,37 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let minimizer = Minimizer() // Construct the fuzzer instance. - return Fuzzer(configuration: configuration, - scriptRunner: runner, - referenceScriptRunner: referenceRunner, - engine: engine, - mutators: mutators, - codeGenerators: codeGenerators, - programTemplates: programTemplates, - evaluator: evaluator, - environment: environment, - lifter: lifter, - corpus: corpus, - minimizer: minimizer) + return Fuzzer( + configuration: configuration, + scriptRunner: runner, + referenceScriptRunner: referenceRunner, + engine: engine, + mutators: mutators, + codeGenerators: codeGenerators, + programTemplates: programTemplates, + evaluator: evaluator, + environment: environment, + lifter: lifter, + corpus: corpus, + minimizer: minimizer) } // The configuration of the main fuzzer instance. -let mainConfig = Configuration(arguments: CommandLine.arguments, - timeout: timeout.maxTimeout(), - logLevel: logLevel, - startupTests: profile.startupTests, - minimizationLimit: minimizationLimit, - enableDiagnostics: diagnostics, - enableInspection: inspect, - staticCorpus: staticCorpus, - tag: tag, - isWasmEnabled: enableWasm, - storagePath: storagePath, - forDifferentialFuzzing: forDifferentialFuzzing, - instanceId: 0, - dumplingEnabled: profile.isDifferential) +let mainConfig = Configuration( + arguments: CommandLine.arguments, + timeout: timeout.maxTimeout(), + logLevel: logLevel, + startupTests: profile.startupTests, + minimizationLimit: minimizationLimit, + enableDiagnostics: diagnostics, + enableInspection: inspect, + staticCorpus: staticCorpus, + tag: tag, + isWasmEnabled: enableWasm, + storagePath: storagePath, + forDifferentialFuzzing: forDifferentialFuzzing, + instanceId: 0, + dumplingEnabled: profile.isDifferential) let fuzzer = makeFuzzer(with: mainConfig) @@ -607,12 +651,13 @@ fuzzer.sync { if resume, let path = storagePath { // Check if we have an old_corpus directory on disk, this can happen if the user Ctrl-C's during an import. if FileManager.default.fileExists(atPath: path + "/old_corpus") { - logger.info("Corpus import aborted. The old corpus is now in \(path + "/old_corpus").") + logger.info( + "Corpus import aborted. The old corpus is now in \(path + "/old_corpus").") logger.info("You can recover the old corpus by moving it to \(path + "/corpus").") } } let code = reason.toExitCode() - if (code != 0) { + if code != 0 { print("Aborting execution after a fatal error.") } exit(code) @@ -624,10 +669,13 @@ fuzzer.sync { // Move the old corpus to a new directory from which the files will be imported afterwards // before the directory is deleted. if FileManager.default.fileExists(atPath: path + "/old_corpus") { - logger.fatal("Unexpected /old_corpus directory found! Was a previous import aborted? Please check if you need to recover the old corpus manually by moving to to /corpus or deleting it.") + logger.fatal( + "Unexpected /old_corpus directory found! Was a previous import aborted? Please check if you need to recover the old corpus manually by moving to to /corpus or deleting it." + ) } do { - try FileManager.default.moveItem(atPath: path + "/corpus", toPath: path + "/old_corpus") + try FileManager.default.moveItem( + atPath: path + "/corpus", toPath: path + "/old_corpus") } catch { logger.info("Nothing to resume from: \(path)/corpus does not exist") resume = false @@ -637,22 +685,32 @@ fuzzer.sync { try? FileManager.default.removeItem(atPath: path) } else { // The corpus directory must be empty. We already checked this above, so just assert here - let directory = (try? FileManager.default.contentsOfDirectory(atPath: path + "/corpus")) ?? [] + let directory = + (try? FileManager.default.contentsOfDirectory(atPath: path + "/corpus")) ?? [] assert(directory.isEmpty) } - fuzzer.addModule(Storage(for: fuzzer, - storageDir: path, - statisticsExportInterval: exportStatistics ? Double(statisticsExportInterval) * Minutes : nil - )) + fuzzer.addModule( + Storage( + for: fuzzer, + storageDir: path, + statisticsExportInterval: exportStatistics + ? Double(statisticsExportInterval) * Minutes : nil + )) } // Synchronize over the network if requested. if isNetworkParentNode { - fuzzer.addModule(NetworkParent(for: fuzzer, address: addressToBindTo.ip, port: addressToBindTo.port, corpusSynchronizationMode: corpusSyncMode)) + fuzzer.addModule( + NetworkParent( + for: fuzzer, address: addressToBindTo.ip, port: addressToBindTo.port, + corpusSynchronizationMode: corpusSyncMode)) } if isNetworkChildNode { - fuzzer.addModule(NetworkChild(for: fuzzer, hostname: addressToConnectTo.ip, port: addressToConnectTo.port, corpusSynchronizationMode: corpusSyncMode)) + fuzzer.addModule( + NetworkChild( + for: fuzzer, hostname: addressToConnectTo.ip, port: addressToConnectTo.port, + corpusSynchronizationMode: corpusSyncMode)) } // Synchronize with thread workers if requested. @@ -679,8 +737,11 @@ fuzzer.sync { try? FileManager.default.removeItem(atPath: path + "/old_corpus") let duration = Date().timeIntervalSince(start) - let humanReadableDuration = Duration.seconds(duration).formatted(.time(pattern: .hourMinuteSecond)) - logger.info("Corpus import after resume took \((String(format: "%.0f", duration)))s (\(humanReadableDuration)).") + let humanReadableDuration = Duration.seconds(duration).formatted( + .time(pattern: .hourMinuteSecond)) + logger.info( + "Corpus import after resume took \((String(format: "%.0f", duration)))s (\(humanReadableDuration))." + ) } fuzzer.scheduleCorpusImport(corpus, importMode: .interestingOnly(shouldMinimize: false)) // We assume that the programs are already minimized @@ -694,12 +755,17 @@ fuzzer.sync { guard !corpus.isEmpty else { logger.fatal("Cannot import an empty corpus.") } - logger.info("Scheduling corpus import of \(corpus.count) programs with mode \(corpusImportModeName).") + logger.info( + "Scheduling corpus import of \(corpus.count) programs with mode \(corpusImportModeName)." + ) fuzzer.registerEventListener(for: fuzzer.events.CorpusImportComplete) { let duration = Date().timeIntervalSince(start) - let humanReadableDuration = Duration.seconds(duration).formatted(.time(pattern: .hourMinuteSecond)) - logger.info("Existing corpus import took \((String(format: "%.0f", duration)))s (\(humanReadableDuration)).") + let humanReadableDuration = Duration.seconds(duration).formatted( + .time(pattern: .hourMinuteSecond)) + logger.info( + "Existing corpus import took \((String(format: "%.0f", duration)))s (\(humanReadableDuration))." + ) } fuzzer.scheduleCorpusImport(corpus, importMode: corpusImportMode) @@ -716,20 +782,21 @@ fuzzer.sync { for i in 1.. /path/to/jsshell - - Options: - --profile=name : Select one of several preconfigured profiles. - Available profiles: \(profiles.keys). - --no-args : Invoke the shell without any additional arguments from the profile. - """) + print( + """ + Usage: + \(args.programName) [options] --profile= /path/to/jsshell + + Options: + --profile=name : Select one of several preconfigured profiles. + Available profiles: \(profiles.keys). + --no-args : Invoke the shell without any additional arguments from the profile. + """) exit(helpRequested ? 0 : -1) } guard let profileName = args["--profile"], let profile = profiles[profileName] else { - configError("Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)") + configError( + "Please provide a valid profile with --profile=profile_name. Available profiles: \(profiles.keys)" + ) } let jsshellArguments = args.has("--no-args") ? [] : profile.processArgs(false) let runner = JavaScriptExecutor(withExecutablePath: args[0], arguments: jsshellArguments, env: []) let jsProg = """ -(function() { - const maxDepth = 10; // Limit the maximum recursion depth. - const seenObjects = new Map(); - let idCounter = 0; - const flatGraph = {}; - - function walk(currentObj, currentDepth) { - const isObjectOrFunction = currentObj !== null - && (typeof currentObj === 'object' || typeof currentObj === 'function'); - - // Deduplicate objects that appear multiple times in the graph. - if (seenObjects.has(currentObj)) { - return seenObjects.get(currentObj); - } + (function() { + const maxDepth = 10; // Limit the maximum recursion depth. + const seenObjects = new Map(); + let idCounter = 0; + const flatGraph = {}; + + function walk(currentObj, currentDepth) { + const isObjectOrFunction = currentObj !== null + && (typeof currentObj === 'object' || typeof currentObj === 'function'); + + // Deduplicate objects that appear multiple times in the graph. + if (seenObjects.has(currentObj)) { + return seenObjects.get(currentObj); + } - // Store current object for deduplication. - const currentId = idCounter++; - seenObjects.set(currentObj, currentId); - let typeLabel = typeof currentObj; - if (currentObj === null) typeLabel = "null"; - else if (Array.isArray(currentObj)) typeLabel = "array"; + // Store current object for deduplication. + const currentId = idCounter++; + seenObjects.set(currentObj, currentId); + let typeLabel = typeof currentObj; + if (currentObj === null) typeLabel = "null"; + else if (Array.isArray(currentObj)) typeLabel = "array"; - const node = { - type: typeLabel, - properties: {} - }; + const node = { + type: typeLabel, + properties: {} + }; - flatGraph[currentId] = node; + flatGraph[currentId] = node; - if (!isObjectOrFunction) return currentId; - if (currentDepth >= maxDepth) return currentId; + if (!isObjectOrFunction) return currentId; + if (currentDepth >= maxDepth) return currentId; - let properties = []; - try { - properties = Object.getOwnPropertyNames(currentObj); - } catch (e) { - return currentId; - } + let properties = []; + try { + properties = Object.getOwnPropertyNames(currentObj); + } catch (e) { + return currentId; + } - for (const prop of properties) { - let isGetter = typeof(Object.getOwnPropertyDescriptor(currentObj, prop).get) === 'function'; - let value; - try { - value = currentObj[prop]; - } catch (e) { - const errorId = idCounter++; - flatGraph[errorId] = { type: "error", properties: {} }; - node.properties[prop] = { id: errorId, isGetter }; - continue; + for (const prop of properties) { + let isGetter = typeof(Object.getOwnPropertyDescriptor(currentObj, prop).get) === 'function'; + let value; + try { + value = currentObj[prop]; + } catch (e) { + const errorId = idCounter++; + flatGraph[errorId] = { type: "error", properties: {} }; + node.properties[prop] = { id: errorId, isGetter }; + continue; + } + + node.properties[prop] = { + id: walk(value, currentDepth + 1), + isGetter: isGetter + }; + } + return currentId; } - node.properties[prop] = { - id: walk(value, currentDepth + 1), - isGetter: isGetter - }; - } - return currentId; - } - - walk(globalThis, 0); // Start traversal. - const flatJSONData = JSON.stringify(flatGraph, null, 2); - console.log(flatJSONData); -})(); -""" + walk(globalThis, 0); // Start traversal. + const flatJSONData = JSON.stringify(flatGraph, null, 2); + console.log(flatJSONData); + })(); + """ let result = try runner.executeScript(jsProg, withTimeout: 10) guard result.isSuccess else { fatalError("Execution failed: \(result.error)\n\(result.output)") } -let jsEnvironment = JavaScriptEnvironment(additionalBuiltins: profile.additionalBuiltins, additionalObjectGroups: profile.additionalObjectGroups, additionalEnumerations: profile.additionalEnumerations) +let jsEnvironment = JavaScriptEnvironment( + additionalBuiltins: profile.additionalBuiltins, + additionalObjectGroups: profile.additionalObjectGroups, + additionalEnumerations: profile.additionalEnumerations) let jsonString = result.output struct PropertyReference: Codable { @@ -165,12 +171,12 @@ func checkNode(_ nodeId: Int, path: [String]) { } let propertyData = node.properties.filter { - // Each function has a name and a length property. We don't really care about them, so filter - // them out. - (($0.key != "name" && $0.key != "length") || node.type != "function") - // These conversion functions exist on a large amount of objects. The interesting part is - // calling them during type coercion which will happen automatically. - && $0.key != "valueOf" && $0.key != "toString" + // Each function has a name and a length property. We don't really care about them, so filter + // them out. + (($0.key != "name" && $0.key != "length") || node.type != "function") + // These conversion functions exist on a large amount of objects. The interesting part is + // calling them during type coercion which will happen automatically. + && $0.key != "valueOf" && $0.key != "toString" } for (prop, propertyRef) in propertyData { let (childId, isGetter) = (propertyRef.id, propertyRef.isGetter) @@ -186,9 +192,10 @@ func checkNode(_ nodeId: Int, path: [String]) { newPath.append(prop) // Skip paths that are considered uninteresting (e.g. test-only builtins). let pathString = newPath.joined(separator: ".") - let isExcluded = exclusionList[profileName]?.contains { - pathString == $0 || pathString.starts(with: "\($0).") - } ?? false + let isExcluded = + exclusionList[profileName]?.contains { + pathString == $0 || pathString.starts(with: "\($0).") + } ?? false if isExcluded { continue } diff --git a/Sources/REPRLRun/main.swift b/Sources/REPRLRun/main.swift index 41fa352f6..a80b0d2a4 100644 --- a/Sources/REPRLRun/main.swift +++ b/Sources/REPRLRun/main.swift @@ -29,7 +29,6 @@ if CommandLine.arguments.count < 2 { exit(0) } - let ctx = libreprl.reprl_create_context() if ctx == nil { print("Failed to create REPRL context??") @@ -38,7 +37,8 @@ if ctx == nil { let argv = convertToCArray(Array(CommandLine.arguments[1...])) let envp = convertToCArray([]) -if reprl_initialize_context(ctx, argv, envp, /* capture_stdout: */ 1, /* capture stderr: */ 1) != 0 { +if reprl_initialize_context(ctx, argv, envp, /* capture_stdout: */ 1, /* capture stderr: */ 1) != 0 +{ print("Failed to initialize REPRL context: \(String(cString: reprl_get_last_error(ctx)))") } @@ -89,7 +89,9 @@ func runREPRLTests() { if numFailures == 0 { print("All tests passed!") } else { - print("Not all tests passed. That means REPRL support likely isn't properly implemented in the target engine") + print( + "Not all tests passed. That means REPRL support likely isn't properly implemented in the target engine" + ) } } @@ -113,11 +115,15 @@ while true { let (status, exec_time) = execute(code) if status < 0 { - print("Error during script execution: \(String(cString: reprl_get_last_error(ctx))). REPRL support in the target probably isn't working correctly...") + print( + "Error during script execution: \(String(cString: reprl_get_last_error(ctx))). REPRL support in the target probably isn't working correctly..." + ) continue } - print("Execution finished with status \(status) (signaled: \(RIFSIGNALED(status) != 0), timed out: \(RIFTIMEDOUT(status) != 0)) and took \(exec_time / 1000)ms") + print( + "Execution finished with status \(status) (signaled: \(RIFSIGNALED(status) != 0), timed out: \(RIFTIMEDOUT(status) != 0)) and took \(exec_time / 1000)ms" + ) print("========== Fuzzout ==========\n\(String(cString: reprl_fetch_fuzzout(ctx)))") print("========== Stdout ==========\n\(String(cString: reprl_fetch_stdout(ctx)))") print("========== Stderr ==========\n\(String(cString: reprl_fetch_stderr(ctx)))") diff --git a/Sources/RelateTool/main.swift b/Sources/RelateTool/main.swift index 33a9e718a..2bf9dca17 100644 --- a/Sources/RelateTool/main.swift +++ b/Sources/RelateTool/main.swift @@ -35,14 +35,14 @@ public struct V8DifferentialConfig { "--jit-fuzzing", "--maglev-dumping", "--turbofan-dumping", - "--turbofan-dumping-print-deopt-frames" + "--turbofan-dumping-print-deopt-frames", ] public static let referenceArgs: [String] = [ "--no-turbofan", "--no-maglev", "--sparkplug-dumping", - "--interpreter-dumping" + "--interpreter-dumping", ] } @@ -102,7 +102,8 @@ struct Relater { let args = Arguments.parse(from: CommandLine.arguments) guard let jsShellPath = args["--d8"], - let pocPath = args["--poc"] else { + let pocPath = args["--poc"] +else { print("Usage: --d8 --poc [--dump ]") exit(1) } diff --git a/Tests/FuzzilliTests/AnalyzerTest.swift b/Tests/FuzzilliTests/AnalyzerTest.swift index 546e99cd7..a8e60c9e5 100644 --- a/Tests/FuzzilliTests/AnalyzerTest.swift +++ b/Tests/FuzzilliTests/AnalyzerTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class AnalyzerTests: XCTestCase { @@ -105,7 +106,8 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction]) b.await(v3) b.buildAsyncGeneratorFunction(with: .parameters(n: 2)) { _ in - XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction, .generatorFunction]) + XCTAssertEqual( + b.context, [.javascript, .subroutine, .asyncFunction, .generatorFunction]) } XCTAssertEqual(b.context, [.javascript, .subroutine, .asyncFunction]) } @@ -139,12 +141,14 @@ class AnalyzerTests: XCTestCase { let b = fuzzer.makeBuilder() XCTAssertEqual(b.context, .javascript) - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod]) - b.buildDoWhileLoop(do: { - XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod, .loop]) - }, while: { b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + XCTAssertEqual( + b.context, [.javascript, .subroutine, .method, .classMethod, .loop]) + }, while: { b.loadBool(false) }) XCTAssertEqual(b.context, [.javascript, .subroutine, .method, .classMethod]) } } @@ -201,12 +205,12 @@ class AnalyzerTests: XCTestCase { let b = fuzzer.makeBuilder() XCTAssertEqual(b.context, .javascript) - let _ = b.buildCodeString() { + let _ = b.buildCodeString { XCTAssertEqual(b.context, .javascript) b.buildRepeatLoop(n: 10) { _ in b.loadInt(1337) XCTAssertEqual(b.context, [.javascript, .loop]) - let _ = b.buildCodeString() { + let _ = b.buildCodeString { b.loadString("hello world") XCTAssertEqual(b.context, [.javascript]) } @@ -226,11 +230,14 @@ class AnalyzerTests: XCTestCase { let _ = b.buildPlainFunction(with: .parameters(n: 5)) { args in XCTAssertEqual(b.context, [.javascript, .subroutine]) - b.buildIfElse(args[0], ifBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, elseBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) + b.buildIfElse( + args[0], + ifBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + elseBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }) b.buildWhileLoop({ XCTAssertEqual(b.context, [.javascript, .subroutine]) @@ -239,21 +246,27 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } - b.buildDoWhileLoop(do: { - XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) - }, while: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - return b.loadBool(false) - }) + b.buildDoWhileLoop( + do: { + XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) + }, + while: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + return b.loadBool(false) + }) - b.buildForLoop({ - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - return b.loadBool(false) - }, { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) { + b.buildForLoop( + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + return b.loadBool(false) + }, + { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + } + ) { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } @@ -288,13 +301,16 @@ class AnalyzerTests: XCTestCase { } } - b.buildTryCatchFinally(tryBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, catchBody: { _ in - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }, finallyBody: { - XCTAssertEqual(b.context, [.javascript, .subroutine]) - }) + b.buildTryCatchFinally( + tryBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + catchBody: { _ in + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }, + finallyBody: { + XCTAssertEqual(b.context, [.javascript, .subroutine]) + }) b.blockStatement { XCTAssertEqual(b.context, [.javascript, .subroutine]) @@ -302,10 +318,10 @@ class AnalyzerTests: XCTestCase { } XCTAssertEqual(b.context, .javascript) - let _ = b.finalize() + let _ = b.finalize() } - // Tests if the context is correctly identified in nested loops and switches. + // Tests if the context is correctly identified in nested loops and switches. // Needs to work to distinguish when to emit LoopBreak and SwitchBreak. func testBreakContext() { let fuzzer = makeMockFuzzer() @@ -313,13 +329,13 @@ class AnalyzerTests: XCTestCase { let case1 = b.loadInt(1337) let case2 = b.loadInt(9001) - + // Test case 1: switch -> loop -> switch b.buildSwitch(on: case1) { outer_switch in XCTAssertEqual(b.context, .switchBlock) outer_switch.addCase(case1) { XCTAssertEqual(b.context, [.javascript, .switchCase]) - b.buildWhileLoop({ b.loadBool(true) }) { + b.buildWhileLoop({ b.loadBool(true) }) { XCTAssertEqual(b.context, [.javascript, .loop]) b.buildSwitch(on: case2) { inner_switch in XCTAssertEqual(b.context, .switchBlock) @@ -327,7 +343,7 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .switchCase]) } } - } + } } } XCTAssertEqual(b.context, .javascript) @@ -346,7 +362,7 @@ class AnalyzerTests: XCTestCase { } } XCTAssertEqual(b.context, .javascript) - + let _ = b.finalize() } } diff --git a/Tests/FuzzilliTests/CompilerTests.swift b/Tests/FuzzilliTests/CompilerTests.swift index c27269dc6..5e4230683 100644 --- a/Tests/FuzzilliTests/CompilerTests.swift +++ b/Tests/FuzzilliTests/CompilerTests.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest import Foundation +import XCTest + @testable import Fuzzilli /// Compiler testsuite. @@ -27,14 +28,21 @@ import Foundation /// - The test passes if there are no errors along the way and if the output of both executions is identical class CompilerTests: XCTestCase { func testFuzzILCompiler() throws { - guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { - throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + throw XCTSkip( + "Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } // Initialize the parser. This can fail if no node.js executable is found or if the // parser's node.js dependencies are not installed. In that case, skip these tests. guard let parser = JavaScriptParser(executor: nodejs) else { - throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + throw XCTSkip( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } let compiler = JavaScriptCompiler() @@ -65,13 +73,17 @@ class CompilerTests: XCTestCase { let script = lifter.lift(program) let result2 = try nodejs.executeScript(script) guard result2.isSuccess else { - XCTFail("TestCase \(testName) failed to execute after compiling and lifting. Output:\n\(result2.output)\nScript:\n\(script)") + XCTFail( + "TestCase \(testName) failed to execute after compiling and lifting. Output:\n\(result2.output)\nScript:\n\(script)" + ) continue } // The output of both executions must be identical. if result1.output != result2.output { - XCTFail("Testcase \(testName) failed.\nExpected output:\n\(result1.output)\nActual output:\n\(result2.output)") + XCTFail( + "Testcase \(testName) failed.\nExpected output:\n\(result1.output)\nActual output:\n\(result2.output)" + ) } } } diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index fb068f34f..f2b981fa1 100644 --- a/Tests/FuzzilliTests/ContextGraphTest.swift +++ b/Tests/FuzzilliTests/ContextGraphTest.swift @@ -13,12 +13,14 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ContextGraphTests: XCTestCase { func testReachabilityCalculation() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .javascript)) @@ -33,19 +35,24 @@ class ContextGraphTests: XCTestCase { func testSubsetReachabilityCalculation() { let fuzzer = makeMockFuzzer() - let contextGraph = ContextGraph(for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + let contextGraph = ContextGraph( + for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) let reachableContextsWasm = Set(contextGraph.getReachableContexts(from: .wasm)) let reachableContextsWasm2 = Set(contextGraph.getReachableContexts(from: .wasm)) XCTAssertEqual(reachableContextsWasm, reachableContextsWasm2) - let reachableContextsWasmFunction = Set(contextGraph.getReachableContexts(from: .wasmFunction)) + let reachableContextsWasmFunction = Set( + contextGraph.getReachableContexts(from: .wasmFunction)) let reachableContextsJavaScript = Set(contextGraph.getReachableContexts(from: .javascript)) XCTAssertTrue(reachableContextsWasmFunction.isSubset(of: reachableContextsWasm)) - XCTAssertEqual(reachableContextsWasm, - Set([.wasmFunction, - .wasm])) + XCTAssertEqual( + reachableContextsWasm, + Set([ + .wasmFunction, + .wasm, + ])) XCTAssertTrue(reachableContextsWasm.isSubset(of: reachableContextsJavaScript)) } } diff --git a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift index 5863b6c18..fe8149e8c 100644 --- a/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift +++ b/Tests/FuzzilliTests/CrashingInstrumentationMutator.swift @@ -13,6 +13,7 @@ // limitations under the License. import Foundation + @testable import Fuzzilli // This mutator generates a crashing instrumented program. @@ -30,7 +31,7 @@ class CrashingInstrumentationMutator: RuntimeAssistedMutator { override func instrument(_ program: Program, for fuzzer: Fuzzer) -> Program? { let b = fuzzer.makeBuilder() - b.eval("fuzzilli('FUZZILLI_CRASH', 0)"); + b.eval("fuzzilli('FUZZILLI_CRASH', 0)") // Add a JsInternalOperation to satisfy the assertion in RuntimeAssistedMutator.swift:89 let v = b.loadInt(42) @@ -40,8 +41,10 @@ class CrashingInstrumentationMutator: RuntimeAssistedMutator { return b.finalize() } - - override func process(_ output: String, ofInstrumentedProgram instrumentedProgram: Program, using b: ProgramBuilder) -> (Program?, Outcome) { + override func process( + _ output: String, ofInstrumentedProgram instrumentedProgram: Program, + using b: ProgramBuilder + ) -> (Program?, Outcome) { // Purpose of this print: Distinguish crashes originating from instrument() and process(). let printFct = b.createNamedVariable(forBuiltin: "print") b.callFunction(printFct, withArgs: [b.loadString("This is the processed program")]) diff --git a/Tests/FuzzilliTests/DiffOracleTests.swift b/Tests/FuzzilliTests/DiffOracleTests.swift index 00d0e52c9..229588f72 100644 --- a/Tests/FuzzilliTests/DiffOracleTests.swift +++ b/Tests/FuzzilliTests/DiffOracleTests.swift @@ -13,22 +13,23 @@ // limitations under the License. import XCTest + @testable import Fuzzilli final class DiffOracleTests: XCTestCase { func testSimpleIdentity() { let dump = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 - - """ + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 + + """ // Should match itself XCTAssertTrue(DiffOracle.relate(dump, with: dump)) } @@ -37,68 +38,67 @@ final class DiffOracleTests: XCTestCase { // This tests if the second frame correctly inherits 'f:1', 'n:1', 'm:1' from the first frame // and only updates 'b' and 'x'. let unopt = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 - ---I - b:20 - x:200 + ---I + b:20 + x:200 - """ + """ // Even if we explicitly write out the full state in the "Opt" input, // it should match the incremental "Unopt" input if parsing works correctly. let optFull = """ - ---I - b:10 - f:1 - x:100 - n:1 - m:1 - a0:10 - r0:20 - - ---I - b:20 - f:1 - x:200 - n:1 - m:1 - a0:10 - r0:20 - - """ + ---I + b:10 + f:1 + x:100 + n:1 + m:1 + a0:10 + r0:20 + + ---I + b:20 + f:1 + x:200 + n:1 + m:1 + a0:10 + r0:20 + + """ XCTAssertTrue(DiffOracle.relate(optFull, with: unopt)) } - func testOptimizedOutAccumulator() { let unopt = """ - ---I - b:10 - f:1 - x:SecretValue - n:0 - m:0 + ---I + b:10 + f:1 + x:SecretValue + n:0 + m:0 - """ + """ let opt = """ - ---I - b:10 - f:1 - x: - n:0 - m:0 + ---I + b:10 + f:1 + x: + n:0 + m:0 - """ + """ // in Opt should match distinct value in Unopt XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) @@ -106,145 +106,144 @@ final class DiffOracleTests: XCTestCase { func testOptimizedOutArgument() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0:RealVal - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0:RealVal + a1:OtherVal - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0: - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0: + a1:OtherVal - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } func testNonMaterializedArgument() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0:RealVal - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0:RealVal + a1:OtherVal - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:2 - m:0 - a0: - a1:OtherVal + ---I + b:10 + f:1 + x:0 + n:2 + m:0 + a0: + a1:OtherVal - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } func testArgumentMismatch() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:1 - m:0 - a0:ValueA + ---I + b:10 + f:1 + x:0 + n:1 + m:0 + a0:ValueA - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:1 - m:0 - a0:ValueB + ---I + b:10 + f:1 + x:0 + n:1 + m:0 + a0:ValueB - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } func testRegisterMismatch() { let unopt = """ - ---I - b:10 - f:1 - x:0 - n:0 - m:1 - r0:ValueA + ---I + b:10 + f:1 + x:0 + n:0 + m:1 + r0:ValueA - """ + """ let opt = """ - ---I - b:10 - f:1 - x:0 - n:0 - m:1 - r0:ValueB + ---I + b:10 + f:1 + x:0 + n:0 + m:1 + r0:ValueB - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } - func testSkipsUnoptimizedFrames() { // Scenario: Unoptimized dump has extra intermediate steps (frames at offset 20 and 30). // Optimized dump only snapshots offset 10 and 40. This is valid. let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:20 + ---I + b:20 - ---I - b:30 + ---I + b:30 - ---I - b:40 + ---I + b:40 - """ + """ let opt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:40 + ---I + b:40 - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } @@ -253,50 +252,50 @@ final class DiffOracleTests: XCTestCase { // Scenario: Opt dump tries to match b:40 BEFORE b:10. This is invalid. // The relatation consumes the unopt stream forward. let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - ---I - b:40 + ---I + b:40 - """ + """ let opt = """ - ---I - b:40 - f:1 - n:0 - m:0 + ---I + b:40 + f:1 + n:0 + m:0 - ---I - b:10 + ---I + b:10 - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } func testBytecodeOffsetMismatch() { let unopt = """ - ---I - b:10 - f:1 - n:0 - m:0 + ---I + b:10 + f:1 + n:0 + m:0 - """ + """ let opt = """ - ---I - b:99 - f:1 - n:0 - m:0 + ---I + b:99 + f:1 + n:0 + m:0 - """ + """ XCTAssertFalse(DiffOracle.relate(opt, with: unopt)) } @@ -306,36 +305,36 @@ final class DiffOracleTests: XCTestCase { // when n counts change between frames. let unopt = """ - ---I - b:10 - f:1 - n:1 - m:0 - a0:A + ---I + b:10 + f:1 + n:1 + m:0 + a0:A - ---I - b:20 - n:2 - a1:B + ---I + b:20 + n:2 + a1:B - """ + """ // This opt dump expects a0 to still be A (carried over) and a1 to be B. let opt = """ - ---M - b:10 - f:1 - n:1 - m:0 - a0:A + ---M + b:10 + f:1 + n:1 + m:0 + a0:A - ---M - b:20 - n:2 - a0:A - a1:B + ---M + b:20 + n:2 + a0:A + a1:B - """ + """ XCTAssertTrue(DiffOracle.relate(opt, with: unopt)) } @@ -347,36 +346,36 @@ final class DiffOracleTests: XCTestCase { // 3. Go back to having two registers (m:2) in the third frame. r1 should still be B (inherited from frame 0). let trace = """ - ---I - b:10 - f:1 - n:0 - m:2 - r0:A - r1:B - - ---M - b:20 - m:1 - r0:A_Prime - - ---I - b:30 - m:2 - r0:A_Prime - - """ + ---I + b:10 + f:1 + n:0 + m:2 + r0:A + r1:B + + ---M + b:20 + m:1 + r0:A_Prime + + ---I + b:30 + m:2 + r0:A_Prime + + """ let expectedLastFrame = """ - ---I - b:30 - f:1 - n:0 - m:2 - r0:A_Prime - r1:B - - """ + ---I + b:30 + f:1 + n:0 + m:2 + r0:A_Prime + r1:B + + """ XCTAssertTrue(DiffOracle.relate(expectedLastFrame, with: trace)) } @@ -386,31 +385,31 @@ final class DiffOracleTests: XCTestCase { // Frame 2: m=3. The parser must grow the buffer. r1 and r2 should be "". let trace = """ - ---I - b:10 - f:1 - n:0 - m:1 - r0:A + ---I + b:10 + f:1 + n:0 + m:1 + r0:A - ---I - b:20 - m:3 + ---I + b:20 + m:3 - """ + """ // Explicitly check that r1 and r2 are missing in the expanded frame. let explicitMissing = """ - ---I - b:20 - f:1 - n:0 - m:3 - r0:A - r1: - r2: + ---I + b:20 + f:1 + n:0 + m:3 + r0:A + r1: + r2: - """ + """ XCTAssertTrue(DiffOracle.relate(explicitMissing, with: trace)) } @@ -420,62 +419,64 @@ final class DiffOracleTests: XCTestCase { // Buffer should auto-grow and fill with . let trace = """ - ---I - b:10 - f:1 - n:0 - m:10 - r9:Z + ---I + b:10 + f:1 + n:0 + m:10 + r9:Z - """ + """ // This frame should have r0...r8 as and r9 as Z. let expected = """ - ---I - b:10 - f:1 - n:0 - m:10 - r0: - r1: - r2: - r3: - r4: - r5: - r6: - r6: - r7: - r8: - r9:Z - - """ + ---I + b:10 + f:1 + n:0 + m:10 + r0: + r1: + r2: + r3: + r4: + r5: + r6: + r6: + r7: + r8: + r9:Z + + """ XCTAssertTrue(DiffOracle.relate(expected, with: trace)) } func testEmptyStringValueParsing() { let unopt = """ - ---I - b:10 - f:1 - n:0 - m:6 - r0:ValA - r5: + ---I + b:10 + f:1 + n:0 + m:6 + r0:ValA + r5: - """ + """ let opt = """ - ---I - b:10 - f:1 - n:0 - m:6 - r0:ValA - r5: - - """ - - XCTAssertTrue(DiffOracle.relate(opt, with: unopt), "Should handle empty register values (e.g. 'r5:') without crashing") + ---I + b:10 + f:1 + n:0 + m:6 + r0:ValA + r5: + + """ + + XCTAssertTrue( + DiffOracle.relate(opt, with: unopt), + "Should handle empty register values (e.g. 'r5:') without crashing") } } diff --git a/Tests/FuzzilliTests/EngineTests.swift b/Tests/FuzzilliTests/EngineTests.swift index 6d0960a48..e6f1e0cf7 100644 --- a/Tests/FuzzilliTests/EngineTests.swift +++ b/Tests/FuzzilliTests/EngineTests.swift @@ -13,11 +13,12 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class EngineTests: XCTestCase { func testPostProcessorOnGenerativeEngine() throws { - class MockPostProcessor : FuzzingPostProcessor { + class MockPostProcessor: FuzzingPostProcessor { var callCount = 0 func process(_ program: Program, for fuzzer: Fuzzer) -> Program { callCount += 1 @@ -55,7 +56,7 @@ class EngineTests: XCTestCase { let fuzzer = makeMockFuzzer() let processor = DumplingFuzzingPostProcessor() - let rejectedCases: [(ProgramBuilder) -> ()] = [ + let rejectedCases: [(ProgramBuilder) -> Void] = [ { b in let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } b.getProperty("arguments", of: f) @@ -88,7 +89,7 @@ class EngineTests: XCTestCase { XCTAssertThrowsError(try processor.process(program, for: fuzzer), "test case \(i)") } - for acceptedCase: (ProgramBuilder) -> () in [ + for acceptedCase: (ProgramBuilder) -> Void in [ { b in let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in } b.getProperty("not_arguments", of: f) diff --git a/Tests/FuzzilliTests/EnvironmentTest.swift b/Tests/FuzzilliTests/EnvironmentTest.swift index 7819fa883..adb3e8456 100644 --- a/Tests/FuzzilliTests/EnvironmentTest.swift +++ b/Tests/FuzzilliTests/EnvironmentTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class EnvironmentTests: XCTestCase { @@ -25,19 +26,21 @@ class EnvironmentTests: XCTestCase { /// Test all the builtin objects that are reachable from the global this. /// (This does not include anything that needs a constructor to be called.) func testJSEnvironmentLive() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--harmony", "--wasm-test-streaming", "--js-staging"]) let jsProg = buildAndLiftProgram(withLiftingOptions: [.includeComments]) { b in let jsEnvironment = b.fuzzer.environment var seenTypeGroups = Set() var propertiesToCheck: [(Variable, String, String)] = [] - let enqueueProperties = {(builtin: Variable, path: String, type: ILType) in + let enqueueProperties = { (builtin: Variable, path: String, type: ILType) in if type.group == nil || seenTypeGroups.insert(type.group!).inserted { - propertiesToCheck.append(contentsOf: - type.properties.sorted().map {(builtin, $0, "\(path).\($0)")} + - type.methods.sorted().map {(builtin, $0, "\(path).\($0)")}) + propertiesToCheck.append( + contentsOf: + type.properties.sorted().map { (builtin, $0, "\(path).\($0)") } + + type.methods.sorted().map { (builtin, $0, "\(path).\($0)") }) } } - let handleBuiltin = {builtin, path in + let handleBuiltin = { builtin, path in // Do something with the builtin to check that it exists (even if it might not have any // registered properties or methods). // The .LogicOr is only done for error reporting, e.g.: @@ -50,7 +53,7 @@ class EnvironmentTests: XCTestCase { if type.Is(.constructor()), let signature = type.constructorSignature { // If the object is default-constructible, instantiate it. // Otherwise we can't know how to construct a valid instance. - if (signature.parameters.allSatisfy {$0.isOptionalParameter}) { + if (signature.parameters.allSatisfy { $0.isOptionalParameter }) { let instance = b.construct(builtin) enqueueProperties(instance, "(new \(path)())", b.type(of: instance)) } @@ -59,7 +62,7 @@ class EnvironmentTests: XCTestCase { for builtinName in jsEnvironment.builtins.sorted() where builtinName != "undefined" { handleBuiltin(b.createNamedVariable(forBuiltin: builtinName), builtinName) } - let blockList : Set = ["arguments", "caller"] + let blockList: Set = ["arguments", "caller"] while let (builtinVar, name, path) = propertiesToCheck.popLast() { if blockList.contains(name) { continue } let builtin = b.getProperty(name, of: builtinVar) @@ -76,24 +79,28 @@ class EnvironmentTests: XCTestCase { func convertTypedArrayToHex(_ b: ProgramBuilder, _ array: Variable) -> Variable { let toHex = b.buildArrowFunction(with: .parameters(n: 1)) { args in let hex = b.callMethod("toString", on: args[0], withArgs: [b.loadInt(16)]) - let hexPadded = b.callMethod("padStart", on: hex, withArgs: [b.loadInt(2), b.loadString("0")]) + let hexPadded = b.callMethod( + "padStart", on: hex, withArgs: [b.loadInt(2), b.loadString("0")]) b.doReturn(hexPadded) } - let untypedArray = b.construct(b.createNamedVariable(forBuiltin: "Array"), + let untypedArray = b.construct( + b.createNamedVariable(forBuiltin: "Array"), withArgs: [array], spreading: [true]) let hexArray = b.callMethod("map", on: untypedArray, withArgs: [toHex]) return b.callMethod("join", on: hexArray, withArgs: [b.loadString("")]) } func testBase64OptionsBag() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--js-base-64"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--js-base-64"]) let jsProg = buildAndLiftProgram { b in let arrayConstructor = b.createNamedVariable(forBuiltin: "Uint8Array") // Whatever the options object looks like, it should construct something valid. // With the provided input string, the actual options should not matter. let options = b.createOptionsBag(OptionsBag.fromBase64Settings) let inputString = b.loadString("qxI0VniQq83v") - let array = b.callMethod("fromBase64", on: arrayConstructor, withArgs: [inputString, options]) + let array = b.callMethod( + "fromBase64", on: arrayConstructor, withArgs: [inputString, options]) XCTAssert(b.type(of: array).Is(.object(ofGroup: "Uint8Array"))) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [convertTypedArrayToHex(b, array)]) @@ -103,7 +110,8 @@ class EnvironmentTests: XCTestCase { b.callMethod("setFromBase64", on: array, withArgs: [inputString2, options2]) b.callFunction(outputFunc, withArgs: [convertTypedArrayToHex(b, array)]) } - testForOutput(program: jsProg, runner: runner, + testForOutput( + program: jsProg, runner: runner, outputString: "ab1234567890abcdef\nbaaddeadbeefabcdef\n") } } diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 20f549f2b..e41776ea4 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class JSTyperTests: XCTestCase { @@ -46,28 +47,37 @@ class JSTyperTests: XCTestCase { obj.addMethod("m", with: .parameters(.integer)) { args in let this = args[0] // Up to this point, only the "a" property has been installed - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) XCTAssertEqual(b.type(of: args[1]), .integer) let notArg = b.unary(.LogicalNot, args[1]) b.doReturn(notArg) } obj.addGetter(for: "b") { this in // We don't add the "b" property to the |this| type here since it's probably not very useful to access it inside its getter/setter. - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"], withMethods: ["m"])) } obj.addSetter(for: "c") { this, v in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Object0", withProperties: ["a", "b"], withMethods: ["m"])) } } - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b", "c"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "b", "c"], withMethods: ["m"])) let obj2 = b.buildObjectLiteral { obj in obj.addProperty("prop", as: v) obj.addElement(0, as: v) } - XCTAssertEqual(b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["prop"])) + XCTAssertEqual( + b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["prop"])) } func testNestedObjectLiterals() { @@ -79,19 +89,25 @@ class JSTyperTests: XCTestCase { outer.addProperty("a", as: v) outer.addMethod("m", with: .parameters(n: 1)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) b.buildObjectLiteral { inner in inner.addProperty("b", as: v) inner.addMethod("n", with: .parameters(n: 0)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object1", withProperties: ["b"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Object1", withProperties: ["b"])) } } } outer.addProperty("c", as: v) outer.addMethod("o", with: .parameters(n: 0)) { args in let this = args[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Object0", withProperties: ["a", "c"], withMethods: ["m"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Object0", withProperties: ["a", "c"], withMethods: ["m"])) } } } @@ -105,19 +121,25 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: obj, to: intVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) b.setProperty("baz", of: obj, to: intVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) let _ = b.deleteProperty("foo", of: obj) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["bar", "baz"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["bar", "baz"])) // Properties whose values are functions are still treated as properties, not methods. let function = b.buildPlainFunction(with: .parameters(n: 1)) { params in } XCTAssertEqual(b.type(of: function), .functionAndConstructor([.jsAnything] => .undefined)) let obj2 = b.createObject(with: ["foo": intVar, "bar": intVar, "baz": function]) - XCTAssertEqual(b.type(of: obj2), .object(ofGroup: "_fuzz_Object1", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: obj2), + .object(ofGroup: "_fuzz_Object1", withProperties: ["foo", "bar", "baz"])) } func testClasses() { @@ -125,7 +147,7 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let v = b.loadInt(42) - let cls = b.buildClassDefinition() { cls in + let cls = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.string])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -140,7 +162,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"])) XCTAssertEqual(b.type(of: params[1]), .float) XCTAssertEqual(b.type(of: v), .integer | .string) b.reassign(variable: v, value: params[1]) @@ -148,12 +171,19 @@ class JSTyperTests: XCTestCase { } cls.addInstanceGetter(for: "c") { this in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b"], withMethods: ["f"])) } cls.addInstanceMethod("g", with: .parameters(n: 2)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f"] + )) XCTAssertEqual(b.type(of: params[1]), .jsAnything) XCTAssertEqual(b.type(of: params[2]), .jsAnything) } @@ -163,34 +193,61 @@ class JSTyperTests: XCTestCase { cls.addStaticMethod("g", with: .parameters(n: 2)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"])) + XCTAssertEqual( + b.type(of: this), + .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"])) XCTAssertEqual(b.type(of: params[1]), .jsAnything) XCTAssertEqual(b.type(of: params[2]), .jsAnything) } cls.addStaticSetter(for: "e") { this, v in - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"], withMethods: ["g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d"], + withMethods: ["g"])) } cls.addStaticMethod("h", with: .parameters(.integer)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g"])) XCTAssertEqual(b.type(of: params[1]), .integer) } cls.addPrivateInstanceMethod("p", with: .parameters(n: 0)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f", "g"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], + withMethods: ["f", "g"])) } cls.addPrivateStaticMethod("p", with: .parameters(n: 0)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g", "h"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g", "h"])) } } XCTAssertEqual(b.type(of: v), .integer | .string | .float) - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], withMethods: ["g", "h"]) + .constructor([.string] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object( + ofGroup: "_fuzz_Constructor0", withProperties: ["a", "d", "e"], + withMethods: ["g", "h"]) + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "b", "c"], + withMethods: ["f", "g"]))) } func testClasses2() { @@ -200,7 +257,7 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) let s = b.loadString("foo") let f = b.loadFloat(13.37) - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in // Class methods, getters, setters, etc. are treated as conditionally executing blocks. cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in XCTAssertEqual(b.type(of: v), .integer) @@ -247,35 +304,49 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v), .primitive | .object() | .iterable) XCTAssertEqual(b.type(of: s), .jsString | .float) - XCTAssertEqual(b.type(of: f), .boolean) // A static initializer block runs unconditionally + XCTAssertEqual(b.type(of: f), .boolean) // A static initializer block runs unconditionally } func testNestedClasses() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let outer = b.buildClassDefinition() { cls in + let outer = b.buildClassDefinition { cls in cls.addInstanceProperty("a") cls.addInstanceMethod("m", with: .parameters(n: 0)) { args in let inner = b.buildClassDefinition { cls in cls.addInstanceProperty("a") cls.addInstanceProperty("b") } - XCTAssertEqual(b.type(of: inner), .object(ofGroup: "_fuzz_Constructor1") + .constructor([] => .object(ofGroup: "_fuzz_Class1", withProperties: ["a", "b"]))) + XCTAssertEqual( + b.type(of: inner), + .object(ofGroup: "_fuzz_Constructor1") + + .constructor( + [] => .object(ofGroup: "_fuzz_Class1", withProperties: ["a", "b"]))) } cls.addInstanceProperty("c") } - XCTAssertEqual(b.type(of: outer), .object(ofGroup: "_fuzz_Constructor0") + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a", "c"], withMethods: ["m"]))) + XCTAssertEqual( + b.type(of: outer), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "c"], withMethods: ["m"]) + )) } func testSubClasses() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let base1 = b.buildClassDefinition() { cls in + let base1 = b.buildClassDefinition { cls in cls.addInstanceProperty("a") } - XCTAssertEqual(b.type(of: base1), .object(ofGroup: "_fuzz_Constructor0") + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) + XCTAssertEqual( + b.type(of: base1), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor([] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) let v = b.loadInt(42) let base2 = b.buildPlainFunction(with: .parameters(n: 0)) { _ in @@ -284,7 +355,9 @@ class JSTyperTests: XCTestCase { } b.doReturn(obj) } - XCTAssertEqual(b.type(of: base2), .functionAndConstructor([] => .object(ofGroup: "_fuzz_Object2", withProperties: ["b"]))) + XCTAssertEqual( + b.type(of: base2), + .functionAndConstructor([] => .object(ofGroup: "_fuzz_Object2", withProperties: ["b"]))) let base3 = b.buildPlainFunction(with: .parameters(n: 0)) { _ in b.doReturn(v) @@ -297,29 +370,45 @@ class JSTyperTests: XCTestCase { let derived1 = b.buildClassDefinition(withSuperclass: base1) { cls in cls.addInstanceProperty("c") } - XCTAssertEqual(b.type(of: derived1), .object(ofGroup: "_fuzz_Constructor3") + .constructor([] => .object(ofGroup: "_fuzz_Class3", withProperties: ["a", "c"]))) + XCTAssertEqual( + b.type(of: derived1), + .object(ofGroup: "_fuzz_Constructor3") + + .constructor([] => .object(ofGroup: "_fuzz_Class3", withProperties: ["a", "c"]))) let derived2 = b.buildClassDefinition(withSuperclass: base2) { cls in cls.addInstanceProperty("d") } - XCTAssertEqual(b.type(of: derived2), .object(ofGroup: "_fuzz_Constructor5") + .constructor([] => .object(ofGroup: "_fuzz_Class5", withProperties: ["b", "d"]))) + XCTAssertEqual( + b.type(of: derived2), + .object(ofGroup: "_fuzz_Constructor5") + + .constructor([] => .object(ofGroup: "_fuzz_Class5", withProperties: ["b", "d"]))) // base3 does not return an object, so that return type is ignored for the constructor. // TODO: Technically, base3 used as a constructor would return |this|, so we'd have to use the type of |this| if the returned value is not an object in our type inference, but we don't currently do that. let derived3 = b.buildClassDefinition(withSuperclass: base3) { cls in cls.addInstanceProperty("e") } - XCTAssertEqual(b.type(of: derived3), .object(ofGroup: "_fuzz_Constructor7") + .constructor([] => .object(ofGroup: "_fuzz_Class7", withProperties: ["e"]))) + XCTAssertEqual( + b.type(of: derived3), + .object(ofGroup: "_fuzz_Constructor7") + + .constructor([] => .object(ofGroup: "_fuzz_Class7", withProperties: ["e"]))) let derived4 = b.buildClassDefinition(withSuperclass: base4) { cls in cls.addInstanceProperty("f") } - XCTAssertEqual(b.type(of: derived4), .object(ofGroup: "_fuzz_Constructor9") + .constructor([] => .object(ofGroup: "_fuzz_Class9", withProperties: ["f"]))) + XCTAssertEqual( + b.type(of: derived4), + .object(ofGroup: "_fuzz_Constructor9") + + .constructor([] => .object(ofGroup: "_fuzz_Class9", withProperties: ["f"]))) let derived5 = b.buildClassDefinition(withSuperclass: derived1) { cls in cls.addInstanceProperty("g") } - XCTAssertEqual(b.type(of: derived5), .object(ofGroup: "_fuzz_Constructor11") + .constructor([] => .object(ofGroup: "_fuzz_Class11", withProperties: ["a", "c", "g"]))) + XCTAssertEqual( + b.type(of: derived5), + .object(ofGroup: "_fuzz_Constructor11") + + .constructor( + [] => .object(ofGroup: "_fuzz_Class11", withProperties: ["a", "c", "g"]))) } func testSubroutineTypes() { @@ -330,35 +419,59 @@ class JSTyperTests: XCTestCase { let signature2 = [.string, .number] => .undefined // Plain functions are both functions and constructors. This might yield interesting results since these function often return a value. - var f = b.buildPlainFunction(with: .parameters(n: 2)) { params in XCTAssertEqual(b.type(of: params[0]), .jsAnything); XCTAssertEqual(b.type(of: params[1]), .jsAnything) } - XCTAssertEqual(b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) + var f = b.buildPlainFunction(with: .parameters(n: 2)) { params in + XCTAssertEqual(b.type(of: params[0]), .jsAnything) + XCTAssertEqual(b.type(of: params[1]), .jsAnything) + } + XCTAssertEqual( + b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) - f = b.buildPlainFunction(with: .parameters(signature1.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildPlainFunction(with: .parameters(signature1.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .functionAndConstructor(signature1)) - f = b.buildPlainFunction(with: .parameters(n: 2)) { params in XCTAssertEqual(b.type(of: params[0]), .jsAnything); XCTAssertEqual(b.type(of: params[1]), .jsAnything) } - XCTAssertEqual(b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) + f = b.buildPlainFunction(with: .parameters(n: 2)) { params in + XCTAssertEqual(b.type(of: params[0]), .jsAnything) + XCTAssertEqual(b.type(of: params[1]), .jsAnything) + } + XCTAssertEqual( + b.type(of: f), .functionAndConstructor([.jsAnything, .jsAnything] => .undefined)) // All other function types are just functions... - f = b.buildArrowFunction(with: .parameters(signature2.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildArrowFunction(with: .parameters(signature2.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature2)) let signature3 = [.integer, .number] => .jsGenerator - f = b.buildGeneratorFunction(with: .parameters(signature3.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildGeneratorFunction(with: .parameters(signature3.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature3)) - f = b.buildAsyncGeneratorFunction(with: .parameters(signature3.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .integer); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncGeneratorFunction(with: .parameters(signature3.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .integer) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature3)) let signature4 = [.string, .number] => .jsPromise - f = b.buildAsyncFunction(with: .parameters(signature4.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncFunction(with: .parameters(signature4.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature4)) - f = b.buildAsyncArrowFunction(with: .parameters(signature4.parameters)) { params in XCTAssertEqual(b.type(of: params[0]), .string); XCTAssertEqual(b.type(of: params[1]), .number) } + f = b.buildAsyncArrowFunction(with: .parameters(signature4.parameters)) { params in + XCTAssertEqual(b.type(of: params[0]), .string) + XCTAssertEqual(b.type(of: params[1]), .number) + } XCTAssertEqual(b.type(of: f), .function(signature4)) - - // ... except for constructors, which are just constructors (when they are lifted to JavaScript, they explicitly forbid being called as a function). let signature5 = [.integer, .number] => .object(withProperties: ["foo", "bar"]) f = b.buildConstructor(with: .parameters(signature3.parameters)) { params in @@ -386,42 +499,56 @@ class JSTyperTests: XCTestCase { let o = b.createObject(with: ["a": b.loadInt(42)]) b.doReturn(o) } - XCTAssertEqual(b.type(of: f2).signature?.outputType, .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: f2).signature?.outputType, + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"])) let f3 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadFloat(13.37)) - }, elseBody: { - b.doReturn(b.loadString("13.37")) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadFloat(13.37)) + }, + elseBody: { + b.doReturn(b.loadString("13.37")) + }) b.doReturn(b.loadBool(false)) } XCTAssertEqual(b.type(of: f3).signature?.outputType, .float | .jsString) let f4 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadString("foo")) - }, elseBody: { - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadString("foo")) + }, + elseBody: { + }) } XCTAssertEqual(b.type(of: f4).signature?.outputType, .undefined | .jsString) let f5 = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadString("foo")) - }, elseBody: { - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadString("foo")) + }, + elseBody: { + }) b.doReturn(b.loadBool(true)) } XCTAssertEqual(b.type(of: f5).signature?.outputType, .boolean | .jsString) let f6 = b.buildPlainFunction(with: .parameters(n: 1)) { args in b.doReturn(b.loadInt(42)) - b.buildIfElse(args[0], ifBody: { - b.doReturn(b.loadFloat(13.37)) - }, elseBody: { - b.doReturn(b.loadString("13.37")) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(b.loadFloat(13.37)) + }, + elseBody: { + b.doReturn(b.loadString("13.37")) + }) b.doReturn(b.loadBool(false)) } XCTAssertEqual(b.type(of: f6).signature?.outputType, .integer) @@ -450,11 +577,14 @@ class JSTyperTests: XCTestCase { b.doReturn(b.loadInt(42)) } b.buildIf(args[1]) { - b.buildIfElse(args[2], ifBody: { - b.doReturn(b.loadBool(true)) - }, elseBody: { - b.doReturn(b.loadBool(false)) - }) + b.buildIfElse( + args[2], + ifBody: { + b.doReturn(b.loadBool(true)) + }, + elseBody: { + b.doReturn(b.loadBool(false)) + }) // This is ignored: all paths have already returned b.doReturn(b.loadString("foobar")) } @@ -481,7 +611,9 @@ class JSTyperTests: XCTestCase { let o = b.createObject(with: ["a": args[1], "b": args[2]]) b.doReturn(o) } - XCTAssertEqual(b.type(of: c3).signature?.outputType, .object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"])) + XCTAssertEqual( + b.type(of: c3).signature?.outputType, + .object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"])) let g1 = b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(b.loadInt(42)) @@ -545,29 +677,39 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) let obj = b.createObject(with: ["foo": v]) - b.buildIfElse(v, ifBody: { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) - b.setProperty("bar", of: obj, to: v) - b.setProperty("baz", of: obj, to: v) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) - - XCTAssertEqual(b.type(of: v), .integer) - let stringVar = b.loadString("foobar") - b.reassign(variable: v, value: stringVar) - XCTAssertEqual(b.type(of: v), .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) - b.setProperty("bar", of: obj, to: v) - b.setProperty("bla", of: obj, to: v) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) - - XCTAssertEqual(b.type(of: v), .integer) - let floatVar = b.loadFloat(13.37) - b.reassign(variable: v, value: floatVar) - }) + b.buildIfElse( + v, + ifBody: { + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + b.setProperty("bar", of: obj, to: v) + b.setProperty("baz", of: obj, to: v) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + + XCTAssertEqual(b.type(of: v), .integer) + let stringVar = b.loadString("foobar") + b.reassign(variable: v, value: stringVar) + XCTAssertEqual(b.type(of: v), .jsString) + }, + elseBody: { + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + b.setProperty("bar", of: obj, to: v) + b.setProperty("bla", of: obj, to: v) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) + + XCTAssertEqual(b.type(of: v), .integer) + let floatVar = b.loadFloat(13.37) + b.reassign(variable: v, value: floatVar) + }) XCTAssertEqual(b.type(of: v), .string | .float | .object() | .iterable) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) // Test another program using if/else b.reset() @@ -576,17 +718,19 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(42) XCTAssertEqual(b.type(of: v0), .integer) XCTAssertEqual(b.type(of: v1), .integer) - b.buildIfElse(v0, ifBody: { - b.reassign(variable: v0, value: b.loadString("foo")) - b.reassign(variable: v1, value: b.loadString("foo")) - }, elseBody: { - b.reassign(variable: v1, value: b.loadString("bar")) - }) + b.buildIfElse( + v0, + ifBody: { + b.reassign(variable: v0, value: b.loadString("foo")) + b.reassign(variable: v1, value: b.loadString("foo")) + }, + elseBody: { + b.reassign(variable: v1, value: b.loadString("bar")) + }) XCTAssertEqual(b.type(of: v0), .integer | .jsString) XCTAssertEqual(b.type(of: v1), .jsString) - // Test another program using just if b.reset() @@ -606,27 +750,36 @@ class JSTyperTests: XCTestCase { let v = b.loadInt(42) XCTAssertEqual(b.type(of: v), .integer) - b.buildIfElse(v, ifBody: { - b.buildIfElse(v, ifBody: { - b.buildIfElse(v, ifBody: { - b.reassign(variable: v, value: b.loadString("foo")) - XCTAssertEqual(b.type(of: v), .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: v), .integer) - b.reassign(variable: v, value: b.loadBool(true)) - XCTAssertEqual(b.type(of: v), .boolean) - }) - - XCTAssertEqual(b.type(of: v), .boolean | .jsString) - }, elseBody: { + b.buildIfElse( + v, + ifBody: { + b.buildIfElse( + v, + ifBody: { + b.buildIfElse( + v, + ifBody: { + b.reassign(variable: v, value: b.loadString("foo")) + XCTAssertEqual(b.type(of: v), .jsString) + }, + elseBody: { + XCTAssertEqual(b.type(of: v), .integer) + b.reassign(variable: v, value: b.loadBool(true)) + XCTAssertEqual(b.type(of: v), .boolean) + }) + + XCTAssertEqual(b.type(of: v), .boolean | .jsString) + }, + elseBody: { + XCTAssertEqual(b.type(of: v), .integer) + }) + + XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) + }, + elseBody: { XCTAssertEqual(b.type(of: v), .integer) }) - XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) - }, elseBody: { - XCTAssertEqual(b.type(of: v), .integer) - }) - XCTAssertEqual(b.type(of: v), .boolean | .integer | .jsString) } @@ -658,21 +811,24 @@ class JSTyperTests: XCTestCase { let obj = b.createObject(with: ["foo": v]) func body() { - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: obj, to: intVar1) XCTAssertEqual(b.type(of: v), .jsString) let floatVar = b.loadFloat(13.37) b.reassign(variable: v, value: floatVar) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: obj), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v), .float) } // Select loop type switch i { case 0: - b.buildForLoop() { + b.buildForLoop { body() } case 1: @@ -706,7 +862,8 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: intVar2), .integer) XCTAssertEqual(b.type(of: intVar3), .integer) XCTAssertEqual(b.type(of: v), .float | .jsString) - XCTAssertEqual(b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: obj), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.reset() } @@ -714,13 +871,14 @@ class JSTyperTests: XCTestCase { func testBuiltinTypeInference() { let builtinAType = ILType.integer - let builtinBType = ILType.object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]) + let builtinBType = ILType.object( + ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]) let builtinCType = ILType.function([] => .number) let env = JavaScriptEnvironment(additionalBuiltins: [ "A": builtinAType, "B": builtinBType, - "C": builtinCType + "C": builtinCType, ]) let fuzzer = makeMockFuzzer(environment: env) @@ -740,27 +898,30 @@ class JSTyperTests: XCTestCase { let propBarType = ILType.function([] => .jsAnything) let propBazType = ILType.object(withProperties: ["a", "b", "c"]) let additionalObjectGroups: [ObjectGroup] = [ - ObjectGroup(name: "B", - instanceType: .object(ofGroup: "B", withProperties: ["foo", "bar"]), - properties: [ + ObjectGroup( + name: "B", + instanceType: .object(ofGroup: "B", withProperties: ["foo", "bar"]), + properties: [ "foo": propFooType, - "bar": propBarType - ], + "bar": propBarType, + ], overloads: [:]), - ObjectGroup(name: "C", - instanceType: .object(ofGroup: "C", withProperties: ["baz"]), + ObjectGroup( + name: "C", + instanceType: .object(ofGroup: "C", withProperties: ["baz"]), properties: [ - "baz": propBazType, - ], - overloads: [:]) + "baz": propBazType + ], + overloads: [:]), ] let builtins: [String: ILType] = [ "B": .object(ofGroup: "B"), - "C": .object(ofGroup: "C") + "C": .object(ofGroup: "C"), ] - let env = JavaScriptEnvironment(additionalBuiltins: builtins, additionalObjectGroups: additionalObjectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: builtins, additionalObjectGroups: additionalObjectGroups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() @@ -797,22 +958,25 @@ class JSTyperTests: XCTestCase { let m1Signature = [] => .float let m2Signature = [.string] => .object(ofGroup: "X") let groups: [ObjectGroup] = [ - ObjectGroup(name: "B", - instanceType: .object(ofGroup: "B", withMethods: ["m1"]), - properties: [:], - methods: ["m1": m1Signature]), - ObjectGroup(name: "C", - instanceType: .object(ofGroup: "C", withMethods: ["m2"]), - properties: [:], - methods: ["m2": m2Signature]), + ObjectGroup( + name: "B", + instanceType: .object(ofGroup: "B", withMethods: ["m1"]), + properties: [:], + methods: ["m1": m1Signature]), + ObjectGroup( + name: "C", + instanceType: .object(ofGroup: "C", withMethods: ["m2"]), + properties: [:], + methods: ["m2": m2Signature]), ] let builtins: [String: ILType] = [ "B": .object(ofGroup: "B"), - "C": .object(ofGroup: "C") + "C": .object(ofGroup: "C"), ] - let env = JavaScriptEnvironment(additionalBuiltins: builtins, additionalObjectGroups: groups) + let env = JavaScriptEnvironment( + additionalBuiltins: builtins, additionalObjectGroups: groups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() @@ -836,7 +1000,7 @@ class JSTyperTests: XCTestCase { func testConstructorTypeInference() { let aConstructorType = ILType.constructor([.rest(.jsAnything)] => .object(ofGroup: "A")) let builtins: [String: ILType] = [ - "A": aConstructorType, + "A": aConstructorType ] let env = JavaScriptEnvironment(additionalBuiltins: builtins) @@ -869,7 +1033,7 @@ class JSTyperTests: XCTestCase { func testReturnTypeInference() { let aFunctionType = ILType.function([.rest(.jsAnything)] => .primitive) let builtins: [String: ILType] = [ - "a": aFunctionType, + "a": aFunctionType ] let env = JavaScriptEnvironment(additionalBuiltins: builtins) @@ -904,7 +1068,7 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.integer])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -917,7 +1081,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) XCTAssertEqual(b.currentSuperType(), .object()) XCTAssertEqual(b.type(of: params[1]), .float) @@ -926,17 +1091,30 @@ class JSTyperTests: XCTestCase { } } - let superType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: superclass), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => superType)) + let superType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) + XCTAssertEqual( + b.type(of: superclass), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => superType)) let v = b.loadInt(42) let cls = b.buildClassDefinition(withSuperclass: superclass) { cls in cls.addInstanceProperty("b", value: v) cls.addConstructor(with: .parameters([.string])) { params in - XCTAssertEqual(b.currentSuperConstructorType(), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]))) + XCTAssertEqual( + b.currentSuperConstructorType(), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [.integer] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], + withMethods: ["f"]))) let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) XCTAssertEqual(b.currentSuperType(), superType) b.callSuperConstructor(withArgs: [b.loadFloat(42)]) @@ -944,11 +1122,21 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) XCTAssertEqual(b.currentSuperType(), superType) } } - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor2") + .constructor([.string] => .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object(ofGroup: "_fuzz_Constructor2") + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], + withMethods: ["f", "g"]))) } func testBigintTypeInference() { @@ -958,8 +1146,8 @@ class JSTyperTests: XCTestCase { let i1 = b.loadInt(42) let i2 = b.loadInt(43) XCTAssert(b.type(of: i1).Is(.integer)) - let bi1 = b.loadBigInt(4200000000) - let bi2 = b.loadBigInt(4300000000) + let bi1 = b.loadBigInt(4_200_000_000) + let bi2 = b.loadBigInt(4_300_000_000) XCTAssert(b.type(of: bi1).Is(.bigint)) for op in UnaryOperator.allCases { @@ -989,8 +1177,8 @@ class JSTyperTests: XCTestCase { let i3 = b.loadInt(45) let i4 = b.loadInt(46) XCTAssert(b.type(of: i3).Is(.integer)) - let bi3 = b.loadBigInt(4200000000) - let bi4 = b.loadBigInt(4300000000) + let bi3 = b.loadBigInt(4_200_000_000) + let bi4 = b.loadBigInt(4_300_000_000) XCTAssert(b.type(of: bi3).Is(.bigint)) // Logical operators produce .boolean in any case @@ -1014,7 +1202,10 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // The header executes unconditionally, but the body does not - b.buildWhileLoop({ b.reassign(variable: v1, value: b.loadString("foo")); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.reassign(variable: v1, value: b.loadString("foo")) + return b.loadBool(false) + }) { b.reassign(variable: v2, value: b.loadString("bar")) } @@ -1029,9 +1220,14 @@ class JSTyperTests: XCTestCase { let v1 = b.loadInt(0) let v2 = b.loadInt(1) // Both the header and the body execute unconditionally - b.buildDoWhileLoop(do: { - b.reassign(variable: v2, value: b.loadString("foo")) - }, while: { b.reassign(variable: v1, value: b.loadString("bar")); return b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + b.reassign(variable: v2, value: b.loadString("foo")) + }, + while: { + b.reassign(variable: v1, value: b.loadString("bar")) + return b.loadBool(false) + }) XCTAssertEqual(b.type(of: v1), .jsString) XCTAssertEqual(b.type(of: v2), .jsString) @@ -1047,14 +1243,18 @@ class JSTyperTests: XCTestCase { let v4 = b.loadInt(3) // The initializer block and the condition block are always executed. // The afterthought and body block may not be executed. - b.buildForLoop({ - b.reassign(variable: v1, value: b.loadString("foo")) - }, { - b.reassign(variable: v2, value: b.loadString("bar")) - return b.loadBool(false) - }, { - b.reassign(variable: v3, value: b.loadString("baz")) - }) { + b.buildForLoop( + { + b.reassign(variable: v1, value: b.loadString("foo")) + }, + { + b.reassign(variable: v2, value: b.loadString("bar")) + return b.loadBool(false) + }, + { + b.reassign(variable: v3, value: b.loadString("baz")) + } + ) { b.reassign(variable: v4, value: b.loadString("bla")) } @@ -1068,22 +1268,41 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, - { i in XCTAssertEqual(b.type(of: i), .integer); return b.compare(i, with: b.loadInt(10), using: .lessThan) }, - { i in XCTAssertEqual(b.type(of: i), .integer); b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + return b.compare(i, with: b.loadInt(10), using: .lessThan) + }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.unary(.PostInc, i) + } + ) { i in XCTAssertEqual(b.type(of: i), .integer) } - b.buildForLoop(i: { b.loadInt(0) }, - { i in - XCTAssertEqual(b.type(of: i), .integer); - b.buildForLoop(i: { b.loadFloat(12.34) }, { i in XCTAssertEqual(b.type(of: i), .float); return b.loadBool(false) }, { i in XCTAssertEqual(b.type(of: i), .float )}) { i in - XCTAssertEqual(b.type(of: i), .float) - } - return b.compare(i, with: b.loadInt(10), using: .lessThan) + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.buildForLoop( + i: { b.loadFloat(12.34) }, + { i in + XCTAssertEqual(b.type(of: i), .float) + return b.loadBool(false) + }, { i in XCTAssertEqual(b.type(of: i), .float) } + ) { i in + XCTAssertEqual(b.type(of: i), .float) + } + return b.compare(i, with: b.loadInt(10), using: .lessThan) - }, - { i in XCTAssertEqual(b.type(of: i), .integer); b.unary(.PostInc, i) }) { i in + }, + { i in + XCTAssertEqual(b.type(of: i), .integer) + b.unary(.PostInc, i) + } + ) { i in XCTAssertEqual(b.type(of: i), .integer) } } @@ -1100,10 +1319,13 @@ class JSTyperTests: XCTestCase { b.buildSwitch(on: v2) { swtch in swtch.addCase(v3) { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("baz", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "baz"])) XCTAssertEqual(b.type(of: v0), .integer) let stringVar = b.loadString("foobar") @@ -1111,10 +1333,13 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .jsString) } swtch.addDefaultCase { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("qux", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "qux"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "qux"])) XCTAssertEqual(b.type(of: v0), .integer) let boolVal = b.loadBool(false) @@ -1122,10 +1347,13 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(of: v0), .boolean) } swtch.addCase(v4) { - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) b.setProperty("bar", of: v1, to: v0) b.setProperty("bla", of: v1, to: v0) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) + XCTAssertEqual( + b.type(of: v1), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar", "bla"])) XCTAssertEqual(b.type(of: v0), .integer) let floatVar = b.loadFloat(13.37) @@ -1135,7 +1363,8 @@ class JSTyperTests: XCTestCase { } XCTAssertEqual(b.type(of: v0), .float | .boolean | .jsString) - XCTAssertEqual(b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) + XCTAssertEqual( + b.type(of: v1), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo", "bar"])) XCTAssertEqual(b.type(of: v3), .integer) XCTAssertEqual(b.type(of: v4), .jsString) } @@ -1198,22 +1427,25 @@ class JSTyperTests: XCTestCase { func testDestructObjectTypeInference() { let objectGroups: [ObjectGroup] = [ - ObjectGroup(name: "O", - instanceType: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"]), - properties: [ - "foo": .integer, - "bar": .string, - "baz": .boolean - ], - methods: [:]) + ObjectGroup( + name: "O", + instanceType: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"]), + properties: [ + "foo": .integer, + "bar": .string, + "baz": .boolean, + ], + methods: [:]) ] - let env = JavaScriptEnvironment(additionalBuiltins: [:], additionalObjectGroups: objectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: [:], additionalObjectGroups: objectGroups) let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() let obj = b.createNamedVariable(forBuiltin: "myO") - b.setType(ofVariable: obj, to: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"])) + b.setType( + ofVariable: obj, to: .object(ofGroup: "O", withProperties: ["foo", "bar", "baz"])) let outputs = b.destruct(obj, selecting: ["foo", "bar"], hasRestElement: true) XCTAssertEqual(b.type(of: outputs[0]), .integer) @@ -1251,18 +1483,24 @@ class JSTyperTests: XCTestCase { let structType = b.wasmDefineTypeGroup { let structType = b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), - WasmStructTypeDescription.Field(type: .wasmi64, mutability: true)], + fields: [ + WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), + WasmStructTypeDescription.Field(type: .wasmi64, mutability: true), + ], indexTypes: []) let structType2 = b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), - WasmStructTypeDescription.Field(type: .wasmi64, mutability: true)], + fields: [ + WasmStructTypeDescription.Field(type: .wasmi32, mutability: true), + WasmStructTypeDescription.Field(type: .wasmi64, mutability: true), + ], indexTypes: []) XCTAssert(b.type(of: structType).Is(.wasmTypeDef())) // Despite having identical structure, the two struct types are not comparable. XCTAssertFalse(b.type(of: structType).Is(b.type(of: structType2))) XCTAssertFalse(b.type(of: structType2).Is(b.type(of: structType))) - let desc = b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription + let desc = + b.type(of: structType).wasmTypeDefinition!.description! + as! WasmStructTypeDescription XCTAssertEqual(desc.fields.count, 2) XCTAssertEqual(desc.fields[0].type, .wasmi32) XCTAssertEqual(desc.fields[1].type, .wasmi64) @@ -1270,7 +1508,8 @@ class JSTyperTests: XCTestCase { }[0] XCTAssert(b.type(of: structType).Is(.wasmTypeDef())) - let desc = b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription + let desc = + b.type(of: structType).wasmTypeDefinition!.description! as! WasmStructTypeDescription XCTAssertEqual(desc.fields.count, 2) XCTAssertEqual(desc.fields[0].type, .wasmi32) XCTAssertEqual(desc.fields[1].type, .wasmi64) @@ -1313,7 +1552,8 @@ class JSTyperTests: XCTestCase { // Actions like `setProperty` modify the ILType but do not modify any information stored in // the ObjectGroupManager. b.setProperty("foo", of: object, to: b.loadInt(123)) - XCTAssertEqual(b.type(of: object), + XCTAssertEqual( + b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) let fooPropertyNew = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooPropertyNew), .function([] => .jsString)) @@ -1330,7 +1570,8 @@ class JSTyperTests: XCTestCase { o.addProperty("foo", as: stringVal) } - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) + XCTAssertEqual( + b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"])) let fooProperty = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooProperty), .jsString) let fooResult = b.callMethod("foo", on: object) @@ -1372,7 +1613,9 @@ class JSTyperTests: XCTestCase { // In JS, the last value a property is set to, overwrites the previous value. Since // Fuzzilli tracks properties and methods separately, they do not overwrite each other in // the ObjectGroupManager (but maybe should). - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) + XCTAssertEqual( + b.type(of: object), + .object(ofGroup: "_fuzz_Object0", withProperties: ["foo"], withMethods: ["foo"])) let fooProperty = b.getProperty("foo", of: object) XCTAssertEqual(b.type(of: fooProperty), .integer) let fooResult = b.callMethod("foo", on: object) @@ -1383,7 +1626,7 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let classDef = b.buildClassDefinition() { cls in + let classDef = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters([.integer])) { params in let this = params[0] XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) @@ -1396,7 +1639,8 @@ class JSTyperTests: XCTestCase { cls.addInstanceMethod("f", with: .parameters(.float)) { params in let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) XCTAssertEqual(b.currentSuperType(), .object()) XCTAssertEqual(b.type(of: params[1]), .float) @@ -1420,8 +1664,12 @@ class JSTyperTests: XCTestCase { } } - let instanceType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a", "foo", "bar", "baz", "blub"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: classDef), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) + let instanceType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a", "foo", "bar", "baz", "blub"], + withMethods: ["f"]) + XCTAssertEqual( + b.type(of: classDef), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) let instance = b.construct(classDef, withArgs: [b.loadInt(42)]) @@ -1433,55 +1681,79 @@ class JSTyperTests: XCTestCase { } func testDynamicObjectGroupTypingOfClassesWithSubclasses() { - let fuzzer = makeMockFuzzer() - let b = fuzzer.makeBuilder() + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() - let classDef = b.buildClassDefinition() { cls in - cls.addConstructor(with: .parameters([.integer])) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) - XCTAssertEqual(b.currentSuperType(), .object()) + let classDef = b.buildClassDefinition { cls in + cls.addConstructor(with: .parameters([.integer])) { params in + let this = params[0] + XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0")) + XCTAssertEqual(b.currentSuperType(), .object()) - XCTAssertEqual(b.type(of: params[1]), .integer) - } + XCTAssertEqual(b.type(of: params[1]), .integer) + } - cls.addInstanceProperty("a") + cls.addInstanceProperty("a") - cls.addInstanceMethod("f", with: .parameters(.float)) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) - XCTAssertEqual(b.currentSuperType(), .object()) + cls.addInstanceMethod("f", with: .parameters(.float)) { params in + let this = params[0] + XCTAssertEqual( + b.type(of: this), .object(ofGroup: "_fuzz_Class0", withProperties: ["a"])) + XCTAssertEqual(b.currentSuperType(), .object()) - XCTAssertEqual(b.type(of: params[1]), .float) + XCTAssertEqual(b.type(of: params[1]), .float) - b.doReturn(b.loadString("foobar")) - } - } + b.doReturn(b.loadString("foobar")) + } + } - let instanceType = ILType.object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) - XCTAssertEqual(b.type(of: classDef), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) + let instanceType = ILType.object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]) + XCTAssertEqual( + b.type(of: classDef), + .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => instanceType)) - let v = b.loadInt(42) - let cls = b.buildClassDefinition(withSuperclass: classDef) { cls in - cls.addInstanceProperty("b", value: v) + let v = b.loadInt(42) + let cls = b.buildClassDefinition(withSuperclass: classDef) { cls in + cls.addInstanceProperty("b", value: v) - cls.addConstructor(with: .parameters([.string])) { params in - XCTAssertEqual(b.currentSuperConstructorType(), .object(ofGroup: "_fuzz_Constructor0") + .constructor([.integer] => .object(ofGroup: "_fuzz_Class0", withProperties: ["a"], withMethods: ["f"]))) - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) - XCTAssertEqual(b.currentSuperType(), instanceType) + cls.addConstructor(with: .parameters([.string])) { params in + XCTAssertEqual( + b.currentSuperConstructorType(), + .object(ofGroup: "_fuzz_Constructor0") + + .constructor( + [.integer] + => .object( + ofGroup: "_fuzz_Class0", withProperties: ["a"], + withMethods: ["f"]))) + let this = params[0] + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual(b.currentSuperType(), instanceType) - b.callSuperConstructor(withArgs: [b.loadFloat(42)]) - } + b.callSuperConstructor(withArgs: [b.loadFloat(42)]) + } - cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in - let this = params[0] - XCTAssertEqual(b.type(of: this), .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) - XCTAssertEqual(b.currentSuperType(), instanceType) - } - } + cls.addInstanceMethod("g", with: .parameters(.jsAnything)) { params in + let this = params[0] + XCTAssertEqual( + b.type(of: this), + .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f"])) + XCTAssertEqual(b.currentSuperType(), instanceType) + } + } - XCTAssertEqual(b.type(of: cls), .object(ofGroup: "_fuzz_Constructor2") + .constructor([.string] => .object(ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], withMethods: ["f", "g"]))) + XCTAssertEqual( + b.type(of: cls), + .object(ofGroup: "_fuzz_Constructor2") + + .constructor( + [.string] + => .object( + ofGroup: "_fuzz_Class2", withProperties: ["a", "b"], + withMethods: ["f", "g"]))) let instance = b.construct(cls, withArgs: [b.loadString("bla")]) @@ -1490,12 +1762,10 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(b.type(ofProperty: "a", on: instance), .jsAnything) } - func testDynamicObjectGroupTypingOfLiterals() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let int = b.loadInt(42) let object = b.buildObjectLiteral { o in @@ -1505,7 +1775,9 @@ class JSTyperTests: XCTestCase { o.addProperty("bla", as: int) } - XCTAssertEqual(b.type(of: object), .object(ofGroup: "_fuzz_Object0", withProperties: ["bla"], withMethods: ["foo"])) + XCTAssertEqual( + b.type(of: object), + .object(ofGroup: "_fuzz_Object0", withProperties: ["bla"], withMethods: ["foo"])) XCTAssertEqual(b.type(ofProperty: "bla", on: object), .integer) } @@ -1519,7 +1791,11 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobalf64: Variable = b.createWasmGlobal(value: .wasmf64(1337), isMutable: false) - XCTAssertEqual(b.type(of: wasmGlobalf64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmf64, isMutable: false))) + XCTAssertEqual( + b.type(of: wasmGlobalf64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmf64, isMutable: false))) let maxPages: Int? = isShared ? 4 : nil let memory = b.createWasmMemory(minPages: 1, maxPages: maxPages, isShared: isShared) @@ -1551,8 +1827,9 @@ class JSTyperTests: XCTestCase { // This forces an import of the wasmGlobalf64, second global function.wasmLoadGlobal(globalVariable: wasmGlobalf64) // This forces an import and a re-export of the jsTag. - function.wasmBuildLegacyTryVoid(body: { _ in }, - catchClauses: [(tag: jsTag, body: {_, _, _ in })]) + function.wasmBuildLegacyTryVoid( + body: { _ in }, + catchClauses: [(tag: jsTag, body: { _, _, _ in })]) function.wasmUnreachable() return [] } @@ -1560,7 +1837,9 @@ class JSTyperTests: XCTestCase { // Function one wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in // Do a store to import the memory. - function.wasmMemoryStore(memory: memory, dynamicOffset: function.consti32(0), value: args[0], storeType: .I32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory, dynamicOffset: function.consti32(0), value: args[0], + storeType: .I32StoreMem, staticOffset: 0) return [function.consti64(1338)] } @@ -1571,25 +1850,38 @@ class JSTyperTests: XCTestCase { } // Function three - wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32, .wasmi64]) { function, label, _ in + wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32, .wasmi64]) { + function, label, _ in return [function.consti32(1), function.consti64(2)] } // Function four - wasmModule.addWasmFunction(with: [] => [ILType.wasmIndexRef(typeDesc, nullability: true)]) { function, label, _ in - return [function.wasmArrayNewDefault(arrayType: typeGroup[0], size: function.consti32(10))] + wasmModule.addWasmFunction( + with: [] => [ILType.wasmIndexRef(typeDesc, nullability: true)] + ) { function, label, _ in + return [ + function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: function.consti32(10)) + ] } - // Function five wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, _ in // This forces an import and we should see a re-exported function on the module. - return [function.wasmJsCall(function: plainFunction, withArgs: [], withWasmSignature: wasmSignature)!] + return [ + function.wasmJsCall( + function: plainFunction, withArgs: [], withWasmSignature: wasmSignature)! + ] } } let exports = module.loadExports() - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports1", withProperties: ["wg0", "iwg0", "wm0", "iwm0", "wex0", "iwex0"], withMethods: ["w0", "w1", "w2", "w3", "w4", "w5", "iw0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports1", + withProperties: ["wg0", "iwg0", "wm0", "iwm0", "wex0", "iwex0"], + withMethods: ["w0", "w1", "w2", "w3", "w4", "w5", "iw0"])) let fun0 = b.methodSignatures(of: module.getExportedMethod(at: 0), on: exports) let fun1 = b.methodSignatures(of: module.getExportedMethod(at: 1), on: exports) @@ -1609,17 +1901,26 @@ class JSTyperTests: XCTestCase { XCTAssertEqual(reexportedFunction, [[] => .object(ofGroup: "_fuzz_Object0")]) let glob0 = b.getProperty("wg0", of: exports) - XCTAssertEqual(b.type(of: glob0), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: glob0), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmi64, isMutable: true))) let glob1 = b.getProperty("iwg0", of: exports) - XCTAssertEqual(b.type(of: glob1), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmf64, isMutable: false))) + XCTAssertEqual( + b.type(of: glob1), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmf64, isMutable: false))) let mem0 = b.getProperty("wm0", of: exports) let memType = ILType.wasmMemory(limits: Limits(min: 3, max: maxPages), isShared: isShared) XCTAssertEqual(b.type(of: mem0), memType) let importedMem = b.getProperty("iwm0", of: exports) - let importedMemType = ILType.wasmMemory(limits: Limits(min: 1, max: maxPages), isShared: isShared) + let importedMemType = ILType.wasmMemory( + limits: Limits(min: 1, max: maxPages), isShared: isShared) XCTAssertEqual(b.type(of: importedMem), importedMemType) let reexportedJsTag = b.getProperty("iwex0", of: exports) @@ -1643,7 +1944,9 @@ class JSTyperTests: XCTestCase { let signatures = b.methodSignatures(of: "indexOf", on: arrayProto) XCTAssertEqual([[.jsAnything, .opt(.integer)] => .integer], signatures) let indexOf = b.getProperty("indexOf", of: arrayProto) - XCTAssertEqual(b.type(of: indexOf), .unboundFunction([.jsAnything, .opt(.integer)] => .integer, receiver: .jsArray)) + XCTAssertEqual( + b.type(of: indexOf), + .unboundFunction([.jsAnything, .opt(.integer)] => .integer, receiver: .jsArray)) // Date.prototype let dateBuiltin = b.createNamedVariable(forBuiltin: "Date") @@ -1659,7 +1962,8 @@ class JSTyperTests: XCTestCase { let promiseProto = b.getProperty("prototype", of: promiseBuiltin) XCTAssert(b.type(of: dateProto).Is(.object(ofGroup: "Date.prototype"))) let then = b.getProperty("then", of: promiseProto) - XCTAssertEqual(b.type(of: then), .unboundFunction([.function()] => .jsPromise, receiver: .jsPromise)) + XCTAssertEqual( + b.type(of: then), .unboundFunction([.function()] => .jsPromise, receiver: .jsPromise)) // ArrayBuffer.prototype let arrayBufferBuiltin = b.createNamedVariable(forBuiltin: "ArrayBuffer") @@ -1667,15 +1971,22 @@ class JSTyperTests: XCTestCase { let arrayBufferProto = b.getProperty("prototype", of: arrayBufferBuiltin) XCTAssert(b.type(of: arrayBufferProto).Is(.object(ofGroup: "ArrayBuffer.prototype"))) let resize = b.getProperty("resize", of: arrayBufferProto) - XCTAssertEqual(b.type(of: resize), .unboundFunction([.integer] => .undefined, receiver: .jsArrayBuffer)) + XCTAssertEqual( + b.type(of: resize), .unboundFunction([.integer] => .undefined, receiver: .jsArrayBuffer) + ) // ArrayBuffer.prototype let sharedArrayBufferBuiltin = b.createNamedVariable(forBuiltin: "SharedArrayBuffer") - XCTAssert(b.type(of: sharedArrayBufferBuiltin).Is(.object(ofGroup: "SharedArrayBufferConstructor"))) + XCTAssert( + b.type(of: sharedArrayBufferBuiltin).Is( + .object(ofGroup: "SharedArrayBufferConstructor"))) let sharedArrayBufferProto = b.getProperty("prototype", of: sharedArrayBufferBuiltin) - XCTAssert(b.type(of: sharedArrayBufferProto).Is(.object(ofGroup: "SharedArrayBuffer.prototype"))) + XCTAssert( + b.type(of: sharedArrayBufferProto).Is(.object(ofGroup: "SharedArrayBuffer.prototype"))) let grow = b.getProperty("grow", of: sharedArrayBufferProto) - XCTAssertEqual(b.type(of: grow), .unboundFunction([.number] => .undefined, receiver: .jsSharedArrayBuffer)) + XCTAssertEqual( + b.type(of: grow), + .unboundFunction([.number] => .undefined, receiver: .jsSharedArrayBuffer)) // Temporal objects let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") @@ -1685,13 +1996,16 @@ class JSTyperTests: XCTestCase { let instantProto = b.getProperty("prototype", of: instantBuiltin) XCTAssert(b.type(of: instantProto).Is(.object(ofGroup: "Temporal.Instant.prototype"))) let instantRound = b.getProperty("round", of: instantProto) - XCTAssert(b.type(of: instantRound).Is(.unboundFunction([.plain(OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType)] => ILType.jsTemporalInstant, - receiver: .jsTemporalInstant))) + XCTAssert( + b.type(of: instantRound).Is( + .unboundFunction( + [.plain(OptionsBag.jsTemporalDifferenceSettingOrRoundTo.group.instanceType)] + => ILType.jsTemporalInstant, + receiver: .jsTemporalInstant))) let randomString = b.randomVariable(forUseAs: .string) let fromCall = b.callMethod("from", on: instantBuiltin, withArgs: [randomString]) XCTAssert(b.type(of: fromCall).Is(.jsTemporalInstant)) - // We don't test Instant's prototype, since Instant only has nontrivial methods that // use options bag types that are still in flux. @@ -1700,8 +2014,9 @@ class JSTyperTests: XCTestCase { let durationProto = b.getProperty("prototype", of: durationBuiltin) XCTAssert(b.type(of: durationProto).Is(.object(ofGroup: "Temporal.Duration.prototype"))) let negated = b.getProperty("negated", of: durationProto) - XCTAssertEqual(b.type(of: negated), .unboundFunction([] => .jsTemporalDuration, receiver: .jsTemporalDuration)) - + XCTAssertEqual( + b.type(of: negated), + .unboundFunction([] => .jsTemporalDuration, receiver: .jsTemporalDuration)) } @@ -1718,7 +2033,8 @@ class JSTyperTests: XCTestCase { let b = fuzzer.makeBuilder() let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") let durationBuiltin = b.getProperty("Duration", of: temporalBuiltin) - let duration = b.callMethod("from", on: durationBuiltin, withArgs: [b.loadString("P10D")]) + let duration = b.callMethod( + "from", on: durationBuiltin, withArgs: [b.loadString("P10D")]) XCTAssert(b.type(of: duration).Is(.jsTemporalDuration)) let signature = chooseUniform(from: b.methodSignatures(of: "round", on: duration)) let args = b.findOrGenerateArguments(forSignature: signature) @@ -1759,13 +2075,15 @@ class JSTyperTests: XCTestCase { let wasm = b.createNamedVariable(forBuiltin: "WebAssembly") XCTAssert(b.type(of: wasm).Is(.object(ofGroup: "WebAssembly"))) let wasmModuleConstructor = b.getProperty("Module", of: wasm) - XCTAssert(b.type(of: wasmModuleConstructor).Is(.object(ofGroup: "WebAssemblyModuleConstructor"))) - let wasmModule = b.construct(wasmModuleConstructor) // In theory this needs arguments. + XCTAssert( + b.type(of: wasmModuleConstructor).Is(.object(ofGroup: "WebAssemblyModuleConstructor"))) + let wasmModule = b.construct(wasmModuleConstructor) // In theory this needs arguments. XCTAssert(b.type(of: wasmModule).Is(.object(ofGroup: "WebAssembly.Module"))) let wasmGlobalConstructor = b.getProperty("Global", of: wasm) - XCTAssert(b.type(of: wasmGlobalConstructor).Is(.object(ofGroup: "WebAssemblyGlobalConstructor"))) - let wasmGlobal = b.construct(wasmGlobalConstructor) // In theory this needs arguments. + XCTAssert( + b.type(of: wasmGlobalConstructor).Is(.object(ofGroup: "WebAssemblyGlobalConstructor"))) + let wasmGlobal = b.construct(wasmGlobalConstructor) // In theory this needs arguments. // We do not type the constructed value as globals as the "WasmGlobal" object group expects // to have a WasmTypeExtension. XCTAssertFalse(b.type(of: wasmGlobal).Is(.object(ofGroup: "WasmGlobal"))) @@ -1777,56 +2095,75 @@ class JSTyperTests: XCTestCase { // WebAssembly.Global.prototype.valueOf() function. let globalPrototype = b.getProperty("prototype", of: wasmGlobalConstructor) let valueOf = b.getProperty("valueOf", of: globalPrototype) - XCTAssertEqual(b.type(of: valueOf), .unboundFunction([] => .jsAnything, receiver: .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"]))) + XCTAssertEqual( + b.type(of: valueOf), + .unboundFunction( + [] => .jsAnything, + receiver: .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"]))) let wasmMemoryConstructor = b.getProperty("Memory", of: wasm) - let wasmMemory = b.construct(wasmMemoryConstructor) // In theory this needs arguments. + let wasmMemory = b.construct(wasmMemoryConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmMemory).Is(.object(ofGroup: "WasmMemory"))) let realWasmMemory = b.createWasmMemory(minPages: 1, maxPages: 1, isShared: false) XCTAssert(b.type(of: realWasmMemory).Is(.object(ofGroup: "WasmMemory"))) XCTAssert(b.type(of: realWasmMemory).Is(ObjectGroup.jsWasmMemory.instanceType)) let memoryPrototype = b.getProperty("prototype", of: wasmMemoryConstructor) let grow = b.getProperty("grow", of: memoryPrototype) - XCTAssert(b.type(of: grow).Is(.unboundFunction([.number] => .number, receiver: .object(ofGroup: "WasmMemory")))) + XCTAssert( + b.type(of: grow).Is( + .unboundFunction([.number] => .number, receiver: .object(ofGroup: "WasmMemory")))) let wasmTableConstructor = b.getProperty("Table", of: wasm) - let wasmTable = b.construct(wasmTableConstructor) // In theory this needs arguments. + let wasmTable = b.construct(wasmTableConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmTable).Is(.object(ofGroup: "WasmTable"))) - let realWasmTable = b.createWasmTable(elementType: .wasmAnyRef(), limits: .init(min: 0), isTable64: false) + let realWasmTable = b.createWasmTable( + elementType: .wasmAnyRef(), limits: .init(min: 0), isTable64: false) XCTAssert(b.type(of: realWasmTable).Is(.object(ofGroup: "WasmTable"))) XCTAssert(b.type(of: realWasmTable).Is(ObjectGroup.wasmTable.instanceType)) let tablePrototype = b.getProperty("prototype", of: wasmTableConstructor) let tableGrow = b.getProperty("grow", of: tablePrototype) - XCTAssert(b.type(of: tableGrow).Is(.unboundFunction([.number, .opt(.jsAnything)] => .number, receiver: .object(ofGroup: "WasmTable")))) + XCTAssert( + b.type(of: tableGrow).Is( + .unboundFunction( + [.number, .opt(.jsAnything)] => .number, receiver: .object(ofGroup: "WasmTable") + ))) let wasmTagConstructor = b.getProperty("Tag", of: wasm) - let wasmTag = b.construct(wasmTagConstructor) // In theory this needs arguments. + let wasmTag = b.construct(wasmTagConstructor) // In theory this needs arguments. XCTAssertFalse(b.type(of: wasmTag).Is(.object(ofGroup: "WasmTag"))) let realWasmTag = b.createWasmTag(parameterTypes: [.wasmi32]) XCTAssert(b.type(of: realWasmTag).Is(.object(ofGroup: "WasmTag"))) let tagPrototype = b.getProperty("prototype", of: wasmTagConstructor) - XCTAssertEqual(b.type(of: tagPrototype), - .object(ofGroup: "WasmTag.prototype", withProperties: ["constructor"])) + XCTAssertEqual( + b.type(of: tagPrototype), + .object(ofGroup: "WasmTag.prototype", withProperties: ["constructor"])) let wasmExceptionConstructor = b.getProperty("Exception", of: wasm) - let wasmException = b.construct(wasmExceptionConstructor) // In theory this needs arguments. + let wasmException = b.construct(wasmExceptionConstructor) // In theory this needs arguments. XCTAssert(b.type(of: wasmException).Is(.object(ofGroup: "WebAssembly.Exception"))) let isResult = b.callMethod("is", on: wasmException, withArgs: [realWasmTag]) XCTAssertEqual(b.type(of: isResult), .boolean) let exceptionPrototype = b.getProperty("prototype", of: wasmExceptionConstructor) - XCTAssert(b.type(of: exceptionPrototype).Is(ObjectGroup.jsWebAssemblyExceptionPrototype.instanceType)) + XCTAssert( + b.type(of: exceptionPrototype).Is( + ObjectGroup.jsWebAssemblyExceptionPrototype.instanceType)) let exceptionIs = b.getProperty("is", of: exceptionPrototype) - XCTAssert(b.type(of: exceptionIs).Is(.unboundFunction([.plain(ObjectGroup.jsWasmTag.instanceType)] => ILType.boolean, receiver: .object(ofGroup: "WebAssembly.Exception")))) + XCTAssert( + b.type(of: exceptionIs).Is( + .unboundFunction( + [.plain(ObjectGroup.jsWasmTag.instanceType)] => ILType.boolean, + receiver: .object(ofGroup: "WebAssembly.Exception")))) } func testProducingGenerators() { // Make a simple object - let mockEnum = ILType.enumeration(ofName: "MockEnum", withValues: ["mockValue"]); + let mockEnum = ILType.enumeration(ofName: "MockEnum", withValues: ["mockValue"]) let mockObject = ObjectGroup( name: "MockObject", instanceType: nil, properties: [ - "mockField" : mockEnum + "mockField": mockEnum ], methods: [:] ) @@ -1845,7 +2182,7 @@ class JSTyperTests: XCTestCase { return variable } - let mockNamedString = ILType.namedString(ofName: "NamedString"); + let mockNamedString = ILType.namedString(ofName: "NamedString") func generateString() -> String { callCount += 1 return "mockStringValue" @@ -1854,7 +2191,8 @@ class JSTyperTests: XCTestCase { let fuzzer = makeMockFuzzer() fuzzer.environment.registerObjectGroup(mockObject) fuzzer.environment.registerEnumeration(mockEnum) - fuzzer.environment.addProducingGenerator(forType: mockObject.instanceType, with: generateObject) + fuzzer.environment.addProducingGenerator( + forType: mockObject.instanceType, with: generateObject) fuzzer.environment.addNamedStringGenerator(forType: mockNamedString, with: generateString) let b = fuzzer.makeBuilder() b.buildPrefix() @@ -1866,7 +2204,6 @@ class JSTyperTests: XCTestCase { // Test that the returned variable matches the generated one XCTAssertEqual(variable, returnedVar) - // Try to get it to invoke the string generator let variable2 = b.findOrGenerateType(mockNamedString) // Test that the generator was invoked @@ -1887,7 +2224,10 @@ class JSTyperTests: XCTestCase { } func testFindConstructor() { - for ctor in ["TemporalPlainMonthDayConstructor", "DateConstructor", "PromiseConstructor", "SymbolConstructor", "TemporalZonedDateTimeConstructor"] { + for ctor in [ + "TemporalPlainMonthDayConstructor", "DateConstructor", "PromiseConstructor", + "SymbolConstructor", "TemporalZonedDateTimeConstructor", + ] { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() let temporalBuiltin = b.createNamedVariable(forBuiltin: "Temporal") @@ -1909,7 +2249,7 @@ class JSTyperTests: XCTestCase { XCTAssert(unionType.Is(.jsArrayBuffer | .jsSharedArrayBuffer)) XCTAssert(unionType.MayBe(.jsArrayBuffer)) XCTAssert(unionType.MayBe(.jsSharedArrayBuffer)) - XCTAssertFalse(unionType.Is(.jsArrayBuffer)) // It's not *definitely* an ArrayBuffer + XCTAssertFalse(unionType.Is(.jsArrayBuffer)) // It's not *definitely* an ArrayBuffer XCTAssertFalse(unionType.Is(.jsSharedArrayBuffer)) // Common properties should be preserved @@ -1917,8 +2257,8 @@ class JSTyperTests: XCTestCase { XCTAssert(unionType.methods.contains("slice")) // Disjoint properties/methods should be removed in the union - XCTAssertFalse(unionType.methods.contains("resize")) // Only on ArrayBuffer - XCTAssertFalse(unionType.methods.contains("grow")) // Only on SharedArrayBuffer + XCTAssertFalse(unionType.methods.contains("resize")) // Only on ArrayBuffer + XCTAssertFalse(unionType.methods.contains("grow")) // Only on SharedArrayBuffer XCTAssertNil(unionType.group) } diff --git a/Tests/FuzzilliTests/Leb128Test.swift b/Tests/FuzzilliTests/Leb128Test.swift index 0c6ef64f1..701381adb 100644 --- a/Tests/FuzzilliTests/Leb128Test.swift +++ b/Tests/FuzzilliTests/Leb128Test.swift @@ -13,11 +13,12 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class Leb128Tests: XCTestCase { func testUnsignedEncode() { - let encoded = Leb128.unsignedEncode(624485); - XCTAssertEqual(encoded.map({ String(format: "%02hhx", $0)}).joined(), "e58e26") + let encoded = Leb128.unsignedEncode(624485) + XCTAssertEqual(encoded.map({ String(format: "%02hhx", $0) }).joined(), "e58e26") } } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 0f1a51621..0840baf24 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class LifterTests: XCTestCase { @@ -88,12 +89,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - v1.r = SomeObj.foo.bar.baz(42, 42); - v1.s = Math.random() + 13.37; - v1.s; + const v1 = new Object(); + v1.r = SomeObj.foo.bar.baz(42, 42); + v1.s = Math.random() + 13.37; + v1.s; - """ + """ XCTAssertEqual(actual, expected) } @@ -116,11 +117,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - const t1 = SomeObj.foo.bar.baz; - v1.r = t1(42, 42); + const v1 = new Object(); + const t1 = SomeObj.foo.bar.baz; + v1.r = t1(42, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -200,44 +201,43 @@ class LifterTests: XCTestCase { res = b.callMethod("func36", on: effectful, withArgs: [x, z, tmp]) b.setProperty("res12", of: obj, to: res) - let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - v1.res1 = effectful.func1() + effectful.func2(); - const v6 = effectful.func3(); - effectful.func4(); - v1.res2 = v6 + 13.37; - effectful.func5(); - const v11 = effectful.func6(); - effectful.func7(); - v1.res3 = -v11; - v1.res4 = 13.37; - const v15 = effectful.func8(); - const v16 = effectful.func9(); - const v17 = effectful.func10(v15); - v1.res5 = v16; - v1.res6 = v17; - effectful.func11(); - const v19 = effectful.func12(); - v1.res7 = (effectful.func13() + (effectful.func14() * effectful.func15())) / v19; - v1.res8 = effectful.func19(effectful.func16(), effectful.func17(), effectful.func18()); - const v30 = effectful.func20(); - v1.res9 = effectful.func23(effectful.func21(), effectful.func22(), v30); - const v34 = effectful.func24(); - const v35 = effectful.func25(); - v1.res10 = effectful.func27(v34, effectful.func26(), v35); - const v38 = effectful.func28(); - const v39 = effectful.func29(); - v1.res11 = effectful.func31(effectful.func30(), v38, v39); - const v42 = effectful.func32(); - const v43 = effectful.func33(); - const v44 = effectful.func34(); - v1.res12 = effectful.func36(v42, v44, effectful.func35(v43)); - - """ + const v1 = new Object(); + v1.res1 = effectful.func1() + effectful.func2(); + const v6 = effectful.func3(); + effectful.func4(); + v1.res2 = v6 + 13.37; + effectful.func5(); + const v11 = effectful.func6(); + effectful.func7(); + v1.res3 = -v11; + v1.res4 = 13.37; + const v15 = effectful.func8(); + const v16 = effectful.func9(); + const v17 = effectful.func10(v15); + v1.res5 = v16; + v1.res6 = v17; + effectful.func11(); + const v19 = effectful.func12(); + v1.res7 = (effectful.func13() + (effectful.func14() * effectful.func15())) / v19; + v1.res8 = effectful.func19(effectful.func16(), effectful.func17(), effectful.func18()); + const v30 = effectful.func20(); + v1.res9 = effectful.func23(effectful.func21(), effectful.func22(), v30); + const v34 = effectful.func24(); + const v35 = effectful.func25(); + v1.res10 = effectful.func27(v34, effectful.func26(), v35); + const v38 = effectful.func28(); + const v39 = effectful.func29(); + v1.res11 = effectful.func31(effectful.func30(), v38, v39); + const v42 = effectful.func32(); + const v43 = effectful.func33(); + const v44 = effectful.func34(); + v1.res12 = effectful.func36(v42, v44, effectful.func35(v43)); + + """ XCTAssertEqual(actual, expected) } @@ -260,11 +260,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - if (someValue < computeThreshold()) { - doSomething(); - } + if (someValue < computeThreshold()) { + doSomething(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -285,13 +285,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - const v2 = computeNumIterations(); - while (v0 < v2) { - v0++; - } + let v0 = 0; + const v2 = computeNumIterations(); + while (v0 < v2) { + v0++; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -315,12 +315,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = new Object(); - const v6 = func2(func1(1337)); - v1.x = v6; - v1.y = v6; + const v1 = new Object(); + const v6 = func2(func1(1337)); + v1.x = v6; + v1.y = v6; - """ + """ XCTAssertEqual(actual, expected) } @@ -340,11 +340,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - [NaN,NaN,NaN]; - let v2 = NaN; - v2 = 13.37; + [NaN,NaN,NaN]; + let v2 = NaN; + v2 = 13.37; - """ + """ XCTAssertEqual(actual, expected) } @@ -372,12 +372,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - const v2 = a1.x; - return a1.y ? v2 : a1.z; - } + function f0(a1) { + const v2 = a1.x; + return a1.y ? v2 : a1.z; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -403,11 +403,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - return Math.sqrt((a1.x ** 2) + (a1.y ** 2)); - } + function f0(a1) { + return Math.sqrt((a1.x ** 2) + (a1.y ** 2)); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -421,33 +421,34 @@ class LifterTests: XCTestCase { // operation where we force the object to be a variable. let i1 = b.loadInt(0) let i2 = b.loadInt(10) - b.buildDoWhileLoop(do: { - // The SetElement will "un-inline" i2, but for the do-while loop we'll still need the inlined expression (`10`). - b.setElement(0, of: i2, to: i1) - b.setElement(1, of: i2, to: i1) - b.unary(.PostInc, i1) - }, while: { b.compare(i1, with: i2, using: .lessThan) }) + b.buildDoWhileLoop( + do: { + // The SetElement will "un-inline" i2, but for the do-while loop we'll still need the inlined expression (`10`). + b.setElement(0, of: i2, to: i1) + b.setElement(1, of: i2, to: i1) + b.unary(.PostInc, i1) + }, while: { b.compare(i1, with: i2, using: .lessThan) }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - do { - const t2 = 10; - t2[0] = v0; - const t4 = 10; - t4[1] = v0; - v0++; - } while (v0 < 10) + let v0 = 0; + do { + const t2 = 10; + t2[0] = v0; + const t4 = 10; + t4[1] = v0; + v0++; + } while (v0 < 10) - """ + """ XCTAssertEqual(actual, expected) } func testForceVariableDefinitions() { - let createProgram = {(config: Configuration) in + let createProgram = { (config: Configuration) in let fuzzer = makeMockFuzzer(config: config) let b = fuzzer.makeBuilder() let dateBuiltin = b.createNamedVariable(forBuiltin: "Date") @@ -462,20 +463,20 @@ class LifterTests: XCTestCase { let config = Configuration(logLevel: .warning) let actual = createProgram(config) let expected = """ - Date.prototype; - new Array(); + Date.prototype; + new Array(); - """ + """ XCTAssertEqual(actual, expected) } do { let config = Configuration(logLevel: .warning, forDifferentialFuzzing: true) let actual = createProgram(config) let expected = """ - const v1 = Date.prototype; - const v3 = new Array(); + const v1 = Date.prototype; + const v3 = new Array(); - """ + """ XCTAssertEqual(actual, expected) } } @@ -494,16 +495,17 @@ class LifterTests: XCTestCase { b.loadInt(42) b.loadString("foobar") b.createNamedVariable("nonexistant", declarationMode: .none) - let v = b.createNamedVariable("alsoNonexistantButSafeToAccessViaTypeOf", declarationMode: .none) + let v = b.createNamedVariable( + "alsoNonexistantButSafeToAccessViaTypeOf", declarationMode: .none) b.typeof(v) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - typeof alsoNonexistantButSafeToAccessViaTypeOf; + typeof alsoNonexistantButSafeToAccessViaTypeOf; - """ + """ XCTAssertEqual(actual, expected) } @@ -555,39 +557,39 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = "foobar" + 42; - const v7 = Symbol.toPrimitive; - const v20 = { - p1: 42, - __proto__: null, - 0: 13.37, - [-1]: 13.37, - ["foobar"]: "foobar", - p2: 13.37, - [v4]: 42, - __proto__: null, - m(a9, a10) { - return a9 - a10; - }, - [v7]() { - return 42; - }, - get prop() { - return this.p; - }, - set prop(a16) { - this.p = a16; - }, - get ["foobar"]() { - return 42; - }, - set ["foobar"](a19) { - this.p = a19; - }, - ...SomeObject, - }; + const v4 = "foobar" + 42; + const v7 = Symbol.toPrimitive; + const v20 = { + p1: 42, + __proto__: null, + 0: 13.37, + [-1]: 13.37, + ["foobar"]: "foobar", + p2: 13.37, + [v4]: 42, + __proto__: null, + m(a9, a10) { + return a9 - a10; + }, + [v7]() { + return 42; + }, + get prop() { + return this.p; + }, + set prop(a16) { + this.p = a16; + }, + get ["foobar"]() { + return 42; + }, + set ["foobar"](a19) { + this.p = a19; + }, + ...SomeObject, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -597,7 +599,7 @@ class LifterTests: XCTestCase { let v = b.loadInt(42) b.buildObjectLiteral { obj in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { obj.addProperty(name, as: v) obj.addMethod(name, with: .parameters(n: 0)) { args in } @@ -608,34 +610,34 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v9 = { - "???": 42, - "???"() { - }, - 0: 42, - 0() { - }, - "01": 42, - "01"() { - }, - 1: 42, - 1() { - }, - "0.1": 42, - "0.1"() { - }, - "-1": 42, - "-1"() { - }, - $valid_id_42: 42, - $valid_id_42() { - }, - "42_invalid_id": 42, - "42_invalid_id"() { - }, - }; + const v9 = { + "???": 42, + "???"() { + }, + 0: 42, + 0() { + }, + "01": 42, + "01"() { + }, + 1: 42, + 1() { + }, + "0.1": 42, + "0.1"() { + }, + "-1": 42, + "-1"() { + }, + $valid_id_42: 42, + $valid_id_42() { + }, + "42_invalid_id": 42, + "42_invalid_id"() { + }, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -645,7 +647,7 @@ class LifterTests: XCTestCase { let v = b.loadInt(42) b.buildObjectLiteral { obj in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { obj.addGetter(for: name) { _ in b.doReturn(v) } obj.addSetter(for: name) { _, _ in } } @@ -655,50 +657,50 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v25 = { - get "???"() { - return 42; - }, - set "???"(a3) { - }, - get 0() { - return 42; - }, - set 0(a6) { - }, - get "01"() { - return 42; - }, - set "01"(a9) { - }, - get 1() { - return 42; - }, - set 1(a12) { - }, - get "0.1"() { - return 42; - }, - set "0.1"(a15) { - }, - get "-1"() { - return 42; - }, - set "-1"(a18) { - }, - get $valid_id_42() { - return 42; - }, - set $valid_id_42(a21) { - }, - get "42_invalid_id"() { - return 42; - }, - set "42_invalid_id"(a24) { - }, - }; + const v25 = { + get "???"() { + return 42; + }, + set "???"(a3) { + }, + get 0() { + return 42; + }, + set 0(a6) { + }, + get "01"() { + return 42; + }, + set "01"(a9) { + }, + get 1() { + return 42; + }, + set 1(a12) { + }, + get "0.1"() { + return 42; + }, + set "0.1"(a15) { + }, + get "-1"() { + return 42; + }, + set "-1"(a18) { + }, + get $valid_id_42() { + return 42; + }, + set $valid_id_42(a21) { + }, + get "42_invalid_id"() { + return 42; + }, + set "42_invalid_id"(a24) { + }, + }; - """ + """ XCTAssertEqual(actual, expected) } @@ -719,9 +721,9 @@ class LifterTests: XCTestCase { // These must not lift to something like "{ foo: 1, bar: 2 };" as that would be invalid: // the parser cannot distinguish it from a block statement. let expected = """ - const v2 = { foo: 1, bar: 2 }; + const v2 = { foo: 1, bar: 2 }; - """ + """ XCTAssertEqual(actual, expected) } @@ -756,15 +758,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - print({}); - print({ foo: 42, bar: 13.37, 42: "foo" }); - const v9 = { - baz() { - }, - }; - print(v9); + print({}); + print({ foo: 42, bar: 13.37, 42: "foo" }); + const v9 = { + baz() { + }, + }; + print(v9); - """ + """ XCTAssertEqual(actual, expected) } @@ -778,7 +780,7 @@ class LifterTests: XCTestCase { let baz42 = b.binary(baz, i, with: .Add) let toPrimitive = b.createSymbolProperty("toPrimitive") let sm = b.loadString("sm") - let C = b.buildClassDefinition() { cls in + let C = b.buildClassDefinition { cls in cls.addInstanceProperty("foo") cls.addInstanceProperty("bar", value: baz) cls.addInstanceElement(0, value: i) @@ -876,88 +878,88 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v3 = "baz" + 42; - const v5 = Symbol.toPrimitive; - class C7 { - foo; - bar = "baz"; - 0 = 42; - 1; - [-1]; - [v3]; - [2] = v3; - constructor(a9) { - this.foo = a9; - } - m() { - return this.foo; - } - [v5]() { - return this.foo; - } - get baz() { - return 1337; - } - set baz(a17) { - } - get ["baz"]() { - return 1337; - } - set ["baz"](a21) { - } - static foo; - static { - this.foo = 42; - } - static bar = "baz"; - static 0 = 42; - static 1; - static [-1]; - static [v3]; - static [2] = v3; - static m() { - return this.foo; - } - ["sm"]() { - return this.foo; - } - static get baz() { - return 1337; - } - static set baz(a30) { - } - static get ["baz"]() { - return 1337; - } - static set ["baz"](a34) { - } - #ifoo; - #ibar = "baz"; - #im() { - const v36 = this.#ifoo; - this.#ibar = v36; - return v36; - } - #in(a38) { - this.#im(); - this.#ibar += a38; - } - static #sfoo; - static #sbar = "baz"; - static #sm() { - const v41 = this.#sfoo; - this.#sbar = v41; - return v41; - } - static #sn(a43) { - this.#sm(); - this.#sbar += a43; + const v3 = "baz" + 42; + const v5 = Symbol.toPrimitive; + class C7 { + foo; + bar = "baz"; + 0 = 42; + 1; + [-1]; + [v3]; + [2] = v3; + constructor(a9) { + this.foo = a9; + } + m() { + return this.foo; + } + [v5]() { + return this.foo; + } + get baz() { + return 1337; + } + set baz(a17) { + } + get ["baz"]() { + return 1337; + } + set ["baz"](a21) { + } + static foo; + static { + this.foo = 42; + } + static bar = "baz"; + static 0 = 42; + static 1; + static [-1]; + static [v3]; + static [2] = v3; + static m() { + return this.foo; + } + ["sm"]() { + return this.foo; + } + static get baz() { + return 1337; + } + static set baz(a30) { + } + static get ["baz"]() { + return 1337; + } + static set ["baz"](a34) { + } + #ifoo; + #ibar = "baz"; + #im() { + const v36 = this.#ifoo; + this.#ibar = v36; + return v36; + } + #in(a38) { + this.#im(); + this.#ibar += a38; + } + static #sfoo; + static #sbar = "baz"; + static #sm() { + const v41 = this.#sfoo; + this.#sbar = v41; + return v41; + } + static #sn(a43) { + this.#sm(); + this.#sbar += a43; + } } - } - new C7(42); - C7 = Uint8Array; + new C7(42); + C7 = Uint8Array; - """ + """ XCTAssertEqual(actual, expected) } @@ -967,8 +969,8 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let v = b.loadInt(42) - b.buildClassDefinition() { cls in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.buildClassDefinition { cls in + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { cls.addInstanceProperty(name, value: v) cls.addStaticProperty(name, value: v) cls.addInstanceMethod(name, with: .parameters(n: 0)) { params in @@ -982,58 +984,58 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C1 { - "???" = 42; - static "???" = 42; - "???"() { - } - static "???"() { - } - 0 = 42; - static 0 = 42; - 0() { - } - static 0() { - } - "01" = 42; - static "01" = 42; - "01"() { - } - static "01"() { - } - 1 = 42; - static 1 = 42; - 1() { - } - static 1() { - } - "0.1" = 42; - static "0.1" = 42; - "0.1"() { - } - static "0.1"() { - } - "-1" = 42; - static "-1" = 42; - "-1"() { - } - static "-1"() { - } - $valid_id_42 = 42; - static $valid_id_42 = 42; - $valid_id_42() { - } - static $valid_id_42() { - } - "42_invalid_id" = 42; - static "42_invalid_id" = 42; - "42_invalid_id"() { - } - static "42_invalid_id"() { + class C1 { + "???" = 42; + static "???" = 42; + "???"() { + } + static "???"() { + } + 0 = 42; + static 0 = 42; + 0() { + } + static 0() { + } + "01" = 42; + static "01" = 42; + "01"() { + } + static "01"() { + } + 1 = 42; + static 1 = 42; + 1() { + } + static 1() { + } + "0.1" = 42; + static "0.1" = 42; + "0.1"() { + } + static "0.1"() { + } + "-1" = 42; + static "-1" = 42; + "-1"() { + } + static "-1"() { + } + $valid_id_42 = 42; + static $valid_id_42 = 42; + $valid_id_42() { + } + static $valid_id_42() { + } + "42_invalid_id" = 42; + static "42_invalid_id" = 42; + "42_invalid_id"() { + } + static "42_invalid_id"() { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -1042,8 +1044,8 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + b.buildClassDefinition { cls in + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { cls.addInstanceGetter(for: name) { this in } cls.addStaticGetter(for: name) { this in @@ -1059,74 +1061,74 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - get "???"() { - } - static get "???"() { - } - set "???"(a4) { - } - static set "???"(a6) { - } - get 0() { - } - static get 0() { - } - set 0(a10) { - } - static set 0(a12) { - } - get "01"() { - } - static get "01"() { - } - set "01"(a16) { - } - static set "01"(a18) { - } - get 1() { - } - static get 1() { - } - set 1(a22) { - } - static set 1(a24) { - } - get "0.1"() { - } - static get "0.1"() { - } - set "0.1"(a28) { - } - static set "0.1"(a30) { - } - get "-1"() { - } - static get "-1"() { - } - set "-1"(a34) { - } - static set "-1"(a36) { - } - get $valid_id_42() { - } - static get $valid_id_42() { - } - set $valid_id_42(a40) { - } - static set $valid_id_42(a42) { - } - get "42_invalid_id"() { - } - static get "42_invalid_id"() { - } - set "42_invalid_id"(a46) { - } - static set "42_invalid_id"(a48) { + class C0 { + get "???"() { + } + static get "???"() { + } + set "???"(a4) { + } + static set "???"(a6) { + } + get 0() { + } + static get 0() { + } + set 0(a10) { + } + static set 0(a12) { + } + get "01"() { + } + static get "01"() { + } + set "01"(a16) { + } + static set "01"(a18) { + } + get 1() { + } + static get 1() { + } + set 1(a22) { + } + static set 1(a24) { + } + get "0.1"() { + } + static get "0.1"() { + } + set "0.1"(a28) { + } + static set "0.1"(a30) { + } + get "-1"() { + } + static get "-1"() { + } + set "-1"(a34) { + } + static set "-1"(a36) { + } + get $valid_id_42() { + } + static get $valid_id_42() { + } + set $valid_id_42(a40) { + } + static set $valid_id_42(a42) { + } + get "42_invalid_id"() { + } + static get "42_invalid_id"() { + } + set "42_invalid_id"(a46) { + } + static set "42_invalid_id"(a48) { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -1147,14 +1149,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = class { - 1; - } - let d = v0; - new v0(); - new d(); + const v0 = class { + 1; + } + let d = v0; + new v0(); + new d(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1171,13 +1173,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = class { - } - const v1 = class extends v0 { - } - new v1(); + const v0 = class { + } + const v1 = class extends v0 { + } + new v1(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1199,7 +1201,7 @@ class LifterTests: XCTestCase { let va = b.createArray(with: initialValues) b.createArray(with: [b.loadInt(301), b.loadUndefined()]) b.createArray(with: [b.loadUndefined()]) - b.createArray(with: [va, b.loadUndefined()], spreading: [true,false]) + b.createArray(with: [va, b.loadUndefined()], spreading: [true, false]) b.createArray(with: [b.loadUndefined()], spreading: [false]) b.createIntArray(with: [1, 2, 3, 4]) b.createFloatArray(with: [1.1, 2.2, 3.3, 4.4]) @@ -1208,16 +1210,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v6 = "foobar"; - const v8 = [1,2,,4,,6,v6 = undefined]; - [301,,]; - [,]; - [...v8,,]; - [,]; - [1,2,3,4]; - [1.1,2.2,3.3,4.4]; - - """ + let v6 = "foobar"; + const v8 = [1,2,,4,,6,v6 = undefined]; + [301,,]; + [,]; + [...v8,,]; + [,]; + [1,2,3,4]; + [1.1,2.2,3.3,4.4]; + + """ XCTAssertEqual(actual, expected) } @@ -1238,10 +1240,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - [42,,,42]; - [,,]; + [42,,,42]; + [,,]; - """ + """ XCTAssertEqual(actual, expected) } @@ -1264,10 +1266,10 @@ class LifterTests: XCTestCase { // TODO: Lifting could be improved to remove some brackets. let expected = """ - const v1 = Math.random(); - print((4 * ((v1 + v1) + v1)) / 2); + const v1 = Math.random(); + print((4 * ((v1 + v1) + v1)) / 2); - """ + """ XCTAssertEqual(actual, expected) } @@ -1277,19 +1279,19 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let v0 = b.loadRegExp("a", RegExpFlags()) - b.compare(v0, with: v0, using: .equal); + b.compare(v0, with: v0, using: .equal) let v1 = b.loadRegExp("b", RegExpFlags()) - b.compare(v0, with: v1, using: .equal); + b.compare(v0, with: v1, using: .equal) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = /a/; - v0 == v0; - v0 == /b/; + const v0 = /a/; + v0 == v0; + v0 == /b/; - """ + """ XCTAssertEqual(actual, expected) } @@ -1298,15 +1300,15 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let code1 = b.buildCodeString() { - let code2 = b.buildCodeString() { - let code3 = b.buildCodeString() { - let code4 = b.buildCodeString() { + let code1 = b.buildCodeString { + let code2 = b.buildCodeString { + let code3 = b.buildCodeString { + let code4 = b.buildCodeString { let print = b.createNamedVariable(forBuiltin: "print") let msg = b.loadString("Hello") b.callFunction(print, withArgs: [msg]) } - let code5 = b.buildCodeString() { + let code5 = b.buildCodeString { let print = b.createNamedVariable(forBuiltin: "print") let msg = b.loadString("World") b.callFunction(print, withArgs: [msg]) @@ -1328,25 +1330,25 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = ` - const v1 = \\` - const v2 = \\\\\\` - const v3 = \\\\\\\\\\\\\\` - print("Hello"); - \\\\\\\\\\\\\\`; - const v7 = \\\\\\\\\\\\\\` - print("World"); - \\\\\\\\\\\\\\`; - eval(v3); - eval(v7); - \\\\\\`; - eval(v2); - \\`; - eval(v1); - `; - eval(v0); - - """ + const v0 = ` + const v1 = \\` + const v2 = \\\\\\` + const v3 = \\\\\\\\\\\\\\` + print("Hello"); + \\\\\\\\\\\\\\`; + const v7 = \\\\\\\\\\\\\\` + print("World"); + \\\\\\\\\\\\\\`; + eval(v3); + eval(v7); + \\\\\\`; + eval(v2); + \\`; + eval(v1); + `; + eval(v0); + + """ XCTAssertEqual(actual, expected) @@ -1370,14 +1372,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1) { - return a1; - } - f0(13.37); - f0 = () => "foobar"; - f0(); + function f0(a1) { + return a1; + } + f0(13.37); + f0 = () => "foobar"; + f0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1388,13 +1390,16 @@ class LifterTests: XCTestCase { let sf = b.buildPlainFunction(with: .parameters(n: 3)) { args in b.directive("use strict") - b.buildIfElse(args[0], ifBody: { - let v = b.binary(args[1], args[2], with: .Mul) - b.doReturn(v) - }, elseBody: { - let v = b.binary(args[1], args[2], with: .Add) - b.doReturn(v) - }) + b.buildIfElse( + args[0], + ifBody: { + let v = b.binary(args[1], args[2], with: .Mul) + b.doReturn(v) + }, + elseBody: { + let v = b.binary(args[1], args[2], with: .Add) + b.doReturn(v) + }) } b.callFunction(sf, withArgs: [b.loadBool(true), b.loadInt(1), b.loadInt(2)]) @@ -1402,17 +1407,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2, a3) { - 'use strict'; - if (a1) { - return a2 * a3; - } else { - return a2 + a3; + function f0(a1, a2, a3) { + 'use strict'; + if (a1) { + return a2 * a3; + } else { + return a2 + a3; + } } - } - f0(true, 1, 2); + f0(true, 1, 2); - """ + """ XCTAssertEqual(actual, expected) } @@ -1435,20 +1440,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function foo() { - } - function* bar() { - } - async function baz() { - } - async function* bla() { - } - foo(); - bar(); - baz(); - bla(); + function foo() { + } + function* bar() { + } + async function baz() { + } + async function* bla() { + } + foo(); + bar(); + baz(); + bla(); - """ + """ XCTAssertEqual(actual, expected) } @@ -1464,11 +1469,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - foo(); - function foo() { - } + foo(); + function foo() { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -1490,16 +1495,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function F0(a2, a3) { - if (!new.target) { throw 'must be called with new'; } - this.foo = a2; - this.bar = a3; - } - new F0(42, 43); - F0 = Object; - new F0(44, 45); + function F0(a2, a3) { + if (!new.target) { throw 'must be called with new'; } + this.foo = a2; + this.bar = a3; + } + new F0(42, 43); + F0 = Object; + new F0(44, 45); - """ + """ XCTAssertEqual(actual, expected) } @@ -1520,24 +1525,34 @@ class LifterTests: XCTestCase { let r = b.binary(lhs, rhs, with: .Mul) b.yield(r) } - b.callFunction(f1, withArgs: [b.createNamedVariable(forBuiltin: "promise1"), b.createNamedVariable(forBuiltin: "promise2")]) - b.callFunction(f2, withArgs: [b.createNamedVariable(forBuiltin: "promise3"), b.createNamedVariable(forBuiltin: "promise4")]) + b.callFunction( + f1, + withArgs: [ + b.createNamedVariable(forBuiltin: "promise1"), + b.createNamedVariable(forBuiltin: "promise2"), + ]) + b.callFunction( + f2, + withArgs: [ + b.createNamedVariable(forBuiltin: "promise3"), + b.createNamedVariable(forBuiltin: "promise4"), + ]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - async function f0(a1, a2) { - return await a1 + await a2; - } - async function* f6(a7, a8) { - 'use strict'; - yield await a7 * await a8; - } - f0(promise1, promise2); - f6(promise3, promise4); + async function f0(a1, a2) { + return await a1 + await a2; + } + async function* f6(a7, a8) { + 'use strict'; + yield await a7 * await a8; + } + f0(promise1, promise2); + f6(promise3, promise4); - """ + """ XCTAssertEqual(actual, expected) } @@ -1546,7 +1561,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let v1 = b.createObject(with: ["a" : b.loadInt(1337)]) + let v1 = b.createObject(with: ["a": b.loadInt(1337)]) let v2 = b.getProperty("a", of: v1) let v3 = b.loadInt(10) let v4 = b.compare(v2, with: v3, using: .greaterThan) @@ -1556,10 +1571,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = ({ a: 1337 }).a; - v2 > 10 ? v2 : 10; + const v2 = ({ a: 1337 }).a; + v2 > 10 ? v2 : 10; - """ + """ XCTAssertEqual(actual, expected) } @@ -1580,15 +1595,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 1337; - let v1 = 13.37; - v0 += v1; - v1 = "Hello"; - let v3 = 1336; - let v4 = ++v3; - v4++; + let v0 = 1337; + let v1 = 13.37; + v0 += v1; + v1 = "Hello"; + let v3 = 1336; + let v4 = ++v3; + v4++; - """ + """ XCTAssertEqual(actual, expected) } @@ -1610,14 +1625,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 1337; - v0 += 13.37; - v0 *= 13.37; - v0 <<= 13.37; - let v2 = "hello"; - v2 += "world"; + let v0 = 1337; + v0 += 13.37; + v0 *= 13.37; + v0 <<= 13.37; + let v2 = "hello"; + v2 += "world"; - """ + """ XCTAssertEqual(actual, expected) } @@ -1661,7 +1676,10 @@ class LifterTests: XCTestCase { b.setElement(42, of: n, to: n) let o = b.loadInt(53) - b.buildWhileLoop({ b.reassign(variable: o, value: i); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.reassign(variable: o, value: i) + return b.loadBool(false) + }) { } b.callFunction(foo, withArgs: [o]) @@ -1669,31 +1687,31 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v3 = 42; - foo(v3 = 43); - bar(v3); - let v7 = 44; - v7 = 45; - v7 = 46; - foo(v7); - let v11 = 47; - for (let v12 = 0; v12 < 10; v12++) { - v11 = v12; - } - foo(v11); - let v14 = 48; - foo(v14 = 49, v14, v14); - let v17 = 50; - foo(bar(v17 = 51, v17, baz(), v17)); - let v22 = 52; - v22 = []; - v22[42] = v22; - let v24 = 53; - while (v24 = v3, false) { - } - foo(v24); + let v3 = 42; + foo(v3 = 43); + bar(v3); + let v7 = 44; + v7 = 45; + v7 = 46; + foo(v7); + let v11 = 47; + for (let v12 = 0; v12 < 10; v12++) { + v11 = v12; + } + foo(v11); + let v14 = 48; + foo(v14 = 49, v14, v14); + let v17 = 50; + foo(bar(v17 = 51, v17, baz(), v17)); + let v22 = 52; + v22 = []; + v22[42] = v22; + let v24 = 53; + while (v24 = v3, false) { + } + foo(v24); - """ + """ XCTAssertEqual(actual, expected) } @@ -1708,18 +1726,19 @@ class LifterTests: XCTestCase { let marker = b.callFunction(b.createNamedVariable(forBuiltin: "getMarker")) let space = b.loadString(" ") let inner = b.createTemplateString(from: ["Hello", "World"], interpolating: [space]) - let _ = b.createTemplateString(from: ["", "", "", ""], interpolating: [marker, inner, marker] ) + let _ = b.createTemplateString( + from: ["", "", "", ""], interpolating: [marker, inner, marker]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - ``; - `foo${"bar"}baz`; - const v4 = getMarker(); - `${v4}${`Hello${" "}World`}${v4}`; + ``; + `foo${"bar"}baz`; + const v4 = getMarker(); + `${v4}${`Hello${" "}World`}${v4}`; - """ + """ XCTAssertEqual(actual, expected) } @@ -1744,11 +1763,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Obj[1337] = Obj.a.b.c; - const t1 = []; - t1[Obj[0][1][2]] = 42; + Obj[1337] = Obj.a.b.c; + const t1 = []; + t1[Obj[0][1][2]] = 42; - """ + """ XCTAssertEqual(actual, expected) } @@ -1759,7 +1778,7 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(42) let v1 = b.createObject(with: ["foo": v0]) - let v2 = b.loadString("baz") + let v2 = b.loadString("baz") let v3 = b.loadInt(1337) let v4 = b.loadString("42") let v5 = b.loadFloat(13.37) @@ -1769,7 +1788,7 @@ class LifterTests: XCTestCase { b.updateProperty("bar", of: v1, with: v3, using: BinaryOperator.Mul) b.setComputedProperty(v2, of: v1, to: v0) b.updateComputedProperty(v2, of: v1, with: v3, using: BinaryOperator.LogicAnd) - let arr = b.createArray(with: [v3,v3,v3]) + let arr = b.createArray(with: [v3, v3, v3]) b.setElement(0, of: arr, to: v0) b.updateElement(0, of: arr, with: v5, using: BinaryOperator.Sub) @@ -1777,18 +1796,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { foo: 42 }; - v1.foo = 13.37; - v1.foo += "42"; - v1.bar = 1337; - v1.bar *= 1337; - v1["baz"] = 42; - v1["baz"] &&= 1337; - const v6 = [1337,1337,1337]; - v6[0] = 42; - v6[0] -= 13.37; - - """ + const v1 = { foo: 42 }; + v1.foo = 13.37; + v1.foo += "42"; + v1.bar = 1337; + v1.bar *= 1337; + v1["baz"] = 42; + v1["baz"] &&= 1337; + const v6 = [1337,1337,1337]; + v6[0] = 42; + v6[0] -= 13.37; + + """ XCTAssertEqual(actual, expected) } @@ -1806,13 +1825,16 @@ class LifterTests: XCTestCase { b.reassign(variable: v, value: args[0]) } let num = b.loadInt(42) - b.configureProperty("foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) + b.configureProperty( + "foo", of: obj, usingFlags: [.enumerable, .configurable], as: .getter(f1)) b.configureProperty("bar", of: obj, usingFlags: [], as: .setter(f2)) b.configureProperty("foobar", of: obj, usingFlags: [.enumerable], as: .getterSetter(f1, f2)) b.configureProperty("baz", of: obj, usingFlags: [.writable], as: .value(num)) b.configureElement(0, of: obj, usingFlags: [.writable], as: .getter(f1)) b.configureElement(1, of: obj, usingFlags: [.writable, .enumerable], as: .setter(f2)) - b.configureElement(2, of: obj, usingFlags: [.writable, .enumerable, .configurable], as: .getterSetter(f1, f2)) + b.configureElement( + 2, of: obj, usingFlags: [.writable, .enumerable, .configurable], + as: .getterSetter(f1, f2)) b.configureElement(3, of: obj, usingFlags: [], as: .value(num)) let p = b.createNamedVariable(forBuiltin: "ComputedProperty") b.configureComputedProperty(p, of: obj, usingFlags: [.configurable], as: .getter(f1)) @@ -1824,28 +1846,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - let v1 = undefined; - function f2() { - return v1; - } - function f3(a4) { - v1 = a4; - } - Object.defineProperty(v0, "foo", { configurable: true, enumerable: true, get: f2 }); - Object.defineProperty(v0, "bar", { set: f3 }); - Object.defineProperty(v0, "foobar", { enumerable: true, get: f2, set: f3 }); - Object.defineProperty(v0, "baz", { writable: true, value: 42 }); - Object.defineProperty(v0, 0, { writable: true, get: f2 }); - Object.defineProperty(v0, 1, { writable: true, enumerable: true, set: f3 }); - Object.defineProperty(v0, 2, { writable: true, configurable: true, enumerable: true, get: f2, set: f3 }); - Object.defineProperty(v0, 3, { value: 42 }); - Object.defineProperty(v0, ComputedProperty, { configurable: true, get: f2 }); - Object.defineProperty(v0, ComputedProperty, { enumerable: true, set: f3 }); - Object.defineProperty(v0, ComputedProperty, { writable: true, get: f2, set: f3 }); - Object.defineProperty(v0, ComputedProperty, { value: 42 }); - - """ + const v0 = {}; + let v1 = undefined; + function f2() { + return v1; + } + function f3(a4) { + v1 = a4; + } + Object.defineProperty(v0, "foo", { configurable: true, enumerable: true, get: f2 }); + Object.defineProperty(v0, "bar", { set: f3 }); + Object.defineProperty(v0, "foobar", { enumerable: true, get: f2, set: f3 }); + Object.defineProperty(v0, "baz", { writable: true, value: 42 }); + Object.defineProperty(v0, 0, { writable: true, get: f2 }); + Object.defineProperty(v0, 1, { writable: true, enumerable: true, set: f3 }); + Object.defineProperty(v0, 2, { writable: true, configurable: true, enumerable: true, get: f2, set: f3 }); + Object.defineProperty(v0, 3, { value: 42 }); + Object.defineProperty(v0, ComputedProperty, { configurable: true, get: f2 }); + Object.defineProperty(v0, ComputedProperty, { enumerable: true, set: f3 }); + Object.defineProperty(v0, ComputedProperty, { writable: true, get: f2, set: f3 }); + Object.defineProperty(v0, ComputedProperty, { value: 42 }); + + """ XCTAssertEqual(actual, expected) } @@ -1870,13 +1892,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v3 = { bar: 13.37, foo: 1337 }; - delete v3.foo; - delete v3["bar"]; - const t1 = [301,4,68,22]; - delete t1[3]; + const v3 = { bar: 13.37, foo: 1337 }; + delete v3.foo; + delete v3["bar"]; + const t1 = [301,4,68,22]; + delete t1[3]; - """ + """ XCTAssertEqual(actual, expected) } @@ -1907,20 +1929,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - o?.a?.b; - o?.[0]; - o?.["bar"]; - delete o?.unfoo; - delete o?.[1]; - delete o?.["unbar"]; - const t0 = o?.t1; - t0.foo = 42; - const t8 = o?.t2; - t8[0] = 42; - const t10 = o?.t3; - t10["baz"] = 42; - - """ + o?.a?.b; + o?.[0]; + o?.["bar"]; + delete o?.unfoo; + delete o?.[1]; + delete o?.["unbar"]; + const t0 = o?.t1; + t0.foo = 42; + const t8 = o?.t2; + t8[0] = 42; + const t10 = o?.t3; + t10["baz"] = 42; + + """ XCTAssertEqual(actual, expected) } @@ -1941,7 +1963,8 @@ class LifterTests: XCTestCase { b.callMethod("m", on: o, guard: true) let v3 = b.callMethod("n", on: o, guard: true) b.callComputedMethod(b.loadString("o"), on: o, withArgs: [v1, v2, v3], guard: true) - let v4 = b.callComputedMethod(b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) + let v4 = b.callComputedMethod( + b.loadString("p"), on: o, withArgs: [v1, v2, v3], guard: true) b.reassign(variable: v3, value: b.loadString("foo")) b.reassign(variable: v4, value: b.loadString("bar")) b.reassign(variable: v3, value: b.loadString("baz")) @@ -1950,23 +1973,23 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - try { f1(); } catch (e) {} - let v3; - try { v3 = f2(); } catch (e) {} - try { new c1(); } catch (e) {} - let v7; - try { v7 = new c2(); } catch (e) {} - try { obj.m(); } catch (e) {} - let v10; - try { v10 = obj.n(); } catch (e) {} - try { obj["o"](v3, v7, v10); } catch (e) {} - let v14; - try { v14 = obj["p"](v3, v7, v10); } catch (e) {} - v10 = "foo"; - v14 = "bar"; - v10 = "baz"; - - """ + try { f1(); } catch (e) {} + let v3; + try { v3 = f2(); } catch (e) {} + try { new c1(); } catch (e) {} + let v7; + try { v7 = new c2(); } catch (e) {} + try { obj.m(); } catch (e) {} + let v10; + try { v10 = obj.n(); } catch (e) {} + try { obj["o"](v3, v7, v10); } catch (e) {} + let v14; + try { v14 = obj["p"](v3, v7, v10); } catch (e) {} + v10 = "foo"; + v14 = "bar"; + v10 = "baz"; + + """ XCTAssertEqual(actual, expected) } @@ -1982,12 +2005,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - try { - const t0 = "foo"; - new t0(); - } catch (e) {} + try { + const t0 = "foo"; + new t0(); + } catch (e) {} - """ + """ XCTAssertEqual(actual, expected) } @@ -2009,12 +2032,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - eval("print('Hello World!')"); - const t0 = this.eval; - t0("print('Hello World!')"); - this.eval("print('Hello World!')"); + eval("print('Hello World!')"); + const t0 = this.eval; + t0("print('Hello World!')"); + this.eval("print('Hello World!')"); - """ + """ XCTAssertEqual(actual, expected) } @@ -2031,15 +2054,15 @@ class LifterTests: XCTestCase { let values = b.createArray(with: initialValues) let n = b.loadFloat(13.37) let Array = b.createNamedVariable(forBuiltin: "Array") - let _ = b.callFunction(Array, withArgs: [values,n], spreading: [true,false]) + let _ = b.callFunction(Array, withArgs: [values, n], spreading: [true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - Array(...[1,2,"Hello","World"], 13.37); + Array(...[1,2,"Hello","World"], 13.37); - """ + """ XCTAssertEqual(actual, expected) } @@ -2056,9 +2079,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - Math.sin(Math.random()); + Math.sin(Math.random()); - """ + """ XCTAssertEqual(actual, expected) } @@ -2076,11 +2099,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = Math.random(); - let v2 = Function.prototype.call.bind(Math.sin); - v2(Math, v1); + const v1 = Math.random(); + let v2 = Function.prototype.call.bind(Math.sin); + v2(Math, v1); - """ + """ XCTAssertEqual(actual, expected) } @@ -2112,15 +2135,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = Array.prototype.indexOf; - let v3 = v2.bind(); - const v4 = new Array(); - let v5 = v2.bind(v4); - let v7 = v2.bind(v4, "value"); - let v9 = v2.bind(v4, "value", 1); - let v10 = v2.bind(v4, "value", 1, 1); + const v2 = Array.prototype.indexOf; + let v3 = v2.bind(); + const v4 = new Array(); + let v5 = v2.bind(v4); + let v7 = v2.bind(v4, "value"); + let v9 = v2.bind(v4, "value", 1); + let v10 = v2.bind(v4, "value", 1, 1); - """ + """ XCTAssertEqual(actual, expected) } @@ -2140,15 +2163,15 @@ class LifterTests: XCTestCase { let values = b.createArray(with: initialValues) let n1 = b.loadInt(0) let n2 = b.loadInt(4) - b.callMethod("max", on: Math, withArgs: [n1,values,n2], spreading: [false, true, false]) + b.callMethod("max", on: Math, withArgs: [n1, values, n2], spreading: [false, true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - Math.max(0, ...[1,3,9,10,2,6], 4); + Math.max(0, ...[1,3,9,10,2,6], 4); - """ + """ XCTAssertEqual(actual, expected) } @@ -2166,9 +2189,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - ("Hello World")[Symbol.iterator]().next(); + ("Hello World")[Symbol.iterator]().next(); - """ + """ XCTAssertEqual(actual, expected) } @@ -2178,7 +2201,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj) } @@ -2186,17 +2209,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0["???"](); - v0[0](); - v0["01"](); - v0[1](); - v0["0.1"](); - v0["-1"](); - v0.$valid_id_42(); - v0["42_invalid_id"](); - - """ + const v0 = {}; + v0["???"](); + v0[0](); + v0["01"](); + v0[1](); + v0["0.1"](); + v0["-1"](); + v0.$valid_id_42(); + v0["42_invalid_id"](); + + """ XCTAssertEqual(actual, expected) } @@ -2207,7 +2230,7 @@ class LifterTests: XCTestCase { let obj = b.createObject(with: [:]) let values = b.createArray(with: []) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callMethod(name, on: obj, withArgs: [values], spreading: [true]) } @@ -2215,18 +2238,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - const v1 = []; - v0["???"](...v1); - v0[0](...v1); - v0["01"](...v1); - v0[1](...v1); - v0["0.1"](...v1); - v0["-1"](...v1); - v0.$valid_id_42(...v1); - v0["42_invalid_id"](...v1); - - """ + const v0 = {}; + const v1 = []; + v0["???"](...v1); + v0[0](...v1); + v0["01"](...v1); + v0[1](...v1); + v0["0.1"](...v1); + v0["-1"](...v1); + v0.$valid_id_42(...v1); + v0["42_invalid_id"](...v1); + + """ XCTAssertEqual(actual, expected) } @@ -2236,7 +2259,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { let bound = b.bindMethod(name, on: obj) b.callFunction(bound, withArgs: [obj]) } @@ -2245,25 +2268,25 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - let v1 = Function.prototype.call.bind(v0["???"]); - v1(v0); - let v3 = Function.prototype.call.bind(v0[0]); - v3(v0); - let v5 = Function.prototype.call.bind(v0["01"]); - v5(v0); - let v7 = Function.prototype.call.bind(v0[1]); - v7(v0); - let v9 = Function.prototype.call.bind(v0["0.1"]); - v9(v0); - let v11 = Function.prototype.call.bind(v0["-1"]); - v11(v0); - let v13 = Function.prototype.call.bind(v0.$valid_id_42); - v13(v0); - let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); - v15(v0); - - """ + const v0 = {}; + let v1 = Function.prototype.call.bind(v0["???"]); + v1(v0); + let v3 = Function.prototype.call.bind(v0[0]); + v3(v0); + let v5 = Function.prototype.call.bind(v0["01"]); + v5(v0); + let v7 = Function.prototype.call.bind(v0[1]); + v7(v0); + let v9 = Function.prototype.call.bind(v0["0.1"]); + v9(v0); + let v11 = Function.prototype.call.bind(v0["-1"]); + v11(v0); + let v13 = Function.prototype.call.bind(v0.$valid_id_42); + v13(v0); + let v15 = Function.prototype.call.bind(v0["42_invalid_id"]); + v15(v0); + + """ XCTAssertEqual(actual, expected) } @@ -2272,9 +2295,9 @@ class LifterTests: XCTestCase { let fuzzer: Fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.callSuperMethod(name) } } @@ -2284,20 +2307,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - sub() { - super["???"](); - super[0](); - super["01"](); - super[1](); - super["0.1"](); - super["-1"](); - super.$valid_id_42(); - super["42_invalid_id"](); + class C0 { + sub() { + super["???"](); + super[0](); + super["01"](); + super[1](); + super["0.1"](); + super["-1"](); + super.$valid_id_42(); + super["42_invalid_id"](); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -2316,9 +2339,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - SomeObject[RandomMethod()](...[1,2,3,4]); + SomeObject[RandomMethod()](...[1,2,3,4]); - """ + """ XCTAssertEqual(actual, expected) } @@ -2328,9 +2351,10 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let obj = b.createObject(with: [:]) - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.setProperty(name, of: obj, to: b.getProperty(name, of: obj)) - b.updateProperty(name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) + b.updateProperty( + name, of: obj, with: b.getProperty(name, of: obj, guard: true), using: .Add) b.deleteProperty(name, of: obj) } @@ -2338,33 +2362,33 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0["???"] = v0["???"]; - v0["???"] += v0?.["???"]; - delete v0["???"]; - v0[0] = v0[0]; - v0[0] += v0?.[0]; - delete v0[0]; - v0["01"] = v0["01"]; - v0["01"] += v0?.["01"]; - delete v0["01"]; - v0[1] = v0[1]; - v0[1] += v0?.[1]; - delete v0[1]; - v0["0.1"] = v0["0.1"]; - v0["0.1"] += v0?.["0.1"]; - delete v0["0.1"]; - v0["-1"] = v0["-1"]; - v0["-1"] += v0?.["-1"]; - delete v0["-1"]; - v0.$valid_id_42 = v0.$valid_id_42; - v0.$valid_id_42 += v0?.$valid_id_42; - delete v0.$valid_id_42; - v0["42_invalid_id"] = v0["42_invalid_id"]; - v0["42_invalid_id"] += v0?.["42_invalid_id"]; - delete v0["42_invalid_id"]; - - """ + const v0 = {}; + v0["???"] = v0["???"]; + v0["???"] += v0?.["???"]; + delete v0["???"]; + v0[0] = v0[0]; + v0[0] += v0?.[0]; + delete v0[0]; + v0["01"] = v0["01"]; + v0["01"] += v0?.["01"]; + delete v0["01"]; + v0[1] = v0[1]; + v0[1] += v0?.[1]; + delete v0[1]; + v0["0.1"] = v0["0.1"]; + v0["0.1"] += v0?.["0.1"]; + delete v0["0.1"]; + v0["-1"] = v0["-1"]; + v0["-1"] += v0?.["-1"]; + delete v0["-1"]; + v0.$valid_id_42 = v0.$valid_id_42; + v0.$valid_id_42 += v0?.$valid_id_42; + delete v0.$valid_id_42; + v0["42_invalid_id"] = v0["42_invalid_id"]; + v0["42_invalid_id"] += v0?.["42_invalid_id"]; + delete v0["42_invalid_id"]; + + """ XCTAssertEqual(actual, expected) } @@ -2373,9 +2397,9 @@ class LifterTests: XCTestCase { let fuzzer: Fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildClassDefinition() { cls in + b.buildClassDefinition { cls in cls.addInstanceMethod("sub", with: .parameters(n: 0)) { params in - for name in ["???", "0","01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { + for name in ["???", "0", "01", "1", "0.1", "-1", "$valid_id_42", "42_invalid_id"] { b.setSuperProperty(name, to: b.getSuperProperty(name)) b.updateSuperProperty(name, with: b.getSuperProperty(name), using: .Add) } @@ -2386,28 +2410,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - sub() { - super["???"] = super["???"]; - super["???"] += super["???"]; - super[0] = super[0]; - super[0] += super[0]; - super["01"] = super["01"]; - super["01"] += super["01"]; - super[1] = super[1]; - super[1] += super[1]; - super["0.1"] = super["0.1"]; - super["0.1"] += super["0.1"]; - super["-1"] = super["-1"]; - super["-1"] += super["-1"]; - super.$valid_id_42 = super.$valid_id_42; - super.$valid_id_42 += super.$valid_id_42; - super["42_invalid_id"] = super["42_invalid_id"]; - super["42_invalid_id"] += super["42_invalid_id"]; + class C0 { + sub() { + super["???"] = super["???"]; + super["???"] += super["???"]; + super[0] = super[0]; + super[0] += super[0]; + super["01"] = super["01"]; + super["01"] += super["01"]; + super[1] = super[1]; + super[1] += super[1]; + super["0.1"] = super["0.1"]; + super["0.1"] += super["0.1"]; + super["-1"] = super["-1"]; + super["-1"] += super["-1"]; + super.$valid_id_42 = super.$valid_id_42; + super.$valid_id_42 += super.$valid_id_42; + super["42_invalid_id"] = super["42_invalid_id"]; + super["42_invalid_id"] += super["42_invalid_id"]; + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -2425,15 +2449,15 @@ class LifterTests: XCTestCase { let n1 = b.loadFloat(13.37) let n2 = b.loadFloat(13.38) let Array = b.createNamedVariable(forBuiltin: "Array") - b.construct(Array, withArgs: [n1,values,n2], spreading: [false,true,false]) + b.construct(Array, withArgs: [n1, values, n2], spreading: [false, true, false]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - new Array(13.37, ...[1,2,"Hello","World"], 13.38); + new Array(13.37, ...[1,2,"Hello","World"], 13.38); - """ + """ XCTAssertEqual(actual, expected) } @@ -2442,7 +2466,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2468,28 +2492,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - } - f(a4) { - return "foobar"; - } - } - class C6 extends C0 { - constructor(a8) { - super(); - super.bar = 100; - } - g(a11) { - super.bar += 1337; + class C0 { + constructor(a2) { + } + f(a4) { + return "foobar"; + } } - h() { - return super.bar; + class C6 extends C0 { + constructor(a8) { + super(); + super.bar = 100; + } + g(a11) { + super.bar += 1337; + } + h() { + return super.bar; + } } - } - new C6(13.37); + new C6(13.37); - """ + """ XCTAssertEqual(actual, expected) } @@ -2498,7 +2522,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let superclass = b.buildClassDefinition() { cls in + let superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2513,13 +2537,13 @@ class LifterTests: XCTestCase { let C = b.buildClassDefinition(withSuperclass: superclass) { cls in cls.addConstructor(with: .parameters(n: 1)) { params in - b.callSuperConstructor(withArgs: []); + b.callSuperConstructor(withArgs: []) b.setComputedSuperProperty(params[1], to: b.loadInt(100)) } cls.addInstanceMethod("g", with: .parameters(n: 1)) { params in let property = b.binary(b.callFunction(function), params[1], with: .Add) b.doReturn(b.getComputedSuperProperty(property)) - } + } } b.construct(C, withArgs: [b.loadFloat(13.37)]) @@ -2527,28 +2551,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - } - f(a4) { - return "foobar"; + class C0 { + constructor(a2) { + } + f(a4) { + return "foobar"; + } } - } - function f6() { - return "baz"; - } - class C8 extends C0 { - constructor(a10) { - super(); - super[a10] = 100; + function f6() { + return "baz"; } - g(a13) { - return super[f6() + a13]; + class C8 extends C0 { + constructor(a10) { + super(); + super[a10] = 100; + } + g(a13) { + return super[f6() + a13]; + } } - } - new C8(13.37); + new C8(13.37); - """ + """ XCTAssertEqual(actual, expected) @@ -2570,13 +2594,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = { bar: 13.37, foo: 42 }; - let {"foo":v3,...v4} = v2; - let {"foo":v5,"bar":v6,...v7} = v2; - let {...v8} = v2; - let {"foo":v9,"bar":v10,} = v2; + const v2 = { bar: 13.37, foo: 42 }; + let {"foo":v3,...v4} = v2; + let {"foo":v5,"bar":v6,...v7} = v2; + let {...v8} = v2; + let {"foo":v9,"bar":v10,} = v2; - """ + """ XCTAssertEqual(actual, expected) } @@ -2589,27 +2613,27 @@ class LifterTests: XCTestCase { let v1 = b.loadFloat(13.37) let v2 = b.loadString("Hello") let v3 = b.createObject(with: ["foo": v0, "bar": v1]) - b.destruct(v3, selecting: ["foo"], into: [v2,v0], hasRestElement: true) - b.destruct(v3, selecting: ["foo", "bar"], into: [v2,v0,v1], hasRestElement: true) + b.destruct(v3, selecting: ["foo"], into: [v2, v0], hasRestElement: true) + b.destruct(v3, selecting: ["foo", "bar"], into: [v2, v0, v1], hasRestElement: true) b.destruct(v3, selecting: [String](), into: [v2], hasRestElement: true) - b.destruct(v3, selecting: ["foo", "bar"], into: [v2,v1]) + b.destruct(v3, selecting: ["foo", "bar"], into: [v2, v1]) b.destruct(v3, selecting: [String](), into: []) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 42; - let v1 = 13.37; - let v2 = "Hello"; - const v3 = { bar: v1, foo: v0 }; - ({"foo":v2,...v0} = v3); - ({"foo":v2,"bar":v0,...v1} = v3); - ({...v2} = v3); - ({"foo":v2,"bar":v1,} = v3); - ({} = v3); - - """ + let v0 = 42; + let v1 = 13.37; + let v2 = "Hello"; + const v3 = { bar: v1, foo: v0 }; + ({"foo":v2,...v0} = v3); + ({"foo":v2,"bar":v0,...v1} = v3); + ({...v2} = v3); + ({"foo":v2,"bar":v1,} = v3); + ({} = v3); + + """ XCTAssertEqual(actual, expected) } @@ -2624,22 +2648,22 @@ class LifterTests: XCTestCase { initialValues.append(b.loadString("Hello")) initialValues.append(b.loadString("World")) let arr = b.createArray(with: initialValues) - b.destruct(arr, selecting: [0,1]) - b.destruct(arr, selecting: [0,2,5]) - b.destruct(arr, selecting: [0,2], lastIsRest: true) + b.destruct(arr, selecting: [0, 1]) + b.destruct(arr, selecting: [0, 2, 5]) + b.destruct(arr, selecting: [0, 2], lastIsRest: true) b.destruct(arr, selecting: [0], lastIsRest: true) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = [15,30,"Hello","World"]; - let [v5,v6] = v4; - let [v7,,v8,,,v9] = v4; - let [v10,,...v11] = v4; - let [...v12] = v4; + const v4 = [15,30,"Hello","World"]; + let [v5,v6] = v4; + let [v7,,v8,,,v9] = v4; + let [v10,,...v11] = v4; + let [...v12] = v4; - """ + """ XCTAssertEqual(actual, expected) } @@ -2656,20 +2680,20 @@ class LifterTests: XCTestCase { let array = b.createArray(with: initialValues) let i = b.loadInt(1000) let s = b.loadString("foobar") - b.destruct(array, selecting: [0,2], into: [i, s], lastIsRest: true) + b.destruct(array, selecting: [0, 2], into: [i, s], lastIsRest: true) b.destruct(array, selecting: [0], into: [i], lastIsRest: true) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v4 = [15,30,"Hello","World"]; - let v5 = 1000; - let v6 = "foobar"; - [v5,,...v6] = v4; - [...v5] = v4; + const v4 = [15,30,"Hello","World"]; + let v5 = 1000; + let v6 = "foobar"; + [v5,,...v6] = v4; + [...v5] = v4; - """ + """ XCTAssertEqual(actual, expected) } @@ -2698,17 +2722,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let a = 42; - print(a); - print(b); - c = 1337; - var b = 1337; - b = 42; - print(c); - let d; - print(d); - - """ + let a = 42; + print(a); + print(b); + c = 1337; + var b = 1337; + b = 42; + print(c); + let d; + print(d); + + """ XCTAssertEqual(actual, expected) } @@ -2718,13 +2742,15 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, catchBody: { _ in - let v = b.binary(args[0], args[1], with: .Div) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + catchBody: { _ in + let v = b.binary(args[0], args[1], with: .Div) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2732,16 +2758,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } catch(e4) { - return a1 / a2; + function f0(a1, a2) { + try { + return a1 * a2; + } catch(e4) { + return a1 / a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2751,13 +2777,15 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, finallyBody: { - let v = b.binary(args[0], args[1], with: .Mod) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + finallyBody: { + let v = b.binary(args[0], args[1], with: .Mod) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2765,16 +2793,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } finally { - return a1 % a2; + function f0(a1, a2) { + try { + return a1 * a2; + } finally { + return a1 % a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2784,16 +2812,19 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let f = b.buildPlainFunction(with: .parameters(n: 2)) { args in - b.buildTryCatchFinally(tryBody: { - let v = b.binary(args[0], args[1], with: .Mul) - b.doReturn(v) - }, catchBody: { _ in - let v = b.binary(args[0], args[1], with: .Div) - b.doReturn(v) - }, finallyBody: { - let v = b.binary(args[0], args[1], with: .Mod) - b.doReturn(v) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.binary(args[0], args[1], with: .Mul) + b.doReturn(v) + }, + catchBody: { _ in + let v = b.binary(args[0], args[1], with: .Div) + b.doReturn(v) + }, + finallyBody: { + let v = b.binary(args[0], args[1], with: .Mod) + b.doReturn(v) + }) } b.callFunction(f, withArgs: [b.loadInt(1337), b.loadInt(42)]) @@ -2801,18 +2832,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2) { - try { - return a1 * a2; - } catch(e4) { - return a1 / a2; - } finally { - return a1 % a2; + function f0(a1, a2) { + try { + return a1 * a2; + } catch(e4) { + return a1 / a2; + } finally { + return a1 % a2; + } } - } - f0(1337, 42); + f0(1337, 42); - """ + """ XCTAssertEqual(actual, expected) } @@ -2823,7 +2854,7 @@ class LifterTests: XCTestCase { let v0 = b.loadInt(42) let v1 = b.createObject(with: ["foo": v0]) - let v2 = b.getProperty("foo", of: v1) + let v2 = b.getProperty("foo", of: v1) let v3 = b.loadInt(1337) let v4 = b.loadString("42") let v5 = b.loadFloat(13.37) @@ -2832,10 +2863,10 @@ class LifterTests: XCTestCase { swtch.addCase(v3, fallsThrough: false) { b.setProperty("bar", of: v1, to: v3) } - swtch.addCase(v4, fallsThrough: false){ + swtch.addCase(v4, fallsThrough: false) { b.setProperty("baz", of: v1, to: v4) } - swtch.addDefaultCase(fallsThrough: true){ + swtch.addDefaultCase(fallsThrough: true) { b.setProperty("foo", of: v1, to: v5) } swtch.addCase(v0, fallsThrough: true) { @@ -2847,22 +2878,22 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { foo: 42 }; - const v2 = v1.foo; - switch (v2) { - case 1337: - v1.bar = 1337; - break; - case "42": - v1.baz = "42"; - break; - default: - v1.foo = 13.37; - case 42: - v1.bla = v2; - } + const v1 = { foo: 42 }; + const v2 = v1.foo; + switch (v2) { + case 1337: + v1.bar = 1337; + break; + case "42": + v1.baz = "42"; + break; + default: + v1.foo = 13.37; + case 42: + v1.bla = v2; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2880,12 +2911,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - while (v0 < 100) { - v0++; - } + let v0 = 0; + while (v0 < 100) { + v0++; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2903,10 +2934,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - while (shouldContinue()) { - } + while (shouldContinue()) { + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2918,7 +2949,11 @@ class LifterTests: XCTestCase { let f = b.createNamedVariable(forBuiltin: "f") let g = b.createNamedVariable(forBuiltin: "g") let loopVar = b.loadInt(10) - b.buildWhileLoop({ b.callFunction(f); b.callFunction(g); return loopVar }) { + b.buildWhileLoop({ + b.callFunction(f) + b.callFunction(g) + return loopVar + }) { b.unary(.PostDec, loopVar) } @@ -2926,12 +2961,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v2 = 10; - while (f(), g(), v2) { - v2--; - } + let v2 = 10; + while (f(), g(), v2) { + v2--; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2942,23 +2977,31 @@ class LifterTests: XCTestCase { var f = b.createNamedVariable(forBuiltin: "f") var g = b.createNamedVariable(forBuiltin: "g") - b.buildWhileLoop({ b.callFunction(f); let cond = b.callFunction(g); return cond }) { + b.buildWhileLoop({ + b.callFunction(f) + let cond = b.callFunction(g) + return cond + }) { } var program = b.finalize() var actual = fuzzer.lifter.lift(program) var expected = """ - while (f(), g()) { - } + while (f(), g()) { + } - """ + """ XCTAssertEqual(actual, expected) f = b.createNamedVariable(forBuiltin: "f") g = b.createNamedVariable(forBuiltin: "g") - b.buildWhileLoop({ let cond = b.callFunction(f); b.callFunction(g); return cond }) { + b.buildWhileLoop({ + let cond = b.callFunction(f) + b.callFunction(g) + return cond + }) { b.callFunction(b.createNamedVariable(forBuiltin: "body")) } @@ -2966,15 +3009,15 @@ class LifterTests: XCTestCase { actual = fuzzer.lifter.lift(program) expected = """ - while ((() => { - const v2 = f(); - g(); - return v2; - })()) { - body(); - } + while ((() => { + const v2 = f(); + g(); + return v2; + })()) { + body(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -2996,14 +3039,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - while ((() => { - const v1 = foobar(); - return v1 + v1; - })()) { - doLoopBodyStuff(); - } + while ((() => { + const v1 = foobar(); + return v1 + v1; + })()) { + doLoopBodyStuff(); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3016,7 +3059,10 @@ class LifterTests: XCTestCase { let f = b.callFunction(b.createNamedVariable(forBuiltin: "f")) let g = b.callFunction(b.createNamedVariable(forBuiltin: "g")) let h = b.callFunction(b.createNamedVariable(forBuiltin: "h")) - b.buildWhileLoop({ b.callFunction(print, withArgs: [f]); return b.loadBool(false) }) { + b.buildWhileLoop({ + b.callFunction(print, withArgs: [f]) + return b.loadBool(false) + }) { b.callFunction(print, withArgs: [g]) } b.callFunction(print, withArgs: [h]) @@ -3025,15 +3071,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - while (print(v2), false) { - print(v4); - } - print(v6); + const v2 = f(); + const v4 = g(); + const v6 = h(); + while (print(v2), false) { + print(v4); + } + print(v6); - """ + """ XCTAssertEqual(actual, expected) } @@ -3043,28 +3089,33 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let loopVar1 = b.loadInt(0) - b.buildDoWhileLoop(do: { - let loopVar2 = b.loadInt(0) - b.buildDoWhileLoop(do: { - b.unary(.PostInc, loopVar2) - }, while: { b.callFunction(b.createNamedVariable(forBuiltin: "f"), withArgs: [loopVar2]) }) - b.unary(.PostInc, loopVar1) - }, while: { b.compare(loopVar1, with: b.loadInt(42), using: .lessThan) }) + b.buildDoWhileLoop( + do: { + let loopVar2 = b.loadInt(0) + b.buildDoWhileLoop( + do: { + b.unary(.PostInc, loopVar2) + }, + while: { + b.callFunction(b.createNamedVariable(forBuiltin: "f"), withArgs: [loopVar2]) + }) + b.unary(.PostInc, loopVar1) + }, while: { b.compare(loopVar1, with: b.loadInt(42), using: .lessThan) }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - do { - let v1 = 0; + let v0 = 0; do { - v1++; - } while (f(v1)) - v0++; - } while (v0 < 42) + let v1 = 0; + do { + v1++; + } while (f(v1)) + v0++; + } while (v0 < 42) - """ + """ XCTAssertEqual(actual, expected) } @@ -3073,20 +3124,25 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildDoWhileLoop(do: { - let doSomething = b.createNamedVariable(forBuiltin: "doSomething") - b.callFunction(doSomething) - }, while: { b.callFunction(b.createNamedVariable(forBuiltin: "f")); return b.callFunction(b.createNamedVariable(forBuiltin: "g")) }) + b.buildDoWhileLoop( + do: { + let doSomething = b.createNamedVariable(forBuiltin: "doSomething") + b.callFunction(doSomething) + }, + while: { + b.callFunction(b.createNamedVariable(forBuiltin: "f")) + return b.callFunction(b.createNamedVariable(forBuiltin: "g")) + }) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - do { - doSomething(); - } while (f(), g()) + do { + doSomething(); + } while (f(), g()) - """ + """ XCTAssertEqual(actual, expected) } @@ -3099,24 +3155,29 @@ class LifterTests: XCTestCase { let f = b.callFunction(b.createNamedVariable(forBuiltin: "f")) let g = b.callFunction(b.createNamedVariable(forBuiltin: "g")) let h = b.callFunction(b.createNamedVariable(forBuiltin: "h")) - b.buildDoWhileLoop(do: { - b.callFunction(print, withArgs: [f]) - }, while: { b.callFunction(print, withArgs: [g]); return b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + b.callFunction(print, withArgs: [f]) + }, + while: { + b.callFunction(print, withArgs: [g]) + return b.loadBool(false) + }) b.callFunction(print, withArgs: [h]) let program = b.finalize() let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - do { - print(v2); - } while (print(v4), false) - print(v6); + const v2 = f(); + const v4 = g(); + const v6 = h(); + do { + print(v2); + } while (print(v4), false) + print(v6); - """ + """ XCTAssertEqual(actual, expected) } @@ -3125,8 +3186,14 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.loadInt(10), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in - b.buildForLoop(i: { b.loadInt(0) }, { j in b.compare(j, with: i, using: .lessThan) }, { j in b.unary(.PostInc, j) }) { j in + b.buildForLoop( + i: { b.loadInt(0) }, { i in b.compare(i, with: b.loadInt(10), using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in + b.buildForLoop( + i: { b.loadInt(0) }, { j in b.compare(j, with: i, using: .lessThan) }, + { j in b.unary(.PostInc, j) } + ) { j in let print = b.createNamedVariable(forBuiltin: "print") b.callFunction(print, withArgs: [i, j]) } @@ -3136,13 +3203,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i1 = 0; i1 < 10; i1++) { - for (let i8 = 0; i8 < i1; i8++) { - print(i1, i8); + for (let i1 = 0; i1 < 10; i1++) { + for (let i8 = 0; i8 < i1; i8++) { + print(i1, i8); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3151,7 +3218,7 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop() { + b.buildForLoop { b.loopBreak() } @@ -3159,11 +3226,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (;;) { - break; - } + for (;;) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3172,9 +3239,22 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ return [b.callFunction(b.createNamedVariable(forBuiltin: "f1")), b.callFunction(b.createNamedVariable(forBuiltin: "f2"))] }, - { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f3"), withArgs: [vars[0]]); return b.callFunction(b.createNamedVariable(forBuiltin: "f4"), withArgs: [vars[1]]) }, - { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f5"), withArgs: [vars[1]]); b.callFunction(b.createNamedVariable(forBuiltin: "f6"), withArgs: [vars[0]]) }) { vars in + b.buildForLoop( + { + return [ + b.callFunction(b.createNamedVariable(forBuiltin: "f1")), + b.callFunction(b.createNamedVariable(forBuiltin: "f2")), + ] + }, + { vars in + b.callFunction(b.createNamedVariable(forBuiltin: "f3"), withArgs: [vars[0]]) + return b.callFunction(b.createNamedVariable(forBuiltin: "f4"), withArgs: [vars[1]]) + }, + { vars in + b.callFunction(b.createNamedVariable(forBuiltin: "f5"), withArgs: [vars[1]]) + b.callFunction(b.createNamedVariable(forBuiltin: "f6"), withArgs: [vars[0]]) + } + ) { vars in b.callFunction(b.createNamedVariable(forBuiltin: "f7"), withArgs: vars) } @@ -3182,11 +3262,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i4 = f1(), i5 = f2(); f3(i4), f4(i5); f5(i5), f6(i4)) { - f7(i4, i5); - } + for (let i4 = f1(), i5 = f2(); f3(i4), f4(i5); f5(i5), f6(i4)) { + f7(i4, i5); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3194,9 +3274,16 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")); let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")); b.callFunction(b.createNamedVariable(forBuiltin: "h")); return [x, y] }, - { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, - { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) }) { vs in + b.buildForLoop( + { + let x = b.callFunction(b.createNamedVariable(forBuiltin: "f")) + let y = b.callFunction(b.createNamedVariable(forBuiltin: "g")) + b.callFunction(b.createNamedVariable(forBuiltin: "h")) + return [x, y] + }, + { vs in return b.compare(vs[0], with: vs[1], using: .lessThan) }, + { vs in b.reassign(variable: vs[0], value: vs[1], with: .Add) } + ) { vs in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: vs) } @@ -3204,18 +3291,18 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let [i6, i7] = (() => { - const v1 = f(); - const v3 = g(); - h(); - return [v1, v3]; - })(); - i6 < i7; - i6 += i7) { - print(i6, i7); - } + for (let [i6, i7] = (() => { + const v1 = f(); + const v3 = g(); + h(); + return [v1, v3]; + })(); + i6 < i7; + i6 += i7) { + print(i6, i7); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3224,14 +3311,20 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop({ b.callFunction(b.createNamedVariable(forBuiltin: "foo")); b.callFunction(b.createNamedVariable(forBuiltin: "bar")) }, - { - let shouldContinue = b.callFunction(b.createNamedVariable(forBuiltin: "shouldContinue")) - b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { - b.reassign(variable: shouldContinue, value: b.loadBool(false)) - } - return shouldContinue - }) { + b.buildForLoop( + { + b.callFunction(b.createNamedVariable(forBuiltin: "foo")) + b.callFunction(b.createNamedVariable(forBuiltin: "bar")) + }, + { + let shouldContinue = b.callFunction( + b.createNamedVariable(forBuiltin: "shouldContinue")) + b.buildIf(b.callFunction(b.createNamedVariable(forBuiltin: "shouldNotContinue"))) { + b.reassign(variable: shouldContinue, value: b.loadBool(false)) + } + return shouldContinue + } + ) { b.loopBreak() } @@ -3239,19 +3332,19 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (foo(), bar(); - (() => { - let v5 = shouldContinue(); - if (shouldNotContinue()) { - v5 = false; - } - return v5; - })(); - ) { - break; - } + for (foo(), bar(); + (() => { + let v5 = shouldContinue(); + if (shouldNotContinue()) { + v5 = false; + } + return v5; + })(); + ) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3260,7 +3353,10 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, { b.compare($0, with: b.loadInt(100), using: .lessThan) }, + { b.reassign(variable: $0, value: b.loadInt(10), with: .Add) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) } @@ -3268,11 +3364,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i1 = 0; i1 < 100; i1 += 10) { - print(i1); - } + for (let i1 = 0; i1 < 100; i1 += 10) { + print(i1); + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3281,7 +3377,12 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildForLoop(i: { b.callFunction(b.createNamedVariable(forBuiltin: "f")); return b.callFunction(b.createNamedVariable(forBuiltin: "g")) }, {_ in b.loadBool(true) }, { _ in }) { i in + b.buildForLoop( + i: { + b.callFunction(b.createNamedVariable(forBuiltin: "f")) + return b.callFunction(b.createNamedVariable(forBuiltin: "g")) + }, { _ in b.loadBool(true) }, { _ in } + ) { i in b.loopBreak() } @@ -3289,16 +3390,16 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let i4 = (() => { - f(); - return g(); - })(); - ; - ) { - break; - } + for (let i4 = (() => { + f(); + return g(); + })(); + ; + ) { + break; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -3308,7 +3409,10 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, { i in b.reassign(variable: i, value: args[2], with: .Sub)}) { vars in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .greaterThanOrEqual) }, + { i in b.reassign(variable: i, value: args[2], with: .Sub) } + ) { vars in } } @@ -3316,12 +3420,12 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0(a1, a2, a3) { - for (let i4 = a1; i4 >= a2; i4 -= a3) { + function f0(a1, a2, a3) { + for (let i4 = a1; i4 >= a2; i4 -= a3) { + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3336,7 +3440,10 @@ class LifterTests: XCTestCase { let i = b.callFunction(b.createNamedVariable(forBuiltin: "i")) let j = b.callFunction(b.createNamedVariable(forBuiltin: "j")) - b.buildForLoop({ b.callFunction(print, withArgs: [f]) }, { b.callFunction(print, withArgs: [g]) }, { b.callFunction(print, withArgs: [h]) }) { + b.buildForLoop( + { b.callFunction(print, withArgs: [f]) }, { b.callFunction(print, withArgs: [g]) }, + { b.callFunction(print, withArgs: [h]) } + ) { b.callFunction(print, withArgs: [i]) } b.callFunction(print, withArgs: [j]) @@ -3345,17 +3452,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v2 = f(); - const v4 = g(); - const v6 = h(); - const v8 = i(); - const v10 = j(); - for (print(v2); print(v4); print(v6)) { - print(v8); - } - print(v10); + const v2 = f(); + const v4 = g(); + const v6 = h(); + const v8 = i(); + const v10 = j(); + for (print(v2); print(v4); print(v6)) { + print(v8); + } + print(v10); - """ + """ XCTAssertEqual(actual, expected) } @@ -3366,7 +3473,13 @@ class LifterTests: XCTestCase { b.buildPlainFunction(with: .parameters(n: 0)) { _ in let s = b.loadInt(0) // Test that context-dependent operations such as LoadArguments are handled correctly inside loop headers - b.buildForLoop(i: { b.loadInt(0) }, { i in b.compare(i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { b.loadInt(0) }, + { i in + b.compare( + i, with: b.getProperty("length", of: b.loadArguments()), using: .lessThan) + }, { i in b.unary(.PostInc, i) } + ) { i in let arg = b.getComputedProperty(i, of: b.loadArguments()) b.reassign(variable: s, value: arg, with: .Add) } @@ -3377,15 +3490,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0() { - let v1 = 0; - for (let i3 = 0; i3 < arguments.length; i3++) { - v1 += arguments[i3]; + function f0() { + let v1 = 0; + for (let i3 = 0; i3 < arguments.length; i3++) { + v1 += arguments[i3]; + } + return v1; } - return v1; - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3405,13 +3518,13 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = 0; - for (let v1 = 0; v1 < 1337; v1++) { - v0 += v1; - } - print(v0); + let v0 = 0; + for (let v1 = 0; v1 < 1337; v1++) { + v0 += v1; + } + print(v0); - """ + """ XCTAssertEqual(actual, expected) } @@ -3420,12 +3533,14 @@ class LifterTests: XCTestCase { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let a1 = b.createArray(with: [b.loadInt(10), b.loadInt(11), b.loadInt(12), b.loadInt(13), b.loadInt(14)]) + let a1 = b.createArray(with: [ + b.loadInt(10), b.loadInt(11), b.loadInt(12), b.loadInt(13), b.loadInt(14), + ]) let a2 = b.createArray(with: [b.loadInt(20), b.loadInt(21), b.loadInt(22), b.loadInt(23)]) let a3 = b.createArray(with: [b.loadInt(30), b.loadInt(31), b.loadInt(32)]) let a4 = b.createArray(with: [a1, a2, a3]) let print = b.createNamedVariable(forBuiltin: "print") - b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + b.buildForOfLoop(a4, selecting: [0, 2], hasRestElement: true) { args in b.callFunction(print, withArgs: [args[0]]) b.buildForOfLoop(args[1]) { v in b.callFunction(print, withArgs: [v]) @@ -3436,14 +3551,14 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - for (let [v17,,...v18] of [[10,11,12,13,14],[20,21,22,23],[30,31,32]]) { - print(v17); - for (const v20 of v18) { - print(v20); + for (let [v17,,...v18] of [[10,11,12,13,14],[20,21,22,23],[30,31,32]]) { + print(v17); + for (const v20 of v18) { + print(v20); + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3459,7 +3574,7 @@ class LifterTests: XCTestCase { let v3 = b.loadInt(1337) b.reassign(variable: v2, value: v3) b.blockStatement { - let v4 = b.createObject(with: ["a" : v1]) + let v4 = b.createObject(with: ["a": v1]) b.reassign(variable: v2, value: v4) } @@ -3470,17 +3585,17 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v1 = { a: 1337 }; - for (let v2 in v1) { - { - v2 = 1337; + const v1 = { a: 1337 }; + for (let v2 in v1) { { - v2 = { a: v1 }; + v2 = 1337; + { + v2 = { a: v1 }; + } } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3546,28 +3661,28 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - class C0 { - constructor(a2) { - this.foo = a2; + class C0 { + constructor(a2) { + this.foo = a2; + } + baz() { + return this.bar; + } } - baz() { - return this.bar; + const v10 = { foo: 42, __proto__: proto1, bar: 42, baz: 42 }; + switch (42) { + default: + print("default case 1"); + break; + case 43: + print("case 43"); + break; + case 44: + print("case 44"); + break; } - } - const v10 = { foo: 42, __proto__: proto1, bar: 42, baz: 42 }; - switch (42) { - default: - print("default case 1"); - break; - case 43: - print("case 43"); - break; - case 44: - print("case 44"); - break; - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3606,31 +3721,31 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = this; - v0 = 42; - function F2() { - if (!new.target) { throw 'must be called with new'; } - let v3 = this; - v3 = 42; - } - const v5 = { - foo() { - let v4 = this; - v4 = 42; - }, - }; - class C6 { - bar() { - let v7 = this; - v7 = 42; - } - static get baz() { - let v8 = this; - v8 = 42; + let v0 = this; + v0 = 42; + function F2() { + if (!new.target) { throw 'must be called with new'; } + let v3 = this; + v3 = 42; + } + const v5 = { + foo() { + let v4 = this; + v4 = 42; + }, + }; + class C6 { + bar() { + let v7 = this; + v7 = 42; + } + static get baz() { + let v8 = this; + v8 = 42; + } } - } - """ + """ XCTAssertEqual(actual, expected) } @@ -3667,19 +3782,19 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - -(-42); - -(-43n); - -(-4.4); - (-42) ** -4.4; - ~-42; - -42 + -4.4; - let v9 = 42; - v9 = -42; - print(-42, -43n, -4.4); - (-43n).foo; - (-4.4).bar; - - """ + -(-42); + -(-43n); + -(-4.4); + (-42) ** -4.4; + ~-42; + -42 + -4.4; + let v9 = 42; + v9 = -42; + print(-42, -43n, -4.4); + (-43n).foo; + (-4.4).bar; + + """ XCTAssertEqual(actual, expected) } @@ -3698,18 +3813,20 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - let v0 = null; - function f1() { - v0 = new.target; - } + let v0 = null; + function f1() { + v0 = new.target; + } - """ + """ XCTAssertEqual(actual, expected) } // This test is parameterized for normal and named variables with the // respective concrete cases below. - func _testDisposableVariableLifting(_ variableName : String, generateVariable: (ProgramBuilder, Variable) -> Void) { + func _testDisposableVariableLifting( + _ variableName: String, generateVariable: (ProgramBuilder, Variable) -> Void + ) { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -3717,12 +3834,12 @@ class LifterTests: XCTestCase { let v1 = b.loadInt(1) let v2 = b.loadInt(42) let numVariables = b.numberOfVisibleVariables - let dispose = b.createSymbolProperty("dispose"); + let dispose = b.createSymbolProperty("dispose") // Test that the intermediate variable for "Symbol" stays hidden. XCTAssertEqual(b.numberOfVisibleVariables, numVariables + 1) let disposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) - obj.addComputedMethod(dispose, with: .parameters(n:0)) { args in + obj.addComputedMethod(dispose, with: .parameters(n: 0)) { args in b.doReturn(v2) } } @@ -3734,37 +3851,43 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - function f0() { - const v4 = Symbol.dispose; - const v6 = { - value: 1, - [v4]() { - return 42; - }, - }; - using %@ = v6; - } - f0(); + function f0() { + const v4 = Symbol.dispose; + const v6 = { + value: 1, + [v4]() { + return 42; + }, + }; + using %@ = v6; + } + f0(); - """ + """ XCTAssertEqual(actual, String(format: expected, variableName)) } func testLoadDisposableVariableLifting() { - _testDisposableVariableLifting("v7", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.loadDisposableVariable(v) - }) + _testDisposableVariableLifting( + "v7", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.loadDisposableVariable(v) + }) } func testCreateNamedDisposableVariableLifting() { - _testDisposableVariableLifting("dis", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.createNamedDisposableVariable("dis", v) - }) + _testDisposableVariableLifting( + "dis", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.createNamedDisposableVariable("dis", v) + }) } // This test is parameterized for normal and named variables with the // respective concrete cases below. - func _testAsyncDisposableVariableLifting(_ variableName : String, generateVariable: (ProgramBuilder, Variable) -> Void) { + func _testAsyncDisposableVariableLifting( + _ variableName: String, generateVariable: (ProgramBuilder, Variable) -> Void + ) { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -3774,7 +3897,7 @@ class LifterTests: XCTestCase { let asyncDispose = b.createSymbolProperty("asyncDispose") let asyncDisposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) - obj.addComputedMethod(asyncDispose, with: .parameters(n:0)) { args in + obj.addComputedMethod(asyncDispose, with: .parameters(n: 0)) { args in b.doReturn(v2) } } @@ -3790,45 +3913,50 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - async function f0() { - const v4 = Symbol.asyncDispose; - const v6 = { - value: 1, - [v4]() { - return 42; - }, - }; - await using %@ = v6; - } - async function f8() { - await f0(); - } - f8(); + async function f0() { + const v4 = Symbol.asyncDispose; + const v6 = { + value: 1, + [v4]() { + return 42; + }, + }; + await using %@ = v6; + } + async function f8() { + await f0(); + } + f8(); - """ + """ XCTAssertEqual(actual, String(format: expected, variableName)) } func testLoadAsyncDisposableVariableLifting() { - _testAsyncDisposableVariableLifting("v7", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.loadAsyncDisposableVariable(v) - }) + _testAsyncDisposableVariableLifting( + "v7", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.loadAsyncDisposableVariable(v) + }) } func testCreateNamedAsyncDisposableVariableLifting() { - _testAsyncDisposableVariableLifting("dis", generateVariable: { (b: ProgramBuilder, v: Variable) in - b.createNamedAsyncDisposableVariable("dis", v) - }) + _testAsyncDisposableVariableLifting( + "dis", + generateVariable: { (b: ProgramBuilder, v: Variable) in + b.createNamedAsyncDisposableVariable("dis", v) + }) } func testImportAnalysisMisTypedJS() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - let table = b.createWasmTable(elementType: .wasmFuncRef(), limits: Limits(min: 1), isTable64: true) + let table = b.createWasmTable( + elementType: .wasmFuncRef(), limits: Limits(min: 1), isTable64: true) XCTAssertTrue(b.type(of: table).Is(.object(ofGroup: "WasmTable"))) - let f = b.buildPlainFunction(with: .parameters(n: 0)) {_ in + let f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in b.doReturn(b.loadInt(1)) } @@ -3840,7 +3968,8 @@ class LifterTests: XCTestCase { b.buildWasmModule { m in m.addWasmFunction(with: [] => []) { f, _, _ in - f.wasmCallIndirect(signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) + f.wasmCallIndirect( + signature: [] => [], table: table, functionArgs: [], tableIndex: f.consti64(0)) return [] } } @@ -3865,7 +3994,7 @@ class LifterTests: XCTestCase { // Append the mutated instruction now. b.append(instr) // Adopt the rest of the Program. - for i in mutationIndex+1.. v2] - v3, v4 <- WasmEndTypeGroup [v1, v2] - WasmBeginTypeGroup - v5 <- WasmDefineForwardOrSelfReference - v6 <- WasmDefineStructType(.wasmRef(Index) mutability=false, .wasmi32 mutability=true, .wasmRef(null Index) mutability=true) [v3, v5] - v7 <- WasmEndTypeGroup [v6] - - """ + WasmBeginTypeGroup + v0 <- WasmDefineForwardOrSelfReference + v1 <- WasmDefineArrayType .wasmRef(null Index) mutability=false v0 + v2 <- WasmDefineArrayType .wasmi32 mutability=true + WasmResolveForwardReference [v0 => v2] + v3, v4 <- WasmEndTypeGroup [v1, v2] + WasmBeginTypeGroup + v5 <- WasmDefineForwardOrSelfReference + v6 <- WasmDefineStructType(.wasmRef(Index) mutability=false, .wasmi32 mutability=true, .wasmRef(null Index) mutability=true) [v3, v5] + v7 <- WasmEndTypeGroup [v6] + + """ XCTAssertEqual(actual, expected) } @@ -3969,11 +4100,11 @@ class LifterTests: XCTestCase { // The side-effect must be emitted before the arrow function is defined. // The arrow function is assigned to a temporary because it's used as a callee. let expected = """ - sideEffect(); - const t1 = () => 42; - t1(); + sideEffect(); + const t1 = () => 42; + t1(); - """ + """ XCTAssertEqual(actual, expected) } @@ -3992,7 +4123,7 @@ class LifterTests: XCTestCase { b2.doReturn(b2.loadInt(0)) } let sub = b2.binary(arg0, b2.loadInt(1), with: .Sub) - let recCall = b2.callFunction(fRec, withArgs: [sub]) // Recursion! + let recCall = b2.callFunction(fRec, withArgs: [sub]) // Recursion! b2.doReturn(recCall) b2.emit(EndArrowFunction()) @@ -4003,15 +4134,15 @@ class LifterTests: XCTestCase { // Recursive arrow functions are not inlined, so they are assigned to a constant. let expected = """ - const v1 = (a2) => { - if (a2 == 0) { - return 0; - } - return v1(a2 - 1); - }; - v1(10); + const v1 = (a2) => { + if (a2 == 0) { + return 0; + } + return v1(a2 - 1); + }; + v1(10); - """ + """ XCTAssertEqual(actual, expected) } @@ -4029,9 +4160,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - f((a2) => a2); + f((a2) => a2); - """ + """ XCTAssertEqual(actual, expected) } @@ -4041,7 +4172,7 @@ class LifterTests: XCTestCase { let arrowOuter = b.buildArrowFunction(with: .parameters(n: 1)) { argsOuter in let arrowInner = b.buildArrowFunction(with: .parameters(n: 1)) { argsInner in - b.doReturn(b.binary(argsOuter[0], argsInner[0], with: .Add)) + b.doReturn(b.binary(argsOuter[0], argsInner[0], with: .Add)) } b.doReturn(arrowInner) } @@ -4051,10 +4182,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = (a1) => (a3) => a1 + a3; - t0(1); + const t0 = (a1) => (a3) => a1 + a3; + t0(1); - """ + """ XCTAssertEqual(actual, expected) } @@ -4071,10 +4202,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = async () => 42; - t0(); + const t0 = async () => 42; + t0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -4090,11 +4221,11 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = () => { - }; - f(v0, v0); + const v0 = () => { + }; + f(v0, v0); - """ + """ XCTAssertEqual(actual, expected) } @@ -4112,9 +4243,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - obj.x = () => 42; + obj.x = () => 42; - """ + """ XCTAssertEqual(actual, expected) } @@ -4132,10 +4263,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const v0 = {}; - v0.x = () => ({}); + const v0 = {}; + v0.x = () => ({}); - """ + """ XCTAssertEqual(actual, expected) } @@ -4146,7 +4277,8 @@ class LifterTests: XCTestCase { b.buildIf(b.loadBool(true)) { let o = b.buildObjectLiteral { _ in } let f = b.buildArrowFunction(with: .parameters(n: 0)) { _ in - let v = b.createNamedVariable("a", declarationMode: .const, initialValue: b.loadInt(1)) + let v = b.createNamedVariable( + "a", declarationMode: .const, initialValue: b.loadInt(1)) b.doReturn(b.binary(v, v, with: .Add)) } b.setProperty("x", of: o, to: f) @@ -4156,15 +4288,15 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - if (true) { - const v1 = {}; - v1.x = () => { - const a = 1; - return a + a; - }; - } + if (true) { + const v1 = {}; + v1.x = () => { + const a = 1; + return a + a; + }; + } - """ + """ XCTAssertEqual(actual, expected) } @@ -4183,10 +4315,10 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - const t0 = () => ({} + 1); - t0(); + const t0 = () => ({} + 1); + t0(); - """ + """ XCTAssertEqual(actual, expected) } @@ -4200,9 +4332,9 @@ class LifterTests: XCTestCase { let actual = fuzzer.lifter.lift(program) let expected = """ - print("Hello \\"World\\""); + print("Hello \\"World\\""); - """ + """ XCTAssertEqual(actual, expected) } @@ -4210,17 +4342,17 @@ class LifterTests: XCTestCase { func testEmptyWasmModule() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - b.buildWasmModule {_ in} + b.buildWasmModule { _ in } let program = b.finalize() let actual = fuzzer.lifter.lift(program) // An empty Wasm module should only contain the needed prefix but no empty sections. let expected = """ - const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ - 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, - ]))); + const v0 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + ]))); - """ + """ XCTAssertEqual(actual, expected) } diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 535e6401f..fed055235 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class LiveTests: XCTestCase { @@ -26,12 +27,13 @@ class LiveTests: XCTestCase { /// Meta-test ensuring that the test framework can successfully terminate an endless loop. func testEndlessLoopTermination() throws { - let runner = try GetJavaScriptExecutorOrSkipTest() + let runner = try GetJavaScriptExecutorOrSkipTest() - let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { b in - b.loadInt(123) // prefix + let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { + b in + b.loadInt(123) // prefix - let module = b.buildWasmModule() { module in + let module = b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in function.wasmBuildLoop(with: [] => [], args: []) { label, args in function.wasmBranch(to: label) @@ -58,7 +60,8 @@ class LiveTests: XCTestCase { } func testWasmCodeGenerationAndCompilation() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) let results = try Self.runLiveTest(withRunner: runner) { b in // Fuzzilli can't handle situations where there aren't any variables available. @@ -80,13 +83,16 @@ class LiveTests: XCTestCase { b.createWasmJSTag() b.createWasmTag(parameterTypes: [.wasmi32, .wasmf64]) - b.buildWasmModule() { module in - module.addMemory(minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) + b.buildWasmModule { module in + module.addMemory( + minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) let signature = b.randomWasmSignature() module.addWasmFunction(with: signature) { function, label, args in b.buildPrefix() b.build(n: 40) - return signature.outputTypes.map {b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)!} + return signature.outputTypes.map { + b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)! + } } } } @@ -96,7 +102,8 @@ class LiveTests: XCTestCase { } func testWasmCodeGenerationAndCompilationAndExecution() throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--wasm-allow-mixed-eh-for-testing"]) let results = try Self.runLiveTest(withRunner: runner) { b in // Fuzzilli can't handle situations where there aren't any variables available. @@ -119,12 +126,15 @@ class LiveTests: XCTestCase { b.createWasmTag(parameterTypes: [.wasmi32, .wasmf64]) let wasmSignature = b.randomWasmSignature() - let m = b.buildWasmModule() { module in - module.addMemory(minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) + let m = b.buildWasmModule { module in + module.addMemory( + minPages: 2, maxPages: probability(0.5) ? nil : 5, isMemory64: probability(0.5)) module.addWasmFunction(with: wasmSignature) { function, label, args in b.buildPrefix() b.build(n: 40) - return wasmSignature.outputTypes.map {b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)!} + return wasmSignature.outputTypes.map { + b.randomVariable(ofType: $0) ?? function.generateRandomWasmVar(ofType: $0)! + } } } @@ -136,16 +146,16 @@ class LiveTests: XCTestCase { // TODO(pawkra): support shared refs. let args = wasmSignature.parameterTypes.map { switch $0 { - case .wasmi64: - return b.loadBigInt(123) - case ILType.wasmFuncRef(): - return jsFunction - case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): - return b.loadNull() - case ILType.wasmExternRef(), ILType.wasmAnyRef(): - return b.createObject(with: [:]) - default: - return b.loadInt(321) + case .wasmi64: + return b.loadBigInt(123) + case ILType.wasmFuncRef(): + return jsFunction + case ILType.wasmNullExternRef(), ILType.wasmNullFuncRef(), ILType.wasmNullRef(): + return b.loadNull() + case ILType.wasmExternRef(), ILType.wasmAnyRef(): + return b.createObject(with: [:]) + default: + return b.loadInt(321) } } b.callMethod(m.getExportedMethod(at: 0), on: m.loadExports(), withArgs: args) @@ -166,7 +176,10 @@ class LiveTests: XCTestCase { // The closure can use the ProgramBuilder to emit a program of a specific // shape that is then executed with the given runner. We then check that // we stay below the maximum failure rate over the given number of iterations. - static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { + static func runLiveTest( + iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, + body: (ProgramBuilder) -> Void + ) throws -> (failureRate: Double, failureMessages: [String: Int]) { let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -178,11 +191,13 @@ class LiveTests: XCTestCase { var failureDirectory: URL? = nil if ProcessInfo.processInfo.environment["FUZZILLI_TEST_DEBUG"] != nil { - failureDirectory = FileManager().temporaryDirectory.appendingPathComponent("fuzzilli_livetest_failures") + failureDirectory = FileManager().temporaryDirectory.appendingPathComponent( + "fuzzilli_livetest_failures") print("Saving LiveTest failures to \(String(describing: failureDirectory!)).") do { try? FileManager.default.removeItem(at: failureDirectory!) - try FileManager.default.createDirectory(at: failureDirectory!, withIntermediateDirectories: true) + try FileManager.default.createDirectory( + at: failureDirectory!, withIntermediateDirectories: true) } catch {} } @@ -202,7 +217,8 @@ class LiveTests: XCTestCase { } DispatchQueue.concurrentPerform(iterations: n) { i in - let result = executeAndParseResults(program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) + let result = executeAndParseResults( + program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) results[i] = result } @@ -210,7 +226,8 @@ class LiveTests: XCTestCase { switch result! { case .failed(let message): if let path = failureDirectory { - programs[i].program.storeToDisk(atPath: path.appendingPathComponent("failure_\(i).fzil").path) + programs[i].program.storeToDisk( + atPath: path.appendingPathComponent("failure_\(i).fzil").path) } failures += 1 failureMessages[message] = (failureMessages[message] ?? 0) + 1 @@ -224,24 +241,33 @@ class LiveTests: XCTestCase { return (failureRate, failureMessages) } - func checkFailureRate(testResults: (failureRate: Double, failureMessages: [String: Int]), maxFailureRate: Double) { + func checkFailureRate( + testResults: (failureRate: Double, failureMessages: [String: Int]), maxFailureRate: Double + ) { if testResults.failureRate >= maxFailureRate { - var message = "Failure rate is too high. Should be below \(String(format: "%.2f", maxFailureRate * 100))% but we observed \(String(format: "%.2f", testResults.failureRate * 100))%\n" + var message = + "Failure rate is too high. Should be below \(String(format: "%.2f", maxFailureRate * 100))% but we observed \(String(format: "%.2f", testResults.failureRate * 100))%\n" message += "Observed failures:\n" - for (signature, count) in testResults.failureMessages.sorted(by: { $0.value > $1.value }) { + for (signature, count) in testResults.failureMessages.sorted(by: { $0.value > $1.value } + ) { message += " \(count)x \(signature)\n" } if ProcessInfo.processInfo.environment["FUZZILLI_TEST_DEBUG"] == nil { - message += "If you want to dump failing programs to disk you can set FUZZILLI_TEST_DEBUG=1 in your environment." + message += + "If you want to dump failing programs to disk you can set FUZZILLI_TEST_DEBUG=1 in your environment." } XCTFail(message) } } - static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, timeoutInSeconds: Int) -> ExecutionResult { + static func executeAndParseResults( + program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, + timeoutInSeconds: Int + ) -> ExecutionResult { do { - let result = try runner.executeScript(program.jsProgram, + let result = try runner.executeScript( + program.jsProgram, withTimeout: Double(timeoutInSeconds) * Seconds) if result.isFailure { var signature: String? = nil diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 2878c9431..7ecaf6dbe 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class MinimizerTests: XCTestCase { @@ -609,11 +610,14 @@ class MinimizerTests: XCTestCase { // Build input program to be minimized. b.loadString("unused") let f = b.buildPlainFunction(with: .parameters(n: 3)) { args in - b.buildIfElse(args[0], ifBody: { - b.doReturn(args[1]) - }, elseBody: { - b.doReturn(args[2]) - }) + b.buildIfElse( + args[0], + ifBody: { + b.doReturn(args[1]) + }, + elseBody: { + b.doReturn(args[2]) + }) } var a1 = b.loadBool(true) var a2 = b.loadInt(1337) @@ -636,11 +640,14 @@ class MinimizerTests: XCTestCase { a2 = b.loadInt(1337) let u = b.loadUndefined() r = b.loadUndefined() - b.buildIfElse(a1, ifBody: { - b.reassign(variable: r, value: a2) - }, elseBody: { - b.reassign(variable: r, value: u) - }) + b.buildIfElse( + a1, + ifBody: { + b.reassign(variable: r, value: a2) + }, + elseBody: { + b.reassign(variable: r, value: u) + }) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: r) @@ -685,9 +692,11 @@ class MinimizerTests: XCTestCase { var a3 = b.loadInt(2) b.loadString("unused") let f = b.buildPlainFunction(with: .parameters(n: 0)) { args in - b.buildIf(a1, ifBody: { - b.doReturn(a2) - }) + b.buildIf( + a1, + ifBody: { + b.doReturn(a2) + }) b.doReturn(a3) } @@ -710,9 +719,11 @@ class MinimizerTests: XCTestCase { a2 = b.loadInt(1) a3 = b.loadInt(2) r = b.loadUndefined() - b.buildIf(a1, ifBody: { - b.reassign(variable: r, value: a2) - }) + b.buildIf( + a1, + ifBody: { + b.reassign(variable: r, value: a2) + }) b.reassign(variable: r, value: a3) o = b.createObject(with: [:]) b.setProperty("result", of: o, to: a3) @@ -838,23 +849,26 @@ class MinimizerTests: XCTestCase { b.reassign(variable: n3, value: n1) var n4 = b.loadInt(45) b.reassign(variable: n4, value: n3) - b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 + b.setProperty("n4", of: o, to: n4) // This will store n1, i.e. 42 var c = b.loadBool(true) - b.buildIfElse(c, ifBody: { - let n5 = b.loadInt(46) - b.reassign(variable: n1, value: n5) - b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 - b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 - b.reassign(variable: n1, value: n2) - b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 - }, elseBody: { - let n6 = b.loadInt(47) - b.reassign(variable: n1, value: n6) - b.setProperty( "n3", of: o, to: n3) // This will still store n3, i.e. 42 - }) - b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 + b.buildIfElse( + c, + ifBody: { + let n5 = b.loadInt(46) + b.reassign(variable: n1, value: n5) + b.setProperty("n1", of: o, to: n1) // This will store n5, i.e. 46 + b.setProperty("n1", of: o, to: n1) // This will (again) store n5, i.e. 46 + b.reassign(variable: n1, value: n2) + b.setProperty("n1", of: o, to: n1) // This will store n2, i.e. 43 + }, + elseBody: { + let n6 = b.loadInt(47) + b.reassign(variable: n1, value: n6) + b.setProperty("n3", of: o, to: n3) // This will still store n3, i.e. 42 + }) + b.setProperty("n1", of: o, to: n1) // This will store n1, i.e. 42 b.reassign(variable: n1, value: n2) - b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 + b.setProperty("n3", of: o, to: n3) // This will store n3, i.e. 42 evaluator.operationIsImportant(Reassign.self) @@ -874,18 +888,21 @@ class MinimizerTests: XCTestCase { b.reassign(variable: n4, value: n3) b.setProperty("n4", of: o, to: n1) c = b.loadBool(true) - b.buildIfElse(c, ifBody: { - let n5 = b.loadInt(46) - b.reassign(variable: n1, value: n5) - b.setProperty("n1", of: o, to: n5) - b.setProperty("n1", of: o, to: n5) - b.reassign(variable: n1, value: n2) - b.setProperty("n1", of: o, to: n2) - }, elseBody: { - let n6 = b.loadInt(47) - b.reassign(variable: n1, value: n6) - b.setProperty("n3", of: o, to: n3) - }) + b.buildIfElse( + c, + ifBody: { + let n5 = b.loadInt(46) + b.reassign(variable: n1, value: n5) + b.setProperty("n1", of: o, to: n5) + b.setProperty("n1", of: o, to: n5) + b.reassign(variable: n1, value: n2) + b.setProperty("n1", of: o, to: n2) + }, + elseBody: { + let n6 = b.loadInt(47) + b.reassign(variable: n1, value: n6) + b.setProperty("n3", of: o, to: n3) + }) evaluator.nextInstructionIsImportant(in: b) b.setProperty("n1", of: o, to: n1) b.reassign(variable: n1, value: n2) @@ -999,7 +1016,7 @@ class MinimizerTests: XCTestCase { let loopVar = b.loadInt(0) b.buildWhileLoop({ b.compare(loopVar, with: numIterations, using: .lessThan) }) { b.unary(.PostInc, loopVar) - evaluator.nextInstructionIsImportant(in: b) // Otherwise, the minimizer will attempt to simplify the while-loop into a repeat-loop + evaluator.nextInstructionIsImportant(in: b) // Otherwise, the minimizer will attempt to simplify the while-loop into a repeat-loop b.buildWhileLoop({ b.loadBool(true) }) { evaluator.nextInstructionIsImportant(in: b) b.loopBreak() @@ -1037,9 +1054,22 @@ class MinimizerTests: XCTestCase { var f = b.createNamedVariable(forBuiltin: "f") var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") - b.buildForLoop(i: { evaluator.nextInstructionIsImportant(in: b); return b.callFunction(d) }, - { i in evaluator.nextInstructionIsImportant(in: b); b.callFunction(e); return b.compare(i, with: b.loadInt(100), using: .lessThan) }, - { i in evaluator.nextInstructionIsImportant(in: b); b.callFunction(f); b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { + evaluator.nextInstructionIsImportant(in: b) + return b.callFunction(d) + }, + { i in + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(e) + return b.compare(i, with: b.loadInt(100), using: .lessThan) + }, + { i in + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f) + b.unary(.PostInc, i) + } + ) { i in evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [i]) } @@ -1082,9 +1112,23 @@ class MinimizerTests: XCTestCase { var h = b.createNamedVariable(forBuiltin: "h") var limit = b.loadInt(100) // In this case, the for-loop is actually important (we emulate that by marking the EndForLoopAfterthought instruction as important - b.buildForLoop(i: { evaluator.nextInstructionIsImportant(in: b); return b.callFunction(d) }, - { i in b.callFunction(e); evaluator.nextInstructionIsImportant(in: b); return b.compare(i, with: limit, using: .lessThan) }, - { i in b.callFunction(f); evaluator.nextInstructionIsImportant(in: b); b.unary(.PostInc, i); evaluator.nextInstructionIsImportant(in: b) }) { i in + b.buildForLoop( + i: { + evaluator.nextInstructionIsImportant(in: b) + return b.callFunction(d) + }, + { i in + b.callFunction(e) + evaluator.nextInstructionIsImportant(in: b) + return b.compare(i, with: limit, using: .lessThan) + }, + { i in + b.callFunction(f) + evaluator.nextInstructionIsImportant(in: b) + b.unary(.PostInc, i) + evaluator.nextInstructionIsImportant(in: b) + } + ) { i in evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [i]) } @@ -1098,9 +1142,11 @@ class MinimizerTests: XCTestCase { g = b.createNamedVariable(forBuiltin: "g") h = b.createNamedVariable(forBuiltin: "h") limit = b.loadInt(100) - b.buildForLoop(i: { return b.callFunction(d) }, - { i in b.compare(i, with: limit, using: .lessThan) }, - { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { return b.callFunction(d) }, + { i in b.compare(i, with: limit, using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(g, withArgs: [i]) } b.callFunction(h) @@ -1122,7 +1168,12 @@ class MinimizerTests: XCTestCase { var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") var loopVar = b.loadInt(10) - b.buildWhileLoop({ evaluator.nextInstructionIsImportant(in: b); b.callFunction(f); evaluator.nextInstructionIsImportant(in: b); return b.unary(.PostDec, loopVar) }) { + b.buildWhileLoop({ + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f) + evaluator.nextInstructionIsImportant(in: b) + return b.unary(.PostDec, loopVar) + }) { evaluator.nextInstructionIsImportant(in: b) b.callFunction(g, withArgs: [loopVar]) @@ -1165,14 +1216,20 @@ class MinimizerTests: XCTestCase { var g = b.createNamedVariable(forBuiltin: "g") var h = b.createNamedVariable(forBuiltin: "h") var loopVar = b.loadInt(10) - b.buildDoWhileLoop(do: { - evaluator.nextInstructionIsImportant(in: b) - b.callFunction(f, withArgs: [loopVar]) + b.buildDoWhileLoop( + do: { + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(f, withArgs: [loopVar]) - evaluator.nextInstructionIsImportant(in: b) - // The Continue operation is necessary here so that the loop isn't simply deleted. - b.loopContinue() - }, while: { evaluator.nextInstructionIsImportant(in: b); b.callFunction(g); return b.unary(.PostDec, loopVar) }) + evaluator.nextInstructionIsImportant(in: b) + // The Continue operation is necessary here so that the loop isn't simply deleted. + b.loopContinue() + }, + while: { + evaluator.nextInstructionIsImportant(in: b) + b.callFunction(g) + return b.unary(.PostDec, loopVar) + }) evaluator.nextInstructionIsImportant(in: b) b.callFunction(h) @@ -1342,10 +1399,11 @@ class MinimizerTests: XCTestCase { evaluator.nextInstructionIsImportant(in: b) var a = b.createArray(with: [i, i, i]) var f = b.loadFloat(13.37) - b.buildTryCatchFinally(tryBody: { - evaluator.nextInstructionIsImportant(in: b) - b.callMethod("fill", on: a, withArgs: [f]) - }, catchBody: { _ in }) + b.buildTryCatchFinally( + tryBody: { + evaluator.nextInstructionIsImportant(in: b) + b.callMethod("fill", on: a, withArgs: [f]) + }, catchBody: { _ in }) let originalProgram = b.finalize() @@ -1529,7 +1587,10 @@ class MinimizerTests: XCTestCase { b.callMethod("m", on: o, guard: true) // Make sure that none of the operations are removed. - evaluator.operationsAreImportant([GetProperty.self, GetElement.self, GetComputedProperty.self, CallFunction.self, CallMethod.self]) + evaluator.operationsAreImportant([ + GetProperty.self, GetElement.self, GetComputedProperty.self, CallFunction.self, + CallMethod.self, + ]) let originalProgram = b.finalize() @@ -1538,8 +1599,12 @@ class MinimizerTests: XCTestCase { let minimizedProgram = minimize(originalProgram, with: fuzzer) XCTAssertEqual(originalProgram.size, minimizedProgram.size) - let numGuardableOperationsBefore = originalProgram.code.filter({ $0.op is GuardableOperation }).count - let numGuardableOperationsAfter = minimizedProgram.code.filter({ $0.op is GuardableOperation }).count + let numGuardableOperationsBefore = originalProgram.code.filter({ + $0.op is GuardableOperation + }).count + let numGuardableOperationsAfter = minimizedProgram.code.filter({ + $0.op is GuardableOperation + }).count XCTAssertEqual(numGuardableOperationsBefore, numGuardableOperationsAfter) let operationTypesBefore = originalProgram.code.map({ $0.op.name }) @@ -1552,7 +1617,10 @@ class MinimizerTests: XCTestCase { XCTAssertEqual(numGuardedOperationsAfter, 0) } - func runWasmMinimization(program: (MinimizerTests.EvaluatorForMinimizationTests, ProgramBuilder) -> ProgramBuilder.WasmModule, minified: (ProgramBuilder) -> ProgramBuilder.WasmModule) throws { + func runWasmMinimization( + program: (MinimizerTests.EvaluatorForMinimizationTests, ProgramBuilder) -> + ProgramBuilder.WasmModule, minified: (ProgramBuilder) -> ProgramBuilder.WasmModule + ) throws { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) let b = fuzzer.makeBuilder() @@ -1573,9 +1641,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } // Test removing unneeded WasmBeginCatchAll blocks. @@ -1616,18 +1685,24 @@ class MinimizerTests: XCTestCase { let irrelevantTag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in evaluator.nextInstructionIsImportant(in: b) function.WasmBuildThrow(tag: tag, inputs: []) // Mark teh first catch as important. evaluator.nextInstructionIsImportant(in: b) - }, catchClauses: [ - (tag: tag, body: { _, _, _ in - let val = function.consti64(42) - evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - }), - (tag: irrelevantTag, body: { _, _, _ in })]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, _ in + let val = function.consti64(42) + evaluator.nextInstructionIsImportant(in: b) + function.wasmReturn(val) + } + ), + (tag: irrelevantTag, body: { _, _, _ in }), + ]) return [function.consti64(-1)] } } @@ -1639,9 +1714,15 @@ class MinimizerTests: XCTestCase { function.wasmBuildLegacyTryVoid( body: { label in function.WasmBuildThrow(tag: tag, inputs: []) - }, catchClauses: [(tag: tag, body: { _, _, _ in - function.wasmReturn(function.consti64(42)) - })]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, _ in + function.wasmReturn(function.consti64(42)) + } + ) + ]) return [function.consti64(-1)] } } @@ -1654,11 +1735,13 @@ class MinimizerTests: XCTestCase { return b.buildWasmModule { wasmModule in let tag = wasmModule.addTag(parameterTypes: []) wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in let val = function.consti64(42) - evaluator.nextInstructionIsImportant(in: b) - function.wasmReturn(val) - }, catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) + evaluator.nextInstructionIsImportant(in: b) + function.wasmReturn(val) + }, + catchClauses: [(tag: tag, body: { _, _, _ in function.wasmUnreachable() })]) return [function.consti64(-1)] } } @@ -1666,8 +1749,8 @@ class MinimizerTests: XCTestCase { } minified: { b in return b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmReturn(function.consti64(42)) - return [function.consti64(-1)] + function.wasmReturn(function.consti64(42)) + return [function.consti64(-1)] } } } @@ -1703,7 +1786,7 @@ class MinimizerTests: XCTestCase { function.wasmBuildIfElse(args[0], signature: [] => []) { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(43) - } elseBody: { _, _ in + } elseBody: { _, _ in evaluator.nextInstructionIsImportant(in: b) function.consti64(42) } @@ -1725,9 +1808,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationVoidRemoveElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in evaluator.nextInstructionIsImportant(in: b) - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { label, ifArgs in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { label, ifArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) evaluator.nextInstructionIsImportant(in: b) @@ -1741,8 +1827,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { label, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { label, ifArgs in let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) function.wasmReturn(sum) } @@ -1755,9 +1844,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationVoidRemoveIfKeepElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in evaluator.operationIsImportant(WasmBeginIf.self) - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: false) { _, _ in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: false + ) { _, _ in function.wasmUnreachable() } elseBody: { label, elseArgs in evaluator.nextInstructionIsImportant(in: b) @@ -1771,8 +1863,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: args, inverted: true) { label, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: args, inverted: true + ) { label, ifArgs in let sum = function.wasmi32BinOp(args[0], ifArgs[0], binOpKind: .Add) function.wasmReturn(sum) } @@ -1785,8 +1880,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResult() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) let a = function.consti32(42) evaluator.nextInstructionIsImportant(in: b) @@ -1800,7 +1898,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let b = function.consti32(10) let a = function.consti32(42) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1812,8 +1911,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultKeepElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1827,7 +1929,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let b = function.consti32(10) let a = function.consti32(42) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1840,8 +1943,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultButLabelUsedInIf() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) function.wasmBranch(to: label, args: args) return [args[0]] @@ -1854,8 +1960,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in function.wasmBranch(to: label, args: args) return [args[0]] } elseBody: { label, args in @@ -1871,8 +1980,11 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultButLabelUsedInElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1885,8 +1997,11 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32], args: [function.consti32(10)] + ) { label, args in return [function.consti32(123)] } elseBody: { label, args in function.wasmBranch(to: label, args: args) @@ -1901,8 +2016,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultPassingThroughInputInIf() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], + args: [function.consti32(10)] + ) { label, args in evaluator.nextInstructionIsImportant(in: b) return [args[0], function.consti32(123)] } elseBody: { label, args in @@ -1915,7 +2034,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let a = function.consti32(10) let b = function.consti32(123) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1927,8 +2047,12 @@ class MinimizerTests: XCTestCase { func testWasmIfElseMinimizationWithResultPassingThroughInputInElse() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildIfElseWithResult(args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], args: [function.consti32(10)]) { label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildIfElseWithResult( + args[0], signature: [.wasmi32] => [.wasmi32, .wasmi32], + args: [function.consti32(10)] + ) { label, args in return [args[0], args[0]] } elseBody: { label, args in evaluator.nextInstructionIsImportant(in: b) @@ -1941,7 +2065,8 @@ class MinimizerTests: XCTestCase { } minified: { b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in let a = function.consti32(10) let b = function.consti32(123) return [function.wasmi32BinOp(a, b, binOpKind: .Add)] @@ -1953,8 +2078,12 @@ class MinimizerTests: XCTestCase { func testWasmBlockMinimization() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(blockArgs[0], blockArgs[1], binOpKind: .Add) return [sum, blockArgs[1]] @@ -1965,9 +2094,10 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let const10 = function.consti32(10) + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let const10 = function.consti32(10) let sum = function.wasmi32BinOp(args[0], const10, binOpKind: .Add) return [function.wasmi32BinOp(sum, const10, binOpKind: .Mul)] } @@ -1979,8 +2109,12 @@ class MinimizerTests: XCTestCase { func testWasmBlockMinimizationLabelUsed() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) function.wasmBranch(to: label, args: blockArgs) return blockArgs @@ -1991,9 +2125,13 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildBlockWithResults(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildBlockWithResults( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in function.wasmBranch(to: label, args: blockArgs) return blockArgs } @@ -2006,8 +2144,12 @@ class MinimizerTests: XCTestCase { func testWasmLoopMinimization() throws { try runWasmMinimization { evaluator, b in b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let results = function.wasmBuildLoop(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: [args[0], function.consti32(10)]) { label, blockArgs in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let results = function.wasmBuildLoop( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], + args: [args[0], function.consti32(10)] + ) { label, blockArgs in evaluator.nextInstructionIsImportant(in: b) let sum = function.wasmi32BinOp(blockArgs[0], blockArgs[1], binOpKind: .Add) return [sum, blockArgs[1]] @@ -2018,9 +2160,10 @@ class MinimizerTests: XCTestCase { } } minified: { b in - b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let const10 = function.consti32(10) + b.buildWasmModule { wasmModule in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in + let const10 = function.consti32(10) let sum = function.wasmi32BinOp(args[0], const10, binOpKind: .Add) return [function.wasmi32BinOp(sum, const10, binOpKind: .Mul)] } @@ -2083,9 +2226,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2115,7 +2259,8 @@ class MinimizerTests: XCTestCase { let constOne = function.consti32(1) let constZero = function.consti32(0) evaluator.nextInstructionIsImportant(in: b) - let array = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: constOne) + let array = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: constOne) // Not important array, this should make the second type unused and then being // removed from the type group. let _ = function.wasmArrayNewDefault(arrayType: typeGroup[1], size: constOne) @@ -2138,7 +2283,8 @@ class MinimizerTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let constOne = function.consti32(1) let constZero = function.consti32(0) - let array = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: constOne) + let array = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: constOne) let element = function.wasmArrayGet(array: array, index: constZero) return [element] } @@ -2148,9 +2294,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2165,8 +2312,11 @@ class MinimizerTests: XCTestCase { // This signature is only used by the structType which is exposed from this type // group and then used in the struct.new_default inside the wasm function. Still, // due to this indirect usage it must still be kept alive. - let signature = b.wasmDefineSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) - let structType = b.wasmDefineStructType(fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [signature]) + let signature = b.wasmDefineSignatureType( + signature: [.wasmi32] => [.wasmi32], indexTypes: []) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], + indexTypes: [signature]) return [signature, structType] } @@ -2182,8 +2332,11 @@ class MinimizerTests: XCTestCase { // Build expected output program. do { let typeGroup = b.wasmDefineTypeGroup { - let signature = b.wasmDefineSignatureType(signature: [.wasmi32] => [.wasmi32], indexTypes: []) - let structType = b.wasmDefineStructType(fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [signature]) + let signature = b.wasmDefineSignatureType( + signature: [.wasmi32] => [.wasmi32], indexTypes: []) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmRef(.Index(), nullability: true), mutability: true)], + indexTypes: [signature]) return [signature, structType] } @@ -2197,12 +2350,12 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } - func testWasmTypeGroupNestedTypesAndTypeGroupDependencies() throws { let evaluator = EvaluatorForMinimizationTests() let fuzzer = makeMockFuzzer(evaluator: evaluator) @@ -2223,9 +2376,13 @@ class MinimizerTests: XCTestCase { let typeGroupB = b.wasmDefineTypeGroup { return [ // Only used by an unimportant instruction. - b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: false), mutability: false, indexType: typeGroupA[2]), + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: false), mutability: false, + indexType: typeGroupA[2]), // Needed for an important instruction, shall not be removed. - b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: typeGroupA[1]), + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: typeGroupA[1]), ] } @@ -2247,7 +2404,11 @@ class MinimizerTests: XCTestCase { return [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] } let typeGroupB = b.wasmDefineTypeGroup { - return [b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: typeGroupA[0])] + return [ + b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: typeGroupA[0]) + ] } b.buildWasmModule { wasmModule in @@ -2262,9 +2423,10 @@ class MinimizerTests: XCTestCase { // Perform minimization and check that the two programs are equal. let actualProgram = minimize(originalProgram, with: fuzzer) - XCTAssertEqual(expectedProgram, actualProgram, - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") } @@ -2353,10 +2515,14 @@ class MinimizerTests: XCTestCase { func hasAspects(_ execution: Execution, _ aspects: ProgramAspects) -> Bool { // Check if any important instructions were removed, and if yes return false. - var numImportantOperationsBefore = 0, numImportantOperationsAfter = 0 - var numReturnsBefore = 0, numReturnsAfter = 0 - var numFunctionsBefore = 0, numFunctionsAfter = 0 - var numImportantInstructionsBefore = importantInstructions.count, numImportantInstructionsAfter = 0 + var numImportantOperationsBefore = 0 + var numImportantOperationsAfter = 0 + var numReturnsBefore = 0 + var numReturnsAfter = 0 + var numFunctionsBefore = 0 + var numFunctionsAfter = 0 + var numImportantInstructionsBefore = importantInstructions.count + var numImportantInstructionsAfter = 0 for instr in referenceProgram.code { if instr.op is BeginAnyFunction { @@ -2396,7 +2562,9 @@ class MinimizerTests: XCTestCase { } // When keepReturnsInFunctions is set, returns may only be removed if at least one function is also removed (e.g. by inlining) - if keepReturnsInFunctions && numReturnsBefore > numReturnsAfter && numFunctionsBefore == numFunctionsAfter { + if keepReturnsInFunctions && numReturnsBefore > numReturnsAfter + && numFunctionsBefore == numFunctionsAfter + { return false } @@ -2425,7 +2593,9 @@ class MinimizerTests: XCTestCase { func importState(_ state: Data) {} - func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) -> ProgramAspects? { + func computeAspectIntersection(of program: Program, with aspects: ProgramAspects) + -> ProgramAspects? + { return nil } @@ -2433,10 +2603,17 @@ class MinimizerTests: XCTestCase { } // Helper function to perform the minimization. - func minimize(_ program: Program, with fuzzer: Fuzzer, limit: Double = 0.0, performPostprocessing: Bool = true) -> Program { - guard let evaluator = fuzzer.evaluator as? EvaluatorForMinimizationTests else { fatalError("Invalid Evaluator used for minimization tests: \(fuzzer.evaluator)") } + func minimize( + _ program: Program, with fuzzer: Fuzzer, limit: Double = 0.0, + performPostprocessing: Bool = true + ) -> Program { + guard let evaluator = fuzzer.evaluator as? EvaluatorForMinimizationTests else { + fatalError("Invalid Evaluator used for minimization tests: \(fuzzer.evaluator)") + } evaluator.setOriginalProgram(program) let dummyAspects = ProgramAspects(outcome: .succeeded) - return fuzzer.minimizer.minimize(program, withAspects: dummyAspects, limit: limit, performPostprocessing: performPostprocessing) + return fuzzer.minimizer.minimize( + program, withAspects: dummyAspects, limit: limit, + performPostprocessing: performPostprocessing) } } diff --git a/Tests/FuzzilliTests/MutatorTests.swift b/Tests/FuzzilliTests/MutatorTests.swift index 394b0458f..08a6b2377 100644 --- a/Tests/FuzzilliTests/MutatorTests.swift +++ b/Tests/FuzzilliTests/MutatorTests.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest import Testing +import XCTest + @testable import Fuzzilli class MutatorTests: XCTestCase { @@ -109,7 +110,7 @@ class MutatorTests: XCTestCase { return "originalValue" } } - let mockNamedString = ILType.namedString(ofName: "NamedString"); + let mockNamedString = ILType.namedString(ofName: "NamedString") let env = JavaScriptEnvironment() env.addNamedStringGenerator(forType: mockNamedString, with: generateString) @@ -140,7 +141,7 @@ class MutatorTests: XCTestCase { let mutator = OperationMutator() for _ in 1...10 { let newBuilder = fuzzer.makeBuilder() - newBuilder.adopting() { + newBuilder.adopting { mutator.mutate(originalLoadInstruction[0], newBuilder) } @@ -153,7 +154,7 @@ class MutatorTests: XCTestCase { XCTAssertEqual(newLoadInstruction.count, 1) let newLoad = newLoadInstruction[0].op as! LoadString if newLoad.value == "newValue" { - return; + return } } XCTFail("Mutator ran 10 times without rerunning custom string generator") diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 7dc3dfd2a..0e98fb835 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ProgramBuilderTests: XCTestCase { @@ -39,7 +40,7 @@ class ProgramBuilderTests: XCTestCase { // On average, we should generate between n and 2x n instructions. let averageSize = sumOfProgramSizes / numPrograms - XCTAssertLessThanOrEqual(averageSize, 2*N) + XCTAssertLessThanOrEqual(averageSize, 2 * N) } func testTemplateBuilding() { @@ -129,9 +130,10 @@ class ProgramBuilderTests: XCTestCase { let simpleGenerator = CodeGenerator("SimpleGenerator", produces: [.integer]) { b in b.loadInt(Int64.random(in: 0..<100)) } - fuzzer.setCodeGenerators(WeightedList([ - (simpleGenerator, 1), - ])) + fuzzer.setCodeGenerators( + WeightedList([ + (simpleGenerator, 1) + ])) for _ in 0..<10 { b.buildPrefix() @@ -157,10 +159,11 @@ class ProgramBuilderTests: XCTestCase { b.build(n: 5) } } - fuzzer.setCodeGenerators(WeightedList([ - (simpleGenerator, 3), - (recursiveGenerator, 1), - ])) + fuzzer.setCodeGenerators( + WeightedList([ + (simpleGenerator, 3), + (recursiveGenerator, 1), + ])) for _ in 0..<10 { b.buildPrefix() @@ -312,22 +315,24 @@ class ProgramBuilderTests: XCTestCase { b.probabilityOfVariableSelectionTryingToFindAnExactMatch = 1.0 - do { // Search with exact match. + do { // Search with exact match. let (foundVar, matches) = b.randomVariable(forUseAsGuarded: b.type(of: obj)) XCTAssertEqual(obj, foundVar) XCTAssert(matches) } - do { // Search for supertype. - let (foundVar, matches) = b.randomVariable(forUseAsGuarded: .object(withProperties: ["x"])) + do { // Search for supertype. + let (foundVar, matches) = b.randomVariable( + forUseAsGuarded: .object(withProperties: ["x"])) XCTAssertEqual(obj, foundVar) XCTAssert(matches) } - do { // Search for subtype. - let (foundVar, matches) = b.randomVariable(forUseAsGuarded: .object(withProperties: ["x", "y", "z"])) + do { // Search for subtype. + let (foundVar, matches) = b.randomVariable( + forUseAsGuarded: .object(withProperties: ["x", "y", "z"])) XCTAssertEqual(obj, foundVar) XCTAssertFalse(matches) } - do { // Search for unrelated type. We ignore the variable, since it's completely random. + do { // Search for unrelated type. We ignore the variable, since it's completely random. let (_, matches) = b.randomVariable(forUseAsGuarded: .string) XCTAssertFalse(matches) } @@ -506,7 +511,8 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(42) b.loadInt(43) b.loadInt(44) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) // The same is true if we have variables of other types, but not enough to // ensure that a function using these types as parameter types can be called @@ -514,7 +520,8 @@ class ProgramBuilderTests: XCTestCase { let s = b.loadString("foo") let a = b.createIntArray(with: [1, 2, 3]) let o = b.createObject(with: [:]) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer) // But as soon as we have a sufficient number of other types as well, // we expect those to be used as well. @@ -528,7 +535,11 @@ class ProgramBuilderTests: XCTestCase { let types = [b.type(of: i), b.type(of: s), b.type(of: a), b.type(of: o)] var usesOfParameterType = [ILType: Int]() for _ in 0..<100 { - guard case .plain(let paramType) = b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0] else { return XCTFail("Unexpected parameter" )} + guard + case .plain(let paramType) = b.randomParameters( + n: 1, withRestParameterProbability: 0 + ).parameterTypes[0] + else { return XCTFail("Unexpected parameter") } XCTAssert(types.contains(paramType)) usesOfParameterType[paramType] = (usesOfParameterType[paramType] ?? 0) + 1 } @@ -536,8 +547,12 @@ class ProgramBuilderTests: XCTestCase { // However, if we set the probability of using .jsAnything as parameter to 100%, we expect to only see .jsAnything parameters. b.probabilityOfUsingAnythingAsParameterTypeIfAvoidable = 1.0 - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything) - XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything + ) + XCTAssertEqual( + b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything + ) } func testParameterGeneration3() { @@ -560,7 +575,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssertEqual(b.type(of: p1), .object(withProperties: ["x", "y"])) XCTAssertEqual(b.type(of: p1), b.type(of: p2)) - let f1 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f1 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let p = args[0] XCTAssertEqual(b.type(of: p), b.type(of: p1)) XCTAssertEqual(b.type(of: p).properties, ["x", "y"]) @@ -580,7 +597,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssert(b.type(of: a1).properties.contains("length")) XCTAssert(b.type(of: a1).methods.contains("slice")) - let f2 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f2 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let a = args[0] XCTAssertEqual(b.type(of: a), b.type(of: a1)) } @@ -599,7 +618,9 @@ class ProgramBuilderTests: XCTestCase { XCTAssertEqual(b.type(of: n1), b.type(of: n2)) XCTAssertEqual(b.type(of: n2), b.type(of: n3)) - let f3 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in + let f3 = b.buildPlainFunction( + with: b.randomParameters(n: 1, withRestParameterProbability: 0) + ) { args in let a = args[0] XCTAssertEqual(b.type(of: a), b.type(of: n1)) } @@ -618,11 +639,14 @@ class ProgramBuilderTests: XCTestCase { let params = b.randomParameters(n: 2, withRestParameterProbability: 1.0) XCTAssertEqual(params.count, 2) XCTAssert(params.parameters.hasRestParameter) - guard case .plain(_) = params.parameterTypes[0] else { return XCTFail("Expected a plain parameter") } - guard case .rest(_) = params.parameterTypes[1] else { return XCTFail("Expected a rest parameter") } + guard case .plain(_) = params.parameterTypes[0] else { + return XCTFail("Expected a plain parameter") + } + guard case .rest(_) = params.parameterTypes[1] else { + return XCTFail("Expected a rest parameter") + } } - func testObjectLiteralBuilding() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -820,14 +844,17 @@ class ProgramBuilderTests: XCTestCase { let i1 = b.loadInt(0x41) var i2 = b.loadInt(0x42) let cond = b.compare(i1, with: i2, using: .lessThan) - b.buildIfElse(cond, ifBody: { - let String = b.createNamedVariable(forBuiltin: "String") - splicePoint = b.indexOfNextInstruction() - b.callMethod("fromCharCode", on: String, withArgs: [i1]) - b.callMethod("fromCharCode", on: String, withArgs: [i2]) - }, elseBody: { - b.binary(i1, i2, with: .Add) - }) + b.buildIfElse( + cond, + ifBody: { + let String = b.createNamedVariable(forBuiltin: "String") + splicePoint = b.indexOfNextInstruction() + b.callMethod("fromCharCode", on: String, withArgs: [i1]) + b.callMethod("fromCharCode", on: String, withArgs: [i2]) + }, + elseBody: { + b.binary(i1, i2, with: .Add) + }) let original = b.finalize() // @@ -856,9 +883,10 @@ class ProgramBuilderTests: XCTestCase { // Original Program // var i = b.loadInt(42) - b.buildDoWhileLoop(do: { - b.unary(.PostInc, i) - }, while: { b.compare(i, with: b.loadInt(44), using: .lessThan) }) + b.buildDoWhileLoop( + do: { + b.unary(.PostInc, i) + }, while: { b.compare(i, with: b.loadInt(44), using: .lessThan) }) b.loadFloat(13.37) var arr = b.createArray(with: [i, i, i]) b.getProperty("length", of: arr) @@ -923,7 +951,7 @@ class ProgramBuilderTests: XCTestCase { // // Actual Program // - let idx = original.code.lastInstruction.index - 1 // Splice at EndWhileLoop + let idx = original.code.lastInstruction.index - 1 // Splice at EndWhileLoop XCTAssert(original.code[idx].op is EndWhileLoop) b.splice(from: original, at: idx) let actual = b.finalize() @@ -1025,20 +1053,23 @@ class ProgramBuilderTests: XCTestCase { // Original Program // var n = b.loadInt(10) - var f = Variable(number: 1) // Need to declare this up front as the builder interface doesn't support recursive calls + var f = Variable(number: 1) // Need to declare this up front as the builder interface doesn't support recursive calls // The whole function is included due to the recursive call f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - b.buildIfElse(n, ifBody: { - b.unary(.PostDec, n) - let r = b.callFunction(f) - let two = b.loadInt(2) - splicePoint = b.indexOfNextInstruction() - let v = b.binary(r, two, with: .Mul) - b.doReturn(v) - }, elseBody: { - let one = b.loadInt(1) - b.doReturn(one) - }) + b.buildIfElse( + n, + ifBody: { + b.unary(.PostDec, n) + let r = b.callFunction(f) + let two = b.loadInt(2) + splicePoint = b.indexOfNextInstruction() + let v = b.binary(r, two, with: .Mul) + b.doReturn(v) + }, + elseBody: { + let one = b.loadInt(1) + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) b.callFunction(f) @@ -1056,17 +1087,20 @@ class ProgramBuilderTests: XCTestCase { n = b.loadInt(10) f = Variable(number: 1) f = b.buildPlainFunction(with: .parameters(n: 0)) { _ in - b.buildIfElse(n, ifBody: { - b.unary(.PostDec, n) - let r = b.callFunction(f) - let two = b.loadInt(2) - splicePoint = b.indexOfNextInstruction() - let v = b.binary(r, two, with: .Mul) - b.doReturn(v) - }, elseBody: { - let one = b.loadInt(1) - b.doReturn(one) - }) + b.buildIfElse( + n, + ifBody: { + b.unary(.PostDec, n) + let r = b.callFunction(f) + let two = b.loadInt(2) + splicePoint = b.indexOfNextInstruction() + let v = b.binary(r, two, with: .Mul) + b.doReturn(v) + }, + elseBody: { + let one = b.loadInt(1) + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) let expected = b.finalize() @@ -1126,10 +1160,12 @@ class ProgramBuilderTests: XCTestCase { let v = b.await(promise) let zero = b.loadInt(0) let c = b.compare(v, with: zero, using: .notEqual) - b.buildIfElse(c, ifBody: { - splicePoint = b.indexOfNextInstruction() - b.unary(.PostDec, v) - }, elseBody: {}) + b.buildIfElse( + c, + ifBody: { + splicePoint = b.indexOfNextInstruction() + b.unary(.PostDec, v) + }, elseBody: {}) } b.callFunction(f) let original = b.finalize() @@ -1167,14 +1203,16 @@ class ProgramBuilderTests: XCTestCase { // b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in let s1 = b.loadString("foo") - b.buildTryCatchFinally(tryBody: { - let s2 = b.loadString("bar") - splicePoint = b.indexOfNextInstruction() - let s3 = b.binary(s1, s2, with: .Add) - b.yield(s3) - }, catchBody: { e in - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + let s2 = b.loadString("bar") + splicePoint = b.indexOfNextInstruction() + let s3 = b.binary(s1, s2, with: .Add) + b.yield(s3) + }, + catchBody: { e in + b.yield(e) + }) let s4 = b.loadString("baz") b.yield(s4) } @@ -1210,12 +1248,14 @@ class ProgramBuilderTests: XCTestCase { let baz = b.loadString("baz") b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(foo) - b.buildTryCatchFinally(tryBody: { - b.throwException(bar) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + b.throwException(bar) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.yield(e) + }) b.yield(baz) } let original = b.finalize() @@ -1236,12 +1276,14 @@ class ProgramBuilderTests: XCTestCase { b.buildGeneratorFunction(with: .parameters(n: 0)) { _ in b.yield(b.loadInt(1337)) let bar = b.loadString("bar") - b.buildTryCatchFinally(tryBody: { - b.throwException(bar) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.yield(e) - }) + b.buildTryCatchFinally( + tryBody: { + b.throwException(bar) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.yield(e) + }) b.yield(b.loadInt(1338)) } let expected = b.finalize() @@ -1263,11 +1305,14 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(0) b.buildWhileLoop({ b.compare(i, with: b.loadInt(100), using: .lessThan) }) { splicePoint = b.indexOfNextInstruction() - b.buildIfElse(args[0], ifBody: { - b.yield(i) - }, elseBody: { - b.loopContinue() - }) + b.buildIfElse( + args[0], + ifBody: { + b.yield(i) + }, + elseBody: { + b.loopContinue() + }) b.unary(.PostInc, i) } } @@ -1300,11 +1345,14 @@ class ProgramBuilderTests: XCTestCase { let i = b.loadInt(0) b.buildWhileLoop({ b.compare(i, with: b.loadInt(100), using: .lessThan) }) { splicePoint = b.indexOfNextInstruction() - b.buildIfElse(args[0], ifBody: { - b.yield(i) - }, elseBody: { - b.loopContinue() - }) + b.buildIfElse( + args[0], + ifBody: { + b.yield(i) + }, + elseBody: { + b.loopContinue() + }) b.unary(.PostInc, i) } } @@ -1454,7 +1502,8 @@ class ProgramBuilderTests: XCTestCase { // with a function that's never called. // To test this reliably, we set the probability of remapping inner outputs to 100% but also check // that it is reasonably high by default. - XCTAssertGreaterThanOrEqual(b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing, 0.5) + XCTAssertGreaterThanOrEqual( + b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing, 0.5) b.probabilityOfRemappingAnInstructionsInnerOutputsDuringSplicing = 1.0 b.loadString("Foo") @@ -1481,15 +1530,18 @@ class ProgramBuilderTests: XCTestCase { let zero = b.loadInt(0) let one = b.loadInt(1) let c = b.compare(n, with: zero, using: .greaterThan) - b.buildIfElse(c, ifBody: { - let nMinusOne = b.binary(n, one, with: .Sub) - let t = b.callFunction(f, withArgs: [nMinusOne]) - splicePoint = b.indexOfNextInstruction() - let r = b.binary(n, t, with: .Mul) - b.doReturn(r) - }, elseBody: { - b.doReturn(one) - }) + b.buildIfElse( + c, + ifBody: { + let nMinusOne = b.binary(n, one, with: .Sub) + let t = b.callFunction(f, withArgs: [nMinusOne]) + splicePoint = b.indexOfNextInstruction() + let r = b.binary(n, t, with: .Mul) + b.doReturn(r) + }, + elseBody: { + b.doReturn(one) + }) } XCTAssertEqual(f.number, 0) let i = b.loadInt(42) @@ -1518,15 +1570,18 @@ class ProgramBuilderTests: XCTestCase { let zero = b.loadInt(0) let one = b.loadInt(1) let c = b.compare(n, with: zero, using: .greaterThan) - b.buildIfElse(c, ifBody: { - let nMinusOne = b.binary(n, one, with: .Sub) - let t = b.callFunction(f, withArgs: [nMinusOne]) - splicePoint = b.indexOfNextInstruction() - let r = b.binary(n, t, with: .Mul) - b.doReturn(r) - }, elseBody: { - b.doReturn(one) - }) + b.buildIfElse( + c, + ifBody: { + let nMinusOne = b.binary(n, one, with: .Sub) + let t = b.callFunction(f, withArgs: [nMinusOne]) + splicePoint = b.indexOfNextInstruction() + let r = b.binary(n, t, with: .Mul) + b.doReturn(r) + }, + elseBody: { + b.doReturn(one) + }) } XCTAssertEqual(f.number, 1) let expected = b.finalize() @@ -1673,7 +1728,7 @@ class ProgramBuilderTests: XCTestCase { // For splicing, we will not use a variable of an unknown type as replacement. let unknown = b.createNamedVariable(forBuiltin: "unknown") XCTAssertEqual(b.type(of: unknown), .jsAnything) - b.loadBool(true) // This should also never be used as replacement as it definitely has a different type + b.loadBool(true) // This should also never be used as replacement as it definitely has a different type b.splice(from: original, at: splicePoint, mergeDataFlow: true) let actual = b.finalize() @@ -1863,7 +1918,8 @@ class ProgramBuilderTests: XCTestCase { } func testClassDefinitionSplicing2() { - var splicePoint1 = -1, splicePoint2 = -1 + var splicePoint1 = -1 + var splicePoint2 = -1 let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -1963,7 +2019,10 @@ class ProgramBuilderTests: XCTestCase { // var f = b.buildPlainFunction(with: .parameters(n: 2)) { args in splicePoint = b.indexOfNextInstruction() - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) b.loopBreak() } @@ -1984,7 +2043,10 @@ class ProgramBuilderTests: XCTestCase { // f = b.buildPlainFunction(with: .parameters(n: 2)) { args in splicePoint = b.indexOfNextInstruction() - b.buildForLoop(i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, { i in b.unary(.PostInc, i) }) { i in + b.buildForLoop( + i: { args[0] }, { i in b.compare(i, with: args[1], using: .lessThan) }, + { i in b.unary(.PostInc, i) } + ) { i in b.callFunction(b.createNamedVariable(forBuiltin: "print"), withArgs: [i]) b.loopBreak() } @@ -1997,7 +2059,8 @@ class ProgramBuilderTests: XCTestCase { func testSplicingOfMutatingOperations() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() - XCTAssertGreaterThan(b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable, 0.0) + XCTAssertGreaterThan( + b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable, 0.0) b.probabilityOfIncludingAnInstructionThatMayMutateARequiredVariable = 1.0 // @@ -2014,8 +2077,10 @@ class ProgramBuilderTests: XCTestCase { b.setProperty("f", of: o, to: f2) let object = b.createNamedVariable(forBuiltin: "Object") let descriptor = b.createObject(with: ["value": b.loadString("foobar")]) - b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) - b.callMethod("defineProperty", on: object, withArgs: [o2, b.loadString("s"), descriptor]) + b.callMethod( + "defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) + b.callMethod( + "defineProperty", on: object, withArgs: [o2, b.loadString("s"), descriptor]) let json = b.createNamedVariable(forBuiltin: "JSON") b.callMethod("stringify", on: json, withArgs: [o]) } @@ -2035,12 +2100,12 @@ class ProgramBuilderTests: XCTestCase { f2 = b.loadFloat(13.37) let i = b.loadInt(42) let f = b.loadFloat(13.37) - b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included + b.reassign(variable: f2, value: b.loadFloat(133.7)) // (Possibly) mutating instruction must be included let o = b.createObject(with: ["i": i, "f": f]) - b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included + b.setProperty("f", of: o, to: f2) // (Possibly) mutating instruction must be included let object = b.createNamedVariable(forBuiltin: "Object") let descriptor = b.createObject(with: ["value": b.loadString("foobar")]) - b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) // (Possibly) mutating instruction must be included + b.callMethod("defineProperty", on: object, withArgs: [o, b.loadString("s"), descriptor]) // (Possibly) mutating instruction must be included let json = b.createNamedVariable(forBuiltin: "JSON") b.callMethod("stringify", on: json, withArgs: [o]) let expected = b.finalize() @@ -2056,7 +2121,7 @@ class ProgramBuilderTests: XCTestCase { // // Original Program // - var superclass = b.buildClassDefinition() { cls in + var superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } @@ -2087,7 +2152,7 @@ class ProgramBuilderTests: XCTestCase { // // Actual Program // - superclass = b.buildClassDefinition() { cls in + superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } } @@ -2103,7 +2168,7 @@ class ProgramBuilderTests: XCTestCase { // // Expected Program // - superclass = b.buildClassDefinition() { cls in + superclass = b.buildClassDefinition { cls in cls.addConstructor(with: .parameters(n: 1)) { params in } } @@ -2129,14 +2194,15 @@ class ProgramBuilderTests: XCTestCase { // b.buildAsyncGeneratorFunction(with: .parameters(n: 2)) { _ in let p = b.createNamedVariable(forBuiltin: "thePromise") - b.buildDoWhileLoop(do: { - let v0 = b.loadInt(42) - let _ = b.createObject(with: ["foo": v0]) - splicePoint = b.indexOfNextInstruction() - b.await(p) - let v8 = b.loadInt(1337) - b.yield(v8) - }, while: { b.loadBool(false) }) + b.buildDoWhileLoop( + do: { + let v0 = b.loadInt(42) + let _ = b.createObject(with: ["foo": v0]) + splicePoint = b.indexOfNextInstruction() + b.await(p) + let v8 = b.loadInt(1337) + b.yield(v8) + }, while: { b.loadBool(false) }) } let original = b.finalize() @@ -2162,7 +2228,8 @@ class ProgramBuilderTests: XCTestCase { } func testLoopSplicing1() { - var splicePoint = -1, invalidSplicePoint = -1 + var splicePoint = -1 + var invalidSplicePoint = -1 let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -2178,12 +2245,15 @@ class ProgramBuilderTests: XCTestCase { b.buildWhileLoop({ b.compare(i2, with: end2, using: .lessThan) }) { let mid = b.binary(end2, b.loadInt(2), with: .Div) let cond = b.compare(i2, with: mid, using: .greaterThan) - b.buildIfElse(cond, ifBody: { - b.loopContinue() - }, elseBody: { - invalidSplicePoint = b.indexOfNextInstruction() - b.loopBreak() - }) + b.buildIfElse( + cond, + ifBody: { + b.loopContinue() + }, + elseBody: { + invalidSplicePoint = b.indexOfNextInstruction() + b.loopBreak() + }) b.unary(.PostInc, i2) } b.unary(.PostInc, i) @@ -2205,11 +2275,14 @@ class ProgramBuilderTests: XCTestCase { b.buildWhileLoop({ b.compare(i2, with: end2, using: .lessThan) }) { let mid = b.binary(end2, b.loadInt(2), with: .Div) let cond = b.compare(i2, with: mid, using: .greaterThan) - b.buildIfElse(cond, ifBody: { - b.loopContinue() - }, elseBody: { - b.loopBreak() - }) + b.buildIfElse( + cond, + ifBody: { + b.loopContinue() + }, + elseBody: { + b.loopBreak() + }) b.unary(.PostInc, i2) } let expected = b.finalize() @@ -2253,16 +2326,18 @@ class ProgramBuilderTests: XCTestCase { // // Original Program // - b.buildDoWhileLoop(do: { - let foo = b.createNamedVariable(forBuiltin: "foo") - b.callFunction(foo) - }, while: { - // Test that splicing out of the header works. - let bar = b.createNamedVariable(forBuiltin: "bar") - splicePoint = b.indexOfNextInstruction() - b.callFunction(bar) - return b.loadBool(false) - }) + b.buildDoWhileLoop( + do: { + let foo = b.createNamedVariable(forBuiltin: "foo") + b.callFunction(foo) + }, + while: { + // Test that splicing out of the header works. + let bar = b.createNamedVariable(forBuiltin: "bar") + splicePoint = b.indexOfNextInstruction() + b.callFunction(bar) + return b.loadBool(false) + }) let original = b.finalize() // @@ -2338,13 +2413,15 @@ class ProgramBuilderTests: XCTestCase { // Original Program // let s = b.loadString("foo") - b.buildTryCatchFinally(tryBody: { - let v = b.loadString("bar") - b.throwException(v) - }, catchBody: { e in - splicePoint = b.indexOfNextInstruction() - b.reassign(variable: e, value: s) - }) + b.buildTryCatchFinally( + tryBody: { + let v = b.loadString("bar") + b.throwException(v) + }, + catchBody: { e in + splicePoint = b.indexOfNextInstruction() + b.reassign(variable: e, value: s) + }) let original = b.finalize() // @@ -2367,7 +2444,7 @@ class ProgramBuilderTests: XCTestCase { b.wasmDefineTypeGroup { let typeA = b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) let typeB = b.wasmDefineArrayType(elementType: .wasmi64, mutability: false) - splicePoint = b.indexOfNextInstruction() // the WasmEndTypeGroup + splicePoint = b.indexOfNextInstruction() // the WasmEndTypeGroup return [typeA, typeB] } let original = b.finalize() @@ -2390,14 +2467,15 @@ class ProgramBuilderTests: XCTestCase { b.wasmDefineTypeGroup { [ b.wasmDefineArrayType(elementType: .wasmi32, mutability: false), - b.wasmDefineArrayType(elementType: .wasmi64, mutability: false) + b.wasmDefineArrayType(elementType: .wasmi64, mutability: false), ] } let expected = b.finalize() - XCTAssertEqual(actual, expected, - "Actual:\n\(FuzzILLifter().lift(actual.code))\n\n" + - "Expected:\n\(FuzzILLifter().lift(expected.code))") + XCTAssertEqual( + actual, expected, + "Actual:\n\(FuzzILLifter().lift(actual.code))\n\n" + + "Expected:\n\(FuzzILLifter().lift(expected.code))") } func testCodeStringSplicing() { @@ -2410,7 +2488,7 @@ class ProgramBuilderTests: XCTestCase { // b.buildRepeatLoop(n: 5) { _ in b.loadThis() - let code = b.buildCodeString() { + let code = b.buildCodeString { let i = b.loadInt(42) let o = b.createObject(with: ["i": i]) let json = b.createNamedVariable(forBuiltin: "JSON") @@ -2431,7 +2509,7 @@ class ProgramBuilderTests: XCTestCase { // // Expected Program // - let code = b.buildCodeString() { + let code = b.buildCodeString { let i = b.loadInt(42) let o = b.createObject(with: ["i": i]) let json = b.createNamedVariable(forBuiltin: "JSON") @@ -2537,7 +2615,7 @@ class ProgramBuilderTests: XCTestCase { let variables = b.findOrGenerateArguments(forSignature: signature) XCTAssertTrue(b.type(of: variables[0]).Is(.object(ofGroup: "ArrayBuffer"))) - if (variables.count > 1) { + if variables.count > 1 { XCTAssertTrue(b.type(of: variables[1]).Is(.number)) } @@ -2568,7 +2646,8 @@ class ProgramBuilderTests: XCTestCase { let previous = b.numberOfVisibleVariables - args = b.findOrGenerateArguments(forSignature: signature2, maxNumberOfVariablesToGenerate: 1) + args = b.findOrGenerateArguments( + forSignature: signature2, maxNumberOfVariablesToGenerate: 1) XCTAssertEqual(args.count, 2) // Ensure first object has the right type, and that we only generated one more variable @@ -2579,20 +2658,29 @@ class ProgramBuilderTests: XCTestCase { func testFindOrGenerateTypeWorksRecursively() { // Types let jsD8 = ILType.object(ofGroup: "D8", withProperties: ["test"], withMethods: []) - let jsD8Test = ILType.object(ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) - let jsD8FastCAPI = ILType.object(ofGroup: "D8FastCAPI", withProperties: [], withMethods: ["throw_no_fallback", "add_32bit_int"]) + let jsD8Test = ILType.object( + ofGroup: "D8Test", withProperties: ["FastCAPI"], withMethods: []) + let jsD8FastCAPI = ILType.object( + ofGroup: "D8FastCAPI", withProperties: [], + withMethods: ["throw_no_fallback", "add_32bit_int"]) let jsD8FastCAPIConstructor = ILType.constructor([] => jsD8FastCAPI) // Object groups - let jsD8Group = ObjectGroup(name: "D8", instanceType: jsD8, properties: ["test" : jsD8Test], methods: [:]) - let jsD8TestGroup = ObjectGroup(name: "D8Test", instanceType: jsD8Test, properties: ["FastCAPI": jsD8FastCAPIConstructor], methods: [:]) - let jsD8FastCAPIGroup = ObjectGroup(name: "D8FastCAPI", instanceType: jsD8FastCAPI, properties: [:], - methods:["throw_no_fallback": [] => ILType.integer, - "add_32bit_int": [.integer, .integer] => .integer + let jsD8Group = ObjectGroup( + name: "D8", instanceType: jsD8, properties: ["test": jsD8Test], methods: [:]) + let jsD8TestGroup = ObjectGroup( + name: "D8Test", instanceType: jsD8Test, + properties: ["FastCAPI": jsD8FastCAPIConstructor], methods: [:]) + let jsD8FastCAPIGroup = ObjectGroup( + name: "D8FastCAPI", instanceType: jsD8FastCAPI, properties: [:], + methods: [ + "throw_no_fallback": [] => ILType.integer, + "add_32bit_int": [.integer, .integer] => .integer, ]) let additionalObjectGroups = [jsD8Group, jsD8TestGroup, jsD8FastCAPIGroup] - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: additionalObjectGroups) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: additionalObjectGroups) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2613,9 +2701,11 @@ class ProgramBuilderTests: XCTestCase { let objType = ILType.object(ofGroup: "Test", withProperties: [], withMethods: []) let constructor = ILType.constructor([] => objType) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["myBuiltin" : constructor], additionalObjectGroups: [testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["myBuiltin": constructor], additionalObjectGroups: [testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2631,11 +2721,14 @@ class ProgramBuilderTests: XCTestCase { let objType = ILType.object(ofGroup: "Test", withProperties: [], withMethods: []) // Object groups - let jsD8Group = ObjectGroup(name: "D8", instanceType: jsD8, properties: [:], methods: ["test" : [] => objType]) + let jsD8Group = ObjectGroup( + name: "D8", instanceType: jsD8, properties: [:], methods: ["test": [] => objType]) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: [jsD8Group, testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: [jsD8Group, testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2655,15 +2748,19 @@ class ProgramBuilderTests: XCTestCase { name: "D8", instanceType: jsD8, properties: [:], - overloads: ["test" : [ - [.string] => .integer, - [.integer, .integer] => .string, - [] => objType - ]]) + overloads: [ + "test": [ + [.string] => .integer, + [.integer, .integer] => .string, + [] => objType, + ] + ]) - let testGroup = ObjectGroup(name: "Test", instanceType: objType, properties: [:], methods: [:]) + let testGroup = ObjectGroup( + name: "Test", instanceType: objType, properties: [:], methods: [:]) - let env = JavaScriptEnvironment(additionalBuiltins: ["d8" : jsD8], additionalObjectGroups: [jsD8Group, testGroup]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["d8": jsD8], additionalObjectGroups: [jsD8Group, testGroup]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2680,11 +2777,16 @@ class ProgramBuilderTests: XCTestCase { let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: []) let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) - let group2 = ObjectGroup(name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") - let group3 = ObjectGroup(name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") - let group4 = ObjectGroup(name: "group4", instanceType: type4, properties: [:], methods: [:], parent: "group3") + let group2 = ObjectGroup( + name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") + let group3 = ObjectGroup( + name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") + let group4 = ObjectGroup( + name: "group4", instanceType: type4, properties: [:], methods: [:], parent: "group3") - let env = JavaScriptEnvironment(additionalBuiltins: ["type3": type3], additionalObjectGroups: [group1, group2, group3, group4]) + let env = JavaScriptEnvironment( + additionalBuiltins: ["type3": type3], + additionalObjectGroups: [group1, group2, group3, group4]) let config = Configuration(logLevel: .error) let fuzzer = makeMockFuzzer(config: config, environment: env) let b = fuzzer.makeBuilder() @@ -2729,35 +2831,35 @@ class ProgramBuilderTests: XCTestCase { } func testFindOrGenerateTypeWithSubtypeWithMethod() { - let type1 = ILType.object(ofGroup: "group1", withProperties: [], withMethods: []) - let type2 = ILType.object(ofGroup: "group2", withProperties: [], withMethods: []) - let type3 = ILType.object(ofGroup: "group3", withProperties: [], withMethods: []) - let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: ["method3"]) - - let type4Constructor = ILType.constructor([] => type4) - - let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) - let group2 = ObjectGroup( - name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") - let group3 = ObjectGroup( - name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") - let group4 = ObjectGroup( - name: "group4", instanceType: type4, properties: [:], - methods: [ - "method3": [] => type3 - ]) - - let env = JavaScriptEnvironment( - additionalBuiltins: ["group4": type4Constructor], - additionalObjectGroups: [group1, group2, group3, group4]) - let config = Configuration(logLevel: .error) - let fuzzer = makeMockFuzzer(config: config, environment: env) - let b = fuzzer.makeBuilder() - b.buildPrefix() - // Get a random variable and then change the type - - let obj = b.findOrGenerateType(type1) - XCTAssert(b.type(of: obj).Is(type3)) + let type1 = ILType.object(ofGroup: "group1", withProperties: [], withMethods: []) + let type2 = ILType.object(ofGroup: "group2", withProperties: [], withMethods: []) + let type3 = ILType.object(ofGroup: "group3", withProperties: [], withMethods: []) + let type4 = ILType.object(ofGroup: "group4", withProperties: [], withMethods: ["method3"]) + + let type4Constructor = ILType.constructor([] => type4) + + let group1 = ObjectGroup(name: "group1", instanceType: type1, properties: [:], methods: [:]) + let group2 = ObjectGroup( + name: "group2", instanceType: type2, properties: [:], methods: [:], parent: "group1") + let group3 = ObjectGroup( + name: "group3", instanceType: type3, properties: [:], methods: [:], parent: "group2") + let group4 = ObjectGroup( + name: "group4", instanceType: type4, properties: [:], + methods: [ + "method3": [] => type3 + ]) + + let env = JavaScriptEnvironment( + additionalBuiltins: ["group4": type4Constructor], + additionalObjectGroups: [group1, group2, group3, group4]) + let config = Configuration(logLevel: .error) + let fuzzer = makeMockFuzzer(config: config, environment: env) + let b = fuzzer.makeBuilder() + b.buildPrefix() + // Get a random variable and then change the type + + let obj = b.findOrGenerateType(type1) + XCTAssert(b.type(of: obj).Is(type3)) } func testFindOrGenerateTypeEnum() { @@ -2778,10 +2880,10 @@ class ProgramBuilderTests: XCTestCase { analyzer.analyze() let instruction = analyzer.definition(of: obj) switch instruction.op.opcode { - case .loadString(let value): - XCTAssert(allowedValues.contains(value.value)) - default: - XCTAssert(false) + case .loadString(let value): + XCTAssert(allowedValues.contains(value.value)) + default: + XCTAssert(false) } } @@ -2795,10 +2897,11 @@ class ProgramBuilderTests: XCTestCase { } let env = JavaScriptEnvironment( - additionalBuiltins: ["foo" : .function([] => type1)], + additionalBuiltins: ["foo": .function([] => type1)], additionalObjectGroups: [group1]) let config = Configuration(logLevel: .error) - let fuzzer = makeMockFuzzer(config: config, environment: env, codeGenerators: [(testGenerator, 1)]) + let fuzzer = makeMockFuzzer( + config: config, environment: env, codeGenerators: [(testGenerator, 1)]) let b = fuzzer.makeBuilder() // Manually create a Variable, we don't want to use buildPrefix as we then might accidentally already create variable of type `type1`. @@ -2836,8 +2939,11 @@ class ProgramBuilderTests: XCTestCase { let b = fuzzer.makeBuilder() let typeGroupA = b.wasmDefineTypeGroup { - [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi64, mutability: false)], indexTypes: [])] + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi64, mutability: false)], indexTypes: []), + ] } let arrayDefI32 = typeGroupA[0] let structDef = typeGroupA[1] @@ -2938,10 +3044,14 @@ class ProgramBuilderTests: XCTestCase { let emptyMemory = b.createWasmMemory(minPages: 0) b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let (dynamicOffset, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: emptyMemory, alignment: 1) - return [function.wasmMemoryLoad(memory: emptyMemory, - dynamicOffset: dynamicOffset, loadType: .I32LoadMem, - staticOffset: staticOffset)] + let (dynamicOffset, staticOffset) = b.generateAlignedMemoryIndexes( + forMemory: emptyMemory, alignment: 1) + return [ + function.wasmMemoryLoad( + memory: emptyMemory, + dynamicOffset: dynamicOffset, loadType: .I32LoadMem, + staticOffset: staticOffset) + ] } } } @@ -2950,9 +3060,12 @@ class ProgramBuilderTests: XCTestCase { let emptyMemory = b.createWasmMemory(minPages: 0) b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - return [function.wasmMemoryLoad(memory: emptyMemory, - dynamicOffset: function.consti32(0), loadType: .I32LoadMem, - staticOffset: 0)] + return [ + function.wasmMemoryLoad( + memory: emptyMemory, + dynamicOffset: function.consti32(0), loadType: .I32LoadMem, + staticOffset: 0) + ] } } } @@ -3003,13 +3116,14 @@ class ProgramBuilderTests: XCTestCase { let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - if case .wasmMemorySize = instr.op.opcode { - return true - } else { - return false - } - })) + XCTAssertTrue( + program.code.contains(where: { instr in + if case .wasmMemorySize = instr.op.opcode { + return true + } else { + return false + } + })) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } @@ -3037,8 +3151,10 @@ class ProgramBuilderTests: XCTestCase { let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: N) XCTAssertGreaterThan(numGeneratedInstructions, 0) // All generator input requirements are fulfilled. - XCTAssert(generator.parts.allSatisfy { - $0.inputs.constraints.allSatisfy { b.randomVariable(ofType: $0.type) != nil }}) + XCTAssert( + generator.parts.allSatisfy { + $0.inputs.constraints.allSatisfy { b.randomVariable(ofType: $0.type) != nil } + }) // All generator `produces` guarantees are fulfilled. XCTAssert(generator.produces.allSatisfy { b.randomVariable(ofType: $0.type) != nil }) let _ = b.finalize() @@ -3054,10 +3170,13 @@ class ProgramBuilderTests: XCTestCase { b.buildPrefix() // TODO(mliedtke): The mechanism needs to learn how to resolve nested input dependencies. - b.wasmDefineTypeGroup {[ - b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), - ]} + b.wasmDefineTypeGroup { + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), + ] + } let generator = fuzzer.codeGenerators.filter { $0.name == "WasmArrayGetGenerator" @@ -3067,27 +3186,30 @@ class ProgramBuilderTests: XCTestCase { let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) XCTAssertNotNil(syntheticGenerator) - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) + let numGeneratedInstructions = b.complete( + generator: syntheticGenerator!, withBudget: 30) let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - switch instr.op.opcode { + XCTAssertTrue( + program.code.contains(where: { instr in + switch instr.op.opcode { case .wasmArrayGet(_): return true default: return false - } - })) + } + })) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } func testWasmGCScheduling() { func test( - _ generatorName: String, - expectAny: repeat (each ExpectedOp).Type, - requiresTypes: Bool = false) { + _ generatorName: String, + expectAny: repeat (each ExpectedOp).Type, + requiresTypes: Bool = false + ) { let fuzzer = makeMockFuzzer() let numPrograms = 30 @@ -3098,25 +3220,30 @@ class ProgramBuilderTests: XCTestCase { // TODO(mliedtke): The mechanism needs to learn how to resolve nested input + // context dependencies. if requiresTypes { - b.wasmDefineTypeGroup {[ - b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), - b.wasmDefineStructType(fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), - ]} + b.wasmDefineTypeGroup { + [ + b.wasmDefineArrayType(elementType: .wasmi32, mutability: true), + b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []), + ] + } } - let generator = fuzzer.codeGenerators.filter {$0.name == generatorName}[0] + let generator = fuzzer.codeGenerators.filter { $0.name == generatorName }[0] let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) XCTAssertNotNil(syntheticGenerator) - let numGeneratedInstructions = b.complete(generator: syntheticGenerator!, withBudget: 30) + let numGeneratedInstructions = b.complete( + generator: syntheticGenerator!, withBudget: 30) let program = b.finalize() - XCTAssertTrue(program.code.contains(where: { instr in - for match in repeat instr.op is (each ExpectedOp) { - if match { return true } - } - return false - }), generatorName) + XCTAssertTrue( + program.code.contains(where: { instr in + for match in repeat instr.op is (each ExpectedOp) { + if match { return true } + } + return false + }), generatorName) XCTAssertGreaterThan(numGeneratedInstructions, 0) } } @@ -3139,7 +3266,8 @@ class ProgramBuilderTests: XCTestCase { b.buildPrefix() if let syntheticGenerator = b.assembleSyntheticGenerator(for: generator) { - let generatedInstructions = b.complete(generator: syntheticGenerator, withBudget: 40) + let generatedInstructions = b.complete( + generator: syntheticGenerator, withBudget: 40) if generatedInstructions == 0 { failures[generator.name, default: 0] += 1 @@ -3175,20 +3303,22 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { } func testNested() { - let loopGenerator = CodeGenerator("TestDoWhileLoop", [ - GeneratorStub("BeginLoop") { b in - let loopVar = b.loadInt(0) - b.runtimeData.push("loopVar", loopVar) - b.emit(BeginDoWhileLoopBody()) - }, - GeneratorStub("EndLoop") { b in - let loopVar = b.runtimeData.pop("loopVar") - b.unary(.PreInc, loopVar) - b.emit(BeginDoWhileLoopHeader()) - let cond = b.compare(loopVar, with: b.loadInt(3), using: .lessThan) - b.emit(EndDoWhileLoop(), withInputs: [cond]) - } - ]) + let loopGenerator = CodeGenerator( + "TestDoWhileLoop", + [ + GeneratorStub("BeginLoop") { b in + let loopVar = b.loadInt(0) + b.runtimeData.push("loopVar", loopVar) + b.emit(BeginDoWhileLoopBody()) + }, + GeneratorStub("EndLoop") { b in + let loopVar = b.runtimeData.pop("loopVar") + b.unary(.PreInc, loopVar) + b.emit(BeginDoWhileLoopHeader()) + let cond = b.compare(loopVar, with: b.loadInt(3), using: .lessThan) + b.emit(EndDoWhileLoop(), withInputs: [cond]) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(loopGenerator), """ @@ -3206,23 +3336,25 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { func testMultiLabel() { var counter: Int64 = 0 - let defineAndAddGenerator = CodeGenerator("TestMultiLabel", [ - GeneratorStub("Define") { b in - b.runtimeData.push("first", b.loadInt(counter)) - counter += 1 - b.runtimeData.push("second", b.loadInt(counter)) - counter += 1 - b.runtimeData.push("third", b.loadInt(counter)) - counter += 1 - }, - GeneratorStub("Add") { b in - // The order in which the different lables are popped doesn't matter. - let third = b.runtimeData.pop("third") - let first = b.runtimeData.pop("first") - let second = b.runtimeData.pop("second") - b.binary(b.binary(first, second, with: .Add), third, with: .Add) - } - ]) + let defineAndAddGenerator = CodeGenerator( + "TestMultiLabel", + [ + GeneratorStub("Define") { b in + b.runtimeData.push("first", b.loadInt(counter)) + counter += 1 + b.runtimeData.push("second", b.loadInt(counter)) + counter += 1 + b.runtimeData.push("third", b.loadInt(counter)) + counter += 1 + }, + GeneratorStub("Add") { b in + // The order in which the different lables are popped doesn't matter. + let third = b.runtimeData.pop("third") + let first = b.runtimeData.pop("first") + let second = b.runtimeData.pop("second") + b.binary(b.binary(first, second, with: .Add), third, with: .Add) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(defineAndAddGenerator), """ @@ -3234,22 +3366,24 @@ class ProgramBuilderRuntimeDataTests: XCTestCase { func testPassOn() { var counter: Int64 = 10 - let defineAndAddGenerator = CodeGenerator("TestPassOn", [ - GeneratorStub("Define") { b in - let value = b.loadInt(counter) - b.runtimeData.push("value", value) - b.binary(value, b.loadInt(0), with: .Add) - counter += 1 - }, - GeneratorStub("AddOne") { b in - let value = b.runtimeData.peek("value") - b.binary(value, b.loadInt(1), with: .Add) - }, - GeneratorStub("SubOne") { b in - let value = b.runtimeData.pop("value") - b.binary(value, b.loadInt(1), with: .Sub) - }, - ]) + let defineAndAddGenerator = CodeGenerator( + "TestPassOn", + [ + GeneratorStub("Define") { b in + let value = b.loadInt(counter) + b.runtimeData.push("value", value) + b.binary(value, b.loadInt(0), with: .Add) + counter += 1 + }, + GeneratorStub("AddOne") { b in + let value = b.runtimeData.peek("value") + b.binary(value, b.loadInt(1), with: .Add) + }, + GeneratorStub("SubOne") { b in + let value = b.runtimeData.pop("value") + b.binary(value, b.loadInt(1), with: .Sub) + }, + ]) XCTAssertEqual( runFuzzerWithGenerator(defineAndAddGenerator), """ diff --git a/Tests/FuzzilliTests/ProgramSerializationTest.swift b/Tests/FuzzilliTests/ProgramSerializationTest.swift index 9cbceaa49..65b2e5164 100644 --- a/Tests/FuzzilliTests/ProgramSerializationTest.swift +++ b/Tests/FuzzilliTests/ProgramSerializationTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli func testAndCompareSerialization(program: Program) { @@ -81,10 +82,10 @@ class ProgramSerializationTests: XCTestCase { b.append(Instruction(complexOp, output: b.nextVariable(), inputs: [v(2), v(3)])) let program = b.finalize() - XCTAssert(program.code[0].op === program.code[2].op && - program.code[0].op === program.code[4].op) - XCTAssert(program.code[5].op === program.code[7].op && - program.code[5].op === program.code[9].op) + XCTAssert( + program.code[0].op === program.code[2].op && program.code[0].op === program.code[4].op) + XCTAssert( + program.code[5].op === program.code[7].op && program.code[5].op === program.code[9].op) let encodingCache = OperationCache.forEncoding() let decodingCache = OperationCache.forDecoding() @@ -96,10 +97,8 @@ class ProgramSerializationTests: XCTestCase { XCTAssertEqual(program, copy) XCTAssert(copy.code[0].op !== program.code[0].op) - XCTAssert(copy.code[0].op === copy.code[2].op && - copy.code[0].op === copy.code[4].op) - XCTAssert(copy.code[5].op === copy.code[7].op && - copy.code[5].op === copy.code[9].op) + XCTAssert(copy.code[0].op === copy.code[2].op && copy.code[0].op === copy.code[4].op) + XCTAssert(copy.code[5].op === copy.code[7].op && copy.code[5].op === copy.code[9].op) } // As our equality operation is based on the protobuf representation, we do these tests here. diff --git a/Tests/FuzzilliTests/RingBufferTest.swift b/Tests/FuzzilliTests/RingBufferTest.swift index a23abc7dd..702c0e950 100644 --- a/Tests/FuzzilliTests/RingBufferTest.swift +++ b/Tests/FuzzilliTests/RingBufferTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class RingBufferTests: XCTestCase { diff --git a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift index 4d1182b96..4b2eb9e34 100644 --- a/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift +++ b/Tests/FuzzilliTests/RuntimeAssistedMutatorTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class RuntimeAssistedMutatorTests: XCTestCase { @@ -21,10 +22,14 @@ class RuntimeAssistedMutatorTests: XCTestCase { var env: [(String, String)] = [] func run(_ script: String, withTimeout timeout: UInt32) -> Execution { // Minimization can change quotation marks. Checking for both here to be on the safe side. - if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") { - return MockExecution(outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + if script.contains("fuzzilli('FUZZILLI_CRASH', 0)") + || script.contains("fuzzilli(\"FUZZILLI_CRASH\", 0)") + { + return MockExecution( + outcome: .crashed(9), stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } else { - return MockExecution(outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) + return MockExecution( + outcome: .succeeded, stdout: "", stderr: "", fuzzout: "", execTime: 0.1) } } func setEnvironmentVariable(_ key: String, to value: String) {} @@ -45,7 +50,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on processed program") + let crashEventTriggered = self.expectation( + description: "Crash reported on processed program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let lifted = fuzzer.lifter.lift(ev.program) if lifted.contains("This is the processed program") { @@ -69,7 +75,8 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + let crashEventTriggered = self.expectation( + description: "Crash reported on instrumented program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let lifted = fuzzer.lifter.lift(ev.program) if !lifted.contains("This is the processed program") { @@ -83,15 +90,22 @@ class RuntimeAssistedMutatorTests: XCTestCase { // This test checks that if *only* the instrumented program crashes, this program is minimized. - func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { - guard let nodejs = JavaScriptExecutor(type: .nodejs, withArguments: ["--allow-natives-syntax"]) else { - throw XCTSkip("Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + func testOnlyInstrumentedProgramCrashesAndIsMinimized() throws { + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + throw XCTSkip( + "Could not find NodeJS executable. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } // Initialize the parser. This can fail if no node.js executable is found or if the // parser's node.js dependencies are not installed. In that case, skip these tests. guard JavaScriptParser(executor: nodejs) != nil else { - throw XCTSkip("The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser.") + throw XCTSkip( + "The JavaScript parser does not appear to be working. See Sources/Fuzzilli/Compiler/Parser/README.md for details on how to set up the parser." + ) } class CrashEvaluator: MockEvaluator { @@ -116,13 +130,15 @@ class RuntimeAssistedMutatorTests: XCTestCase { b.loadInt(42) let program = b.finalize() - let crashEventTriggered = self.expectation(description: "Crash reported on instrumented program") + let crashEventTriggered = self.expectation( + description: "Crash reported on instrumented program") fuzzer.registerEventListener(for: fuzzer.events.CrashFound) { ev in let actualProgram = ev.program - XCTAssertEqual(expectedProgram, actualProgram, - "The reported program should be the minimized version of the instrumented program.\n" + - "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + - "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + XCTAssertEqual( + expectedProgram, actualProgram, + "The reported program should be the minimized version of the instrumented program.\n" + + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") crashEventTriggered.fulfill() } diff --git a/Tests/FuzzilliTests/ScriptWriterTest.swift b/Tests/FuzzilliTests/ScriptWriterTest.swift index ac816db6e..b4f6d5235 100644 --- a/Tests/FuzzilliTests/ScriptWriterTest.swift +++ b/Tests/FuzzilliTests/ScriptWriterTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class ScriptWriterTest: XCTestCase { @@ -21,17 +22,17 @@ class ScriptWriterTest: XCTestCase { var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 10) w.emit("My name is Ozymandias, king of kings. Look on my works, ye Mighty, and despair!") let expected = """ - My name is - Ozymandias - , king of - kings. - Look on my - works, ye - Mighty, - and - despair! + My name is + Ozymandias + , king of + kings. + Look on my + works, ye + Mighty, + and + despair! - """ + """ XCTAssertEqual(expected, w.code) } @@ -46,39 +47,39 @@ class ScriptWriterTest: XCTestCase { w.emit("and despair!") w.decreaseIndentionLevel() let expected = """ - My name - is - Ozymandi - as, - king - of - kings. - Look on - my - works, - ye - Mighty, - and - despai - r! + My name + is + Ozymandi + as, + king + of + kings. + Look on + my + works, + ye + Mighty, + and + despai + r! - """ + """ XCTAssertEqual(expected, w.code) } func testLineSplittingMultiSpace() { - var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 8) - let str = (0...10).map {"\($0)\(String(repeating: " ", count: $0))"}.joined() - w.emit(str) - let expected = """ - 01 2 3 - 4 5 - 6 7 - 8 - 9 - 10 + var w = ScriptWriter(indent: 2, initialIndentionLevel: 0, maxLineLength: 8) + let str = (0...10).map { "\($0)\(String(repeating: " ", count: $0))" }.joined() + w.emit(str) + let expected = """ + 01 2 3 + 4 5 + 6 7 + 8 + 9 + 10 - """ - XCTAssertEqual(expected, w.code) + """ + XCTAssertEqual(expected, w.code) } } diff --git a/Tests/FuzzilliTests/TestUtils.swift b/Tests/FuzzilliTests/TestUtils.swift index 414d1fbfa..0928898bb 100644 --- a/Tests/FuzzilliTests/TestUtils.swift +++ b/Tests/FuzzilliTests/TestUtils.swift @@ -14,6 +14,7 @@ import Foundation import XCTest + @testable import Fuzzilli extension Program: @retroactive Equatable { @@ -49,20 +50,27 @@ func v(_ n: Int) -> Variable { func GetJavaScriptExecutorOrSkipTest() throws -> JavaScriptExecutor { guard let runner = JavaScriptExecutor() else { - throw XCTSkip("Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable).") + throw XCTSkip( + "Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable)." + ) } return runner } -func GetJavaScriptExecutorOrSkipTest(type: JavaScriptExecutor.ExecutorType, withArguments args: [String]) throws -> JavaScriptExecutor { +func GetJavaScriptExecutorOrSkipTest( + type: JavaScriptExecutor.ExecutorType, withArguments args: [String] +) throws -> JavaScriptExecutor { guard let runner = JavaScriptExecutor(type: type, withArguments: args) else { - throw XCTSkip("Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable).") + throw XCTSkip( + "Could not find js shell executable. Install Node.js (or if you want to use a different shell, modify the FUZZILLI_TEST_SHELL variable)." + ) } return runner } - -func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (ProgramBuilder) -> ()) -> String { +func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (ProgramBuilder) -> Void) + -> String +{ let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -75,13 +83,14 @@ func buildAndLiftProgram(withLiftingOptions: LiftingOptions, buildFunc: (Program // AssertThat prog == Deserialize(Serilize(prog)) let prog = b.finalize() let serializedBytes = try! prog.asProtobuf().serializedData() - let deserialized = try! Program(from: Fuzzilli_Protobuf_Program(serializedBytes: serializedBytes)) + let deserialized = try! Program( + from: Fuzzilli_Protobuf_Program(serializedBytes: serializedBytes)) XCTAssertEqual(prog, deserialized) return fuzzer.lifter.lift(prog, withOptions: withLiftingOptions) } -func buildAndLiftProgram(buildFunc: (ProgramBuilder) -> ()) -> String { +func buildAndLiftProgram(buildFunc: (ProgramBuilder) -> Void) -> String { return buildAndLiftProgram(withLiftingOptions: [], buildFunc: buildFunc) } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 677032925..91f17cdb2 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class TypeSystemTests: XCTestCase { @@ -28,7 +29,8 @@ class TypeSystemTests: XCTestCase { for t2 in typeSuite { for t3 in typeSuite { if t1 >= t2 && t2 >= t3 { - XCTAssert(t1 >= t3, "\(t1) >= \(t2) && \(t2) >= \(t3) implies \(t1) => \(t3)") + XCTAssert( + t1 >= t3, "\(t1) >= \(t2) && \(t2) >= \(t3) implies \(t1) => \(t3)") } } } @@ -41,7 +43,8 @@ class TypeSystemTests: XCTestCase { if t1 >= t2 && t2 >= t1 { XCTAssert(t1 == t2, "\(t1) >= \(t2) && \(t2) >= \(t1) implies \(t1) == \(t2)") } else if t1 >= t2 { - XCTAssertFalse(t2 >= t1, "\(t1) >= \(t2) && \(t1) != \(t2) implies \(t2) !>= \(t1)") + XCTAssertFalse( + t2 >= t1, "\(t1) >= \(t2) && \(t1) != \(t2) implies \(t2) !>= \(t1)") } } } @@ -62,7 +65,9 @@ class TypeSystemTests: XCTestCase { XCTAssert(.object(withMethods: ["m1"]) != .object()) XCTAssert(.function() == .function()) - XCTAssert(.function([.integer, .rest(.integer)] => .undefined) == .function([.integer, .rest(.integer)] => .undefined)) + XCTAssert( + .function([.integer, .rest(.integer)] => .undefined) + == .function([.integer, .rest(.integer)] => .undefined)) XCTAssert(.function([.integer, .rest(.integer)] => .undefined) != .function()) // Test equality properties for all types in the test suite @@ -72,7 +77,9 @@ class TypeSystemTests: XCTestCase { XCTAssert(t1 >= t2, "\(t1) == \(t2) implies \(t1) >= \(t2)") XCTAssert(t2 >= t1, "\(t1) == \(t2) implies \(t2) >= \(t1)") } else { - XCTAssertFalse(t1 >= t2 && t2 >= t1, "\(t1) != \(t2) implies !(\(t1) >= \(t2) && \(t2) >= \(t1))") + XCTAssertFalse( + t1 >= t2 && t2 >= t1, + "\(t1) != \(t2) implies !(\(t1) >= \(t2) && \(t2) >= \(t1))") } } } @@ -118,8 +125,10 @@ class TypeSystemTests: XCTestCase { // assumes the function has the signature of f2). // See also the signature subsumption test for more complicated examples. XCTAssert(ILType.function([.jsAnything] => .integer).Is(.function([.integer] => .number))) - XCTAssertFalse(ILType.function([.integer] => .integer).Is(.function([.jsAnything] => .number))) - XCTAssertFalse(ILType.function([.jsAnything] => .number).Is(.function([.jsAnything] => .integer))) + XCTAssertFalse( + ILType.function([.integer] => .integer).Is(.function([.jsAnything] => .number))) + XCTAssertFalse( + ILType.function([.jsAnything] => .number).Is(.function([.jsAnything] => .integer))) for t1 in typeSuite { for t2 in typeSuite { @@ -132,7 +141,8 @@ class TypeSystemTests: XCTestCase { } if t2.Is(t1) { - XCTAssertFalse(t2.MayNotBe(t1), "(\(t2)).Is(\(t1)) <=> !((\(t2)).MayNotBe(\(t1)))") + XCTAssertFalse( + t2.MayNotBe(t1), "(\(t2)).Is(\(t1)) <=> !((\(t2)).MayNotBe(\(t1)))") XCTAssert(t1 >= t2, "\(t1) >= \(t2) <=> (\(t2)).Is(\(t1))") } else { XCTAssertFalse(t1 >= t2, "\(t1) >= \(t2) <=> (\(t2)).Is(\(t1))") @@ -162,10 +172,13 @@ class TypeSystemTests: XCTestCase { // The way to think about is is (probably) that a function taking .jsAnything may still be called // with a .integer as argument. However, from a practical point of view the function that takes .integer // may in fact also be fine with a different argument. - XCTAssert(ILType.function([.integer] => .jsAnything).MayBe(.function([.jsAnything] => .jsAnything))) + XCTAssert( + ILType.function([.integer] => .jsAnything).MayBe( + .function([.jsAnything] => .jsAnything))) // But (at least from a theoretical point-of-view) a function taking a .integer is definitely not a function // that takes (only) a string as first parameter. - XCTAssertFalse(ILType.function([.integer] => .jsAnything).MayBe(.function([.string] => .jsAnything))) + XCTAssertFalse( + ILType.function([.integer] => .jsAnything).MayBe(.function([.string] => .jsAnything))) XCTAssert((ILType.integer | ILType.boolean).MayBe(ILType.integer | ILType.string)) XCTAssertFalse((ILType.integer + ILType.object()).MayBe(ILType.string + ILType.object())) @@ -195,16 +208,19 @@ class TypeSystemTests: XCTestCase { if t1 & t2 != .nothing { XCTAssert(t2.MayBe(t1), "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") } else { - XCTAssertFalse(t2.MayBe(t1), "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") + XCTAssertFalse( + t2.MayBe(t1), "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") } XCTAssert((t1 | t2).MayBe(t1), "A union type may be one of its parts") XCTAssert((t1 | t2).MayBe(t2), "A union type may be one of its parts") if t2.MayBe(t1) { - XCTAssert(t1 & t2 != .nothing, "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") + XCTAssert( + t1 & t2 != .nothing, "\(t1) & \(t2) != .nothing <=> (\(t2)).MayBe(\(t1))") } else { - XCTAssert(t1 & t2 == .nothing, "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") + XCTAssert( + t1 & t2 == .nothing, "\(t1) & \(t2) == .nothing <=> !(\(t2)).MayBe(\(t1))") } } } @@ -277,7 +293,9 @@ class TypeSystemTests: XCTestCase { // E.g. string objects never subsume objects, but can subsume other string objects if the // properties and methods are a subset. if t1.baseType == t2.baseType && (t1.group == nil || t1.group == t2.group) { - if t1.properties.isSubset(of: t2.properties) && t1.methods.isSubset(of: t2.methods) && t1.wasmType == t2.wasmType { + if t1.properties.isSubset(of: t2.properties) + && t1.methods.isSubset(of: t2.methods) && t1.wasmType == t2.wasmType + { XCTAssert(t1 >= t2, "\(t1) >= \(t2)") } } @@ -316,8 +334,10 @@ class TypeSystemTests: XCTestCase { let fooObj = ILType.object(withProperties: fooProperties, withMethods: fooMethods) let barObj = ILType.object(withProperties: barProperties, withMethods: barMethods) let bazObj = ILType.object(withProperties: bazProperties, withMethods: bazMethods) - let fooBarObj = ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods) - let fooBazObj = ILType.object(withProperties: fooBazProperties, withMethods: fooBazMethods) + let fooBarObj = ILType.object( + withProperties: fooBarProperties, withMethods: fooBarMethods) + let fooBazObj = ILType.object( + withProperties: fooBazProperties, withMethods: fooBazMethods) // Foo, Bar, Baz, FooBar, and FooBaz objects are all objects, but not every object is a Foo, Bar, Baz, FooBar, or FooBaz object. XCTAssert(object >= fooObj) @@ -332,10 +352,22 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(fooBazObj >= object) // Order of property and methods names does not matter. - XCTAssert(fooBarObj >= ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) - XCTAssert(fooBarObj >= ILType.object(withProperties: fooBarProperties.reversed(), withMethods: fooBarMethods.reversed())) - XCTAssert(fooBarObj == ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) - XCTAssert(fooBarObj == ILType.object(withProperties: fooBarProperties.reversed(), withMethods: fooBarMethods.reversed())) + XCTAssert( + fooBarObj + >= ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) + XCTAssert( + fooBarObj + >= ILType.object( + withProperties: fooBarProperties.reversed(), + withMethods: fooBarMethods.reversed())) + XCTAssert( + fooBarObj + == ILType.object(withProperties: fooBarProperties, withMethods: fooBarMethods)) + XCTAssert( + fooBarObj + == ILType.object( + withProperties: fooBarProperties.reversed(), + withMethods: fooBarMethods.reversed())) // No subsumption relationship between Foo, Bar, and Baz objects XCTAssertFalse(fooObj >= barObj) @@ -405,7 +437,9 @@ class TypeSystemTests: XCTestCase { let fooBarBazProperties = fooProperties + barProperties + bazProperties let fooBarBazMethods = fooMethods + barMethods + bazMethods XCTAssert(fooObj + barObj + bazObj == fooBarObj + fooBazObj) - XCTAssert(fooBarObj + fooBazObj == .object(withProperties: fooBarBazProperties, withMethods: fooBarBazMethods)) + XCTAssert( + fooBarObj + fooBazObj + == .object(withProperties: fooBarBazProperties, withMethods: fooBarBazMethods)) } } @@ -494,9 +528,17 @@ class TypeSystemTests: XCTestCase { // Repeat the below tests for functions, constructors, and function constructors (function and constructor at the same time) // We call something that is a function or a constructor (or both) a "callable". - let anyCallables = [ILType.function(), ILType.constructor(), ILType.functionAndConstructor()] - let callable1s = [ILType.function(signature1), ILType.constructor(signature1), ILType.functionAndConstructor(signature1)] - let callable2s = [ILType.function(signature2), ILType.constructor(signature2), ILType.functionAndConstructor(signature2)] + let anyCallables = [ + ILType.function(), ILType.constructor(), ILType.functionAndConstructor(), + ] + let callable1s = [ + ILType.function(signature1), ILType.constructor(signature1), + ILType.functionAndConstructor(signature1), + ] + let callable2s = [ + ILType.function(signature2), ILType.constructor(signature2), + ILType.functionAndConstructor(signature2), + ] for i in 0..<3 { let anyCallable = anyCallables[i] @@ -558,13 +600,16 @@ class TypeSystemTests: XCTestCase { } func testWasmGlobalSubsumption() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmi64Mutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmi64Mutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: true) - let ILTypeGlobalI32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalI64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) + let ILTypeGlobalI32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalI64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) XCTAssert(ILTypeGlobalI32Mutable >= ILTypeGlobalI32Mutable) // Types which don't have equal WasmTypeExtension don't subsume. @@ -574,9 +619,12 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(ILTypeGlobalI64Mutable >= ILTypeGlobalI32Mutable) XCTAssertFalse(ILTypeGlobalI32NonMutable >= ILTypeGlobalI64Mutable) - let ILTypeGlobalI32MutableNoGroup: ILType = ILType.object(withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32MutableNoProperty: ILType = ILType.object(ofGroup: "WasmGlobal", withWasmType: wasmi32Mutable) - let ILTypeGlobalI32MutableNoWasmType: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"]) + let ILTypeGlobalI32MutableNoGroup: ILType = ILType.object( + withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32MutableNoProperty: ILType = ILType.object( + ofGroup: "WasmGlobal", withWasmType: wasmi32Mutable) + let ILTypeGlobalI32MutableNoWasmType: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"]) let ILTypeGlobalOnlyGroup: ILType = ILType.object(ofGroup: "WasmGlobal") let ILTypeGlobalOnlyProperty: ILType = ILType.object(withProperties: ["value"]) @@ -594,19 +642,23 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse(ILTypeGlobalI32Mutable >= ILTypeGlobalOnlyProperty) // Groups should match. - let ILTypeWrongGroup = ILType.object(ofGroup: "SomeOtherGroup", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeWrongGroup = ILType.object( + ofGroup: "SomeOtherGroup", withProperties: ["value"], withWasmType: wasmi32Mutable) XCTAssertFalse(ILTypeWrongGroup >= ILTypeGlobalI32Mutable) XCTAssertFalse(ILTypeGlobalI32Mutable >= ILTypeWrongGroup) } func testWasmGlobalUnion() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmf32Mutable = WasmGlobalType(valueType:ILType.wasmf32, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmf32Mutable = WasmGlobalType(valueType: ILType.wasmf32, isMutable: true) - let ILTypeGlobalI32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalF32Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf32Mutable) + let ILTypeGlobalI32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalF32Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf32Mutable) XCTAssertEqual(ILTypeGlobalI32Mutable | ILTypeGlobalI32Mutable, ILTypeGlobalI32Mutable) @@ -628,34 +680,46 @@ class TypeSystemTests: XCTestCase { // .wasmGlobalType extension.) XCTAssertEqual(ILTypeGlobalI32Mutable | .object(ofGroup: "WasmGlobal"), .object()) XCTAssert(.object(ofGroup: "WasmGlobal") >= ILTypeGlobalI32Mutable) - XCTAssertEqual(ILTypeGlobalI32Mutable | .object(withProperties: ["value"]), .object(withProperties: ["value"])) + XCTAssertEqual( + ILTypeGlobalI32Mutable | .object(withProperties: ["value"]), + .object(withProperties: ["value"])) XCTAssert(.object(withProperties: ["value"]) >= ILTypeGlobalI32Mutable) } func testWasmGlobalIntersection() { - let wasmi64Mutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: true) - let wasmi64NonMutable = WasmGlobalType(valueType:ILType.wasmi64, isMutable: false) - let wasmf64Mutable = WasmGlobalType(valueType:ILType.wasmf64, isMutable: true) + let wasmi64Mutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: true) + let wasmi64NonMutable = WasmGlobalType(valueType: ILType.wasmi64, isMutable: false) + let wasmf64Mutable = WasmGlobalType(valueType: ILType.wasmf64, isMutable: true) - let ILTypeGlobalI64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) - let ILTypeGlobalI64NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64NonMutable) - let ILTypeGlobalF64Mutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) + let ILTypeGlobalI64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable) + let ILTypeGlobalI64NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64NonMutable) + let ILTypeGlobalF64Mutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalI64Mutable, ILTypeGlobalI64Mutable) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalI64NonMutable, .nothing) XCTAssertEqual(ILTypeGlobalI64Mutable & ILTypeGlobalF64Mutable, .nothing) - XCTAssertEqual(ILTypeGlobalI64Mutable & .object(withProperties: ["value"]), ILTypeGlobalI64Mutable) - XCTAssertEqual((ILTypeGlobalI64Mutable & ILType.object(withWasmType: wasmi64Mutable)), ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable)) + XCTAssertEqual( + ILTypeGlobalI64Mutable & .object(withProperties: ["value"]), ILTypeGlobalI64Mutable) + XCTAssertEqual( + (ILTypeGlobalI64Mutable & ILType.object(withWasmType: wasmi64Mutable)), + ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi64Mutable)) } func testWasmGlobalIsAndMayBe() { - let wasmi32Mutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: true) - let wasmi32NonMutable = WasmGlobalType(valueType:ILType.wasmi32, isMutable: false) - let wasmf64Mutable = WasmGlobalType(valueType:ILType.wasmf64, isMutable: true) + let wasmi32Mutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: true) + let wasmi32NonMutable = WasmGlobalType(valueType: ILType.wasmi32, isMutable: false) + let wasmf64Mutable = WasmGlobalType(valueType: ILType.wasmf64, isMutable: true) - let ILTypeGlobalI32Mutable: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) - let ILTypeGlobalI32NonMutable = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) - let ILTypeGlobalF64Mutable: ILType = ILType.object(ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) + let ILTypeGlobalI32Mutable: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32Mutable) + let ILTypeGlobalI32NonMutable = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmi32NonMutable) + let ILTypeGlobalF64Mutable: ILType = ILType.object( + ofGroup: "WasmGlobal", withProperties: ["value"], withWasmType: wasmf64Mutable) XCTAssert(ILTypeGlobalI32Mutable.Is(.object(ofGroup: "WasmGlobal"))) XCTAssert(ILTypeGlobalI32Mutable.Is(.object(withProperties: ["value"]))) @@ -686,7 +750,7 @@ class TypeSystemTests: XCTestCase { XCTAssert(.integer | .float | .string >= .string) XCTAssert(.integer | .float | .string >= .integer | .float) XCTAssert(.integer | .float | .string >= .integer | .string) - XCTAssert(.integer | .float | .string >= .float | .string) + XCTAssert(.integer | .float | .string >= .float | .string) XCTAssert(.integer | .float | .string >= .integer | .float | .string) XCTAssert(.integer | .float | .string == .integer | .float | .string) @@ -715,13 +779,14 @@ class TypeSystemTests: XCTestCase { for t2 in primitiveTypes { for t3 in primitiveTypes { if t3 != t1 && t3 != t2 { - XCTAssertFalse(t1 | t2 >= t3, "\(t3) != \(t1) && \(t3) != \(t2) => \(t1) | \(t2) !>= \(t3)") + XCTAssertFalse( + t1 | t2 >= t3, + "\(t3) != \(t1) && \(t3) != \(t2) => \(t1) | \(t2) !>= \(t3)") } } } } - for t1 in typeSuite { XCTAssert(t1 | t1 == t1, "\(t1) | \(t1) (\(t1 | t1)) == \(t1)") @@ -787,12 +852,19 @@ class TypeSystemTests: XCTestCase { // Maybe a bit less intuitively, the intersection of two functions with different signatures can also exist. // In the following example, the more general signature of the two functions is the intersection as that's what // both functions "have in common". - XCTAssertEqual(ILType.function([.jsAnything] => .integer) & .function([.integer] => .jsAnything), .function([.jsAnything] => .integer)) - XCTAssertEqual(ILType.function([.jsAnything] => .jsAnything) & .function([.integer] => .jsAnything), .function([.jsAnything] => .jsAnything)) + XCTAssertEqual( + ILType.function([.jsAnything] => .integer) & .function([.integer] => .jsAnything), + .function([.jsAnything] => .integer)) + XCTAssertEqual( + ILType.function([.jsAnything] => .jsAnything) & .function([.integer] => .jsAnything), + .function([.jsAnything] => .jsAnything)) // In this example, the parameter type is widened and the return type is narrowed. - XCTAssertEqual(ILType.function([.integer] => .integer) & .function([.jsAnything] => .jsAnything), .function([.jsAnything] => .integer)) + XCTAssertEqual( + ILType.function([.integer] => .integer) & .function([.jsAnything] => .jsAnything), + .function([.jsAnything] => .integer)) // However, here the return types are incompatible - XCTAssertEqual(ILType.function([.integer] => .integer) & .function([.integer] => .string), .nothing) + XCTAssertEqual( + ILType.function([.integer] => .integer) & .function([.integer] => .string), .nothing) // Now test the basic invariants of intersections for all types in the type suite. for t1 in typeSuite { @@ -800,7 +872,8 @@ class TypeSystemTests: XCTestCase { for t2 in typeSuite { // Intersecting is symmetric - XCTAssert(t1 & t2 == t2 & t1, "\(t1) & \(t2) (\(t2 & t2)) == \(t2) & \(t1) (\(t2 & t1))") + XCTAssert( + t1 & t2 == t2 & t1, "\(t1) & \(t2) (\(t2 & t2)) == \(t2) & \(t1) (\(t2 & t1))") let intersection = t1 & t2 @@ -810,7 +883,8 @@ class TypeSystemTests: XCTestCase { // If one of the two inputs subsumes the other, then the result will be the subsumed type. if t1 >= t2 { - XCTAssert(t1 & t2 == t2, "\(t1) >= \(t2) => \(t1) & \(t2) (\(t1 & t2)) == \(t2)") + XCTAssert( + t1 & t2 == t2, "\(t1) >= \(t2) => \(t1) & \(t2) (\(t1 & t2)) == \(t2)") } } } @@ -851,12 +925,17 @@ class TypeSystemTests: XCTestCase { for t3 in typeSuite { if t3 >= t1 || t3 >= t2 { // If t1 or t2 are a t3, than the merged type t1 + t2 must also be a t3. - XCTAssert(t3 >= merged, "\(t3) >= \(t1) || \(t3) >= \(t2) implies \(t3) >= \(t1) + \(t2) (\(merged))") + XCTAssert( + t3 >= merged, + "\(t3) >= \(t1) || \(t3) >= \(t2) implies \(t3) >= \(t1) + \(t2) (\(merged))" + ) } guard t1.canMerge(with: t3) && t2.canMerge(with: t3) else { continue } if t1 >= t2 { - XCTAssert(t1 + t3 >= t2 + t3, "\(t1) >= \(t2) implies \(t1) + \(t3) >= \(t2) + \(t3)") + XCTAssert( + t1 + t3 >= t2 + t3, + "\(t1) >= \(t2) implies \(t1) + \(t3) >= \(t2) + \(t3)") } } } @@ -876,11 +955,15 @@ class TypeSystemTests: XCTestCase { } // Callables with different signatures cannot be merged - else if t1.isCallable && t2.isCallable && t1.signature != nil && t2.signature != nil && t1.signature != t2.signature { + else if t1.isCallable && t2.isCallable && t1.signature != nil && t2.signature != nil + && t1.signature != t2.signature + { XCTAssertFalse(t1.canMerge(with: t2)) } - else if t1.isCallable && t2.isCallable && t1.receiver != nil && t2.receiver != nil && t1.receiver != t2.receiver { + else if t1.isCallable && t2.isCallable && t1.receiver != nil && t2.receiver != nil + && t1.receiver != t2.receiver + { XCTAssertFalse(t1.canMerge(with: t2)) } @@ -935,7 +1018,8 @@ class TypeSystemTests: XCTestCase { XCTAssertFalse([.integer, .integer] => .undefined >= [.integer, .string] => .undefined) // Or, phrased differentley still, a function that accepts anything as first // parameter is a function that accepts an integer as first parameter. - XCTAssert(ILType.function([.jsAnything] => .undefined).Is(.function([.integer] => .undefined))) + XCTAssert( + ILType.function([.jsAnything] => .undefined).Is(.function([.integer] => .undefined))) // However, the other direction does not hold: if we want a function that // accepts anything as first parameter, we cannot use a function that // requires an integer as first parameter instead. @@ -976,9 +1060,11 @@ class TypeSystemTests: XCTestCase { XCTAssert([] => .undefined >= [.opt(.integer), .opt(.float)] => .undefined) XCTAssert([.opt(.integer)] => .undefined >= [.opt(.jsAnything)] => .undefined) XCTAssert([.opt(.integer)] => .undefined >= [] => .undefined) - XCTAssert([.string, .opt(.integer)] => .undefined >= [.string, .jsAnything...] => .undefined) + XCTAssert( + [.string, .opt(.integer)] => .undefined >= [.string, .jsAnything...] => .undefined) XCTAssert([.integer] => .undefined >= [.opt(.integer)] => .undefined) - XCTAssertFalse([.integer, .integer] => .undefined >= [.opt(.integer), .opt(.string)] => .undefined) + XCTAssertFalse( + [.integer, .integer] => .undefined >= [.opt(.integer), .opt(.string)] => .undefined) XCTAssertFalse([.opt(.integer)] => .undefined >= [.integer] => .undefined) XCTAssertFalse([.opt(.integer)] => .undefined >= [.string...] => .undefined) XCTAssertFalse([.string...] => .undefined >= [.opt(.integer)] => .undefined) @@ -1002,24 +1088,40 @@ class TypeSystemTests: XCTestCase { // Previously we would just say that all objects are the same anyways. // Now we want them to be interchangeable, e.g. for splicing in JS. XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object0").Is(.object(ofGroup: "_fuzz_Object1"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_WasmExports0").Is(.object(ofGroup: "_fuzz_WasmExports1"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_WasmModule0").Is(.object(ofGroup: "_fuzz_WasmModule1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_WasmExports0").Is(.object(ofGroup: "_fuzz_WasmExports1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_WasmModule0").Is(.object(ofGroup: "_fuzz_WasmModule1"))) XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Constructor0"))) - - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Constructor1"))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Constructor0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Constructor1").Is(.object(ofGroup: "_fuzz_Class0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Constructor1"))) // Negative tests to make sure they don't subsume if they don't subsume based on properties / methods.. - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object1", withMethods: ["a"]).Is(.object(ofGroup: "_fuzz_Object0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Object1").Is(.object(ofGroup: "_fuzz_Object0", withMethods: ["a"]))) - - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Class1", withProperties: ["a"]).Is(.object(ofGroup: "_fuzz_Class0"))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Class1").Is(.object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) - - XCTAssertTrue(ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"]).Is(.object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) - XCTAssertFalse(ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["b"]).Is(.object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Object1", withMethods: ["a"]).Is( + .object(ofGroup: "_fuzz_Object0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Object1").Is( + .object(ofGroup: "_fuzz_Object0", withMethods: ["a"]))) + + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Class1", withProperties: ["a"]).Is( + .object(ofGroup: "_fuzz_Class0"))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Class1").Is( + .object(ofGroup: "_fuzz_Class0", withProperties: ["a"]))) + + XCTAssertTrue( + ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["a", "b"]).Is( + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) + XCTAssertFalse( + ILType.object(ofGroup: "_fuzz_Object1", withProperties: ["b"]).Is( + .object(ofGroup: "_fuzz_Object0", withProperties: ["a"]))) } @@ -1047,34 +1149,68 @@ class TypeSystemTests: XCTestCase { // Test object types XCTAssertEqual(ILType.object().description, ".object()") - XCTAssertEqual(ILType.object(withProperties: ["foo"]).description, ".object(withProperties: [\"foo\"])") - XCTAssertEqual(ILType.object(withMethods: ["m"]).description, ".object(withMethods: [\"m\"])") + XCTAssertEqual( + ILType.object(withProperties: ["foo"]).description, ".object(withProperties: [\"foo\"])" + ) + XCTAssertEqual( + ILType.object(withMethods: ["m"]).description, ".object(withMethods: [\"m\"])") // Property and method order is not defined let fooBarObj = ILType.object(withProperties: ["foo", "bar"]) - XCTAssert(fooBarObj.description == ".object(withProperties: [\"foo\", \"bar\"])" || fooBarObj.description == ".object(withProperties: [\"bar\", \"foo\"])") + XCTAssert( + fooBarObj.description == ".object(withProperties: [\"foo\", \"bar\"])" + || fooBarObj.description == ".object(withProperties: [\"bar\", \"foo\"])") let objWithMethods = ILType.object(withMethods: ["m1", "m2"]) - XCTAssert(objWithMethods.description == ".object(withMethods: [\"m1\", \"m2\"])" || objWithMethods.description == ".object(withMethods: [\"m2\", \"m1\"])") + XCTAssert( + objWithMethods.description == ".object(withMethods: [\"m1\", \"m2\"])" + || objWithMethods.description == ".object(withMethods: [\"m2\", \"m1\"])") let fooBarObjWithMethod = ILType.object(withProperties: ["foo", "bar"], withMethods: ["m"]) - XCTAssert(fooBarObjWithMethod.description == ".object(withProperties: [\"foo\", \"bar\"], withMethods: [\"m\"])" || fooBarObjWithMethod.description == ".object(withProperties: [\"bar\", \"foo\"], withMethods: [\"m\"])") + XCTAssert( + fooBarObjWithMethod.description + == ".object(withProperties: [\"foo\", \"bar\"], withMethods: [\"m\"])" + || fooBarObjWithMethod.description + == ".object(withProperties: [\"bar\", \"foo\"], withMethods: [\"m\"])" + ) // Test function and constructor types XCTAssertEqual(ILType.function().description, ".function()") - XCTAssertEqual(ILType.function([.rest(.jsAnything)] => .jsAnything).description, ".function([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.function([.float, .opt(.integer)] => .object()).description, ".function([.float, .opt(.integer)] => .object())") - XCTAssertEqual(ILType.function([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".function([.integer, .boolean, .jsAnything...] => .object())") + XCTAssertEqual( + ILType.function([.rest(.jsAnything)] => .jsAnything).description, + ".function([.jsAnything...] => .jsAnything)") + XCTAssertEqual( + ILType.function([.float, .opt(.integer)] => .object()).description, + ".function([.float, .opt(.integer)] => .object())") + XCTAssertEqual( + ILType.function([.integer, .boolean, .rest(.jsAnything)] => .object()).description, + ".function([.integer, .boolean, .jsAnything...] => .object())") XCTAssertEqual(ILType.constructor().description, ".constructor()") - XCTAssertEqual(ILType.constructor([.rest(.jsAnything)] => .jsAnything).description, ".constructor([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.constructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".constructor([.integer, .boolean, .jsAnything...] => .object())") + XCTAssertEqual( + ILType.constructor([.rest(.jsAnything)] => .jsAnything).description, + ".constructor([.jsAnything...] => .jsAnything)") + XCTAssertEqual( + ILType.constructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, + ".constructor([.integer, .boolean, .jsAnything...] => .object())") XCTAssertEqual(ILType.functionAndConstructor().description, ".function() + .constructor()") - XCTAssertEqual(ILType.functionAndConstructor([.rest(.jsAnything)] => .jsAnything).description, ".function([.jsAnything...] => .jsAnything) + .constructor([.jsAnything...] => .jsAnything)") - XCTAssertEqual(ILType.functionAndConstructor([.integer, .boolean, .rest(.jsAnything)] => .object()).description, ".function([.integer, .boolean, .jsAnything...] => .object()) + .constructor([.integer, .boolean, .jsAnything...] => .object())") - - XCTAssertEqual(ILType.unboundFunction([.integer, .boolean, .rest(.jsAnything)] => .object(), receiver: .object()).description, ".unboundFunction([.integer, .boolean, .jsAnything...] => .object(), receiver: .object())") + XCTAssertEqual( + ILType.functionAndConstructor([.rest(.jsAnything)] => .jsAnything).description, + ".function([.jsAnything...] => .jsAnything) + .constructor([.jsAnything...] => .jsAnything)" + ) + XCTAssertEqual( + ILType.functionAndConstructor([.integer, .boolean, .rest(.jsAnything)] => .object()) + .description, + ".function([.integer, .boolean, .jsAnything...] => .object()) + .constructor([.integer, .boolean, .jsAnything...] => .object())" + ) + + XCTAssertEqual( + ILType.unboundFunction( + [.integer, .boolean, .rest(.jsAnything)] => .object(), receiver: .object() + ).description, + ".unboundFunction([.integer, .boolean, .jsAnything...] => .object(), receiver: .object())" + ) XCTAssertEqual(ILType.unboundFunction().description, ".unboundFunction(nil, receiver: nil)") // Test other "well-known" types @@ -1100,15 +1236,31 @@ class TypeSystemTests: XCTestCase { let strObj = ILType.string + ILType.object(withProperties: ["foo"]) XCTAssertEqual(strObj.description, ".string + .object(withProperties: [\"foo\"])") - let funcObj = ILType.object(withProperties: ["foo"], withMethods: ["m"]) + ILType.function([.integer, .rest(.jsAnything)] => .boolean) - XCTAssertEqual(funcObj.description, ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean)") - - let funcConstrObj = ILType.object(withProperties: ["foo"], withMethods: ["m"]) + ILType.functionAndConstructor([.integer, .rest(.jsAnything)] => .boolean) - XCTAssertEqual(funcConstrObj.description, ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean) + .constructor([.integer, .jsAnything...] => .boolean)") + let funcObj = + ILType.object(withProperties: ["foo"], withMethods: ["m"]) + + ILType.function([.integer, .rest(.jsAnything)] => .boolean) + XCTAssertEqual( + funcObj.description, + ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean)" + ) + + let funcConstrObj = + ILType.object(withProperties: ["foo"], withMethods: ["m"]) + + ILType.functionAndConstructor([.integer, .rest(.jsAnything)] => .boolean) + XCTAssertEqual( + funcConstrObj.description, + ".object(withProperties: [\"foo\"], withMethods: [\"m\"]) + .function([.integer, .jsAnything...] => .boolean) + .constructor([.integer, .jsAnything...] => .boolean)" + ) // Test union of merged types - let strObjOrFuncObj = (ILType.string + ILType.object(withProperties: ["foo"])) | (ILType.function([.rest(.jsAnything)] => .float) + ILType.object(withProperties: ["foo"])) - XCTAssertEqual(strObjOrFuncObj.description, ".string + .object(withProperties: [\"foo\"]) | .object(withProperties: [\"foo\"]) + .function()") + let strObjOrFuncObj = + (ILType.string + ILType.object(withProperties: ["foo"])) + | (ILType.function([.rest(.jsAnything)] => .float) + + ILType.object(withProperties: ["foo"])) + XCTAssertEqual( + strObjOrFuncObj.description, + ".string + .object(withProperties: [\"foo\"]) | .object(withProperties: [\"foo\"]) + .function()" + ) let nullExn = ILType.wasmRef(.WasmExn, shared: true, nullability: true) let nonNullAny = ILType.wasmRef(.WasmAny, shared: false, nullability: false) @@ -1116,44 +1268,55 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(nonNullAny.description, ".wasmRef(.Abstract(WasmAny))") // TODO(pawkra): add shared variant. - let arrayDesc = WasmArrayTypeDescription(elementType: .wasmi32, mutability: false, typeGroupIndex: 0) + let arrayDesc = WasmArrayTypeDescription( + elementType: .wasmi32, mutability: false, typeGroupIndex: 0) let arrayRef = ILType.wasmIndexRef(arrayDesc, nullability: true) XCTAssertEqual(arrayRef.description, ".wasmRef(null Index 0 Array[immutable .wasmi32])") - let nullableSelfRef = ILType.wasmRef(.Index(.init(WasmTypeDescription.selfReference)), nullability: true) - let structDesc = WasmStructTypeDescription(fields: [ - .init(type: .wasmf32, mutability: true), - .init(type: nullableSelfRef, mutability: false), // unresolved - .init(type: arrayRef, mutability: true) - ], typeGroupIndex: 1) + let nullableSelfRef = ILType.wasmRef( + .Index(.init(WasmTypeDescription.selfReference)), nullability: true) + let structDesc = WasmStructTypeDescription( + fields: [ + .init(type: .wasmf32, mutability: true), + .init(type: nullableSelfRef, mutability: false), // unresolved + .init(type: arrayRef, mutability: true), + ], typeGroupIndex: 1) let structRef = ILType.wasmIndexRef(structDesc, nullability: false) - XCTAssertEqual(structRef.description, - ".wasmRef(Index 1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index selfReference), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structRef.description, + ".wasmRef(Index 1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index selfReference), mutable .wasmRef(null Index 0 Array)])" + ) // Create a cycle (a "resolved" self reference) for an array element type. arrayDesc.elementType = arrayRef - XCTAssertEqual(arrayRef.description, + XCTAssertEqual( + arrayRef.description, ".wasmRef(null Index 0 Array[immutable .wasmRef(null Index 0 Array)])") // Create a cycle for a struct field type. structDesc.fields[1].type = .wasmIndexRef(structDesc, nullability: true) - XCTAssertEqual(structRef.description, - ".wasmRef(Index 1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structRef.description, + ".wasmRef(Index 1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") // Type definitions print the same thing as references just with .wasmTypeDef instead of // .wasmRef. let arrayDef = ILType.wasmTypeDef(description: arrayDesc) - XCTAssertEqual(arrayDef.description, + XCTAssertEqual( + arrayDef.description, ".wasmTypeDef(0 Array[immutable .wasmRef(null Index 0 Array)])") let structDef = ILType.wasmTypeDef(description: structDesc) - XCTAssertEqual(structDef.description, - ".wasmTypeDef(1 Struct[mutable .wasmf32, " + - "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") + XCTAssertEqual( + structDef.description, + ".wasmTypeDef(1 Struct[mutable .wasmf32, " + + "immutable .wasmRef(null Index 1 Struct), mutable .wasmRef(null Index 0 Array)])") let signatureDesc = WasmSignatureTypeDescription( - signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef(shared: true)], typeGroupIndex: 0) + signature: [.wasmi32, arrayRef] => [structRef, .wasmNullRef(shared: true)], + typeGroupIndex: 0) let signatureDef = ILType.wasmTypeDef(description: signatureDesc) - XCTAssertEqual(signatureDef.description, - ".wasmTypeDef(0 Func[[.wasmi32, .wasmRef(null Index 0 Array)] => " + - "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null shared WasmNone))]])") + XCTAssertEqual( + signatureDef.description, + ".wasmTypeDef(0 Func[[.wasmi32, .wasmRef(null Index 0 Array)] => " + + "[.wasmRef(Index 1 Struct), .wasmRef(.Abstract(null shared WasmNone))]])") // A generic index type without a type description. // These are e.g. used by the element types for arrays and structs inside the operation as @@ -1164,7 +1327,8 @@ class TypeSystemTests: XCTestCase { } func testWasmSubsumptionRules() { - let wasmTypes: [ILType] = [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allNullableAbstractWasmRefTypes() + let wasmTypes: [ILType] = + [.wasmi32, .wasmi64, .wasmf32, .wasmf64] + ILType.allNullableAbstractWasmRefTypes() // Make sure that no Wasm type is subsumed by (JS-)anything. for t in wasmTypes { XCTAssertEqual(t <= .jsAnything, false) @@ -1172,38 +1336,60 @@ class TypeSystemTests: XCTestCase { } func testWasmTypeExtensionSubsumptionRules() { - let arrayi32Desc = WasmArrayTypeDescription(elementType: .wasmi32, mutability: true, typeGroupIndex: 0) - let arrayi64Desc = WasmArrayTypeDescription(elementType: .wasmi64, mutability: true, typeGroupIndex: 0) + let arrayi32Desc = WasmArrayTypeDescription( + elementType: .wasmi32, mutability: true, typeGroupIndex: 0) + let arrayi64Desc = WasmArrayTypeDescription( + elementType: .wasmi64, mutability: true, typeGroupIndex: 0) // Test Wasm reference type definitions. XCTAssertNotEqual(ILType.wasmTypeDef(), ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertNotEqual(ILType.wasmTypeDef(description: arrayi64Desc), - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertEqual(ILType.wasmTypeDef(description: arrayi32Desc), - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssert(ILType.wasmTypeDef(description:arrayi32Desc) <= ILType.wasmTypeDef()) - XCTAssert(ILType.wasmTypeDef(description: arrayi32Desc) <= - ILType.wasmTypeDef(description: arrayi32Desc)) - XCTAssertFalse(ILType.wasmTypeDef(description: arrayi32Desc) <= - ILType.wasmTypeDef(description: arrayi64Desc)) + XCTAssertNotEqual( + ILType.wasmTypeDef(description: arrayi64Desc), + ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssertEqual( + ILType.wasmTypeDef(description: arrayi32Desc), + ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssert(ILType.wasmTypeDef(description: arrayi32Desc) <= ILType.wasmTypeDef()) + XCTAssert( + ILType.wasmTypeDef(description: arrayi32Desc) + <= ILType.wasmTypeDef(description: arrayi32Desc)) + XCTAssertFalse( + ILType.wasmTypeDef(description: arrayi32Desc) + <= ILType.wasmTypeDef(description: arrayi64Desc)) // Test Wasm references. - XCTAssert(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmRef(.Index(), nullability: true)) - XCTAssert(ILType.wasmRef(.Index(), nullability: false) <= ILType.wasmRef(.Index(), nullability: false)) - XCTAssert(ILType.wasmRef(.Index(), nullability: false) <= ILType.wasmRef(.Index(), nullability: true)) - XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmRef(.Index(), nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmRef(.Index(), nullability: true)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: false) + <= ILType.wasmRef(.Index(), nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: false) + <= ILType.wasmRef(.Index(), nullability: true)) + XCTAssertFalse( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmRef(.Index(), nullability: false)) XCTAssertFalse(ILType.wasmi32 <= ILType.wasmRef(.Index(), nullability: true)) XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmi32) - XCTAssertFalse(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi64Desc, nullability: true)) - XCTAssertFalse(ILType.wasmIndexRef(arrayi64Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssert(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssert(ILType.wasmIndexRef(arrayi32Desc, nullability: true) - >= ILType.wasmIndexRef(arrayi32Desc, nullability: false)) - XCTAssert(ILType.wasmRef(.Index(), nullability: true) >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) - XCTAssertFalse(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi64Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmIndexRef(arrayi64Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssert( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssert( + ILType.wasmIndexRef(arrayi32Desc, nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: false)) + XCTAssert( + ILType.wasmRef(.Index(), nullability: true) + >= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) + XCTAssertFalse( + ILType.wasmRef(.Index(), nullability: true) + <= ILType.wasmIndexRef(arrayi32Desc, nullability: true)) XCTAssert(ILType.wasmRef(.Index(), nullability: true) <= ILType.wasmGenericRef) XCTAssertFalse(ILType.wasmGenericRef <= ILType.wasmRef(.Index(), nullability: true)) @@ -1254,10 +1440,10 @@ class TypeSystemTests: XCTestCase { XCTAssert(WasmAbstractHeapType.allCases.allSatisfy(allTypes.contains)) // All types in the same type group share the same bottom type. - XCTAssert(groupAny.allSatisfy {$0.getBottom() == .WasmNone}) - XCTAssert(groupExtern.allSatisfy {$0.getBottom() == .WasmNoExtern}) - XCTAssert(groupFunc.allSatisfy {$0.getBottom() == .WasmNoFunc}) - XCTAssert(groupExn.allSatisfy {$0.getBottom() == .WasmNoExn}) + XCTAssert(groupAny.allSatisfy { $0.getBottom() == .WasmNone }) + XCTAssert(groupExtern.allSatisfy { $0.getBottom() == .WasmNoExtern }) + XCTAssert(groupFunc.allSatisfy { $0.getBottom() == .WasmNoFunc }) + XCTAssert(groupExn.allSatisfy { $0.getBottom() == .WasmNoExn }) // The union and intersection of of two unrelated types are nil. for groupA in allGroups { @@ -1290,8 +1476,10 @@ class TypeSystemTests: XCTestCase { // Tests on the whole ILType. for shared in [true, false] { - let ref: (WasmAbstractHeapType) -> ILType = {t in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t in ILType.wasmRef(t, shared: shared, nullability: true)} + let ref: (WasmAbstractHeapType) -> ILType = { t in + ILType.wasmRef(t, shared: shared, nullability: false, ) + } + let refNull = { t in ILType.wasmRef(t, shared: shared, nullability: true) } for type in allTypes { let refT = ref(type) @@ -1314,20 +1502,23 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(ref(.WasmI31).union(with: refNull(.WasmExn)), .wasmGenericRef) XCTAssertEqual(ref(.WasmAny).intersection(with: refNull(.WasmEq)), ref(.WasmEq)) - XCTAssertEqual(refNull(.WasmI31).intersection(with: refNull(.WasmStruct)), refNull(.WasmNone)) + XCTAssertEqual( + refNull(.WasmI31).intersection(with: refNull(.WasmStruct)), refNull(.WasmNone)) // Note that `ref none` is a perfectly valid type in Wasm but such a reference can never be // constructed. XCTAssertEqual(ref(.WasmArray).intersection(with: refNull(.WasmStruct)), ref(.WasmNone)) XCTAssertEqual(refNull(.WasmArray).intersection(with: ref(.WasmAny)), ref(.WasmArray)) } - let ref = {t, shared in ILType.wasmRef(t, shared: shared, nullability: false,)} - let refNull = {t, shared in ILType.wasmRef(t, shared: shared, nullability: true)} + let ref = { t, shared in ILType.wasmRef(t, shared: shared, nullability: false, ) } + let refNull = { t, shared in ILType.wasmRef(t, shared: shared, nullability: true) } // Shared and unshared ref hierarchies are disjoint. for (lhsShared, rhsShared) in [(true, false), (false, true)] { for type in allTypes { - XCTAssertEqual(ref(type, lhsShared).union(with: ref(type, rhsShared)), .wasmGenericRef) - XCTAssertEqual(refNull(type, lhsShared).union(with: refNull(type, rhsShared)), .wasmGenericRef) + XCTAssertEqual( + ref(type, lhsShared).union(with: ref(type, rhsShared)), .wasmGenericRef) + XCTAssertEqual( + refNull(type, lhsShared).union(with: refNull(type, rhsShared)), .wasmGenericRef) } } } @@ -1338,8 +1529,10 @@ class TypeSystemTests: XCTestCase { XCTAssertNotEqual(ILType.unboundFunction(receiver: .object()), .unboundFunction()) XCTAssert(ILType.unboundFunction(receiver: .object()).Is(.unboundFunction())) XCTAssertFalse(ILType.unboundFunction().Is(.unboundFunction(receiver: .object()))) - XCTAssert(ILType.unboundFunction(receiver: .object()).Is(.unboundFunction(receiver: .jsAnything))) - XCTAssertFalse(ILType.unboundFunction(receiver: .jsAnything).Is(.unboundFunction(receiver: .object()))) + XCTAssert( + ILType.unboundFunction(receiver: .object()).Is(.unboundFunction(receiver: .jsAnything))) + XCTAssertFalse( + ILType.unboundFunction(receiver: .jsAnything).Is(.unboundFunction(receiver: .object()))) let receiverNil = ILType.unboundFunction() let receiverObject = ILType.unboundFunction(receiver: .object()) @@ -1355,102 +1548,109 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(receiverObject.intersection(with: receiverNil), receiverObject) } - let primitiveTypes: [ILType] = [.undefined, .integer, .float, .string, .boolean, .bigint, .regexp] + let primitiveTypes: [ILType] = [ + .undefined, .integer, .float, .string, .boolean, .bigint, .regexp, + ] // A set of different types used by various tests. // TODO(cffsmith): Test and adjust types with a WasmTypeExtension. - let typeSuite: [ILType] = [.undefined, - .integer, - .float, - .string, - .boolean, - .bigint, - .regexp, - .iterable, - .jsAnything, - .nothing, - .object(), - .object(ofGroup: "A"), - .object(ofGroup: "B"), - .object(withProperties: ["foo"]), - .object(withProperties: ["bar"]), - .object(withProperties: ["baz"]), - .object(withProperties: ["foo", "bar"]), - .object(withProperties: ["foo", "baz"]), - .object(withProperties: ["foo", "bar", "baz"]), - .object(withMethods: ["m1"]), - .object(withMethods: ["m2"]), - .object(withMethods: ["m1", "m2"]), - .object(withProperties: ["foo"], withMethods: ["m1"]), - .object(withProperties: ["foo"], withMethods: ["m2"]), - .object(withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(withProperties: ["baz"], withMethods: ["m1"]), - .object(withProperties: ["bar"], withMethods: ["m1", "m2"]), - .object(withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .object(withProperties: ["foo", "bar", "baz"], withMethods: ["m1", "m2"]), - .object(ofGroup: "A", withProperties: ["foo"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"]), - .object(ofGroup: "A", withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .object(ofGroup: "B", withProperties: ["foo"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"]), - .object(ofGroup: "B", withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo"], withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1"]), - .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), - .function(), - .function([.string] => .string), - .function([.string] => .jsAnything), - .function([.primitive] => .string), - .function([.string, .string] => .jsAnything), - .function([.integer] => .number), - .function([.jsAnything...] => .jsAnything), - .function([.integer, .string, .opt(.jsAnything)] => .float), - .unboundFunction(), - .unboundFunction([.string] => .string), - .unboundFunction([.string] => .string, receiver: .object()), - .unboundFunction([.string] => .jsAnything, receiver: .object()), - .constructor(), - .constructor([.string] => .string), - .constructor([.string] => .jsAnything), - .constructor([.primitive] => .string), - .constructor([.string, .string] => .jsAnything), - .constructor([.integer] => .number), - .constructor([.jsAnything...] => .object()), - .constructor([.integer, .string, .opt(.jsAnything)] => .object()), - .functionAndConstructor(), - .functionAndConstructor([.string] => .string), - .functionAndConstructor([.string] => .jsAnything), - .functionAndConstructor([.primitive] => .string), - .functionAndConstructor([.string, .string] => .jsAnything), - .functionAndConstructor([.integer] => .number), - .functionAndConstructor([.jsAnything...] => .jsAnything), - .functionAndConstructor([.integer, .string, .opt(.jsAnything)] => .object()), - .number, - .primitive, - .string | .object(), - .string | .object(withProperties: ["foo"]), - .object(withProperties: ["foo"]) | .function(), - .object(withProperties: ["foo"]) | .constructor([.rest(.jsAnything)] => .object()), - .primitive | .object() | .function() | .constructor(), - .string + .object(withProperties: ["foo", "bar"]), - .integer + .object(withProperties: ["foo"], withMethods: ["m"]), - .object(withProperties: ["foo", "bar"]) + .function([.integer] => .jsAnything), - .object(ofGroup: "A", withProperties: ["foo", "bar"]) + .constructor([.integer] => .jsAnything), - .object(withMethods: ["m1"]) + .functionAndConstructor([.integer, .boolean] => .jsAnything), - .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]) + .functionAndConstructor([.integer, .boolean] => .jsAnything), - // Wasm types - .wasmAnything, - .wasmi32, - .wasmf32, - .wasmi64, - .wasmf64, - .wasmFunctionDef([.wasmi32] => [.wasmi64]), - .wasmFunctionDef([.wasmf32] => [.wasmi32]), - .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), - .wasmMemory(limits: Limits(min: 10)), - .wasmMemory(limits: Limits(min: 10, max: 20)), - ] + ILType.allNullableAbstractWasmRefTypes() + let typeSuite: [ILType] = + [ + .undefined, + .integer, + .float, + .string, + .boolean, + .bigint, + .regexp, + .iterable, + .jsAnything, + .nothing, + .object(), + .object(ofGroup: "A"), + .object(ofGroup: "B"), + .object(withProperties: ["foo"]), + .object(withProperties: ["bar"]), + .object(withProperties: ["baz"]), + .object(withProperties: ["foo", "bar"]), + .object(withProperties: ["foo", "baz"]), + .object(withProperties: ["foo", "bar", "baz"]), + .object(withMethods: ["m1"]), + .object(withMethods: ["m2"]), + .object(withMethods: ["m1", "m2"]), + .object(withProperties: ["foo"], withMethods: ["m1"]), + .object(withProperties: ["foo"], withMethods: ["m2"]), + .object(withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(withProperties: ["baz"], withMethods: ["m1"]), + .object(withProperties: ["bar"], withMethods: ["m1", "m2"]), + .object(withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .object(withProperties: ["foo", "bar", "baz"], withMethods: ["m1", "m2"]), + .object(ofGroup: "A", withProperties: ["foo"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"]), + .object(ofGroup: "A", withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(ofGroup: "A", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .object(ofGroup: "B", withProperties: ["foo"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"]), + .object(ofGroup: "B", withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo"], withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1"]), + .object(ofGroup: "B", withProperties: ["foo", "bar"], withMethods: ["m1", "m2"]), + .function(), + .function([.string] => .string), + .function([.string] => .jsAnything), + .function([.primitive] => .string), + .function([.string, .string] => .jsAnything), + .function([.integer] => .number), + .function([.jsAnything...] => .jsAnything), + .function([.integer, .string, .opt(.jsAnything)] => .float), + .unboundFunction(), + .unboundFunction([.string] => .string), + .unboundFunction([.string] => .string, receiver: .object()), + .unboundFunction([.string] => .jsAnything, receiver: .object()), + .constructor(), + .constructor([.string] => .string), + .constructor([.string] => .jsAnything), + .constructor([.primitive] => .string), + .constructor([.string, .string] => .jsAnything), + .constructor([.integer] => .number), + .constructor([.jsAnything...] => .object()), + .constructor([.integer, .string, .opt(.jsAnything)] => .object()), + .functionAndConstructor(), + .functionAndConstructor([.string] => .string), + .functionAndConstructor([.string] => .jsAnything), + .functionAndConstructor([.primitive] => .string), + .functionAndConstructor([.string, .string] => .jsAnything), + .functionAndConstructor([.integer] => .number), + .functionAndConstructor([.jsAnything...] => .jsAnything), + .functionAndConstructor([.integer, .string, .opt(.jsAnything)] => .object()), + .number, + .primitive, + .string | .object(), + .string | .object(withProperties: ["foo"]), + .object(withProperties: ["foo"]) | .function(), + .object(withProperties: ["foo"]) | .constructor([.rest(.jsAnything)] => .object()), + .primitive | .object() | .function() | .constructor(), + .string + .object(withProperties: ["foo", "bar"]), + .integer + .object(withProperties: ["foo"], withMethods: ["m"]), + .object(withProperties: ["foo", "bar"]) + .function([.integer] => .jsAnything), + .object(ofGroup: "A", withProperties: ["foo", "bar"]) + + .constructor([.integer] => .jsAnything), + .object(withMethods: ["m1"]) + + .functionAndConstructor([.integer, .boolean] => .jsAnything), + .object(ofGroup: "A", withProperties: ["foo"], withMethods: ["m1"]) + + .functionAndConstructor([.integer, .boolean] => .jsAnything), + // Wasm types + .wasmAnything, + .wasmi32, + .wasmf32, + .wasmi64, + .wasmf64, + .wasmFunctionDef([.wasmi32] => [.wasmi64]), + .wasmFunctionDef([.wasmf32] => [.wasmi32]), + .wasmFunctionDef([.wasmExternRef()] => [.wasmExternRef()]), + .wasmMemory(limits: Limits(min: 10)), + .wasmMemory(limits: Limits(min: 10, max: 20)), + ] + ILType.allNullableAbstractWasmRefTypes() } diff --git a/Tests/FuzzilliTests/VariableMapTest.swift b/Tests/FuzzilliTests/VariableMapTest.swift index 9dbbca9b2..98da6ecf0 100644 --- a/Tests/FuzzilliTests/VariableMapTest.swift +++ b/Tests/FuzzilliTests/VariableMapTest.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class VariableMapTests: XCTestCase { @@ -105,7 +106,7 @@ class VariableMapTests: XCTestCase { for i in 0..<1000 { withProbability(0.75) { - map[v(i)] = Int.random(in: 0..<1000000) + map[v(i)] = Int.random(in: 0..<1_000_000) } } @@ -124,7 +125,7 @@ class VariableMapTests: XCTestCase { for i in 0..<1000 { withProbability(0.75) { - let value = Int.random(in: 0..<1000000) + let value = Int.random(in: 0..<1_000_000) map1[v(i)] = value map2[v(i)] = value } @@ -138,7 +139,7 @@ class VariableMapTests: XCTestCase { var map = VariableMap() for i in 0..<1000 { withProbability(0.5) { - map[v(i)] = Int.random(in: 0..<1000000) + map[v(i)] = Int.random(in: 0..<1_000_000) } } @@ -172,7 +173,7 @@ class VariableMapTests: XCTestCase { for i in 0.. [.wasmi32]) { f, _, _ in let valueToStore = f.consti32(1337) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i32Store, offset: 0) - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i32Store, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load, offset: 0) return [loadedValue] } } @@ -40,10 +44,13 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in - let valueToStore = f.consti64(0x1122334455667788) + let valueToStore = f.consti64(0x1122_3344_5566_7788) let address = f.consti32(16) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i64Store, offset: 0) - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i64Store, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load, offset: 0) return [loadedValue] } } @@ -83,12 +90,15 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { f, _, _ in // The store will wrap this to 0xFF - let valueToStore = f.consti32(0x123456FF) + let valueToStore = f.consti32(0x1234_56FF) let address = f.consti32(4) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i32Store8, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i32Store8, offset: 0) // The load will zero-extend 0xFF to 255 - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load8U, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load8U, offset: 0) return [loadedValue] } } @@ -97,12 +107,15 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in // The store will wrap this to 0xEF - let valueToStore = f.consti64(0x1234567890ABCDEF) + let valueToStore = f.consti64(0x1234_5678_90AB_CDEF) let address = f.consti32(4) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: .i64Store8, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: .i64Store8, offset: 0) // The load will zero-extend 0xEF to 239 - let loadedValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load8U, offset: 0) + let loadedValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load8U, offset: 0) return [loadedValue] } } @@ -138,9 +151,10 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(1) // Unaligned for 4-byte access + let address = f.consti32(1) // Unaligned for 4-byte access // This should trap. - f.wasmAtomicLoad(memory: memory, address: address, loadType: .i32Load, offset: 0) + f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i32Load, offset: 0) return [] } } @@ -148,9 +162,10 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(4) // Unaligned for 8-byte access + let address = f.consti32(4) // Unaligned for 8-byte access // This should trap. - f.wasmAtomicLoad(memory: memory, address: address, loadType: .i64Load, offset: 0) + f.wasmAtomicLoad( + memory: memory, address: address, loadType: .i64Load, offset: 0) return [] } } @@ -159,10 +174,12 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(2) // Unaligned for 4-byte access + let address = f.consti32(2) // Unaligned for 4-byte access // This should trap. let value = f.consti32(0x1337) - f.wasmAtomicStore(memory: memory, address: address, value: value, storeType: .i32Store, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: value, storeType: .i32Store, + offset: 0) return [] } } @@ -170,10 +187,12 @@ class WasmAtomicsTests: XCTestCase { // memory64 for memory in [unsharedMemory, sharedMemory] { wasmModule.addWasmFunction(with: [] => []) { f, _, _ in - let address = f.consti32(7) // Unaligned for 8-byte access + let address = f.consti32(7) // Unaligned for 8-byte access // This should trap. - let value = f.consti64(0xDEADBEEF) - f.wasmAtomicStore(memory: memory, address: address, value: value, storeType: .i64Store, offset: 0) + let value = f.consti64(0xDEAD_BEEF) + f.wasmAtomicStore( + memory: memory, address: address, value: value, storeType: .i64Store, + offset: 0) return [] } } @@ -202,26 +221,27 @@ class WasmAtomicsTests: XCTestCase { var expectedResults: [String] = [] let js = buildAndLiftProgram { b in - let testCases: [( - op: WasmAtomicRMWType, - storeType: WasmAtomicStoreType, - loadType: WasmAtomicLoadType, - valueType: ILType - )] = - [.i32Add, .i32Sub, .i32And, .i32Or, .i32Xor, .i32Xchg] - .map { ($0, .i32Store, .i32Load, .wasmi32) } + - [.i32Add8U, .i32Sub8U, .i32And8U, .i32Or8U, .i32Xor8U, .i32Xchg8U] - .map { ($0, .i32Store8, .i32Load8U, .wasmi32) } + - [.i32Add16U, .i32Sub16U, .i32And16U, .i32Or16U, .i32Xor16U, .i32Xchg16U] - .map { ($0, .i32Store16, .i32Load16U, .wasmi32) } + - [.i64Add, .i64Sub, .i64And, .i64Or, .i64Xor, .i64Xchg] - .map { ($0, .i64Store, .i64Load, .wasmi64) } + - [.i64Add8U, .i64Sub8U, .i64And8U, .i64Or8U, .i64Xor8U, .i64Xchg8U] - .map { ($0, .i64Store8, .i64Load8U, .wasmi64) } + - [.i64Add16U, .i64Sub16U, .i64And16U, .i64Or16U, .i64Xor16U, .i64Xchg16U] - .map { ($0, .i64Store16, .i64Load16U, .wasmi64) } + - [.i64Add32U, .i64Sub32U, .i64And32U, .i64Or32U, .i64Xor32U, .i64Xchg32U] - .map { ($0, .i64Store32, .i64Load32U, .wasmi64) } + let testCases: + [( + op: WasmAtomicRMWType, + storeType: WasmAtomicStoreType, + loadType: WasmAtomicLoadType, + valueType: ILType + )] = + [.i32Add, .i32Sub, .i32And, .i32Or, .i32Xor, .i32Xchg] + .map { ($0, .i32Store, .i32Load, .wasmi32) } + + [.i32Add8U, .i32Sub8U, .i32And8U, .i32Or8U, .i32Xor8U, .i32Xchg8U] + .map { ($0, .i32Store8, .i32Load8U, .wasmi32) } + + [.i32Add16U, .i32Sub16U, .i32And16U, .i32Or16U, .i32Xor16U, .i32Xchg16U] + .map { ($0, .i32Store16, .i32Load16U, .wasmi32) } + + [.i64Add, .i64Sub, .i64And, .i64Or, .i64Xor, .i64Xchg] + .map { ($0, .i64Store, .i64Load, .wasmi64) } + + [.i64Add8U, .i64Sub8U, .i64And8U, .i64Or8U, .i64Xor8U, .i64Xchg8U] + .map { ($0, .i64Store8, .i64Load8U, .wasmi64) } + + [.i64Add16U, .i64Sub16U, .i64And16U, .i64Or16U, .i64Xor16U, .i64Xchg16U] + .map { ($0, .i64Store16, .i64Load16U, .wasmi64) } + + [.i64Add32U, .i64Sub32U, .i64And32U, .i64Or32U, .i64Xor32U, .i64Xchg32U] + .map { ($0, .i64Store32, .i64Load32U, .wasmi64) } let initialValue: Int64 = 12 let operand: Int64 = 10 @@ -233,30 +253,46 @@ class WasmAtomicsTests: XCTestCase { for memory in [unsharedMemory, sharedMemory] { for (op, storeType, loadType, valueType) in testCases { let returnType = valueType - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) - let rhs = (valueType == .wasmi32) ? f.consti32(Int32(operand)) : f.consti64(operand) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + let rhs = + (valueType == .wasmi32) + ? f.consti32(Int32(operand)) : f.consti64(operand) let lhs = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: lhs, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicRMW(memory: memory, lhs: lhs, rhs: rhs, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: lhs, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: lhs, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicRMW( + memory: memory, lhs: lhs, rhs: rhs, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: lhs, loadType: loadType, offset: 0) return [originalValue, finalValue] } - let expectedFinal = switch op { - case .i32Add, .i32Add8U, .i32Add16U, .i64Add, .i64Add8U, .i64Add16U, .i64Add32U: - initialValue + operand - case .i32Sub, .i32Sub8U, .i32Sub16U, .i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U: - initialValue - operand - case .i32And, .i32And8U, .i32And16U, .i64And, .i64And8U, .i64And16U, .i64And32U: - initialValue & operand - case .i32Or, .i32Or8U, .i32Or16U, .i64Or, .i64Or8U, .i64Or16U, .i64Or32U: - initialValue | operand - case .i32Xor, .i32Xor8U, .i32Xor16U, .i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U: - initialValue ^ operand - case .i32Xchg, .i32Xchg8U, .i32Xchg16U, .i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U: - operand - } + let expectedFinal = + switch op { + case .i32Add, .i32Add8U, .i32Add16U, .i64Add, .i64Add8U, .i64Add16U, + .i64Add32U: + initialValue + operand + case .i32Sub, .i32Sub8U, .i32Sub16U, .i64Sub, .i64Sub8U, .i64Sub16U, + .i64Sub32U: + initialValue - operand + case .i32And, .i32And8U, .i32And16U, .i64And, .i64And8U, .i64And16U, + .i64And32U: + initialValue & operand + case .i32Or, .i32Or8U, .i32Or16U, .i64Or, .i64Or8U, .i64Or16U, + .i64Or32U: + initialValue | operand + case .i32Xor, .i32Xor8U, .i32Xor16U, .i64Xor, .i64Xor8U, .i64Xor16U, + .i64Xor32U: + initialValue ^ operand + case .i32Xchg, .i32Xchg8U, .i32Xchg16U, .i64Xchg, .i64Xchg8U, + .i64Xchg16U, .i64Xchg32U: + operand + } expectedResults.append("\(initialValue),\(expectedFinal)\n") } } @@ -282,20 +318,21 @@ class WasmAtomicsTests: XCTestCase { var expectedResults: [String] = [] let js = buildAndLiftProgram { b in - let testCases: [( - op: WasmAtomicCmpxchgType, - storeType: WasmAtomicStoreType, - loadType: WasmAtomicLoadType, - valueType: ILType - )] = [ - (.i32Cmpxchg, .i32Store, .i32Load, .wasmi32), - (.i32Cmpxchg8U, .i32Store8, .i32Load8U, .wasmi32), - (.i32Cmpxchg16U, .i32Store16, .i32Load16U, .wasmi32), - (.i64Cmpxchg, .i64Store, .i64Load, .wasmi64), - (.i64Cmpxchg8U, .i64Store8, .i64Load8U, .wasmi64), - (.i64Cmpxchg16U, .i64Store16, .i64Load16U, .wasmi64), - (.i64Cmpxchg32U, .i64Store32, .i64Load32U, .wasmi64), - ] + let testCases: + [( + op: WasmAtomicCmpxchgType, + storeType: WasmAtomicStoreType, + loadType: WasmAtomicLoadType, + valueType: ILType + )] = [ + (.i32Cmpxchg, .i32Store, .i32Load, .wasmi32), + (.i32Cmpxchg8U, .i32Store8, .i32Load8U, .wasmi32), + (.i32Cmpxchg16U, .i32Store16, .i32Load16U, .wasmi32), + (.i64Cmpxchg, .i64Store, .i64Load, .wasmi64), + (.i64Cmpxchg8U, .i64Store8, .i64Load8U, .wasmi64), + (.i64Cmpxchg16U, .i64Store16, .i64Load16U, .wasmi64), + (.i64Cmpxchg32U, .i64Store32, .i64Load32U, .wasmi64), + ] let initialValue: Int64 = 12 let replacement: Int64 = 10 @@ -308,27 +345,49 @@ class WasmAtomicsTests: XCTestCase { for (op, storeType, loadType, valueType) in testCases { let returnType = valueType // Successful exchange - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) let expected = valueToStore - let replacement = (valueType == .wasmi32) ? f.consti32(Int32(replacement)) : f.consti64(replacement) + let replacement = + (valueType == .wasmi32) + ? f.consti32(Int32(replacement)) : f.consti64(replacement) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicCmpxchg(memory: memory, address: address, expected: expected, replacement: replacement, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicCmpxchg( + memory: memory, address: address, expected: expected, + replacement: replacement, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: loadType, offset: 0) return [originalValue, finalValue] } expectedResults.append("\(initialValue),\(replacement)\n") // Unsuccessful exchange - wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { f, _, _ in - let valueToStore = (valueType == .wasmi32) ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) - let expected = (valueType == .wasmi32) ? f.consti32(Int32(initialValue - 1)) : f.consti64(initialValue - 1) - let replacement = (valueType == .wasmi32) ? f.consti32(Int32(replacement)) : f.consti64(replacement) + wasmModule.addWasmFunction(with: [] => [returnType, returnType]) { + f, _, _ in + let valueToStore = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue)) : f.consti64(initialValue) + let expected = + (valueType == .wasmi32) + ? f.consti32(Int32(initialValue - 1)) : f.consti64(initialValue - 1) + let replacement = + (valueType == .wasmi32) + ? f.consti32(Int32(replacement)) : f.consti64(replacement) let address = f.consti32(8) - f.wasmAtomicStore(memory: memory, address: address, value: valueToStore, storeType: storeType, offset: 0) - let originalValue = f.wasmAtomicCmpxchg(memory: memory, address: address, expected: expected, replacement: replacement, op: op, offset: 0) - let finalValue = f.wasmAtomicLoad(memory: memory, address: address, loadType: loadType, offset: 0) + f.wasmAtomicStore( + memory: memory, address: address, value: valueToStore, + storeType: storeType, offset: 0) + let originalValue = f.wasmAtomicCmpxchg( + memory: memory, address: address, expected: expected, + replacement: replacement, op: op, offset: 0) + let finalValue = f.wasmAtomicLoad( + memory: memory, address: address, loadType: loadType, offset: 0) return [originalValue, finalValue] } expectedResults.append("\(initialValue),\(initialValue)\n") @@ -349,4 +408,4 @@ class WasmAtomicsTests: XCTestCase { testForOutput(program: js, runner: runner, outputString: expectedOutput) } -} \ No newline at end of file +} diff --git a/Tests/FuzzilliTests/WasmTableTests.swift b/Tests/FuzzilliTests/WasmTableTests.swift index 2e4f9335f..9234ab415 100644 --- a/Tests/FuzzilliTests/WasmTableTests.swift +++ b/Tests/FuzzilliTests/WasmTableTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli class WasmTableTests: XCTestCase { @@ -22,7 +23,8 @@ class WasmTableTests: XCTestCase { let js = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in - let table = wasmModule.addTable(elementType: .wasmFuncRef(), minSize: 10, maxSize: 20, isTable64: false) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), minSize: 10, maxSize: 20, isTable64: false) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { f, _, _ in let size = f.wasmTableSize(table: table) diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 8fe71c418..5006e0c91 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -13,6 +13,7 @@ // limitations under the License. import XCTest + @testable import Fuzzilli @discardableResult @@ -34,28 +35,60 @@ func testForOutput(program: String, runner: JavaScriptExecutor, outputString: St func testForOutputRegex(program: String, runner: JavaScriptExecutor, outputPattern: String) { let result = testExecuteScript(program: program, runner: runner) let matches = result.output.matches(of: try! Regex(outputPattern)) - XCTAssertEqual(matches.isEmpty, false, "Output:\n\(result.output)\nExpected output:\n\(outputPattern)Error Output:\n\(result.error)") + XCTAssertEqual( + matches.isEmpty, false, + "Output:\n\(result.output)\nExpected output:\n\(outputPattern)Error Output:\n\(result.error)" + ) } -func testForErrorOutput(program: String, runner: JavaScriptExecutor, errorMessageContains errormsg: String) { +func testForErrorOutput( + program: String, runner: JavaScriptExecutor, errorMessageContains errormsg: String +) { let result = testExecuteScript(program: program, runner: runner) - XCTAssert(result.output.contains(errormsg) || result.error.contains(errormsg), "Error messages don't match, got stdout:\n\(result.output)\nstderr:\n\(result.error)") + XCTAssert( + result.output.contains(errormsg) || result.error.contains(errormsg), + "Error messages don't match, got stdout:\n\(result.output)\nstderr:\n\(result.error)") } class WasmSignatureConversionTests: XCTestCase { func testJsSignatureConversion() { - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmi32] => [.wasmi32]) - XCTAssertEqual(ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmf32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1)])), [.wasmf32] => [.wasmi32]) + XCTAssertEqual( + ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, + availableTypes: WeightedList([ + (.wasmi32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1), + ])), [.wasmi32] => [.wasmi32]) + XCTAssertEqual( + ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, + availableTypes: WeightedList([ + (.wasmf32, 1), (.wasmFuncRef(), 1), (.wasmExternRef(), 1), + ])), [.wasmf32] => [.wasmi32]) } func testWasmSignatureConversion() { - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmi64] => [.wasmf32]), [.integer, .bigint] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmExnRef()] => [.wasmf64]), [.integer, .jsAnything] => .float) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmExternRef(), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.Index(), nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmRef(.WasmExtern, nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature([.wasmi32, .wasmi64] => [.wasmf32]), + [.integer, .bigint] => .float) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmi32, .wasmExnRef()] => [.wasmf64]), [.integer, .jsAnything] => .float) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmExternRef(), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmRef(.Index(), nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature( + [.wasmRef(.WasmExtern, nullability: false), .wasmFuncRef()] => [.wasmf64, .wasmf64]), + [.jsAnything, .function()] => .jsArray) // TODO(cffsmith): Change this once we know how we want to represent .wasmSimd128 types in JS. - XCTAssertEqual(ProgramBuilder.convertWasmSignatureToJsSignature([.wasmSimd128] => [.wasmSimd128]), [.jsAnything] => .jsAnything) + XCTAssertEqual( + ProgramBuilder.convertWasmSignatureToJsSignature([.wasmSimd128] => [.wasmSimd128]), + [.jsAnything] => .jsAnything) } } @@ -71,12 +104,15 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, arg in let var64 = function.consti64(41) - let added = function.wasmi64BinOp(var64, arg[0], binOpKind: WasmIntegerBinaryOpKind.Add) + let added = function.wasmi64BinOp( + var64, arg[0], binOpKind: WasmIntegerBinaryOpKind.Add) return [added] } - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { function, label, arg in - let subbed = function.wasmi64BinOp(arg[0], arg[1], binOpKind: WasmIntegerBinaryOpKind.Sub) + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { + function, label, arg in + let subbed = function.wasmi64BinOp( + arg[0], arg[1], binOpKind: WasmIntegerBinaryOpKind.Sub) return [subbed] } } @@ -88,7 +124,8 @@ class WasmFoundationTests: XCTestCase { let num = b.loadBigInt(1) let res1 = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [num]) - let res2 = b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: [res1, num]) + let res2 = b.callMethod( + module.getExportedMethod(at: 2), on: exports, withArgs: [res1, num]) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -104,7 +141,8 @@ class WasmFoundationTests: XCTestCase { let runner = try GetJavaScriptExecutorOrSkipTest() let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in function.wasmBranchIf(args[0], to: label, args: args) return [function.consti32(-1)] } @@ -113,7 +151,8 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let res0 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res0)]) } @@ -125,18 +164,27 @@ class WasmFoundationTests: XCTestCase { let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in // Test branch if and fall-through. - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmBranchIf(args[0], to: label, args: [function.consti32(1), function.consti64(2), function.constf32(3)]) + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmBranchIf( + args[0], to: label, + args: [function.consti32(1), function.consti64(2), function.constf32(3)]) return [function.consti32(4), function.consti64(5), function.constf32(6)] } // Test explicit return. - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmReturn([function.consti32(7), function.consti64(8), function.constf32(9)]) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmReturn([ + function.consti32(7), function.consti64(8), function.constf32(9), + ]) return [function.consti32(-1), function.consti64(-1), function.constf32(-1)] } // Test unconditional branch. - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { function, label, args in - function.wasmBranch(to: label, args: [function.consti32(10), function.consti64(11), function.constf32(12)]) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi64, .wasmf32]) { + function, label, args in + function.wasmBranch( + to: label, + args: [function.consti32(10), function.consti64(11), function.constf32(12)]) return [function.consti32(-1), function.consti64(-1), function.constf32(-1)] } } @@ -144,13 +192,16 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") [ - b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]), - b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]), + b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]), + b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]), b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: []), b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: []), - ].forEach {b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: $0)])} + ].forEach { b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: $0)]) } } - testForOutput(program: jsProg, runner: runner, outputString: "1,2,3\n4,5,6\n7,8,9\n10,11,12\n") + testForOutput( + program: jsProg, runner: runner, outputString: "1,2,3\n4,5,6\n7,8,9\n10,11,12\n") } func testExportNaming() throws { @@ -158,14 +209,23 @@ class WasmFoundationTests: XCTestCase { let jsProg = buildAndLiftProgram { b in // This test tests whether re-exported imports and module defined globals are re-ordered from the typer. let wasmGlobali32: Variable = b.createWasmGlobal(value: .wasmi32(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali32), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi32, isMutable: true))) - - let wasmGlobalf32: Variable = b.createWasmGlobal(value: .wasmf32(42.0), isMutable: false) - XCTAssertEqual(b.type(of: wasmGlobalf32), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmf32, isMutable: false))) + XCTAssertEqual( + b.type(of: wasmGlobali32), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi32, isMutable: true))) + + let wasmGlobalf32: Variable = b.createWasmGlobal( + value: .wasmf32(42.0), isMutable: false) + XCTAssertEqual( + b.type(of: wasmGlobalf32), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmf32, isMutable: false))) let module = b.buildWasmModule { wasmModule in // Imports are always before internal globals, this breaks the logic if we add a global and then import a global. - wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in + wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in // This load forces an import // This should be iwg0 fun.wasmLoadGlobal(globalVariable: wasmGlobalf32) @@ -173,7 +233,7 @@ class WasmFoundationTests: XCTestCase { } // This adds an internally defined global, it should be wg0 wasmModule.addGlobal(wasmGlobal: .wasmi64(4141), isMutable: true) - wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in + wasmModule.addWasmFunction(with: [] => []) { fun, _, _ in // This load forces an import // This should be iwg1 fun.wasmLoadGlobal(globalVariable: wasmGlobali32) @@ -183,20 +243,30 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: ["iwg0", "iwg1", "wg0"], withMethods: ["w1", "w0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: ["iwg0", "iwg1", "wg0"], + withMethods: ["w1", "w0"])) let outputFunc = b.createNamedVariable(forBuiltin: "output") // Now let's actually see what the re-exported values are and see that the types don't match with what the programbuilder will see. // TODO: Is this an issue? will the programbuilder still be queriable for variables? I think so, it is internally consistent within the module... let firstExport = b.getProperty("iwg0", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: firstExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: firstExport))]) let secondExport = b.getProperty("wg0", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: secondExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: secondExport))]) let thirdExport = b.getProperty("iwg1", of: exports) - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.getProperty("value", of: thirdExport))]) + b.callFunction( + outputFunc, + withArgs: [b.callMethod("toString", on: b.getProperty("value", of: thirdExport))]) } testForOutput(program: jsProg, runner: runner, outputString: "42\n4141\n1337\n") @@ -222,28 +292,43 @@ class WasmFoundationTests: XCTestCase { XCTAssertEqual(b.type(of: functionB).signature, [.integer] => .number) let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { + function, label, args in // Manually set the availableTypes here for testing - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([(.wasmi64, 1)])) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, + availableTypes: WeightedList([(.wasmi64, 1)])) XCTAssertEqual(wasmSignature, [.wasmi64] => [.wasmi64]) - let varA = function.wasmJsCall(function: functionA, withArgs: [args[0]], withWasmSignature: wasmSignature)! + let varA = function.wasmJsCall( + function: functionA, withArgs: [args[0]], withWasmSignature: wasmSignature)! return [varA] } wasmModule.addWasmFunction(with: [] => [.wasmf32]) { function, _, _ in // Manually set the availableTypes here for testing - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionB).signature!, availableTypes: WeightedList([(.wasmi32, 1), (.wasmf32, 1)])) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionB).signature!, + availableTypes: WeightedList([(.wasmi32, 1), (.wasmf32, 1)])) XCTAssertEqual(wasmSignature.parameterTypes.count, 1) - XCTAssert(wasmSignature.parameterTypes[0] == .wasmi32 || wasmSignature.parameterTypes[0] == .wasmf32) - XCTAssert(wasmSignature.outputTypes == [.wasmi32] || wasmSignature.outputTypes == [.wasmf32]) - let varA = wasmSignature.parameterTypes[0] == .wasmi32 ? function.consti32(1337) : function.constf32(1337) - let varRet = function.wasmJsCall(function: functionB, withArgs: [varA], withWasmSignature: wasmSignature)! + XCTAssert( + wasmSignature.parameterTypes[0] == .wasmi32 + || wasmSignature.parameterTypes[0] == .wasmf32) + XCTAssert( + wasmSignature.outputTypes == [.wasmi32] + || wasmSignature.outputTypes == [.wasmf32]) + let varA = + wasmSignature.parameterTypes[0] == .wasmi32 + ? function.consti32(1337) : function.constf32(1337) + let varRet = function.wasmJsCall( + function: functionB, withArgs: [varA], withWasmSignature: wasmSignature)! return [varRet] } wasmModule.addWasmFunction(with: [] => [.wasmf32]) { function, _, _ in let varA = function.constf32(1337.1) - let varRet = function.wasmJsCall(function: functionB, withArgs: [varA], withWasmSignature: [.wasmf32] => [.wasmf32])! + let varRet = function.wasmJsCall( + function: functionB, withArgs: [varA], + withWasmSignature: [.wasmf32] => [.wasmf32])! return [varRet] } } @@ -261,7 +346,8 @@ class WasmFoundationTests: XCTestCase { b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res1)]) // We do not control whether the JS function is imported with a floating point or an integer type, so the // fractional digits might be lost. Round the result to make the output predictable. - let res2Rounded = b.callFunction(b.createNamedVariable(forBuiltin: "Math.round"), withArgs: [res2]) + let res2Rounded = b.callFunction( + b.createNamedVariable(forBuiltin: "Math.round"), withArgs: [res2]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res2Rounded)]) } @@ -286,7 +372,8 @@ class WasmFoundationTests: XCTestCase { let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports) let integer = b.loadBigInt(1) - let res1 = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [integer]) + let res1 = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [integer]) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -338,14 +425,22 @@ class WasmFoundationTests: XCTestCase { let tag = wasmModule.addTag(parameterTypes: [.wasmi32, .wasmi32]) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { _ in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123), function.consti32(456)]) - }, catchClauses: [(tag: tag, body: { _, _, e in - // The exception values are e[0] = 123 and e[1] = 456. - function.wasmReassign(variable: e[0], to: e[1]) - // The exception values should now be e[0] = 456, e[1] = 456. - function.wasmReturn(e[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { _ in + function.WasmBuildThrow( + tag: tag, inputs: [function.consti32(123), function.consti32(456)]) + }, + catchClauses: [ + ( + tag: tag, + body: { _, _, e in + // The exception values are e[0] = 123 and e[1] = 456. + function.wasmReassign(variable: e[0], to: e[1]) + // The exception values should now be e[0] = 456, e[1] = 456. + function.wasmReturn(e[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -381,12 +476,15 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobali64: Variable = b.createWasmGlobal(value: .wasmi64(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: wasmGlobali64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .wasmi64(1339), isMutable: true) - // Function 0 wasmModule.addWasmFunction(with: [] => []) { function, _, _ in // This forces an import of the wasmGlobali64 @@ -420,9 +518,11 @@ class WasmFoundationTests: XCTestCase { let nameOfExportedGlobals = ["iwg0", "wg0"] let nameOfExportedFunctions = ["w0", "w1", "w2"] - - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: nameOfExportedGlobals, withMethods: nameOfExportedFunctions)) - + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: nameOfExportedGlobals, + withMethods: nameOfExportedFunctions)) let value = b.getProperty("value", of: wasmGlobali64) let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -451,7 +551,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in // Note that globals of exnref can only be defined in wasm, not in JS. let global = wasmModule.addGlobal(wasmGlobal: .exnref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmExnRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmExnRef(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let value = function.wasmLoadGlobal(globalVariable: global) @@ -460,8 +564,12 @@ class WasmFoundationTests: XCTestCase { // Throw an exception, catch it and store it in the global. wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [catchLabel], catches: [.AllRef]) { _, _ in + let exnref = function.wasmBuildBlockWithResults( + with: [] => [.wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [catchLabel], catches: [.AllRef] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(42)]) return [] } @@ -473,9 +581,14 @@ class WasmFoundationTests: XCTestCase { // Rethrow the exception stored in the global, catch it and extract the integer. wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.Ref] + ) { _, _ in + function.wasmBuildThrowRef( + exception: function.wasmLoadGlobal(globalVariable: global)) return [] } return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] @@ -509,9 +622,14 @@ class WasmFoundationTests: XCTestCase { let otherModule = b.buildWasmModule { wasmModule in // Rethrow the exception stored in the global, catch it and extract the integer. wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.Ref]) { _, _ in - function.wasmBuildThrowRef(exception: function.wasmLoadGlobal(globalVariable: global)) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.Ref] + ) { _, _ in + function.wasmBuildThrowRef( + exception: function.wasmLoadGlobal(globalVariable: global)) return [] } return [function.consti32(-1), function.wasmRefNull(type: .wasmExnRef())] @@ -538,7 +656,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .externref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmExternRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmExternRef(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] @@ -579,7 +701,11 @@ class WasmFoundationTests: XCTestCase { // TODO(pawkra): add shared ref variant. let global: Variable = b.createWasmGlobal(value: .externref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmExternRef(), isMutable: true))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "undefined" (because we didn't provide an explicit initialization). @@ -604,7 +730,11 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in let global = wasmModule.addGlobal(wasmGlobal: .i31ref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: .wasmI31Ref(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: .wasmI31Ref(), isMutable: true))) wasmModule.addWasmFunction(with: [] => [.wasmI31Ref()]) { function, label, args in [function.wasmLoadGlobal(globalVariable: global)] @@ -644,7 +774,11 @@ class WasmFoundationTests: XCTestCase { // TODO(pawkra): add shared ref variant. let global: Variable = b.createWasmGlobal(value: .i31ref, isMutable: true) - XCTAssertEqual(b.type(of: global), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(), isMutable: true))) + XCTAssertEqual( + b.type(of: global), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmI31Ref(), isMutable: true))) let outputFunc = b.createNamedVariable(forBuiltin: "output") // The initial value is "null" (because we didn't provide an explicit initialization). @@ -668,16 +802,25 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let javaScriptTable = b.createWasmTable(elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64) - XCTAssertEqual(b.type(of: javaScriptTable), .wasmTable(wasmTableType: WasmTableType(elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64, knownEntries: []))) + let javaScriptTable = b.createWasmTable( + elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), isTable64: isTable64) + XCTAssertEqual( + b.type(of: javaScriptTable), + .wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmExternRef(), limits: Limits(min: 5, max: 25), + isTable64: isTable64, knownEntries: []))) let object = b.createObject(with: ["a": b.loadInt(41), "b": b.loadInt(42)]) // Set a value into the table - b.callMethod("set", on: javaScriptTable, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1), object]) + b.callMethod( + "set", on: javaScriptTable, + withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1), object]) let module = b.buildWasmModule { wasmModule in - let tableRef = wasmModule.addTable(elementType: .wasmExternRef(), minSize: 2, isTable64: isTable64) + let tableRef = wasmModule.addTable( + elementType: .wasmExternRef(), minSize: 2, isTable64: isTable64) wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, _, _ in let offset = isTable64 ? function.consti64(0) : function.consti32(0) @@ -696,7 +839,8 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let json = b.createNamedVariable(forBuiltin: "JSON") - b.callFunction(outputFunc, withArgs: [b.callMethod("stringify", on: json, withArgs: [res0])]) + b.callFunction( + outputFunc, withArgs: [b.callMethod("stringify", on: json, withArgs: [res0])]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -726,36 +870,49 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, params in [function.wasmi32BinOp(params[0], function.consti32(1), binOpKind: .Add)] } - wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), .init(indexInTable: 1, signature: [] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: isTable64) + wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), + .init(indexInTable: 1, signature: [] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: isTable64) } let exports = module.loadExports() let table = b.getProperty("wt0", of: exports) - XCTAssertEqual(b.type(of: exports), .object(ofGroup: "_fuzz_WasmExports0", withProperties: ["wt0"], withMethods: ["w0", "iw0"])) + XCTAssertEqual( + b.type(of: exports), + .object( + ofGroup: "_fuzz_WasmExports0", withProperties: ["wt0"], withMethods: ["w0", "iw0"])) let importedFunction = b.getProperty("iw0", of: exports) XCTAssertEqual(b.type(of: importedFunction), .function([] => .bigint)) // This is the table type that we expect to see on the exports based on the dynamic object group typing. - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: isTable64, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), - .init(indexInTable: 1, signature: [] => [.wasmi64]) - - ])) + let tableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: isTable64, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi32] => [.wasmi32]), + .init(indexInTable: 1, signature: [] => [.wasmi64]), + + ])) XCTAssertEqual(b.type(of: table), tableType) - let tableElement0 = b.callMethod("get", on: table, withArgs: [isTable64 ? b.loadBigInt(0) : b.loadInt(0)]) - let tableElement1 = b.callMethod("get", on: table, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1)]) + let tableElement0 = b.callMethod( + "get", on: table, withArgs: [isTable64 ? b.loadBigInt(0) : b.loadInt(0)]) + let tableElement1 = b.callMethod( + "get", on: table, withArgs: [isTable64 ? b.loadBigInt(1) : b.loadInt(1)]) let output0 = b.callFunction(tableElement0, withArgs: [b.loadInt(42)]) let output1 = b.callFunction(tableElement1, withArgs: []) @@ -792,20 +949,31 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: false) - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - let results = fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: false) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + let results = fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.wasmi64BinOp(results[0], results[1], binOpKind: .Add)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) } } @@ -842,37 +1010,53 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - wasmModule.addTable(elementType: .wasmFuncRef(), + wasmModule.addTable( + elementType: .wasmFuncRef(), minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], definedEntryValues: [wasmFunction, jsFunction], isTable64: false) } let table = b.getProperty("wt0", of: module.loadExports()) - let tableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), - .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]) - ])) + let tableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ])) XCTAssertEqual(b.type(of: table), tableType) let module2 = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - let results = fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + let results = fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.wasmi64BinOp(results[0], results[1], binOpKind: .Add)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) } - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmFuncRef()]) { function, label, params in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmFuncRef()]) { + function, label, params in [function.wasmTableGet(tableRef: table, idx: params[0])] } - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { + function, label, params in [params[0], params[0]] } } @@ -883,14 +1067,16 @@ class WasmFoundationTests: XCTestCase { let reexportedTable = b.getProperty("iwt0", of: exports) // This is the table type that we expect to see on the exports based on the dynamic object group typing. - let reexportedTableType = ILType.wasmTable(wasmTableType: WasmTableType(elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, knownEntries: [ - .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), - .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]) - - ])) + let reexportedTableType = ILType.wasmTable( + wasmTableType: WasmTableType( + elementType: .wasmFuncRef(), limits: Limits(min: 10), isTable64: false, + knownEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + + ])) XCTAssertEqual(b.type(of: reexportedTable), reexportedTableType) - let callIndirectSig0 = b.getProperty(module2.getExportedMethod(at: 0), of: exports) let result0 = b.callFunction(callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(10)]) let callIndirectSig1 = b.getProperty(module2.getExportedMethod(at: 1), of: exports) @@ -906,8 +1092,11 @@ class WasmFoundationTests: XCTestCase { // It is also possible to change the slot and perform the call_indirect now pointing to a // different function as long as signatures still match. - b.callMethod("set", on: table, withArgs: [b.loadInt(0), b.getProperty(module2.getExportedMethod(at: 3), of: exports)]) - let resultNew = b.callFunction(callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(42)]) + b.callMethod( + "set", on: table, + withArgs: [b.loadInt(0), b.getProperty(module2.getExportedMethod(at: 3), of: exports)]) + let resultNew = b.callFunction( + callIndirectSig0, withArgs: [b.loadInt(0), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: resultNew)]) let prog = b.finalize() @@ -925,17 +1114,23 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, params in + let callee = wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, params in return [function.wasmi32BinOp(params[0], params[1], binOpKind: .Sub)] } - let calleeMultiResult = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in + let calleeMultiResult = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in return [function.consti32(100), function.consti32(200)] } wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, params in - let callResult = function.wasmCallDirect(signature: [.wasmi32, .wasmi32] => [.wasmi32], function: callee, functionArgs: [params[0], function.consti32(1)]) - let multiResult = function.wasmCallDirect(signature: [] => [.wasmi32, .wasmi32], function: calleeMultiResult, functionArgs: []) + let callResult = function.wasmCallDirect( + signature: [.wasmi32, .wasmi32] => [.wasmi32], function: callee, + functionArgs: [params[0], function.consti32(1)]) + let multiResult = function.wasmCallDirect( + signature: [] => [.wasmi32, .wasmi32], function: calleeMultiResult, + functionArgs: []) let sum1 = function.wasmi32BinOp(multiResult[0], multiResult[1], binOpKind: .Add) return [function.wasmi32BinOp(sum1, callResult[0], binOpKind: .Add)] } @@ -964,12 +1159,15 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in + let callee = wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in return [function.consti32(100), function.consti32(200)] } - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { function, label, params in - function.wasmReturnCallDirect(signature: [] => [.wasmi32, .wasmi32], function: callee, functionArgs: []) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32]) { + function, label, params in + function.wasmReturnCallDirect( + signature: [] => [.wasmi32, .wasmi32], function: callee, functionArgs: []) return [function.consti32(-1), function.consti32(-1)] } } @@ -996,20 +1194,31 @@ class WasmFoundationTests: XCTestCase { } let module = b.buildWasmModule { wasmModule in - let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) { function, label, params in + let wasmFunction = wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64, .wasmi64]) + { function, label, params in return [params[0], function.consti64(1)] } - let table = wasmModule.addTable(elementType: .wasmFuncRef(), - minSize: 10, - definedEntries: [.init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64])], - definedEntryValues: [wasmFunction, jsFunction], - isTable64: false) - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi64]) { fn, label, params in - fn.wasmReturnCallIndirect(signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + let table = wasmModule.addTable( + elementType: .wasmFuncRef(), + minSize: 10, + definedEntries: [ + .init(indexInTable: 0, signature: [.wasmi64] => [.wasmi64, .wasmi64]), + .init(indexInTable: 1, signature: [.wasmi64] => [.wasmi64]), + ], + definedEntryValues: [wasmFunction, jsFunction], + isTable64: false) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi64]) { + fn, label, params in + fn.wasmReturnCallIndirect( + signature: [.wasmi64] => [.wasmi64, .wasmi64], table: table, + functionArgs: [params[1]], tableIndex: params[0]) return [fn.consti64(-1), fn.consti64(-1)] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { fn, label, params in - fn.wasmReturnCallIndirect(signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], tableIndex: params[0]) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + fn, label, params in + fn.wasmReturnCallIndirect( + signature: [.wasmi64] => [.wasmi64], table: table, functionArgs: [params[1]], + tableIndex: params[0]) return [fn.consti64(-1)] } } @@ -1044,31 +1253,43 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() - let wasmMemory: Variable = b.createWasmMemory(minPages: 10, maxPages: 20, isShared: isShared, isMemory64: isMemory64) - XCTAssertEqual(b.type(of: wasmMemory), .wasmMemory(limits: Limits(min: 10, max: 20), isShared: isShared, isMemory64: isMemory64)) + let wasmMemory: Variable = b.createWasmMemory( + minPages: 10, maxPages: 20, isShared: isShared, isMemory64: isMemory64) + XCTAssertEqual( + b.type(of: wasmMemory), + .wasmMemory( + limits: Limits(min: 10, max: 20), isShared: isShared, isMemory64: isMemory64)) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in let value = function.consti32(1337) let offset = isMemory64 ? function.consti64(10) : function.consti32(10) - function.wasmMemoryStore(memory: wasmMemory, dynamicOffset: offset, value: value, storeType: .I32StoreMem, staticOffset: 0) - let val = function.wasmMemoryLoad(memory: wasmMemory, dynamicOffset: offset, loadType: .I64LoadMem, staticOffset: 0) + function.wasmMemoryStore( + memory: wasmMemory, dynamicOffset: offset, value: value, + storeType: .I32StoreMem, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: wasmMemory, dynamicOffset: offset, loadType: .I64LoadMem, + staticOffset: 0) return [val] } } let viewBuiltin = b.createNamedVariable(forBuiltin: "DataView") - XCTAssertEqual(b.type(of: b.getProperty("buffer", of: wasmMemory)), .jsArrayBuffer | .jsSharedArrayBuffer) + XCTAssertEqual( + b.type(of: b.getProperty("buffer", of: wasmMemory)), + .jsArrayBuffer | .jsSharedArrayBuffer) let view = b.construct(viewBuiltin, withArgs: [b.getProperty("buffer", of: wasmMemory)]) // Read the value of the memory. - let value = b.callMethod("getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) + let value = b.callMethod( + "getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) let exports = module.loadExports() let res0 = b.callMethod(module.getExportedMethod(at: 0), on: exports) - let valueAfter = b.callMethod("getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) + let valueAfter = b.callMethod( + "getUint32", on: view, withArgs: [b.loadInt(10), b.loadBool(true)]) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: res0)]) @@ -1102,21 +1323,28 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - let memory = wasmModule.addMemory(minPages: 5, maxPages: 12, isShared: isShared, isMemory64: isMemory64) + let memory = wasmModule.addMemory( + minPages: 5, maxPages: 12, isShared: isShared, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let value = function.consti64(1337) let storeOffset = function.memoryArgument(8, memoryTypeInfo) - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: .I64StoreMem, staticOffset: 2) + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: .I64StoreMem, staticOffset: 2) let loadOffset = function.memoryArgument(10, memoryTypeInfo) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, + staticOffset: 0) return [val] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) testForOutput(program: jsProg, runner: runner, outputString: "1337\n") @@ -1135,7 +1363,7 @@ class WasmFoundationTests: XCTestCase { func simpleDataSegmentInit(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 5, maxPages: 12, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1144,14 +1372,22 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(16), dataSegmentOffset: i32(3), nrOfBytesToUpdate: i32(8)) - return [f.wasmMemoryLoad(memory: memory, dynamicOffset: memIdx(16), loadType: .I64LoadMem, staticOffset: 0)] + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(16), + dataSegmentOffset: i32(3), nrOfBytesToUpdate: i32(8)) + return [ + f.wasmMemoryLoad( + memory: memory, dynamicOffset: memIdx(16), loadType: .I64LoadMem, + staticOffset: 0) + ] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) } // "AAAABBBB" -> 0x4242424241414141 @@ -1169,7 +1405,7 @@ class WasmFoundationTests: XCTestCase { func testDropDataSegment() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in let segment = wasmModule.addDataSegment(segment: [0xAA]) @@ -1185,7 +1421,7 @@ class WasmFoundationTests: XCTestCase { func testDropDataSegmentTwoTimes() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in let segment = wasmModule.addDataSegment(segment: [0xAA]) @@ -1203,7 +1439,7 @@ class WasmFoundationTests: XCTestCase { func testInitSingleMemoryFromTwoSegments(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1213,14 +1449,24 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment1, memory: memory, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) - f.wasmMemoryInit(dataSegment: segment2, memory: memory, memoryOffset: memIdx(4), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) - return [f.wasmMemoryLoad(memory: memory, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0)] + f.wasmMemoryInit( + dataSegment: segment1, memory: memory, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) + f.wasmMemoryInit( + dataSegment: segment2, memory: memory, memoryOffset: memIdx(4), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(4)) + return [ + f.wasmMemoryLoad( + memory: memory, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) + ] } } let res = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } // "AAAABBBB" -> 0x4242424241414141 @@ -1238,7 +1484,7 @@ class WasmFoundationTests: XCTestCase { func testInitTwoMemoriesFromOneSegment(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory1 = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory1).wasmMemoryType! @@ -1248,20 +1494,32 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory1, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) - f.wasmMemoryInit(dataSegment: segment, memory: memory2, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) - let val1 = f.wasmMemoryLoad(memory: memory1, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0) - let val2 = f.wasmMemoryLoad(memory: memory2, dynamicOffset: memIdx(0), loadType: .I64LoadMem, staticOffset: 0) + f.wasmMemoryInit( + dataSegment: segment, memory: memory1, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory2, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(8)) + let val1 = f.wasmMemoryLoad( + memory: memory1, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) + let val2 = f.wasmMemoryLoad( + memory: memory2, dynamicOffset: memIdx(0), loadType: .I64LoadMem, + staticOffset: 0) return [val1, val2] } } let res = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } // "AAAABBBB" -> 0x4242424241414141 - testForOutput(program: jsProg, runner: runner, outputString: "4774451407296217409,4774451407296217409\n") + testForOutput( + program: jsProg, runner: runner, + outputString: "4774451407296217409,4774451407296217409\n") } func testInitTwoMemoriesFromOneSegment32() throws { @@ -1275,7 +1533,7 @@ class WasmFoundationTests: XCTestCase { func testMemoryInitOutOfBoundsMemory(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1285,14 +1543,18 @@ class WasmFoundationTests: XCTestCase { // Memory size is one page (65536 bytes), so this should be out of bounds. let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(65536), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(1)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(65536), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(1)) return [] } } b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) } - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } func testMemoryInitOutOfBoundsMemory32() throws { @@ -1306,7 +1568,7 @@ class WasmFoundationTests: XCTestCase { func testMemoryInitOutOfBoundsSegment(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let memory = wasmModule.addMemory(minPages: 1, isMemory64: isMemory64) let memoryTypeInfo = b.type(of: memory).wasmMemoryType! @@ -1316,14 +1578,18 @@ class WasmFoundationTests: XCTestCase { // Data segment size is 1, so this should be out of bounds. let i32 = f.consti32 let memIdx: (Int64) -> Variable = { v in f.memoryArgument(v, memoryTypeInfo) } - f.wasmMemoryInit(dataSegment: segment, memory: memory, memoryOffset: memIdx(0), dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(2)) + f.wasmMemoryInit( + dataSegment: segment, memory: memory, memoryOffset: memIdx(0), + dataSegmentOffset: i32(0), nrOfBytesToUpdate: i32(2)) return [] } } b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) } - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } func testMemoryInitOutOfBoundsSegment32() throws { @@ -1334,7 +1600,7 @@ class WasmFoundationTests: XCTestCase { try testMemoryInitOutOfBoundsSegment(isMemory64: true) } - func testMemory64Index() throws{ + func testMemory64Index() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -1349,16 +1615,22 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => []) { function, _, _ in let value = function.consti64(1337) let storeOffset = function.consti64(1 << 32) - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: .I64StoreMem, staticOffset: 2) + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: .I64StoreMem, staticOffset: 2) return [] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) - testForErrorOutput(program: jsProg, runner: runner, errorMessageContains: "RuntimeError: memory access out of bounds") + testForErrorOutput( + program: jsProg, runner: runner, + errorMessageContains: "RuntimeError: memory access out of bounds") } // This test doesn't check the result of the Wasm loads, just exectues them. @@ -1379,7 +1651,9 @@ class WasmFoundationTests: XCTestCase { for loadType in WasmMemoryLoadType.allCases { wasmModule.addWasmFunction(with: [] => [loadType.numberType()]) { function, _, _ in let loadOffset = isMemory64 ? function.consti64(9) : function.consti32(9) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: loadType, staticOffset: 0) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: loadType, + staticOffset: 0) return [val] } } @@ -1387,7 +1661,9 @@ class WasmFoundationTests: XCTestCase { for idx in 0.. []) { function, _, _ in let storeOffset = isMemory64 ? function.consti64(13) : function.consti32(13) - let value = switch storeType.numberType() { + let value = + switch storeType.numberType() { case .wasmi32: function.consti32(8) case .wasmi64: function.consti64(8) case .wasmf32: function.constf32(8.4) case .wasmf64: function.constf64(8.4) case .wasmSimd128: function.constSimd128(value: Array(0..<16)) default: fatalError("Non-existent value to be stored") - } - function.wasmMemoryStore(memory: memory, dynamicOffset: storeOffset, value: value, storeType: storeType, staticOffset: 2) + } + function.wasmMemoryStore( + memory: memory, dynamicOffset: storeOffset, value: value, + storeType: storeType, staticOffset: 2) return [] } } @@ -1434,7 +1713,9 @@ class WasmFoundationTests: XCTestCase { for idx in 0.. [.wasmi32]) { function, _, _ in - let offset = isMemory64 ? function.consti64(Int64(42)) : function.consti32(Int32(42)) - function.wasmMemoryStore(memory: memory0, dynamicOffset: offset, value: function.constf32(1.0), storeType: .F32StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory1, dynamicOffset: offset, value: function.constf64(2.0), storeType: .F64StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory2, dynamicOffset: offset, value: function.consti32(3), storeType: .I32StoreMem, staticOffset: 0) - let load0 = function.wasmMemoryLoad(memory: memory0, dynamicOffset: offset, loadType: .F32LoadMem, staticOffset: 0) - let load1 = function.wasmMemoryLoad(memory: memory1, dynamicOffset: offset, loadType: .F64LoadMem, staticOffset: 0) - let load2 = function.wasmMemoryLoad(memory: memory2, dynamicOffset: offset, loadType: .I32LoadMem, staticOffset: 0) + let offset = + isMemory64 ? function.consti64(Int64(42)) : function.consti32(Int32(42)) + function.wasmMemoryStore( + memory: memory0, dynamicOffset: offset, value: function.constf32(1.0), + storeType: .F32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory1, dynamicOffset: offset, value: function.constf64(2.0), + storeType: .F64StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory2, dynamicOffset: offset, value: function.consti32(3), + storeType: .I32StoreMem, staticOffset: 0) + let load0 = function.wasmMemoryLoad( + memory: memory0, dynamicOffset: offset, loadType: .F32LoadMem, staticOffset: 0) + let load1 = function.wasmMemoryLoad( + memory: memory1, dynamicOffset: offset, loadType: .F64LoadMem, staticOffset: 0) + let load2 = function.wasmMemoryLoad( + memory: memory2, dynamicOffset: offset, loadType: .I32LoadMem, staticOffset: 0) let trunc0 = function.truncatef32Toi32(load0, isSigned: true) let trunc1 = function.truncatef64Toi32(load1, isSigned: true) @@ -1484,7 +1778,9 @@ class WasmFoundationTests: XCTestCase { } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -1505,14 +1801,16 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let memoryA = b.createWasmMemory(minPages: 7, maxPages: 7, isShared: false, isMemory64: isMemory64) + let memoryA = b.createWasmMemory( + minPages: 7, maxPages: 7, isShared: false, isMemory64: isMemory64) let module = b.buildWasmModule { wasmModule in let memoryB = wasmModule.addMemory(minPages: 5, maxPages: 12, isMemory64: isMemory64) let memoryC = wasmModule.addMemory(minPages: 0, maxPages: 1, isMemory64: isMemory64) [memoryA, memoryB, memoryC].forEach { memory in let addrType: ILType = isMemory64 ? .wasmi64 : .wasmi32 - wasmModule.addWasmFunction(with: [] => [addrType, addrType, addrType]) { function, label, args in + wasmModule.addWasmFunction(with: [] => [addrType, addrType, addrType]) { + function, label, args in let growBy = isMemory64 ? function.consti64(1) : function.consti32(1) return [ function.wasmMemorySize(memory: memory), @@ -1525,7 +1823,9 @@ class WasmFoundationTests: XCTestCase { (0..<3).forEach { let res = b.callMethod(module.getExportedMethod(at: $0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res)]) } let jsProg = fuzzer.lifter.lift(b.finalize()) @@ -1559,18 +1859,24 @@ class WasmFoundationTests: XCTestCase { let fillOffset = function.memoryArgument(100, memoryTypeInfo) let byteToSet = function.consti32(0xAA) let nrOfBytesToUpdate = function.memoryArgument(4, memoryTypeInfo) - function.wasmMemoryFill(memory: memory, offset: fillOffset, byteToSet: byteToSet, nrOfBytesToUpdate: nrOfBytesToUpdate) - let loadOffset = function.memoryArgument(102, memoryTypeInfo) - let val = function.wasmMemoryLoad(memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, staticOffset: 0) + function.wasmMemoryFill( + memory: memory, offset: fillOffset, byteToSet: byteToSet, + nrOfBytesToUpdate: nrOfBytesToUpdate) + let loadOffset = function.memoryArgument(102, memoryTypeInfo) + let val = function.wasmMemoryLoad( + memory: memory, dynamicOffset: loadOffset, loadType: .I32LoadMem, + staticOffset: 0) return [val] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) let jsProg = fuzzer.lifter.lift(b.finalize()) - testForOutput(program: jsProg, runner: runner, outputString: "43690\n") // 0x 00 00 AA AA + testForOutput(program: jsProg, runner: runner, outputString: "43690\n") // 0x 00 00 AA AA } func testMemoryBulkOperations32() throws { @@ -1584,17 +1890,20 @@ class WasmFoundationTests: XCTestCase { func memoryCopy(isMemory64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in let mem1 = wasmModule.addMemory(minPages: 1, maxPages: 2, isMemory64: isMemory64) let mem2 = wasmModule.addMemory(minPages: 1, maxPages: 2, isMemory64: isMemory64) let memTypeInfo = b.type(of: mem1).wasmMemoryType! - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { function, _, _ in - let setValueAtOffset = { (value: Int32, offsetValue: Int64) -> () in + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { + function, _, _ in + let setValueAtOffset = { (value: Int32, offsetValue: Int64) -> Void in let valToSet = function.consti32(value) let offset = function.memoryArgument(offsetValue, memTypeInfo) - function.wasmMemoryStore(memory: mem1, dynamicOffset: offset, value: valToSet, storeType: .I32StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: mem1, dynamicOffset: offset, value: valToSet, + storeType: .I32StoreMem, staticOffset: 0) } setValueAtOffset(111, 4) setValueAtOffset(222, 8) @@ -1603,18 +1912,24 @@ class WasmFoundationTests: XCTestCase { let dstOffset = function.memoryArgument(128, memTypeInfo) let srcOffset = function.memoryArgument(8, memTypeInfo) let size = function.memoryArgument(4, memTypeInfo) - function.wasmMemoryCopy(dstMemory: mem2, srcMemory: mem1, dstOffset: dstOffset, srcOffset: srcOffset, size: size) + function.wasmMemoryCopy( + dstMemory: mem2, srcMemory: mem1, dstOffset: dstOffset, + srcOffset: srcOffset, size: size) let loadAtOffset = { (offsetValue: Int64) -> Variable in let dynamicOffset = function.memoryArgument(offsetValue, memTypeInfo) - return function.wasmMemoryLoad(memory: mem2, dynamicOffset: dynamicOffset, loadType: .I32LoadMem, staticOffset: 0) + return function.wasmMemoryLoad( + memory: mem2, dynamicOffset: dynamicOffset, loadType: .I32LoadMem, + staticOffset: 0) } return [loadAtOffset(124), loadAtOffset(128), loadAtOffset(132)] } } let res0 = b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res0)]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("toString", on: res0)]) } testForOutput(program: jsProg, runner: runner, outputString: "0,222,0\n") @@ -1636,259 +1951,395 @@ class WasmFoundationTests: XCTestCase { let testCases: [((ProgramBuilder.WasmModule, Variable) -> Void, String)] = [ // Test v128.load. - ({wasmModule, memory in - wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(3), storeType: .I64StoreMem, staticOffset: 0) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(8), - value: function.consti64(6), storeType: .I64StoreMem, staticOffset: 0) - - let val = function.wasmSimdLoad(kind: .LoadS128, memory: memory, - dynamicOffset: const(0), staticOffset: 0) - let sum = function.wasmi64BinOp( - function.wasmSimdExtractLane(kind: .I64x2, val, 0), - function.wasmSimdExtractLane(kind: .I64x2, val, 1), binOpKind: .Add) - return [sum] - } - }, "9"), + ( + { wasmModule, memory in + wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(3), storeType: .I64StoreMem, staticOffset: 0) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(8), + value: function.consti64(6), storeType: .I64StoreMem, staticOffset: 0) + + let val = function.wasmSimdLoad( + kind: .LoadS128, memory: memory, + dynamicOffset: const(0), staticOffset: 0) + let sum = function.wasmi64BinOp( + function.wasmSimdExtractLane(kind: .I64x2, val, 0), + function.wasmSimdExtractLane(kind: .I64x2, val, 1), binOpKind: .Add) + return [sum] + } + }, "9" + ), // Test v128.store. - ({wasmModule, memory in - wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I64x2, function.consti64(21)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 0) - let loadValue1 = function.wasmMemoryLoad(memory: memory, - dynamicOffset: const(0), loadType: .I64LoadMem, staticOffset: 0) - let loadValue2 = function.wasmMemoryLoad(memory: memory, - dynamicOffset: const(8), loadType: .I64LoadMem, staticOffset: 0) - return [function.wasmi64BinOp(loadValue1, loadValue2, binOpKind: .Add)] - } - }, "42"), + ( + { wasmModule, memory in + wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I64x2, function.consti64(21)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 0) + let loadValue1 = function.wasmMemoryLoad( + memory: memory, + dynamicOffset: const(0), loadType: .I64LoadMem, staticOffset: 0) + let loadValue2 = function.wasmMemoryLoad( + memory: memory, + dynamicOffset: const(8), loadType: .I64LoadMem, staticOffset: 0) + return [function.wasmi64BinOp(loadValue1, loadValue2, binOpKind: .Add)] + } + }, "42" + ), // Test v128.load8x8_s. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(-1)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load8x8S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0)} - } - }, "-1,-1,-1,-1,-1,-1,-1,-1"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(-1)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load8x8S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0) + } + } + }, "-1,-1,-1,-1,-1,-1,-1,-1" + ), // Test v128.load8x8_u. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I8x16, function.consti32(255)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load8x8U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8U, loaded, $0)} - } - }, "255,255,255,255,255,255,255,255"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I8x16, function.consti32(255)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load8x8U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8U, loaded, $0) + } + } + }, "255,255,255,255,255,255,255,255" + ), // Test v128.load16x4_s. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(-2)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load16x4S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "-2,-2,-2,-2"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(-2)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load16x4S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "-2,-2,-2,-2" + ), // Test v128.load16x4_u. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I16x8, function.consti32(65432)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load16x4U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "65432,65432,65432,65432"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I16x8, function.consti32(65432)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load16x4U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "65432,65432,65432,65432" + ), // Test v128.load32x2_s. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat(kind: .I32x4, function.consti32(-3)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load32x2S, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "-3,-3"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat(kind: .I32x4, function.consti32(-3)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load32x2S, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "-3,-3" + ), // Test v128.load32x2_u. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - let storeValue = function.wasmSimdSplat( - kind: .I32x4, function.consti32(-171510507)) - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: storeValue, storeType: .S128StoreMem, staticOffset: 16) - let loaded = function.wasmSimdLoad(kind: .Load32x2U, memory: memory, - dynamicOffset: const(16), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "4123456789,4123456789"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + let storeValue = function.wasmSimdSplat( + kind: .I32x4, function.consti32(-171_510_507)) + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: storeValue, storeType: .S128StoreMem, staticOffset: 16) + let loaded = function.wasmSimdLoad( + kind: .Load32x2U, memory: memory, + dynamicOffset: const(16), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "4123456789,4123456789" + ), // Test v128.load8_splat. - ({wasmModule, memory in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(7), storeType: .I32StoreMem8, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load8Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<16).map {function.wasmSimdExtractLane(kind: .I8x16S, loaded, $0)} - } - }, "7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7"), + ( + { wasmModule, memory in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(7), storeType: .I32StoreMem8, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load8Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<16).map { + function.wasmSimdExtractLane(kind: .I8x16S, loaded, $0) + } + } + }, "7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7" + ), // Test v128.load16_splat. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(8), storeType: .I32StoreMem16, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load16Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0)} - } - }, "8,8,8,8,8,8,8,8"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(8), storeType: .I32StoreMem16, staticOffset: 32 + ) + let loaded = function.wasmSimdLoad( + kind: .Load16Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8S, loaded, $0) + } + } + }, "8,8,8,8,8,8,8,8" + ), // Test v128.load32_splat. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(9), storeType: .I32StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load32Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "9,9,9,9"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(9), storeType: .I32StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load32Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "9,9,9,9" + ), // Test v128.load64_splat. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(10), storeType: .I64StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load64Splat, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "10,10"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(10), storeType: .I64StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load64Splat, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "10,10" + ), // Test v128.load32_zero. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(11), storeType: .I32StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load32Zero, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, loaded, $0)} - } - }, "11,0,0,0"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(11), storeType: .I32StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load32Zero, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, loaded, $0) + } + } + }, "11,0,0,0" + ), // Test v128.load64_zero. - ({wasmModule, memory in - let returnType = (0..<2).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(12), storeType: .I64StoreMem, staticOffset: 32) - let loaded = function.wasmSimdLoad(kind: .Load64Zero, memory: memory, - dynamicOffset: const(32), staticOffset: 0) - return (0..<2).map {function.wasmSimdExtractLane(kind: .I64x2, loaded, $0)} - } - }, "12,0"), + ( + { wasmModule, memory in + let returnType = (0..<2).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(12), storeType: .I64StoreMem, staticOffset: 32) + let loaded = function.wasmSimdLoad( + kind: .Load64Zero, memory: memory, + dynamicOffset: const(32), staticOffset: 0) + return (0..<2).map { + function.wasmSimdExtractLane(kind: .I64x2, loaded, $0) + } + } + }, "12,0" + ), // Test v128.load8_lane and v128.store8_lane. - ({wasmModule, memory in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(13), storeType: .I32StoreMem8, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I8x16, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 15) - function.wasmSimdStoreLane(kind: .Store8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 15) - let reloaded = function.wasmSimdLoadLane(kind: .Load8, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<16).map {function.wasmSimdExtractLane(kind: .I8x16U, reloaded, $0)} - } - }, "42,13,42,42,42,42,42,42,42,42,42,42,42,42,42,13"), + ( + { wasmModule, memory in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(13), storeType: .I32StoreMem8, staticOffset: 64 + ) + let splat = function.wasmSimdSplat(kind: .I8x16, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 15) + function.wasmSimdStoreLane( + kind: .Store8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 15) + let reloaded = function.wasmSimdLoadLane( + kind: .Load8, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<16).map { + function.wasmSimdExtractLane(kind: .I8x16U, reloaded, $0) + } + } + }, "42,13,42,42,42,42,42,42,42,42,42,42,42,42,42,13" + ), // Test v128.load16_lane and v128.store16_lane. - ({wasmModule, memory in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(14), storeType: .I32StoreMem16, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I16x8, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 7) - function.wasmSimdStoreLane(kind: .Store16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 7) - let reloaded = function.wasmSimdLoadLane(kind: .Load16, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<8).map {function.wasmSimdExtractLane(kind: .I16x8U, reloaded, $0)} - } - }, "42,14,42,42,42,42,42,14"), + ( + { wasmModule, memory in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(14), storeType: .I32StoreMem16, + staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I16x8, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 7) + function.wasmSimdStoreLane( + kind: .Store16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 7) + let reloaded = function.wasmSimdLoadLane( + kind: .Load16, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<8).map { + function.wasmSimdExtractLane(kind: .I16x8U, reloaded, $0) + } + } + }, "42,14,42,42,42,42,42,14" + ), // Test v128.load32_lane and v128.store32_lane. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti32(15), storeType: .I32StoreMem, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I32x4, function.consti32(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 3) - function.wasmSimdStoreLane(kind: .Store32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 3) - let reloaded = function.wasmSimdLoadLane(kind: .Load32, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) - return (0..<4).map {function.wasmSimdExtractLane(kind: .I32x4, reloaded, $0)} - } - }, "42,15,42,15"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti32(15), storeType: .I32StoreMem, staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I32x4, function.consti32(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 3) + function.wasmSimdStoreLane( + kind: .Store32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 3) + let reloaded = function.wasmSimdLoadLane( + kind: .Load32, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 1) + return (0..<4).map { + function.wasmSimdExtractLane(kind: .I32x4, reloaded, $0) + } + } + }, "42,15,42,15" + ), // Test v128.load64_lane and v128.store64_lane. - ({wasmModule, memory in - let returnType = (0..<4).map {_ in ILType.wasmi64} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let const = isMemory64 ? function.consti64 : {function.consti32(Int32($0))} - function.wasmMemoryStore(memory: memory, dynamicOffset: const(0), - value: function.consti64(16), storeType: .I64StoreMem, staticOffset: 64) - let splat = function.wasmSimdSplat(kind: .I64x2, function.consti64(42)) - let loaded = function.wasmSimdLoadLane(kind: .Load64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 1) - function.wasmSimdStoreLane(kind: .Store64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 1) - let reloaded = function.wasmSimdLoadLane(kind: .Load64, memory: memory, - dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 0) - return [ - function.wasmSimdExtractLane(kind: .I64x2, loaded, 0), - function.wasmSimdExtractLane(kind: .I64x2, loaded, 1), - function.wasmSimdExtractLane(kind: .I64x2, reloaded, 0), - function.wasmSimdExtractLane(kind: .I64x2, reloaded, 1)] - } - }, "42,16,16,16"), + ( + { wasmModule, memory in + let returnType = (0..<4).map { _ in ILType.wasmi64 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let const = + isMemory64 ? function.consti64 : { function.consti32(Int32($0)) } + function.wasmMemoryStore( + memory: memory, dynamicOffset: const(0), + value: function.consti64(16), storeType: .I64StoreMem, staticOffset: 64) + let splat = function.wasmSimdSplat(kind: .I64x2, function.consti64(42)) + let loaded = function.wasmSimdLoadLane( + kind: .Load64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: splat, lane: 1) + function.wasmSimdStoreLane( + kind: .Store64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, from: loaded, lane: 1) + let reloaded = function.wasmSimdLoadLane( + kind: .Load64, memory: memory, + dynamicOffset: const(0), staticOffset: 64, into: loaded, lane: 0) + return [ + function.wasmSimdExtractLane(kind: .I64x2, loaded, 0), + function.wasmSimdExtractLane(kind: .I64x2, loaded, 1), + function.wasmSimdExtractLane(kind: .I64x2, reloaded, 0), + function.wasmSimdExtractLane(kind: .I64x2, reloaded, 1), + ] + } + }, "42,16,16,16" + ), ] let module = b.buildWasmModule { wasmModule in @@ -1900,12 +2351,13 @@ class WasmFoundationTests: XCTestCase { for (i, _) in testCases.enumerated() { let res = b.callMethod(module.getExportedMethod(at: i), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("toString", on: res)]) } let jsProg = fuzzer.lifter.lift(b.finalize()) - let expected = testCases.map {$0.1}.joined(separator: "\n") + "\n" + let expected = testCases.map { $0.1 }.joined(separator: "\n") + "\n" testForOutput(program: jsProg, runner: runner, outputString: expected) } @@ -1917,9 +2369,11 @@ class WasmFoundationTests: XCTestCase { try wasmSimdLoadStore(isMemory64: true) } - func wasmSimdSplatAndExtractLane(splat: WasmSimdSplat.Kind, - extractLane: WasmSimdExtractLane.Kind, - replaceLane: WasmSimdReplaceLane.Kind) throws { + func wasmSimdSplatAndExtractLane( + splat: WasmSimdSplat.Kind, + extractLane: WasmSimdExtractLane.Kind, + replaceLane: WasmSimdReplaceLane.Kind + ) throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) @@ -1929,13 +2383,16 @@ class WasmFoundationTests: XCTestCase { XCTAssertEqual(extractLane.laneCount(), replaceLane.laneCount()) let module = b.buildWasmModule { wasmModule in - let sig = [splat.laneType()] => (0.. (0.. [UInt8] = { uint16Array in - return uint16Array.flatMap { value -> [UInt8] in + return uint16Array.flatMap { value -> [UInt8] in let highByte = UInt8((value >> 8) & 0xFF) let lowByte = UInt8(value & 0xFF) return [lowByte, highByte] @@ -2013,618 +2494,1188 @@ class WasmFoundationTests: XCTestCase { return byteArray } - let testCases: [((ProgramBuilder.WasmModule) -> Void, String)] = [ // Test q15mulr_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([16383, 16384, 32767, 65535, 65535, 32765, UInt16(bitPattern: -32768), 32768])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.q15mulr_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8192,8192,32766,0,1,1,32767,-1"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 16383, 16384, 32767, 65535, 65535, 32765, + UInt16(bitPattern: -32768), 32768, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.q15mulr_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8192,8192,32766,0,1,1,32767,-1" + ), // // Test narrow_s - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 128, 256, 0, 1, 128, 256])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([-1, -128, -129, -256, -1, -128, -129, -256].map( {UInt16(bitPattern: $0)}))) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_s) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16S, result, $0)} - } - }, "0,1,127,127,0,1,127,127,-1,-128,-128,-128,-1,-128,-128,-128"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 128, 256, 0, 1, 128, 256])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [-1, -128, -129, -256, -1, -128, -129, -256].map({ + UInt16(bitPattern: $0) + }))) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_s + ) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16S, result, $0) + } + } + }, "0,1,127,127,0,1,127,127,-1,-128,-128,-128,-1,-128,-128,-128" + ), // Test narrow_u - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_u) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} - } - }, "0,1,127,128,255,255,255,255,0,1,127,128,255,255,255,255"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 127, 128, 255, 256, 512, 1024])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.narrow_u + ) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } + } + }, "0,1,127,128,255,255,255,255,0,1,127,128,255,255,255,255" + ), // Test shl - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, 16, 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shl) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,2,4,8,16,18,32,36"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, 16, 18])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shl) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,2,4,8,16,18,32,36" + ), // Test shr_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,1,2,4,4,-8,9"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18, + ])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,1,2,4,4,-8,9" + ), // Test shr_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18])) - let varB = function.consti32(1) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,1,2,4,4,32760,9"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 4, 8, 9, UInt16(bitPattern: -16), 18, + ])) + let varB = function.consti32(1) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.shr_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,1,2,4,4,32760,9" + ), // Test add - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 32767])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8,10,12,14,16,18,20,-32762"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 32767])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8,10,12,14,16,18,20,-32762" + ), // Test add_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray( - [UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32768), UInt16(bitPattern: -32768), 32767, 32767, 32767, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray( - [UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -1), 1, 1, UInt16(bitPattern: -1), UInt16(bitPattern: -2), 4])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-32768,32767,-32768,-32767,32767,32766,32765,11"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray( + [ + UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32768), + UInt16(bitPattern: -32768), 32767, 32767, 32767, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [ + UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -1), 1, 1, + UInt16(bitPattern: -1), UInt16(bitPattern: -2), 4, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.add_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-32768,32767,-32768,-32767,32767,32766,32765,11" + ), // Test add_sat_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray( - [65534, 65534, 65534, 8, 9, 10, 11, 12])) - let varB = function.constSimd128(value: uint16ArrayToByteArray( - [0, 1, 2, 3, 4, 5, 6, 7])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.add_sat_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "65534,65535,65535,11,13,15,17,19"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray( + [65534, 65534, 65534, 8, 9, 10, 11, 12])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray( + [0, 1, 2, 3, 4, 5, 6, 7])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.add_sat_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "65534,65535,65535,11,13,15,17,19" + ), // Test sub - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([UInt16(bitPattern:-2), 3, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([32767, 0, 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "32767,3,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + UInt16(bitPattern: -2), 3, 6, 9, 12, 15, 18, 21, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([32767, 0, 1, 2, 3, 4, 5, 6])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "32767,3,5,7,9,11,13,15" + ), // Test sub_sat_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([UInt16(bitPattern:-2), 32000, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([32767, UInt16(bitPattern:-1000), 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub_sat_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-32768,32767,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + UInt16(bitPattern: -2), 32000, 6, 9, 12, 15, 18, 21, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 32767, UInt16(bitPattern: -1000), 1, 2, 3, 4, 5, 6, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.sub_sat_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-32768,32767,5,7,9,11,13,15" + ), // Test sub_sat_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 3, 6, 9, 12, 15, 18, 21])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([1, 0, 1, 2, 3, 4, 5, 6])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.sub_sat_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,3,5,7,9,11,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 3, 6, 9, 12, 15, 18, 21])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([1, 0, 1, 2, 3, 4, 5, 6])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.sub_sat_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,3,5,7,9,11,13,15" + ), // Test mul - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 15])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.mul) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,9,20,33,48,65,84,105"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 15])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.mul) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,9,20,33,48,65,84,105" + ), // Test min_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "0,1,2,3,4,5,6,65534"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "0,1,2,3,4,5,6,65534" + ), // Test min_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 8, 0, UInt16(bitPattern:-8), 4, UInt16(bitPattern:-5), 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 0, UInt16(bitPattern:-8), 0, 0, UInt16(bitPattern:-12), 13, 14])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "0,0,-8,-8,0,-12,6,7"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 8, 0, UInt16(bitPattern: -8), 4, UInt16(bitPattern: -5), 6, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, 0, UInt16(bitPattern: -8), 0, 0, UInt16(bitPattern: -12), 13, 14, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.min_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "0,0,-8,-8,0,-12,6,7" + ), // Test max_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "8,9,10,11,12,13,14,65535"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 65535])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 9, 10, 11, 12, 13, 14, 65534])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "8,9,10,11,12,13,14,65535" + ), // Test max_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 8, 0, UInt16(bitPattern:-8), 4, UInt16(bitPattern:-5), 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 0, UInt16(bitPattern:-8), 0, 0, UInt16(bitPattern:-12), 13, 14])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8,8,0,0,4,-5,13,14"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 8, 0, UInt16(bitPattern: -8), 4, UInt16(bitPattern: -5), 6, 7, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, 0, UInt16(bitPattern: -8), 0, 0, UInt16(bitPattern: -12), 13, 14, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.max_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8,8,0,0,4,-5,13,14" + ), // Test dot_i16x8_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 4, 5, UInt16(bitPattern: -4), 5, 32767, 32767])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([2, 3, 6, 7, 6, UInt16(bitPattern: -7), 32767, 32767])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.dot_i16x8_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,59,-59,2147352578"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 4, 5, UInt16(bitPattern: -4), 5, 32767, 32767, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 2, 3, 6, 7, 6, UInt16(bitPattern: -7), 32767, 32767, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.dot_i16x8_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,59,-59,2147352578" + ), // Test avgr_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 10, 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.avgr_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "4,6,7,9,10,12,13,15"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 10, 12, 14, 16, 18, 20, 22])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.avgr_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "4,6,7,9,10,12,13,15" + ), // Test extmul_low_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern:-7)])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_low_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "0,-10,24,42"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern: -7), + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_low_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "0,-10,24,42" + ), // Test extmul_high_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern:-7)])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_high_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "64,90,120,-154"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 0, 1, 2, 3, 4, 5, 6, UInt16(bitPattern: -7), + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 22, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_high_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "64,90,120,-154" + ), // Test extmul_low_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 256, 2, 3, 4, 5, 6, 7])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, 256, 12, 14, 16, 18, 20, 22])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_low_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "0,65536,24,42"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 256, 2, 3, 4, 5, 6, 7])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([8, 256, 12, 14, 16, 18, 20, 22])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_low_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "0,65536,24,42" + ), // Test extmul_high_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 256])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 65535])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i32x4, WasmSimd128IntegerBinOpKind.extmul_high_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "64,90,120,16776960"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([0, 1, 2, 3, 4, 5, 6, 256])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 8, UInt16(bitPattern: -10), 12, 14, 16, 18, 20, 65535, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i32x4, + WasmSimd128IntegerBinOpKind.extmul_high_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "64,90,120,16776960" + ), // Test relaxed_swizzle. - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 4, 6, 5, 6, 4, 3, 2, 1, 9, 23, 24, 43, 20, 11, 6]) - let varB = function.constSimd128(value: [255, 3, 2, 1, 0, 4, 2, 3, 1, 14, 26, 11, 13, 7, 9, 6]) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i8x16, WasmSimd128IntegerBinOpKind.relaxed_swizzle) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16S, result, $0)} - } - }, "0,5,6,4,1,6,6,5,4,11,(23|0),24,20,2,9,3"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 4, 6, 5, 6, 4, 3, 2, 1, 9, 23, 24, 43, 20, 11, 6, + ]) + let varB = function.constSimd128(value: [ + 255, 3, 2, 1, 0, 4, 2, 3, 1, 14, 26, 11, 13, 7, 9, 6, + ]) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i8x16, + WasmSimd128IntegerBinOpKind.relaxed_swizzle) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16S, result, $0) + } + } + }, "0,5,6,4,1,6,6,5,4,11,(23|0),24,20,2,9,3" + ), // Test relaxed_q15mulr_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([16383, 16384, 32767, 65535, 65535, 32765, UInt16(bitPattern: -32768), 32768])) - let varB = function.constSimd128(value: uint16ArrayToByteArray([16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1])) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.relaxed_q15_mulr_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "8192,8192,32766,0,1,1,(-32768|32767),-1"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 16383, 16384, 32767, 65535, 65535, 32765, + UInt16(bitPattern: -32768), 32768, + ])) + let varB = function.constSimd128( + value: uint16ArrayToByteArray([ + 16384, 16384, 32767, 65535, 32768, 1, UInt16(bitPattern: -32768), 1, + ])) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.relaxed_q15_mulr_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "8192,8192,32766,0,1,1,(-32768|32767),-1" + ), // Test relaxed_dot_i8x16_i7x16_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 127, 127]) - let varB = function.constSimd128(value: - [10, 20, UInt8(bitPattern:-30), 40, 100, UInt8(bitPattern:-100), 50, UInt8(bitPattern:-50), 10, 20, UInt8(bitPattern:-30), 40, 50, UInt8(bitPattern:-50), 100, UInt8(bitPattern:-6)]) - let result = function.wasmSimd128IntegerBinOp(varA, varB, WasmSimd128Shape.i16x8, WasmSimd128IntegerBinOpKind.relaxed_dot_i8x16_i7x16_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "50,(70|838),(-100|1436),(-50|1998),(290|1998),(150|2966),(-50|3534),(11938|32767)"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 127, 127, + ]) + let varB = function.constSimd128(value: [ + 10, 20, UInt8(bitPattern: -30), 40, 100, UInt8(bitPattern: -100), 50, + UInt8(bitPattern: -50), 10, 20, UInt8(bitPattern: -30), 40, 50, + UInt8(bitPattern: -50), 100, UInt8(bitPattern: -6), + ]) + let result = function.wasmSimd128IntegerBinOp( + varA, varB, WasmSimd128Shape.i16x8, + WasmSimd128IntegerBinOpKind.relaxed_dot_i8x16_i7x16_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, + "50,(70|838),(-100|1436),(-50|1998),(290|1998),(150|2966),(-50|3534),(11938|32767)" + ), // Test extadd_pairwise_i8x16_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, UInt8(bitPattern:-1), UInt8(bitPattern:-2), UInt8(bitPattern:-3), UInt8(bitPattern:-4), 127, 127, - UInt8(bitPattern:-128), UInt8(bitPattern:-128), 10, UInt8(bitPattern:-10), 20, UInt8(bitPattern:-20)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "3,7,-3,-7,254,-256,0,0"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, UInt8(bitPattern: -1), UInt8(bitPattern: -2), + UInt8(bitPattern: -3), UInt8(bitPattern: -4), 127, 127, + UInt8(bitPattern: -128), UInt8(bitPattern: -128), 10, + UInt8(bitPattern: -10), 20, UInt8(bitPattern: -20), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "3,7,-3,-7,254,-256,0,0" + ), // Test extadd_pairwise_i8x16_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [1, 2, 3, 4, 255, 255, 128, 128, 10, 20, 30, 40, 50, 60, 70, 80]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "3,7,510,256,30,70,110,150"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 255, 255, 128, 128, 10, 20, 30, 40, 50, 60, 70, 80, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i8x16_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "3,7,510,256,30,70,110,150" + ), // Test extadd_pairwise_i16x8_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, 2, 3, 4, 32767, 32767, UInt16(bitPattern: -32768), UInt16(bitPattern: -32768)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,7,65534,-65536"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, 2, 3, 4, 32767, 32767, UInt16(bitPattern: -32768), + UInt16(bitPattern: -32768), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,7,65534,-65536" + ), // Test extadd_pairwise_i16x8_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, 2, 3, 4, 65535, 65535, 32768, 32768])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "3,7,131070,65536"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([1, 2, 3, 4, 65535, 65535, 32768, 32768])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.extadd_pairwise_i16x8_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "3,7,131070,65536" + ), // Test abs // Note: abs(Int16.min) is Int16.min in Wasm. - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, UInt16(bitPattern: -32767), 10, UInt16(bitPattern: -10)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.abs) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "1,1,0,-32768,32767,32767,10,10"), // abs(-32768) is -32768 in Wasm SIMD i16x8.abs + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, + UInt16(bitPattern: -32767), 10, UInt16(bitPattern: -10), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.abs) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "1,1,0,-32768,32767,32767,10,10" + ), // abs(-32768) is -32768 in Wasm SIMD i16x8.abs // Test neg // Note: neg(Int16.min) is Int16.min in Wasm. - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: uint16ArrayToByteArray([1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, 10, UInt16(bitPattern: -10), UInt16(bitPattern: -32767)])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.neg) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,1,0,-32768,-32767,-10,10,32767"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: uint16ArrayToByteArray([ + 1, UInt16(bitPattern: -1), 0, UInt16(bitPattern: -32768), 32767, 10, + UInt16(bitPattern: -10), UInt16(bitPattern: -32767), + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.neg) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,1,0,-32768,-32767,-10,10,32767" + ), // Test popcnt - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [0, 1, 3, 7, 15, 255, 127, UInt8(bitPattern:-1), 128, UInt8(bitPattern:-2), UInt8(bitPattern:-3), UInt8(bitPattern:-4), UInt8(bitPattern:-5), - UInt8(bitPattern:-6), UInt8(bitPattern:-7), UInt8(bitPattern:-8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.popcnt) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} // Popcnt result is unsigned - } - }, "0,1,2,3,4,8,7,8,1,7,7,6,7,6,6,5"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 0, 1, 3, 7, 15, 255, 127, UInt8(bitPattern: -1), 128, + UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), + UInt8(bitPattern: -5), + UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.popcnt) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } // Popcnt result is unsigned + } + }, "0,1,2,3,4,8,7,8,1,7,7,6,7,6,6,5" + ), // Test extend_low_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,2,3,4,5,6,7,8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,2,3,4,5,6,7,8" + ), // Test extend_high_s - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_s) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8S, result, $0)} - } - }, "-1,-2,-3,-4,-5,-6,-7,-8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_s) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8S, result, $0) + } + } + }, "-1,-2,-3,-4,-5,-6,-7,-8" + ), // Test extend_low_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "255,2,3,4,5,6,7,8"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + UInt8(bitPattern: -1), 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_low_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "255,2,3,4,5,6,7,8" + ), // Test extend_high_u - ({wasmModule in - let returnType = (0..<8).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, - UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), UInt8(bitPattern: -7), UInt8(bitPattern: -8)]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_u) - return (0..<8).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I16x8U, result, $0)} - } - }, "255,254,253,252,251,250,249,248"), + ( + { wasmModule in + let returnType = (0..<8).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, + UInt8(bitPattern: -1), UInt8(bitPattern: -2), UInt8(bitPattern: -3), + UInt8(bitPattern: -4), UInt8(bitPattern: -5), UInt8(bitPattern: -6), + UInt8(bitPattern: -7), UInt8(bitPattern: -8), + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i16x8, WasmSimd128IntegerUnOpKind.extend_high_u) + return (0..<8).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I16x8U, result, $0) + } + } + }, "255,254,253,252,251,250,249,248" + ), // Test all_true positive - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) - return [result, result] // hack to not confuse JS code extracting the result, as it always expects an array - } - }, "1,1"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) + return [result, result] // hack to not confuse JS code extracting the result, as it always expects an array + } + }, "1,1" + ), // Test all_true negative - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) - return [result, result] - } - }, "0,0"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.all_true) + return [result, result] + } + }, "0,0" + ), // Test bitmask - ({wasmModule in - let returnType = (0..<2).map {_ in ILType.wasmi32 } - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: - [255, 200, 2, 230, 8, 16, 64, 127, 128, 129, 150, 180, 0, 1, 4, 8]) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.bitmask) - return [result, result] - } - }, "3851,3851"), + ( + { wasmModule in + let returnType = (0..<2).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 255, 200, 2, 230, 8, 16, 64, 127, 128, 129, 150, 180, 0, 1, 4, 8, + ]) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i8x16, WasmSimd128IntegerUnOpKind.bitmask) + return [result, result] + } + }, "3851,3851" + ), // Test relaxed_trunc_f32x4_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-2147483648),1,-2,(2147483647|-2147483648)"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([ + 0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude, + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-2147483648),1,-2,(2147483647|-2147483648)" + ), // Test relaxed_trunc_f32x4_u - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_u) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),1,(0|-1),-1"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([ + 0.0 / 0.0, 1.5, -2.5, Float.greatestFiniteMagnitude, + ])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f32x4_u) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),1,(0|-1),-1" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test relaxed_trunc_f64x2_s_zero corner cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-2147483648),(2147483647|-2147483648),0,0"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-2147483648),(2147483647|-2147483648),0,0" + ), // Test relaxed_trunc_f64x2_s_zero standard cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "-3,7,0,0"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_s_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "-3,7,0,0" + ), // Test relaxed_trunc_f64x2_u_zero corner cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),(0|-1),0,0"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: doubleToByteArray([0.0 / 0.0, Double.greatestFiniteMagnitude])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),(0|-1),0,0" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test relaxed_trunc_f64x2_u_zero standard cases - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) - let result = function.wasmSimd128IntegerUnOp(varA, WasmSimd128Shape.i32x4, WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - }, "(0|-1),7,0,0"), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: doubleToByteArray([-3.5, 7.6])) + let result = function.wasmSimd128IntegerUnOp( + varA, WasmSimd128Shape.i32x4, + WasmSimd128IntegerUnOpKind.relaxed_trunc_f64x2_u_zero) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(0|-1),7,0,0" + ), // note: we use -1 to denote UINT32_MAX as it is pain to make .wasmi32 represented as unsigned integer // Test float add - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 1.5, 2.6, 3.7])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 5.9, 7.0, 8.1])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.add) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,7.40,9.60,11.80"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 1.5, 2.6, 3.7])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 5.9, 7.0, 8.1])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.add) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,7.40,9.60,11.80" + ), // Test float sub - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.sub) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,-4.40,4.40,4.40"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.sub) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,-4.40,4.40,4.40" + ), // Test float mul - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.mul) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,8.85,18.20,29.97"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.mul) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,8.85,18.20,29.97" + ), // Test float div - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 1.5, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 5.9, 2.6, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.div) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,0.25,2.69,2.19"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 1.5, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 5.9, 2.6, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.div) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,0.25,2.69,2.19" + ), // Test float min - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.min) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,NaN,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.min) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,NaN,NaN" + ), // Test float max - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.max) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,NaN,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.max) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,NaN,NaN" + ), // Test float pmin - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmin) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,7,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmin) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,7,NaN" + ), // Test float pmax - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmax) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,7,NaN"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.pmax) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,7,NaN" + ), // Test float relaxed_min - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.relaxed_min) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"0,1.50,(NaN|7),(NaN|3.70)"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, + WasmSimd128FloatBinOpKind.relaxed_min) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "0,1.50,(NaN|7),(NaN|3.70)" + ), // Test float relaxed_max - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) - let result = function.wasmSimd128FloatBinOp(varA, varB, WasmSimd128Shape.f32x4, WasmSimd128FloatBinOpKind.relaxed_max) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"4.80,5.90,(NaN|7),(NaN|3.70)"), - // Test madd - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) - let varC = function.constSimd128(value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) - let result = function.wasmSimd128FloatTernaryOp(varA, varB, varC, WasmSimd128Shape.f32x4, WasmSimd128FloatTernaryOpKind.madd) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"9.20,19.15,30.30,42.47"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 0.0 / 0.0])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 0.0 / 0.0, 3.7])) + let result = function.wasmSimd128FloatBinOp( + varA, varB, WasmSimd128Shape.f32x4, + WasmSimd128FloatBinOpKind.relaxed_max) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "4.80,5.90,(NaN|7),(NaN|3.70)" + ), + // Test madd + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) + let varC = function.constSimd128( + value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) + let result = function.wasmSimd128FloatTernaryOp( + varA, varB, varC, WasmSimd128Shape.f32x4, + WasmSimd128FloatTernaryOpKind.madd) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "9.20,19.15,30.30,42.47" + ), // Test nmadd - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmf32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) - let varB = function.constSimd128(value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) - let varC = function.constSimd128(value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) - let result = function.wasmSimd128FloatTernaryOp(varA, varB, varC, WasmSimd128Shape.f32x4, WasmSimd128FloatTernaryOpKind.nmadd) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.F32x4, result, $0)} - } - },"9.20,1.45,-7.50,-17.47"), + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmf32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128( + value: floatToByteArray([0.0, 5.9, 7.0, 8.1])) + let varB = function.constSimd128( + value: floatToByteArray([4.8, 1.5, 2.7, 3.7])) + let varC = function.constSimd128( + value: floatToByteArray([9.2, 10.3, 11.4, 12.5])) + let result = function.wasmSimd128FloatTernaryOp( + varA, varB, varC, WasmSimd128Shape.f32x4, + WasmSimd128FloatTernaryOpKind.nmadd) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.F32x4, result, $0) + } + } + }, "9.20,1.45,-7.50,-17.47" + ), // Test relaxed_laneselect - ({wasmModule in - let returnType = (0..<16).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [34, 23, 27, 164, 4, 123, 34, 23, 27, 164, 4, 123, 34, 23, 27, 164]) - let varB = function.constSimd128(value: [42, 24, 160, 35, 24, 28, 42, 24, 160, 35, 24, 28, 42, 24, 160, 35]) - let varC = function.constSimd128(value: [255, 0, 128, 129, 20, 65, 255, 0, 128, 129, 20, 65, 255, 0, 128, 129]) - let result = function.wasmSimd128IntegerTernaryOp(varA, varB, varC, WasmSimd128Shape.i8x16, WasmSimd128IntegerTernaryOpKind.relaxed_laneselect) - return (0..<16).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I8x16U, result, $0)} - } - },"34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164)"), + ( + { wasmModule in + let returnType = (0..<16).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 34, 23, 27, 164, 4, 123, 34, 23, 27, 164, 4, 123, 34, 23, 27, 164, + ]) + let varB = function.constSimd128(value: [ + 42, 24, 160, 35, 24, 28, 42, 24, 160, 35, 24, 28, 42, 24, 160, 35, + ]) + let varC = function.constSimd128(value: [ + 255, 0, 128, 129, 20, 65, 255, 0, 128, 129, 20, 65, 255, 0, 128, 129, + ]) + let result = function.wasmSimd128IntegerTernaryOp( + varA, varB, varC, WasmSimd128Shape.i8x16, + WasmSimd128IntegerTernaryOpKind.relaxed_laneselect) + return (0..<16).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I8x16U, result, $0) + } + } + }, + "34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164),(12|24),(93|28),34,24,(32|27),(162|164)" + ), // Test relaxed_dot_i8x16_i7x16_add_s - ({wasmModule in - let returnType = (0..<4).map {_ in ILType.wasmi32} - wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in - let varA = function.constSimd128(value: [34, 23, 27, 124, 4, 123, 34, 23, 27, 124, 4, 123, 34, 23, 27, 124]) - let varB = function.constSimd128(value: [42, 24, 160, 35, 24, 28, 42, 24, 120, 35, 24, 28, 42, 24, 120, 35]) - let varC = function.constSimd128(value: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]) // i32x4 vector in fact - let result = function.wasmSimd128IntegerTernaryOp(varA, varB, varC, WasmSimd128Shape.i32x4, WasmSimd128IntegerTernaryOpKind.relaxed_dot_i8x16_i7x16_add_s) - return (0..<4).map {function.wasmSimdExtractLane(kind: WasmSimdExtractLane.Kind.I32x4, result, $0)} - } - },"(3729|10641),5522,11123,9564") + ( + { wasmModule in + let returnType = (0..<4).map { _ in ILType.wasmi32 } + wasmModule.addWasmFunction(with: [] => returnType) { function, label, args in + let varA = function.constSimd128(value: [ + 34, 23, 27, 124, 4, 123, 34, 23, 27, 124, 4, 123, 34, 23, 27, 124, + ]) + let varB = function.constSimd128(value: [ + 42, 24, 160, 35, 24, 28, 42, 24, 120, 35, 24, 28, 42, 24, 120, 35, + ]) + let varC = function.constSimd128(value: [ + 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, + ]) // i32x4 vector in fact + let result = function.wasmSimd128IntegerTernaryOp( + varA, varB, varC, WasmSimd128Shape.i32x4, + WasmSimd128IntegerTernaryOpKind.relaxed_dot_i8x16_i7x16_add_s) + return (0..<4).map { + function.wasmSimdExtractLane( + kind: WasmSimdExtractLane.Kind.I32x4, result, $0) + } + } + }, "(3729|10641),5522,11123,9564" + ), ] let module = b.buildWasmModule { wasmModule in - for(createWasmFunction, _) in testCases { + for (createWasmFunction, _) in testCases { createWasmFunction(wasmModule) } } @@ -2643,13 +3694,17 @@ class WasmFoundationTests: XCTestCase { let rawValues = b.callMethod(module.getExportedMethod(at: i), on: module.loadExports()) - b.callFunction(print, withArgs: - [b.callMethod("join", on: b.callMethod("map", on:rawValues, withArgs: [setFormat]))] + b.callFunction( + print, + withArgs: [ + b.callMethod( + "join", on: b.callMethod("map", on: rawValues, withArgs: [setFormat])) + ] ) } let jsProg = fuzzer.lifter.lift(b.finalize()) - let expected = testCases.map {$0.1}.joined(separator: "\n") + "\n" + let expected = testCases.map { $0.1 }.joined(separator: "\n") + "\n" testForOutputRegex(program: jsProg, runner: runner, outputPattern: expected) } @@ -2689,7 +3744,8 @@ class WasmFoundationTests: XCTestCase { function.wasmBuildLoop(with: [] => [], args: []) { label, args in XCTAssert(b.type(of: label).Is(.anyLabel)) let result = function.wasmi32BinOp(ctr, one, binOpKind: .Add) - let varUpdate = function.wasmi64BinOp(variable, function.consti64(2), binOpKind: .Add) + let varUpdate = function.wasmi64BinOp( + variable, function.consti64(2), binOpKind: .Add) function.wasmReassign(variable: ctr, to: result) function.wasmReassign(variable: variable, to: varUpdate) let comp = function.wasmi32CompareOp(ctr, max, using: .Lt_s) @@ -2722,22 +3778,30 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in - let loopResult = function.wasmBuildLoop(with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: args) { loopLabel, loopArgs in - let incFirst = function.wasmi32BinOp(loopArgs[0], function.consti32(1), binOpKind: .Add) - let incSecond = function.wasmi32BinOp(loopArgs[1], function.consti32(2), binOpKind: .Add) + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in + let loopResult = function.wasmBuildLoop( + with: [.wasmi32, .wasmi32] => [.wasmi32, .wasmi32], args: args + ) { loopLabel, loopArgs in + let incFirst = function.wasmi32BinOp( + loopArgs[0], function.consti32(1), binOpKind: .Add) + let incSecond = function.wasmi32BinOp( + loopArgs[1], function.consti32(2), binOpKind: .Add) let condition = function.wasmi32CompareOp(incFirst, incSecond, using: .Gt_s) function.wasmBranchIf(condition, to: loopLabel, args: [incFirst, incSecond]) return [incFirst, incSecond] } - function.wasmBuildIfElse(function.wasmi32CompareOp(loopResult[1], function.consti32(20), using: .Ne)) { label, args in + function.wasmBuildIfElse( + function.wasmi32CompareOp(loopResult[1], function.consti32(20), using: .Ne) + ) { label, args in function.wasmUnreachable() } return [loopResult[0]] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(10), b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(10), b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -2756,8 +3820,8 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in let variable = args[0] - let condVariable = function.consti32(10); - let result = function.consti32(0); + let condVariable = function.consti32(10) + let result = function.consti32(0) let comp = function.wasmi32CompareOp(variable, condVariable, using: .Lt_s) @@ -2775,7 +3839,8 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1337)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1337)]) let outputFunc = b.createNamedVariable(forBuiltin: "output") b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) @@ -2792,12 +3857,16 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + function, label, args in let inputs = [args[1], function.consti64(3)] - function.wasmBuildIfElse(args[0], signature: [.wasmi64, .wasmi64] => [], args: inputs, inverted: false) { label, ifArgs in + function.wasmBuildIfElse( + args[0], signature: [.wasmi64, .wasmi64] => [], args: inputs, inverted: false + ) { label, ifArgs in function.wasmReturn(ifArgs[0]) - } elseBody: {label, ifArgs in - function.wasmReturn(function.wasmi64BinOp(ifArgs[0], ifArgs[1], binOpKind: .Shl)) + } elseBody: { label, ifArgs in + function.wasmReturn( + function.wasmi64BinOp(ifArgs[0], ifArgs[1], binOpKind: .Shl)) } return [function.consti64(-1)] } @@ -2805,9 +3874,12 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - var wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1), b.loadBigInt(42)]) + var wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, + withArgs: [b.loadInt(1), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0), b.loadBigInt(1)]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0), b.loadBigInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -2822,11 +3894,14 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(args[0], signature: [.wasmi32] => [], args: [args[1]], inverted: false) { ifLabel, ifArgs in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in + function.wasmBuildIfElse( + args[0], signature: [.wasmi32] => [], args: [args[1]], inverted: false + ) { ifLabel, ifArgs in function.wasmBranchIf(ifArgs[0], to: ifLabel) function.wasmReturn(function.consti32(100)) - } elseBody: {elseLabel, ifArgs in + } elseBody: { elseLabel, ifArgs in function.wasmBranchIf(ifArgs[0], to: elseLabel) function.wasmReturn(function.consti32(200)) } @@ -2837,15 +3912,15 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let runAndPrint = {args in + let runAndPrint = { args in let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: args) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) } - runAndPrint([b.loadInt(1), b.loadInt(0)]) // 100 - runAndPrint([b.loadInt(1), b.loadInt(1)]) // 300 - runAndPrint([b.loadInt(0), b.loadInt(0)]) // 200 - runAndPrint([b.loadInt(0), b.loadInt(1)]) // 300 + runAndPrint([b.loadInt(1), b.loadInt(0)]) // 100 + runAndPrint([b.loadInt(1), b.loadInt(1)]) // 300 + runAndPrint([b.loadInt(0), b.loadInt(0)]) // 200 + runAndPrint([b.loadInt(0), b.loadInt(1)]) // 300 let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -2860,9 +3935,11 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - let blockResult = function.wasmBuildIfElseWithResult(args[0], signature: [] => [.wasmi64, .wasmi64], args: []) {label, args in + let blockResult = function.wasmBuildIfElseWithResult( + args[0], signature: [] => [.wasmi64, .wasmi64], args: [] + ) { label, args in return [function.consti64(123), function.consti64(10)] - } elseBody: {label, args in + } elseBody: { label, args in return [function.consti64(321), function.consti64(10)] } let sum = function.wasmi64BinOp(blockResult[0], blockResult[1], binOpKind: .Add) @@ -2870,9 +3947,11 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let outTrue = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let outTrue = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: outTrue)]) - let outFalse = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let outFalse = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: outFalse)]) let prog = b.finalize() @@ -2896,8 +3975,10 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { _, _ in - let one = function.wasmJsCall(function: jsReturnOne, withArgs: [], + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0]), hint: .Unlikely) { + _, _ in + let one = function.wasmJsCall( + function: jsReturnOne, withArgs: [], withWasmSignature: [] => [.wasmi32])! function.wasmReturn(one) } @@ -2912,13 +3993,17 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let out0 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let out0 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out0)]) - let out5 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(5)]) + let out5 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(5)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out5)]) - let out1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let out1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out1)]) - let out3 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(3)]) + let out3 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(3)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: out3)]) let prog = b.finalize() @@ -2973,8 +4058,10 @@ class WasmFoundationTests: XCTestCase { function.wasmBuildLegacyTryVoid { label in XCTAssert(b.type(of: label).Is(.anyLabel)) // Manually set the availableTypes here for testing. - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) - function.wasmJsCall(function: functionA, withArgs: [], withWasmSignature: wasmSignature) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, availableTypes: WeightedList([])) + function.wasmJsCall( + function: functionA, withArgs: [], withWasmSignature: wasmSignature) function.wasmUnreachable() } catchAllBody: { label in function.wasmReturn(function.consti64(123)) @@ -3013,16 +4100,26 @@ class WasmFoundationTests: XCTestCase { b.buildIfElse(supportsJSTag) { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) - let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature(b.type(of: functionA).signature!, availableTypes: WeightedList([])) - function.wasmJsCall(function: functionA, withArgs: [], withWasmSignature: wasmSignature) - function.wasmUnreachable() - }, catchClauses: [(tag: jstag, body: { label, exception, args in - function.wasmReturn(function.consti64(123)) - })], catchAllBody: { label in - function.wasmUnreachable() - }) + function.wasmBuildLegacyTryVoid( + body: { label in + XCTAssert(b.type(of: label).Is(.anyLabel)) + let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( + b.type(of: functionA).signature!, availableTypes: WeightedList([])) + function.wasmJsCall( + function: functionA, withArgs: [], withWasmSignature: wasmSignature) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: jstag, + body: { label, exception, args in + function.wasmReturn(function.consti64(123)) + } + ) + ], + catchAllBody: { label in + function.wasmUnreachable() + }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3068,21 +4165,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) - function.WasmBuildThrow(tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) - function.wasmUnreachable() - }, catchClauses: [ - (tag: otherTag, body: { label, exception, args in + function.wasmBuildLegacyTryVoid( + body: { label in + XCTAssert(b.type(of: label).Is(.anyLabel)) + function.WasmBuildThrow( + tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: otherTag, + body: { label, exception, args in + function.wasmUnreachable() + } + ), + ( + tag: throwTag, + body: { label, exception, args in + let result = function.wasmi64BinOp( + args[0], function.extendi32Toi64(args[1], isSigned: true), + binOpKind: .Add) + function.wasmReturn(result) + } + ), + ], + catchAllBody: { label in function.wasmUnreachable() - }), - (tag: throwTag, body: { label, exception, args in - let result = function.wasmi64BinOp(args[0], function.extendi32Toi64(args[1], isSigned: true), binOpKind: .Add) - function.wasmReturn(result) }) - ], catchAllBody: { label in - function.wasmUnreachable() - }) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3105,11 +4214,18 @@ class WasmFoundationTests: XCTestCase { let tag = b.createWasmTag(parameterTypes: []) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { tryLabel in - function.WasmBuildThrow(tag: tag, inputs: []) - }, catchClauses: [(tag: tag, body: { catchLabel, exceptionLabel, args in - function.wasmBranch(to: catchLabel) - })]) + function.wasmBuildLegacyTryVoid( + body: { tryLabel in + function.WasmBuildThrow(tag: tag, inputs: []) + }, + catchClauses: [ + ( + tag: tag, + body: { catchLabel, exceptionLabel, args in + function.wasmBranch(to: catchLabel) + } + ) + ]) return [function.consti32(42)] } } @@ -3151,7 +4267,6 @@ class WasmFoundationTests: XCTestCase { testForOutput(program: jsProg, runner: runner, outputString: "42\n") } - func testTryCatchWasmExceptionNominal() throws { let runner = try GetJavaScriptExecutorOrSkipTest() let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -3187,23 +4302,37 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, param in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildIfElse(param[0], hint: .None) { _, _ in - function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) - } elseBody: { _, _ in - function.WasmBuildThrow(tag: importedTag, inputs: [function.consti32(123)]) - } - function.wasmUnreachable() - }, catchClauses: [ - (tag: importedTag, body: { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(1), binOpKind: .Add)) - }), - (tag: definedTag, body: { label, exception, args in - function.wasmReturn(function.wasmi32BinOp(args[0], function.consti32(4), binOpKind: .Add)) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildIfElse(param[0], hint: .None) { _, _ in + function.WasmBuildThrow(tag: definedTag, inputs: [param[0]]) + } elseBody: { _, _ in + function.WasmBuildThrow( + tag: importedTag, inputs: [function.consti32(123)]) + } + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: importedTag, + body: { label, exception, args in + function.wasmReturn( + function.wasmi32BinOp( + args[0], function.consti32(1), binOpKind: .Add)) + } + ), + ( + tag: definedTag, + body: { label, exception, args in + function.wasmReturn( + function.wasmi32BinOp( + args[0], function.consti32(4), binOpKind: .Add)) + } + ), + ], + catchAllBody: { label in + function.wasmUnreachable() }) - ], catchAllBody: { label in - function.wasmUnreachable() - }) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3241,18 +4370,28 @@ class WasmFoundationTests: XCTestCase { let argI64 = function.consti64(321) let signature = [.wasmi64, .wasmi32] => [] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - function.wasmBuildLegacyTryWithResult(signature: signature, signatureDef: signatureDef, - args: [argI64, argI32], body: { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) - XCTAssertEqual(b.type(of: args[0]), .wasmi64) - XCTAssertEqual(b.type(of: args[1]), .wasmi32) - function.WasmBuildThrow(tag: tag, inputs: args) - return [] - }, catchClauses: [(tag: tag, body: { label, exception, args in - let result = function.wasmi64BinOp(args[0], function.extendi32Toi64(args[1], isSigned: true), binOpKind: .Add) - function.wasmReturn(result) - return [] - })]) + function.wasmBuildLegacyTryWithResult( + signature: signature, signatureDef: signatureDef, + args: [argI64, argI32], + body: { label, args in + XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssertEqual(b.type(of: args[0]), .wasmi64) + XCTAssertEqual(b.type(of: args[1]), .wasmi32) + function.WasmBuildThrow(tag: tag, inputs: args) + return [] + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + let result = function.wasmi64BinOp( + args[0], function.extendi32Toi64(args[1], isSigned: true), + binOpKind: .Add) + function.wasmReturn(result) + return [] + } + ) + ]) function.wasmUnreachable() return [function.consti64(-1)] } @@ -3284,31 +4423,49 @@ class WasmFoundationTests: XCTestCase { let contant42 = function.consti64(42) let signature = [.wasmi32] => [.wasmi32, .wasmi64] let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature) - let result = function.wasmBuildLegacyTryWithResult(signature: signature, - signatureDef: signatureDef, args: args, body: { label, args in - function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in - function.WasmBuildThrow(tag: tagVoid, inputs: []) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq)) { _, _ in - function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(100)]) - } - function.wasmBuildIfElse(function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq)) { _, _ in - function.WasmBuildThrow(tag: tagi32Other, inputs: [function.consti32(200)]) - } - return [args[0], contant42] - }, catchClauses: [ - (tagi32, {label, exception, args in + let result = function.wasmBuildLegacyTryWithResult( + signature: signature, + signatureDef: signatureDef, args: args, + body: { label, args in + function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in + function.WasmBuildThrow(tag: tagVoid, inputs: []) + } + function.wasmBuildIfElse( + function.wasmi32CompareOp(args[0], function.consti32(1), using: .Eq) + ) { _, _ in + function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(100)]) + } + function.wasmBuildIfElse( + function.wasmi32CompareOp(args[0], function.consti32(2), using: .Eq) + ) { _, _ in + function.WasmBuildThrow( + tag: tagi32Other, inputs: [function.consti32(200)]) + } return [args[0], contant42] - }), - (tagi32Other, {label, exception, args in - let value = function.wasmi32BinOp(args[0], function.consti32(2), binOpKind: .Add) - function.wasmBranch(to: label, args: [value, contant42]) - return [function.consti32(-1), function.consti64(-1)] - }), - ], catchAllBody: { _ in - return [function.consti32(900), contant42] - }) - function.wasmBuildIfElse(function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None) { _, _ in + }, + catchClauses: [ + ( + tagi32, + { label, exception, args in + return [args[0], contant42] + } + ), + ( + tagi32Other, + { label, exception, args in + let value = function.wasmi32BinOp( + args[0], function.consti32(2), binOpKind: .Add) + function.wasmBranch(to: label, args: [value, contant42]) + return [function.consti32(-1), function.consti64(-1)] + } + ), + ], + catchAllBody: { _ in + return [function.consti32(900), contant42] + }) + function.wasmBuildIfElse( + function.wasmi64CompareOp(result[1], contant42, using: .Ne), hint: .None + ) { _, _ in function.wasmUnreachable() } return [result[0]] @@ -3321,18 +4478,20 @@ class WasmFoundationTests: XCTestCase { // to the EndTry block. At the end of the wasm function it performs a wasm return of the // result of the EndTry. for (input, expected) in [ - // input 0 throws tagVoid which is not caught, so the catchAllBody returns 900. - (0, 900), - // input 1 throws tagi32(100) which is caught by a catch clause that returns the - // tag argument. - (1, 100), - // input 2 throws tagi32Other(200) which is caught by a catch clause that branches - // to the end of its block adding 2 to the tag argument. - (2, 202), - // input 3 doesn't throw anything, the try body returns the value directly, meaning - // the value "falls-through" from the try body to the endTry operation. - (3, 3)] { - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(input))]) + // input 0 throws tagVoid which is not caught, so the catchAllBody returns 900. + (0, 900), + // input 1 throws tagi32(100) which is caught by a catch clause that returns the + // tag argument. + (1, 100), + // input 2 throws tagi32Other(200) which is caught by a catch clause that branches + // to the end of its block adding 2 to the tag argument. + (2, 202), + // input 3 doesn't throw anything, the try body returns the value directly, meaning + // the value "falls-through" from the try body to the endTry operation. + (3, 3), + ] { + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(input))]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) expectedString += "\(expected)\n" } @@ -3372,22 +4531,33 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { tryLabel in - // Even though we have a try-catch_all, the delegate "skips" this catch block. The delegate acts as - // if the exception was thrown by the block whose label is passed into it. - function.wasmBuildLegacyTryVoid(body: { unusedLabel in - let val = function.consti32(42) - function.wasmBuildLegacyTryDelegate(with: [.wasmi32] => [], args: [val], body: {label, args in - function.WasmBuildThrow(tag: tag, inputs: args) - }, delegate: tryLabel) + function.wasmBuildLegacyTryVoid( + body: { tryLabel in + // Even though we have a try-catch_all, the delegate "skips" this catch block. The delegate acts as + // if the exception was thrown by the block whose label is passed into it. + function.wasmBuildLegacyTryVoid( + body: { unusedLabel in + let val = function.consti32(42) + function.wasmBuildLegacyTryDelegate( + with: [.wasmi32] => [], args: [val], + body: { label, args in + function.WasmBuildThrow(tag: tag, inputs: args) + }, delegate: tryLabel) + function.wasmUnreachable() + }, + catchAllBody: { label in + function.wasmUnreachable() + }) function.wasmUnreachable() - }, catchAllBody: { label in - function.wasmUnreachable() - }) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3412,10 +4582,13 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in function.wasmBuildBlock(with: [] => [], args: []) { label, _ in let val = function.consti32(42) - let result = function.wasmBuildLegacyTryDelegateWithResult(with: [.wasmi32] => [.wasmi32, .wasmi32], args: [val], body: {tryLabel, args in - return [args[0], function.consti32(10)] - }, delegate: label) - function.wasmReturn(function.wasmi32BinOp(result[0], result[1], binOpKind: .Add)) + let result = function.wasmBuildLegacyTryDelegateWithResult( + with: [.wasmi32] => [.wasmi32, .wasmi32], args: [val], + body: { tryLabel, args in + return [args[0], function.consti32(10)] + }, delegate: label) + function.wasmReturn( + function.wasmi32BinOp(result[0], result[1], binOpKind: .Add)) } function.wasmUnreachable() return [function.consti32(-1)] @@ -3457,16 +4630,30 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmBuildLegacyRethrow(exception) - })]) - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmBuildLegacyRethrow(exception) + } + ) + ]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3508,23 +4695,46 @@ class WasmFoundationTests: XCTestCase { } */ wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in - function.wasmBuildLegacyTryVoid(body: { label in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) - }, catchClauses: [(tag: tag, body: { label, outerException, args in - function.wasmBuildLegacyTryVoid(body: { label in - function.WasmBuildThrow(tag: tag, inputs: [function.consti32(456)]) - function.wasmUnreachable() - }, catchClauses: [(tag: tag, body: { label, innerException, args in - // There are two "active" exceptions: - // outerException: [123: i32] - // innerException: [456: i32] - function.wasmBuildLegacyRethrow(outerException) - })]) - })]) - }, catchClauses: [(tag: tag, body: { label, exception, args in - function.wasmReturn(args[0]) - })]) + function.wasmBuildLegacyTryVoid( + body: { label in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow(tag: tag, inputs: [function.consti32(123)]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, outerException, args in + function.wasmBuildLegacyTryVoid( + body: { label in + function.WasmBuildThrow( + tag: tag, inputs: [function.consti32(456)]) + function.wasmUnreachable() + }, + catchClauses: [ + ( + tag: tag, + body: { label, innerException, args in + // There are two "active" exceptions: + // outerException: [123: i32] + // innerException: [456: i32] + function.wasmBuildLegacyRethrow( + outerException) + } + ) + ]) + } + ) + ]) + }, + catchClauses: [ + ( + tag: tag, + body: { label, exception, args in + function.wasmReturn(args[0]) + } + ) + ]) function.wasmUnreachable() return [function.consti32(-1)] } @@ -3548,9 +4758,11 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmf64]) { function, _, _ in let argI32 = function.consti32(12345) let argF64 = function.constf64(543.21) - function.wasmBuildBlock(with: [.wasmi32, .wasmf64] => [], args: [argI32, argF64]) { blockLabel, args in + function.wasmBuildBlock(with: [.wasmi32, .wasmf64] => [], args: [argI32, argF64]) { + blockLabel, args in XCTAssertEqual(args.count, 2) - let result = function.wasmf64BinOp(function.converti32Tof64(args[0], isSigned: true), args[1], binOpKind: .Add) + let result = function.wasmf64BinOp( + function.converti32Tof64(args[0], isSigned: true), args[1], binOpKind: .Add) function.wasmReturn(result) } function.wasmUnreachable() @@ -3574,10 +4786,13 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in - let blockResult = function.wasmBuildBlockWithResults(with: [.wasmi32] => [.wasmi64, .wasmi32], args: [function.consti32(1234)]) { blockLabel, args in + let blockResult = function.wasmBuildBlockWithResults( + with: [.wasmi32] => [.wasmi64, .wasmi32], args: [function.consti32(1234)] + ) { blockLabel, args in return [function.extendi32Toi64(args[0], isSigned: true), args[0]] } - let sum = function.wasmi64BinOp(blockResult[0], + let sum = function.wasmi64BinOp( + blockResult[0], function.extendi32Toi64(blockResult[1], isSigned: true), binOpKind: .Add) return [sum] } @@ -3599,19 +4814,30 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let blockResult = function.wasmBuildBlockWithResults(with: [.wasmi32] => [.wasmi32, .wasmi64], args: args) { blockLabel, blockArgs in - function.wasmBranchIf(blockArgs[0], to: blockLabel, args: [function.wasmi32BinOp(blockArgs[0], args[0], binOpKind: .Add), function.consti64(1)]) - function.wasmBranch(to: blockLabel, args: [function.consti32(12345), function.consti64(54321)]) + let blockResult = function.wasmBuildBlockWithResults( + with: [.wasmi32] => [.wasmi32, .wasmi64], args: args + ) { blockLabel, blockArgs in + function.wasmBranchIf( + blockArgs[0], to: blockLabel, + args: [ + function.wasmi32BinOp(blockArgs[0], args[0], binOpKind: .Add), + function.consti64(1), + ]) + function.wasmBranch( + to: blockLabel, args: [function.consti32(12345), function.consti64(54321)]) return [function.consti32(-1), function.consti64(0)] } - let sum = function.wasmi32BinOp(blockResult[0], function.wrapi64Toi32(blockResult[1]), binOpKind: .Add) + let sum = function.wasmi32BinOp( + blockResult[0], function.wrapi64Toi32(blockResult[1]), binOpKind: .Add) return [sum] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) let prog = b.finalize() @@ -3637,11 +4863,14 @@ class WasmFoundationTests: XCTestCase { } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) - let wasmOut3 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-1)]) + let wasmOut3 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut3)]) let prog = b.finalize() @@ -3656,29 +4885,44 @@ class WasmFoundationTests: XCTestCase { let b = fuzzer.makeBuilder() let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi64] => [.wasmi64]) { + function, label, args in // Fuzzilli doesn't have support for handling stack-polymorphic cases after // non-returning instructions like br_table or return. let dummy = [function.consti64(-1), function.consti64(-1)] - let block1Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label1, _ in - let block2Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label2, _ in - let block3Result = function.wasmBuildBlockWithResults(with: [] => [.wasmi64, .wasmi64], args: []) { label3, _ in - function.wasmBranchTable(on: args[0], labels: [label1, label2, label3], + let block1Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label1, _ in + let block2Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label2, _ in + let block3Result = function.wasmBuildBlockWithResults( + with: [] => [.wasmi64, .wasmi64], args: [] + ) { label3, _ in + function.wasmBranchTable( + on: args[0], labels: [label1, label2, label3], args: [args[1], function.extendi32Toi64(args[0], isSigned: false)]) return dummy } - function.wasmReturn(function.wasmi64BinOp(block3Result[0], block3Result[1], binOpKind: .Add)) + function.wasmReturn( + function.wasmi64BinOp(block3Result[0], block3Result[1], binOpKind: .Add) + ) return dummy } - function.wasmReturn(function.wasmi64BinOp(block2Result[0], function.consti64(2), binOpKind: .Add)) + function.wasmReturn( + function.wasmi64BinOp( + block2Result[0], function.consti64(2), binOpKind: .Add)) return dummy } - return [function.wasmi64BinOp(block1Result[0], function.consti64(1), binOpKind: .Add)] + return [ + function.wasmi64BinOp(block1Result[0], function.consti64(1), binOpKind: .Add) + ] } } let exports = module.loadExports() for val in [0, 1, 2, 100] { - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(Int64(val)), b.loadBigInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) } @@ -3696,20 +4940,28 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - let blockResult = function.wasmBuildTryTable(with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi32], args: [args[0], function.consti64(1234)], catches: []) { tryLabel, tryArgs in - let isZero = function.wasmi32CompareOp(tryArgs[0], function.consti32(0), using: .Eq) - function.wasmBranchIf(isZero, to: tryLabel, args: [function.consti64(10), function.consti32(20)]) + let blockResult = function.wasmBuildTryTable( + with: [.wasmi32, .wasmi64] => [.wasmi64, .wasmi32], + args: [args[0], function.consti64(1234)], catches: [] + ) { tryLabel, tryArgs in + let isZero = function.wasmi32CompareOp( + tryArgs[0], function.consti32(0), using: .Eq) + function.wasmBranchIf( + isZero, to: tryLabel, args: [function.consti64(10), function.consti32(20)]) return [tryArgs[1], tryArgs[0]] } - let sum = function.wasmi64BinOp(blockResult[0], + let sum = function.wasmi64BinOp( + blockResult[0], function.extendi32Toi64(blockResult[1], isSigned: true), binOpKind: .Add) return [sum] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3728,8 +4980,13 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in function.wasmBuildBlock(with: [] => [], args: []) { catchAllNoRefLabel, _ in - let catchNoRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchNoRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchNoRefLabel, catchAllNoRefLabel], catches: [.NoRef, .AllNoRef]) { _, _ in + let catchNoRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchNoRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchNoRefLabel, catchAllNoRefLabel], + catches: [.NoRef, .AllNoRef] + ) { _, _ in function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) } elseBody: { _, _ in @@ -3746,9 +5003,11 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3766,9 +5025,15 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchAllRefLabel, _ in - let catchRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchRefLabel, catchAllRefLabel], catches: [.Ref, .AllRef]) { _, _ in + function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { + catchAllRefLabel, _ in + let catchRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchRefLabel, catchAllRefLabel], + catches: [.Ref, .AllRef] + ) { _, _ in function.wasmBuildIfElse(function.wasmi32EqualZero(args[0])) { _, _ in function.WasmBuildThrow(tag: tagVoid, inputs: []) } elseBody: { _, _ in @@ -3786,9 +5051,11 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(123)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) let prog = b.finalize() @@ -3805,15 +5072,18 @@ class WasmFoundationTests: XCTestCase { let tagFromJS = b.createWasmTag(parameterTypes: [defineInWasm ? .wasmi64 : .wasmi32]) let moduleThrow = b.buildWasmModule { wasmModule in - let tagFromWasm = wasmModule.addTag(parameterTypes: [defineInWasm ? .wasmi32 : .wasmi64]) + let tagFromWasm = wasmModule.addTag(parameterTypes: [defineInWasm ? .wasmi32 : .wasmi64] + ) wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in - function.WasmBuildThrow(tag: defineInWasm ? tagFromWasm : tagFromJS, inputs: [args[0]]) + function.WasmBuildThrow( + tag: defineInWasm ? tagFromWasm : tagFromJS, inputs: [args[0]]) return [] } // Unused function that forces usage of the js tag if not used in the previous function. // (So that both get exported.) wasmModule.addWasmFunction(with: [.wasmi64] => []) { function, label, args in - function.WasmBuildThrow(tag: defineInWasm ? tagFromJS : tagFromWasm, inputs: [args[0]]) + function.WasmBuildThrow( + tag: defineInWasm ? tagFromJS : tagFromWasm, inputs: [args[0]]) return [] } } @@ -3823,21 +5093,29 @@ class WasmFoundationTests: XCTestCase { let wasmTagExported = b.getProperty("wex0", of: moduleThrow.loadExports()) // The re-exported tag is prefixed with the `i` for `imported`. let jsTagExported = b.getProperty("iwex0", of: moduleThrow.loadExports()) - let wasmTagExportedType = ILType.object(ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi32 : .wasmi64])) - let jsTagExportedType = ILType.object(ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi64 : .wasmi32])) + let wasmTagExportedType = ILType.object( + ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi32 : .wasmi64])) + let jsTagExportedType = ILType.object( + ofGroup: "WasmTag", withWasmType: WasmTagType([defineInWasm ? .wasmi64 : .wasmi32])) XCTAssertEqual(b.type(of: wasmTagExported), wasmTagExportedType) XCTAssertEqual(b.type(of: jsTagExported), jsTagExportedType) let tagToUse = defineInWasm ? wasmTagExported : jsTagExported let moduleCatch = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let catchNoRefI32 = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchNoRefLabel, _ in + let catchNoRefI32 = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchNoRefLabel, _ in // The usage of tagToUse in the try_table below is the interesting part of // this test case: It triggers an import of the tag exported by the previous // module and expects that we have all the correct information about it // (including the tag's parameter types.) - function.wasmBuildTryTable(with: [] => [], args: [tagToUse, catchNoRefLabel], catches: [.NoRef]) { _, _ in - function.wasmJsCall(function: throwFct, withArgs: [function.consti32(42)], withWasmSignature: [.wasmi32] => []) + function.wasmBuildTryTable( + with: [] => [], args: [tagToUse, catchNoRefLabel], catches: [.NoRef] + ) { _, _ in + function.wasmJsCall( + function: throwFct, withArgs: [function.consti32(42)], + withWasmSignature: [.wasmi32] => []) return [] } return [function.consti32(-1)] @@ -3870,7 +5148,9 @@ class WasmFoundationTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() // Assumption: All types apart from bottom (null) & shared types are supported in the JS API. - let supportedTypes = WasmAbstractHeapType.allNonBottomTypes().map {ILType.wasmRef($0, nullability: true)} + let supportedTypes = WasmAbstractHeapType.allNonBottomTypes().map { + ILType.wasmRef($0, nullability: true) + } b.createWasmTag(parameterTypes: supportedTypes) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog, withOptions: [.includeComments]) @@ -3895,16 +5175,23 @@ class WasmFoundationTests: XCTestCase { let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in // Inner function that throws, catches and then rethrows the value. - let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32, .wasmExnRef()], args: []) { catchRefLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchRefLabel], catches: [.Ref]) { _, _ in + let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { + function, label, args in + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32, .wasmExnRef()], args: [] + ) { catchRefLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchRefLabel], catches: [.Ref] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [args[0]]) return [] } return [function.consti32(0), function.wasmRefNull(type: .wasmExnRef())] } // Print the caught i32 value. - function.wasmJsCall(function: printInteger, withArgs: [caughtValues[0]], withWasmSignature: [.wasmi32] => []) + function.wasmJsCall( + function: printInteger, withArgs: [caughtValues[0]], + withWasmSignature: [.wasmi32] => []) // To rethrow the exception, perform a throw_ref with the exnref. function.wasmBuildThrowRef(exception: caughtValues[1]) return [] @@ -3912,9 +5199,14 @@ class WasmFoundationTests: XCTestCase { // Outer function that calls the inner function and catches the rethrown exception. wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let caughtValues = function.wasmBuildBlockWithResults(with: [] => [.wasmi32], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [tagi32, catchLabel], catches: [.NoRef]) { _, _ in - function.wasmCallDirect(signature: [.wasmi32] => [], function: callee, functionArgs: args) + let caughtValues = function.wasmBuildBlockWithResults( + with: [] => [.wasmi32], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [tagi32, catchLabel], catches: [.NoRef] + ) { _, _ in + function.wasmCallDirect( + signature: [.wasmi32] => [], function: callee, functionArgs: args) return [] } return [function.consti32(-1)] @@ -3924,7 +5216,8 @@ class WasmFoundationTests: XCTestCase { } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -3970,11 +5263,16 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi64]) { function, label, args in - [function.wasmSelect(on: args[0], - trueValue: function.consti64(123), falseValue: function.consti64(321))] + [ + function.wasmSelect( + on: args[0], + trueValue: function.consti64(123), falseValue: function.consti64(321)) + ] } - wasmModule.addWasmFunction(with: [.wasmi32, .wasmExternRef(), .wasmExternRef()] => [.wasmExternRef()]) { function, label, args in + wasmModule.addWasmFunction( + with: [.wasmi32, .wasmExternRef(), .wasmExternRef()] => [.wasmExternRef()] + ) { function, label, args in [function.wasmSelect(on: args[0], trueValue: args[1], falseValue: args[2])] } } @@ -3982,16 +5280,20 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") // Select with i64. - var wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + var wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) - wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) // Select with externref. let hello = b.loadString("Hello") let world = b.loadString("World") - wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(1), hello, world]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(1), hello, world]) b.callFunction(outputFunc, withArgs: [wasmOut]) - wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(0), hello, world]) + wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(0), hello, world]) b.callFunction(outputFunc, withArgs: [wasmOut]) let prog = b.finalize() @@ -4011,8 +5313,10 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayA = function.wasmArrayNewFixed(arrayType: arrayi32, elements: [function.consti32(123)]) - let arrayB = function.wasmArrayNewFixed(arrayType: arrayi32, elements: [function.consti32(-321)]) + let arrayA = function.wasmArrayNewFixed( + arrayType: arrayi32, elements: [function.consti32(123)]) + let arrayB = function.wasmArrayNewFixed( + arrayType: arrayi32, elements: [function.consti32(-321)]) let array = function.wasmSelect(on: args[0], trueValue: arrayA, falseValue: arrayB) return [function.wasmArrayGet(array: array, index: function.consti32(0))] } @@ -4020,9 +5324,11 @@ class WasmFoundationTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut1 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut1 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut1)]) - let wasmOut2 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) + let wasmOut2 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(1)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut2)]) let prog = b.finalize() @@ -4040,26 +5346,35 @@ class WasmFoundationTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") let printMessage = b.buildPlainFunction(with: .parameters(.integer)) { args in - b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: b.loadString("This should never be called!"))]) + b.callFunction( + outputFunc, + withArgs: [ + b.callMethod("toString", on: b.loadString("This should never be called!")) + ]) } let module = b.buildWasmModule { wasmModule in - let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { function, label, args in + let callee = wasmModule.addWasmFunction(with: [.wasmi32] => []) { + function, label, args in return [] } // Outer function that is supposed to call callee. wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in // This direct call accidentally got wrongly lifted to calling the imported js function (printMessage). - function.wasmCallDirect(signature: [.wasmi32] => [], function: callee, functionArgs: args) + function.wasmCallDirect( + signature: [.wasmi32] => [], function: callee, functionArgs: args) function.wasmReturn(function.consti32(42)) // This call is unreachable and only exists here to trigger the import of the printMessage function. - function.wasmJsCall(function: printMessage, withArgs: [args[0]], withWasmSignature: [.wasmi32] => []) + function.wasmJsCall( + function: printMessage, withArgs: [args[0]], withWasmSignature: [.wasmi32] => [] + ) return [function.consti32(-1)] } } let exports = module.loadExports() - let wasmOut = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -4079,8 +5394,11 @@ class WasmFoundationTests: XCTestCase { let moduleA = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in function.wasmReturn(function.consti64(-1)) - return [function.wasmJsCall(function: jsFunction, - withArgs: [], withWasmSignature: [] => [.wasmi64])!] + return [ + function.wasmJsCall( + function: jsFunction, + withArgs: [], withWasmSignature: [] => [.wasmi64])! + ] } } @@ -4088,14 +5406,18 @@ class WasmFoundationTests: XCTestCase { let reexportedJSFct = b.getProperty("iw0", of: exportsA) // Test that the type system knows about the re-exported function, so that it is // discoverable by code generators. - XCTAssert(b.type(of: exportsA).Is( - .object(ofGroup: nil, withProperties: [], withMethods: ["w0", "iw0"]))) + XCTAssert( + b.type(of: exportsA).Is( + .object(ofGroup: nil, withProperties: [], withMethods: ["w0", "iw0"]))) XCTAssert(b.type(of: reexportedJSFct).Is(.function([] => .bigint))) let moduleB = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - [function.wasmJsCall(function: reexportedJSFct, - withArgs: [], withWasmSignature: [] => [.wasmi64])!] + [ + function.wasmJsCall( + function: reexportedJSFct, + withArgs: [], withWasmSignature: [] => [.wasmi64])! + ] } } let exportsB = moduleB.loadExports() @@ -4114,10 +5436,10 @@ class WasmFoundationTests: XCTestCase { func testDefineElementSegments() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in - let f1 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} - let f2 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} + let f1 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } + let f2 = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } wasmModule.addElementSegment(elements: []) wasmModule.addElementSegment(elements: [f1]) wasmModule.addElementSegment(elements: [f1, f2]) @@ -4129,9 +5451,9 @@ class WasmFoundationTests: XCTestCase { func testDropElementSegments() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in b.buildWasmModule { wasmModule in - let function = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return []} + let function = wasmModule.addWasmFunction(with: [] => []) { _, _, _ in return [] } let segment = wasmModule.addElementSegment(elements: [function]) wasmModule.addWasmFunction(with: [] => []) { f, _, _ in f.wasmDropElementSegment(elementSegment: segment) @@ -4145,18 +5467,26 @@ class WasmFoundationTests: XCTestCase { func wasmTableInit(isTable64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { module in - let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(1)]} - let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} - let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} + let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(1)] + } + let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(2)] + } + let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(3)] + } // TODO(pawkra): add shared ref variant. - module.addTable(elementType: .wasmFuncRef(), + module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], @@ -4165,20 +5495,28 @@ class WasmFoundationTests: XCTestCase { let elemSegment2 = module.addElementSegment(elements: [f3, f3, f1, f2]) module.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in - let tableOffset = { (i: Int) in isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i))} - f.wasmTableInit(elementSegment: elemSegment2, table: table2, tableOffset: tableOffset(5), elementSegmentOffset: f.consti32(2), nrOfElementsToUpdate: f.consti32(2)) + let tableOffset = { (i: Int) in + isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i)) + } + f.wasmTableInit( + elementSegment: elemSegment2, table: table2, tableOffset: tableOffset(5), + elementSegmentOffset: f.consti32(2), nrOfElementsToUpdate: f.consti32(2)) let callIndirect = { (table: Variable, idx: Int) in let idxVar = isTable64 ? f.consti64(Int64(idx)) : f.consti32(Int32(idx)) - return f.wasmCallIndirect(signature: [] => [.wasmi64], table: table, functionArgs: [], tableIndex: idxVar) + return f.wasmCallIndirect( + signature: [] => [.wasmi64], table: table, functionArgs: [], + tableIndex: idxVar) } - return callIndirect(table2, 5) + callIndirect(table2, 6) + return callIndirect(table2, 5) + callIndirect(table2, 6) } } let res = b.callMethod(module.getExportedMethod(at: 3), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.arrayToStringForTesting(res)]) - } + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.arrayToStringForTesting(res)]) + } - testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") + testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") } func testTableInit32() throws { @@ -4192,39 +5530,58 @@ class WasmFoundationTests: XCTestCase { func wasmTableCopy(isTable64: Bool) throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram() { b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { module in - let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(1)]} - let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(2)]} - let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in return [f.consti64(3)]} + let f1 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(1)] + } + let f2 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(2)] + } + let f3 = module.addWasmFunction(with: [] => [.wasmi64]) { f, _, _ in + return [f.consti64(3)] + } // TODO(pawkra): add shared ref variant. - let table1 = module.addTable(elementType: .wasmFuncRef(), + let table1 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, definedEntries: [], definedEntryValues: [], isTable64: isTable64) - let table2 = module.addTable(elementType: .wasmFuncRef(), + let table2 = module.addTable( + elementType: .wasmFuncRef(), minSize: 10, - definedEntries: (0..<4).map { WasmTableType.IndexInTableAndWasmSignature.init(indexInTable: $0, signature: [] => [.wasmi64]) }, + definedEntries: (0..<4).map { + WasmTableType.IndexInTableAndWasmSignature.init( + indexInTable: $0, signature: [] => [.wasmi64]) + }, definedEntryValues: [f3, f3, f1, f2], isTable64: isTable64) module.addWasmFunction(with: [] => [.wasmi64, .wasmi64]) { f, _, _ in - let const = { (i: Int) in isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i))} - f.wasmTableCopy(dstTable: table1, srcTable: table2, dstOffset: const(1), srcOffset: const(2), count: const(2)) + let const = { (i: Int) in + isTable64 ? f.consti64(Int64(i)) : f.consti32(Int32(i)) + } + f.wasmTableCopy( + dstTable: table1, srcTable: table2, dstOffset: const(1), + srcOffset: const(2), count: const(2)) let callIndirect = { (table: Variable, idx: Int) in let idxVar = isTable64 ? f.consti64(Int64(idx)) : f.consti32(Int32(idx)) - return f.wasmCallIndirect(signature: [] => [.wasmi64], table: table, functionArgs: [], tableIndex: idxVar) + return f.wasmCallIndirect( + signature: [] => [.wasmi64], table: table, functionArgs: [], + tableIndex: idxVar) } return callIndirect(table1, 1) + callIndirect(table1, 2) } } let res = b.callMethod(module.getExportedMethod(at: 3), on: module.loadExports()) - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.arrayToStringForTesting(res)]) - } + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.arrayToStringForTesting(res)]) + } - testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") + testForOutput(program: jsProg, runner: runner, outputString: "1,2\n") } func testTableCopy32() throws { @@ -4245,27 +5602,35 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) - let arrayOfArrays = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: false), mutability: true, indexType: arrayi32) + let arrayOfArrays = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: false), mutability: true, + indexType: arrayi32) return [arrayi32, arrayOfArrays] } let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let array = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [ - function.consti32(42), - function.consti32(43), - function.consti32(44), - ]) - let arrayOfArrays = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [array]) - let innerArray = function.wasmArrayGet(array: arrayOfArrays, index: function.consti32(0)) - function.wasmArraySet(array: innerArray, index: function.consti32(1), element: function.consti32(100)) + let array = function.wasmArrayNewFixed( + arrayType: typeGroup[0], + elements: [ + function.consti32(42), + function.consti32(43), + function.consti32(44), + ]) + let arrayOfArrays = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [array]) + let innerArray = function.wasmArrayGet( + array: arrayOfArrays, index: function.consti32(0)) + function.wasmArraySet( + array: innerArray, index: function.consti32(1), element: function.consti32(100)) return [function.wasmArrayGet(array: innerArray, index: function.consti32(1))] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4287,17 +5652,24 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for type in typeGroup { - wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { function, label, args in - let array = function.wasmArrayNewFixed(arrayType: type, elements: [ - function.consti32(-100), - function.consti32(0), - ]) - function.wasmArraySet(array: array, index: function.consti32(1), - element: function.consti32(42)) + wasmModule.addWasmFunction(with: [] => [.wasmi32, .wasmi32, .wasmi32]) { + function, label, args in + let array = function.wasmArrayNewFixed( + arrayType: type, + elements: [ + function.consti32(-100), + function.consti32(0), + ]) + function.wasmArraySet( + array: array, index: function.consti32(1), + element: function.consti32(42)) return [ - function.wasmArrayGet(array: array, index: function.consti32(0), isSigned: true), - function.wasmArrayGet(array: array, index: function.consti32(0), isSigned: false), - function.wasmArrayGet(array: array, index: function.consti32(1), isSigned: true), + function.wasmArrayGet( + array: array, index: function.consti32(0), isSigned: true), + function.wasmArrayGet( + array: array, index: function.consti32(0), isSigned: false), + function.wasmArrayGet( + array: array, index: function.consti32(1), isSigned: true), ] } } @@ -4329,11 +5701,15 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let array1 = function.wasmArrayNewDefault(arrayType: typeGroup[0], size: function.consti32(3)) - let array2 = function.wasmArrayNewDefault(arrayType: typeGroup[1], size: function.consti32(2)) + let array1 = function.wasmArrayNewDefault( + arrayType: typeGroup[0], size: function.consti32(3)) + let array2 = function.wasmArrayNewDefault( + arrayType: typeGroup[1], size: function.consti32(2)) let sum = function.wasmi32BinOp( function.wasmArrayGet(array: array1, index: function.consti32(0)), - function.truncatef64Toi32(function.wasmArrayGet(array: array2, index: function.consti32(1)), isSigned: true), + function.truncatef64Toi32( + function.wasmArrayGet(array: array2, index: function.consti32(1)), + isSigned: true), binOpKind: .Add) return [sum] } @@ -4341,7 +5717,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4361,8 +5738,10 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arraySize3 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(3)) - let arraySize7 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(7)) + let arraySize3 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(3)) + let arraySize7 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(7)) let result = function.wasmi32BinOp( function.wasmArrayLen(arraySize3), function.wasmArrayLen(arraySize7), @@ -4373,7 +5752,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4388,8 +5768,14 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let types = b.wasmDefineTypeGroup { - let structOfi32 = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], indexTypes: []) - let structOfStruct = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [structOfi32]) + let structOfi32 = b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + let structOfStruct = b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field( + type: .wasmRef(.Index(), nullability: true), mutability: true) + ], indexTypes: [structOfi32]) return [structOfi32, structOfStruct] } let structOfi32 = types[0] @@ -4401,15 +5787,18 @@ class WasmGCTests: XCTestCase { function.wasmStructSet(theStruct: innerStruct, fieldIndex: 0, value: args[0]) let outerStruct = function.wasmStructNewDefault(structType: structOfStruct) function.wasmStructSet(theStruct: outerStruct, fieldIndex: 0, value: innerStruct) - let retrievedInnerStruct = function.wasmStructGet(theStruct: outerStruct, fieldIndex: 0) - let retrievedValue = function.wasmStructGet(theStruct: retrievedInnerStruct, fieldIndex: 0) + let retrievedInnerStruct = function.wasmStructGet( + theStruct: outerStruct, fieldIndex: 0) + let retrievedValue = function.wasmStructGet( + theStruct: retrievedInnerStruct, fieldIndex: 0) return [retrievedValue] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4424,8 +5813,14 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let types = b.wasmDefineTypeGroup { - let structOfi32 = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], indexTypes: []) - let structOfStruct = b.wasmDefineStructType(fields: [WasmStructTypeDescription.Field(type: .wasmRef(.Index(), nullability: true), mutability: true)], indexTypes: [structOfi32]) + let structOfi32 = b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + let structOfStruct = b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field( + type: .wasmRef(.Index(), nullability: true), mutability: true) + ], indexTypes: [structOfi32]) return [structOfi32, structOfStruct] } let structOfi32 = types[0] @@ -4434,16 +5829,20 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in let innerStruct = function.wasmStructNew(structType: structOfi32, fields: [args[0]]) - let outerStruct = function.wasmStructNew(structType: structOfStruct, fields: [innerStruct]) - let retrievedInnerStruct = function.wasmStructGet(theStruct: outerStruct, fieldIndex: 0) - let retrievedValue = function.wasmStructGet(theStruct: retrievedInnerStruct, fieldIndex: 0) + let outerStruct = function.wasmStructNew( + structType: structOfStruct, fields: [innerStruct]) + let retrievedInnerStruct = function.wasmStructGet( + theStruct: outerStruct, fieldIndex: 0) + let retrievedValue = function.wasmStructGet( + theStruct: retrievedInnerStruct, fieldIndex: 0) return [retrievedValue] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let program = b.finalize() @@ -4458,19 +5857,26 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let structType = b.wasmDefineTypeGroup { - return [b.wasmDefineStructType(fields: [ - WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), - WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), - WasmStructTypeDescription.Field(type: .wasmPackedI16, mutability: true), - ], indexTypes: [])] + return [ + b.wasmDefineStructType( + fields: [ + WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), + WasmStructTypeDescription.Field(type: .wasmPackedI8, mutability: true), + WasmStructTypeDescription.Field(type: .wasmPackedI16, mutability: true), + ], indexTypes: []) + ] }[0] let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [] => Array(repeating: .wasmi32, count: 6)) { function, label, args in + wasmModule.addWasmFunction(with: [] => Array(repeating: .wasmi32, count: 6)) { + function, label, args in let structObj = function.wasmStructNewDefault(structType: structType) - function.wasmStructSet(theStruct: structObj, fieldIndex: 0, value: function.consti32(-100)) - function.wasmStructSet(theStruct: structObj, fieldIndex: 1, value: function.consti32(42)) - function.wasmStructSet(theStruct: structObj, fieldIndex: 2, value: function.consti32(-10_000)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 0, value: function.consti32(-100)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 1, value: function.consti32(42)) + function.wasmStructSet( + theStruct: structObj, fieldIndex: 2, value: function.consti32(-10_000)) return [ function.wasmStructGet(theStruct: structObj, fieldIndex: 0, isSigned: true), function.wasmStructGet(theStruct: structObj, fieldIndex: 0, isSigned: false), @@ -4489,7 +5895,8 @@ class WasmGCTests: XCTestCase { let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) - testForOutput(program: jsProg, runner: runner, outputString: "-100,156,42,42,-10000,55536\n") + testForOutput( + program: jsProg, runner: runner, outputString: "-100,156,42,42,-10000,55536\n") } func testSignature() throws { @@ -4499,8 +5906,9 @@ class WasmGCTests: XCTestCase { let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) let selfRef = b.wasmDefineForwardOrSelfReference() let signature = b.wasmDefineSignatureType( - signature: [.wasmRef(.Index(), nullability: true), .wasmi32] => - [.wasmi32, .wasmRef(.Index(), nullability: true)], + signature: [.wasmRef(.Index(), nullability: true), .wasmi32] => [ + .wasmi32, .wasmRef(.Index(), nullability: true), + ], indexTypes: [arrayi32, selfRef]) return [arrayi32, signature] } @@ -4535,7 +5943,7 @@ class WasmGCTests: XCTestCase { let arrayType = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) let signature = b.wasmDefineSignatureType( signature: [.wasmRef(.Index(), nullability: true)] - => [.wasmRef(.Index(), nullability: true)], + => [.wasmRef(.Index(), nullability: true)], indexTypes: [arrayType, arrayType]) return [arrayType, signature] } @@ -4545,13 +5953,16 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let index = function.consti32(0) - let array = function.wasmArrayNewFixed(arrayType: arrayType, + let array = function.wasmArrayNewFixed( + arrayType: arrayType, elements: [function.consti32(1)]) - let arrayResult = function.wasmBuildLoop(with: loopSignature, args: [array]) { loopLabel, args in + let arrayResult = function.wasmBuildLoop(with: loopSignature, args: [array]) { + loopLabel, args in let val = function.wasmArrayGet(array: args[0], index: index) let newVal = function.wasmi32BinOp(val, val, binOpKind: .Add) function.wasmArraySet(array: args[0], index: index, element: newVal) - let cond = function.wasmi32CompareOp(newVal, function.consti32(50), using: .Lt_s) + let cond = function.wasmi32CompareOp( + newVal, function.consti32(50), using: .Lt_s) function.wasmBranchIf(cond, to: loopLabel, args: [args[0]]) return args }[0] @@ -4572,25 +5983,30 @@ class WasmGCTests: XCTestCase { let runner = try GetJavaScriptExecutorOrSkipTest() let jsProg = buildAndLiftProgram { b in - let structType = b.wasmDefineTypeGroup {[ - b.wasmDefineStructType( - fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], - indexTypes: []) - ]}[0] + let structType = b.wasmDefineTypeGroup { + [ + b.wasmDefineStructType( + fields: [WasmStructTypeDescription.Field(type: .wasmi32, mutability: true)], + indexTypes: []) + ] + }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in let structVal = function.wasmStructNewDefault(structType: structType) - function.wasmStructSet(theStruct: structVal, fieldIndex: 0, value: function.consti32(1)) + function.wasmStructSet( + theStruct: structVal, fieldIndex: 0, value: function.consti32(1)) let signature = [b.type(of: structVal)] => [.wasmi32] // This loop creates a new struct on each iteration just for having different // values on the loop entry and the loop backedge (`br_if`). - return function.wasmBuildLoop(with: signature, args: [structVal]) { loopLabel, args in + return function.wasmBuildLoop(with: signature, args: [structVal]) { + loopLabel, args in let val = function.wasmStructGet(theStruct: args[0], fieldIndex: 0) let newVal = function.wasmi32BinOp(val, val, binOpKind: .Add) let newStruct = function.wasmStructNewDefault(structType: structType) function.wasmStructSet(theStruct: newStruct, fieldIndex: 0, value: newVal) - let cond = function.wasmi32CompareOp(newVal, function.consti32(50), using: .Lt_s) + let cond = function.wasmi32CompareOp( + newVal, function.consti32(50), using: .Lt_s) function.wasmBranchIf(cond, to: loopLabel, args: [newStruct]) return [newVal] } @@ -4614,27 +6030,31 @@ class WasmGCTests: XCTestCase { let arrayType = b.wasmDefineTypeGroup { let selfReference = b.wasmDefineForwardOrSelfReference() - let arrayOfSelf = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: selfReference) + let arrayOfSelf = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: selfReference) return [arrayOfSelf] }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in // We can arbitrarily nest these self-referencing arrays. - let array1 = function.wasmArrayNewDefault(arrayType: arrayType, size: function.consti32(12)) + let array1 = function.wasmArrayNewDefault( + arrayType: arrayType, size: function.consti32(12)) let array2 = function.wasmArrayNewFixed(arrayType: arrayType, elements: [array1]) let array3 = function.wasmArrayNewFixed(arrayType: arrayType, elements: [array2]) let zero = function.consti32(0) let innerArray = function.wasmArrayGet( - array: function.wasmArrayGet(array: array3, index: zero), - index: zero) + array: function.wasmArrayGet(array: array3, index: zero), + index: zero) return [function.wasmArrayLen(innerArray)] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4650,7 +6070,9 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let forwardReference = b.wasmDefineForwardOrSelfReference() - let arrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: forwardReference) + let arrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: forwardReference) let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) b.wasmResolveForwardReference(forwardReference, to: arrayi32) return [arrayOfArrayi32, arrayi32] @@ -4658,19 +6080,22 @@ class WasmGCTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [function.consti32(42)]) - let arrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [arrayi32]) + let arrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [function.consti32(42)]) + let arrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[0], elements: [arrayi32]) let zero = function.consti32(0) let result = function.wasmArrayGet( - array: function.wasmArrayGet(array: arrayOfArrayi32, index: zero), - index: zero) + array: function.wasmArrayGet(array: arrayOfArrayi32, index: zero), + index: zero) return [result] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4686,29 +6111,39 @@ class WasmGCTests: XCTestCase { let typeGroup = b.wasmDefineTypeGroup { let forwardReference = b.wasmDefineForwardOrSelfReference() - let arrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) let arrayi32 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) b.wasmResolveForwardReference(forwardReference, to: arrayi32) - let arrayOfArrayOfArrayi32 = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arrayOfArrayOfArrayi32 = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) b.wasmResolveForwardReference(forwardReference, to: arrayOfArrayi32) // Here the forward reference acts as a self reference as we don't resolve it again. - let arraySelf = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: forwardReference) + let arraySelf = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, + indexType: forwardReference) return [arrayOfArrayi32, arrayi32, arrayOfArrayOfArrayi32, arraySelf] } let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in - let arrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[1], elements: [function.consti32(42)]) - let arrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[0], elements: [arrayi32]) - let arrayOfArrayOfArrayi32 = function.wasmArrayNewFixed(arrayType: typeGroup[2], elements: [arrayOfArrayi32]) + let arrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[1], elements: [function.consti32(42)]) + let arrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[0], elements: [arrayi32]) + let arrayOfArrayOfArrayi32 = function.wasmArrayNewFixed( + arrayType: typeGroup[2], elements: [arrayOfArrayi32]) let zero = function.consti32(0) let result = function.wasmArrayGet( - array: function.wasmArrayGet(array: function.wasmArrayGet( - array: arrayOfArrayOfArrayi32, - index: zero), + array: function.wasmArrayGet( + array: function.wasmArrayGet( + array: arrayOfArrayOfArrayi32, index: zero), - index: zero) + index: zero), + index: zero) return [result] } @@ -4716,19 +6151,23 @@ class WasmGCTests: XCTestCase { // that we produce valid Wasm (which means that the type group above was generated as // desired.) wasmModule.addWasmFunction(with: [] => []) { function, label, args in - let arraySelf = function.wasmArrayNewFixed(arrayType: typeGroup[3], elements: [ - function.wasmRefNull(typeDef: typeGroup[3]) - ]) + let arraySelf = function.wasmArrayNewFixed( + arrayType: typeGroup[3], + elements: [ + function.wasmRefNull(typeDef: typeGroup[3]) + ]) // We can also store the arraySelf as an element into iself as the forwardReference // got reset to a selfReference after the wasmResolveForwardReference() operation. - function.wasmArraySet(array: arraySelf, index: function.consti32(0), element: arraySelf) + function.wasmArraySet( + array: arraySelf, index: function.consti32(0), element: arraySelf) return [] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let wasmOut = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) + let wasmOut = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(0)]) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: wasmOut)]) let prog = b.finalize() @@ -4746,7 +6185,9 @@ class WasmGCTests: XCTestCase { return [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] } let typeGroupB = b.wasmDefineTypeGroup { - let typeWithDependency = b.wasmDefineArrayType(elementType: .wasmRef(.Index(), nullability: true), mutability: false, indexType: typeGroupA[0]) + let typeWithDependency = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: false, + indexType: typeGroupA[0]) let arrayi64 = b.wasmDefineArrayType(elementType: .wasmi64, mutability: true) return [arrayi64, typeWithDependency] } @@ -4755,7 +6196,8 @@ class WasmGCTests: XCTestCase { // typeGroupA, it still needs to import both typegroups. let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, label, args in - let arrayi64 = function.wasmArrayNewFixed(arrayType: typeGroupB[0], elements: [function.consti64(42)]) + let arrayi64 = function.wasmArrayNewFixed( + arrayType: typeGroupB[0], elements: [function.consti64(42)]) let result = function.wasmArrayGet(array: arrayi64, index: function.consti32(0)) return [result] } @@ -4777,7 +6219,9 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {[b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)]}[0] + let arrayType = b.wasmDefineTypeGroup { + [b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)] + }[0] let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in @@ -4803,13 +6247,16 @@ class WasmGCTests: XCTestCase { } func refNullAbstractTypes(sharedRef: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let unsupportedHeapType: Set = sharedRef ? [.WasmFunc, .WasmNoFunc, .WasmExn, .WasmNoExn] : [] - let supportedHeapTypes = Array(Set(WasmAbstractHeapType.allCases).subtracting(unsupportedHeapType)) + let unsupportedHeapType: Set = + sharedRef ? [.WasmFunc, .WasmNoFunc, .WasmExn, .WasmNoExn] : [] + let supportedHeapTypes = Array( + Set(WasmAbstractHeapType.allCases).subtracting(unsupportedHeapType)) let module = b.buildWasmModule { wasmModule in for heapType in supportedHeapTypes { @@ -4829,8 +6276,9 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let exportedFctCount = supportedHeapTypes.count - + supportedHeapTypes.count {$0.isUsableInJS()} + let exportedFctCount = + supportedHeapTypes.count + + supportedHeapTypes.count { $0.isUsableInJS() } for i in 0.. [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmEqRef(), .wasmEqRef()] => [.wasmi32]) { + function, label, args in return [function.wasmRefEq(args[0], args[1])] } wasmModule.addWasmFunction(with: [] => [.wasmEqRef()]) { function, label, args in @@ -4879,7 +6330,7 @@ class WasmGCTests: XCTestCase { b.callMethod(wasmRefEq, on: exports, withArgs: [b.loadInt(1), b.loadInt(1)]), b.callMethod(wasmRefEq, on: exports, withArgs: [b.loadInt(0), b.loadInt(1)]), b.callMethod(wasmRefEq, on: exports, withArgs: [array, array]), - b.callMethod(wasmRefEq, on: exports, withArgs: [array, otherArray]) + b.callMethod(wasmRefEq, on: exports, withArgs: [array, otherArray]), ] for input in cases { b.callFunction(outputFunc, withArgs: [input]) } @@ -4890,7 +6341,8 @@ class WasmGCTests: XCTestCase { } func i31Ref(shared: Bool) throws { - let runner = try GetJavaScriptExecutorOrSkipTest(type: .any, withArguments: ["--experimental-wasm-shared"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .any, withArguments: ["--experimental-wasm-shared"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() @@ -4900,28 +6352,36 @@ class WasmGCTests: XCTestCase { wasmModule.addWasmFunction(with: [.wasmi32] => [i31RefT]) { function, label, args in [function.wasmRefI31(args[0], shared: shared)] } - wasmModule.addWasmFunction(with: [i31RefT] => [.wasmi32, .wasmi32]) { function, label, args in - [function.wasmI31Get(args[0], isSigned: true), - function.wasmI31Get(args[0], isSigned: false)] + wasmModule.addWasmFunction(with: [i31RefT] => [.wasmi32, .wasmi32]) { + function, label, args in + [ + function.wasmI31Get(args[0], isSigned: true), + function.wasmI31Get(args[0], isSigned: false), + ] } } let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let positiveI31 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) - let negativeI31 = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-42)]) + let positiveI31 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(42)]) + let negativeI31 = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(-42)]) // An i31ref converts to a JS number. b.callFunction(outputFunc, withArgs: [positiveI31]) b.callFunction(outputFunc, withArgs: [negativeI31]) - let positiveResults = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [positiveI31]) - let negativeResults = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [negativeI31]) + let positiveResults = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [positiveI31]) + let negativeResults = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [negativeI31]) b.callFunction(outputFunc, withArgs: [b.arrayToStringForTesting(positiveResults)]) b.callFunction(outputFunc, withArgs: [b.arrayToStringForTesting(negativeResults)]) let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) - testForOutput(program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") + testForOutput( + program: jsProg, runner: runner, outputString: "42\n-42\n42,42\n-42,2147483606\n") } func testi31RefShared() throws { @@ -4939,7 +6399,8 @@ class WasmGCTests: XCTestCase { let b = fuzzer.makeBuilder() let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmRefExtern()]) { + function, label, args in // As ref.i31 produces a non null `ref i31`, the result of extern.convert_any is a // non-nullable `ref extern`. let result = function.wasmExternConvertAny(function.wasmRefI31(args[0])) @@ -4947,20 +6408,23 @@ class WasmGCTests: XCTestCase { return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmRefAny()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmRefAny()]) { + function, label, args in let result = function.wasmAnyConvertExtern(args[0]) XCTAssertEqual(b.type(of: result), .wasmRefAny()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmExternRef()]) { function, label, args in - let result = function.wasmExternConvertAny(function.wasmRefNull(type: .wasmNullRef())) + let result = function.wasmExternConvertAny( + function.wasmRefNull(type: .wasmNullRef())) XCTAssertEqual(b.type(of: result), .wasmExternRef()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmAnyRef()]) { function, label, args in - let result = function.wasmAnyConvertExtern(function.wasmRefNull(type: .wasmNullExternRef())) + let result = function.wasmAnyConvertExtern( + function.wasmRefNull(type: .wasmNullExternRef())) XCTAssertEqual(b.type(of: result), .wasmAnyRef()) return [result] } @@ -4969,7 +6433,8 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") for i in 0..<4 { - let result = b.callMethod(module.getExportedMethod(at: i), on: exports, withArgs: [b.loadInt(42)]) + let result = b.callMethod( + module.getExportedMethod(at: i), on: exports, withArgs: [b.loadInt(42)]) b.callFunction(outputFunc, withArgs: [result]) } @@ -4984,7 +6449,9 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {b.wasmDefineArrayType(elementType: .wasmi32, mutability: false)}[0] + let arrayType = b.wasmDefineTypeGroup { + b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) + }[0] let tagi32 = b.createWasmTag(parameterTypes: [.wasmi32]) let module = b.buildWasmModule { wasmModule in @@ -4999,10 +6466,14 @@ class WasmGCTests: XCTestCase { function.wasmRefTest(array, refType: refNullType, typeDef: arrayType), function.wasmRefTest(null, refType: refNullType, typeDef: arrayType), ] - let result = results.reduce(function.consti32(0), { acc, r in - let shifted = function.wasmi32BinOp(acc, function.consti32(10), binOpKind: WasmIntegerBinaryOpKind.Mul) - return function.wasmi32BinOp(shifted, r, binOpKind: WasmIntegerBinaryOpKind.Add) - }) + let result = results.reduce( + function.consti32(0), + { acc, r in + let shifted = function.wasmi32BinOp( + acc, function.consti32(10), binOpKind: WasmIntegerBinaryOpKind.Mul) + return function.wasmi32BinOp( + shifted, r, binOpKind: WasmIntegerBinaryOpKind.Add) + }) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in @@ -5016,13 +6487,18 @@ class WasmGCTests: XCTestCase { let result = function.wasmRefTest(ref, refType: refType, typeDef: arrayType) return [result] } - wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmRefExtern()] => [.wasmi32]) { + function, label, args in let result = function.wasmRefTest(args[0], refType: .wasmNullExternRef()) return [result] } wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in - let exnref = function.wasmBuildBlockWithResults(with: [] => [.wasmExnRef()], args: []) { catchLabel, _ in - function.wasmBuildTryTable(with: [] => [], args: [catchLabel], catches: [.AllRef]) { _, _ in + let exnref = function.wasmBuildBlockWithResults( + with: [] => [.wasmExnRef()], args: [] + ) { catchLabel, _ in + function.wasmBuildTryTable( + with: [] => [], args: [catchLabel], catches: [.AllRef] + ) { _, _ in function.WasmBuildThrow(tag: tagi32, inputs: [function.consti32(42)]) return [] } @@ -5051,18 +6527,23 @@ class WasmGCTests: XCTestCase { let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment()) let b = fuzzer.makeBuilder() - let arrayType = b.wasmDefineTypeGroup {b.wasmDefineArrayType(elementType: .wasmi32, mutability: false)}[0] + let arrayType = b.wasmDefineTypeGroup { + b.wasmDefineArrayType(elementType: .wasmi32, mutability: false) + }[0] let module = b.buildWasmModule { wasmModule in - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmArrayRef()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmArrayRef()]) { + function, label, args in let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: [args[0]]) return [array] } - wasmModule.addWasmFunction(with: [.wasmEqRef()] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmEqRef()] => [.wasmi32]) { + function, label, args in let (refType, nonNullRefType, abstractRefType) = ( ILType.wasmRef(.Index(), nullability: true), ILType.wasmRef(.Index(), nullability: false), - ILType.wasmRef(.Abstract(HeapTypeInfo(.WasmArray, shared: false)), nullability: true), + ILType.wasmRef( + .Abstract(HeapTypeInfo(.WasmArray, shared: false)), nullability: true), ) let arrays = [ function.wasmRefCast(args[0], refType: refType, typeDef: arrayType), @@ -5071,9 +6552,12 @@ class WasmGCTests: XCTestCase { ] let value1 = function.wasmArrayGet(array: arrays[0], index: function.consti32(0)) let value2 = function.wasmArrayGet(array: arrays[1], index: function.consti32(0)) - return [function.wasmi32BinOp(value1, value2, binOpKind: WasmIntegerBinaryOpKind.Add)] + return [ + function.wasmi32BinOp(value1, value2, binOpKind: WasmIntegerBinaryOpKind.Add) + ] } - wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmRefExtern()]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmExternRef()] => [.wasmRefExtern()]) { + function, label, args in let cast = function.wasmRefCast(args[0], refType: .wasmRefExtern()) return [cast] } @@ -5081,10 +6565,13 @@ class WasmGCTests: XCTestCase { let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") - let arrayRef = b.callMethod(module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(21)]) - let result = b.callMethod(module.getExportedMethod(at: 1), on: exports, withArgs: [arrayRef]) + let arrayRef = b.callMethod( + module.getExportedMethod(at: 0), on: exports, withArgs: [b.loadInt(21)]) + let result = b.callMethod( + module.getExportedMethod(at: 1), on: exports, withArgs: [arrayRef]) b.callFunction(outputFunc, withArgs: [result]) - let ext = b.callMethod(module.getExportedMethod(at: 2), on: exports, withArgs: [b.loadInt(5)]) + let ext = b.callMethod( + module.getExportedMethod(at: 2), on: exports, withArgs: [b.loadInt(5)]) b.callFunction(outputFunc, withArgs: [ext]) let prog = b.finalize() @@ -5094,11 +6581,12 @@ class WasmGCTests: XCTestCase { func testRefCastError() throws { let runner = try GetJavaScriptExecutorOrSkipTest() - let jsProg = buildAndLiftProgram{ b in + let jsProg = buildAndLiftProgram { b in let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmFuncRef()]) { function, label, args in let funcref = function.wasmRefNull(type: ILType.wasmFuncRef()) - let nullFuncType = ILType.wasmRef(.Abstract(HeapTypeInfo.init(.WasmFunc, shared: false)), nullability: false) + let nullFuncType = ILType.wasmRef( + .Abstract(HeapTypeInfo.init(.WasmFunc, shared: false)), nullability: false) let cast = function.wasmRefCast(funcref, refType: nullFuncType) return [cast] } @@ -5131,7 +6619,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmIntegerBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi64]) { + function, label, args in [function.wasmi64BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5227,7 +6716,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmIntegerBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5323,7 +6813,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmFloatBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmf64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmf64]) { + function, label, args in [function.wasmf64BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5335,7 +6826,8 @@ class WasmNumericalTests: XCTestCase { let divFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Div.rawValue)) let minFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Min.rawValue)) let maxFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Max.rawValue)) - let copysignFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) + let copysignFunc = module.getExportedMethod( + at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -5387,7 +6879,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for binOp in WasmFloatBinaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmf32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmf32]) { + function, label, args in [function.wasmf32BinOp(args[0], args[1], binOpKind: binOp)] } } @@ -5399,7 +6892,8 @@ class WasmNumericalTests: XCTestCase { let divFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Div.rawValue)) let minFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Min.rawValue)) let maxFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Max.rawValue)) - let copysignFunc = module.getExportedMethod(at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) + let copysignFunc = module.getExportedMethod( + at: Int(WasmFloatBinaryOpKind.Copysign.rawValue)) let exports = module.loadExports() let outputFunc = b.createNamedVariable(forBuiltin: "output") @@ -5452,7 +6946,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmIntegerUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64] => [.wasmi64]) { + function, label, args in [function.wasmi64UnOp(args[0], unOpKind: unOp)] } } @@ -5499,7 +6994,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmIntegerUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32UnOp(args[0], unOpKind: unOp)] } } @@ -5547,7 +7043,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmFloatUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64] => [.wasmf64]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64] => [.wasmf64]) { + function, label, args in [function.wasmf64UnOp(args[0], unOpKind: unOp)] } } @@ -5610,7 +7107,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for unOp in WasmFloatUnaryOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32] => [.wasmf32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32] => [.wasmf32]) { + function, label, args in [function.wasmf32UnOp(args[0], unOpKind: unOp)] } } @@ -5674,7 +7172,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmIntegerCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi64, .wasmi64] => [.wasmi32]) { + function, label, args in [function.wasmi64CompareOp(args[0], args[1], using: compOp)] } } @@ -5765,7 +7264,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmIntegerCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmi32, .wasmi32] => [.wasmi32]) { + function, label, args in [function.wasmi32CompareOp(args[0], args[1], using: compOp)] } } @@ -5857,7 +7357,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmFloatCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf64, .wasmf64] => [.wasmi32]) { + function, label, args in [function.wasmf64CompareOp(args[0], args[1], using: compOp)] } } @@ -5916,7 +7417,8 @@ class WasmNumericalTests: XCTestCase { let module = b.buildWasmModule { wasmModule in for compOp in WasmFloatCompareOpKind.allCases { // Instantiate a function for each operator - wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmi32]) { function, label, args in + wasmModule.addWasmFunction(with: [.wasmf32, .wasmf32] => [.wasmi32]) { + function, label, args in [function.wasmf32CompareOp(args[0], args[1], using: compOp)] } } @@ -6342,8 +7844,8 @@ class WasmNumericalTests: XCTestCase { ExpectEq(f32Asi32Func, [b.loadFloat(1.2)], "1067030938") ExpectEq(f64Asi64Func, [b.loadFloat(1.2)], "4608083138725491507") - ExpectEq(i32Asf32Func, [b.loadInt(1067030938)], "1.2000000476837158") - ExpectEq(i64Asf64Func, [b.loadBigInt(4608083138725491507)], "1.2") + ExpectEq(i32Asf32Func, [b.loadInt(1_067_030_938)], "1.2000000476837158") + ExpectEq(i64Asf64Func, [b.loadBigInt(4_608_083_138_725_491_507)], "1.2") let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -6387,7 +7889,7 @@ class WasmNumericalTests: XCTestCase { let outputFunc = b.createNamedVariable(forBuiltin: "output") var outputString = "" - let ExpectEq = { (function: String, arguments: [Variable], output: String)in + let ExpectEq = { (function: String, arguments: [Variable], output: String) in let result = b.callMethod(function, on: exports, withArgs: arguments) b.callFunction(outputFunc, withArgs: [b.callMethod("toString", on: result)]) outputString += output + "\n" @@ -6405,8 +7907,8 @@ class WasmNumericalTests: XCTestCase { ExpectEq(signExtend16Intoi64Func, [b.loadBigInt(0xfffe)], "-2") ExpectEq(signExtend16Intoi64Func, [b.loadBigInt(0xff0001)], "1") - ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xfffffffe)], "-2") - ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xff00000001)], "1") + ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xffff_fffe)], "-2") + ExpectEq(signExtend32Intoi64Func, [b.loadBigInt(0xff_0000_0001)], "1") let prog = b.finalize() let jsProg = fuzzer.lifter.lift(prog) @@ -6538,7 +8040,8 @@ class WasmSpliceTests: XCTestCase { b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) // +1 for the wasm-gc signature type that is created implicitly. splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) @@ -6583,7 +8086,8 @@ class WasmSpliceTests: XCTestCase { b.buildWasmModule { module in module.addWasmFunction(with: [] => []) { function, label, args in let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) // +1 for the wasm-gc signature type that is created implicitly. splicePoint = b.indexOfNextInstruction() + 1 function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) @@ -6615,7 +8119,8 @@ class WasmSpliceTests: XCTestCase { module.addWasmFunction(with: [] => []) { function, _, _ in let _ = function.constf64(42.42) let argument = function.consti32(1337) - let signature = ProgramBuilder.convertJsSignatureToWasmSignature([.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) + let signature = ProgramBuilder.convertJsSignatureToWasmSignature( + [.number] => .integer, availableTypes: WeightedList([(.wasmi32, 1)])) function.wasmJsCall(function: f, withArgs: [argument], withWasmSignature: signature) return [] } @@ -6630,7 +8135,8 @@ class WasmSpliceTests: XCTestCase { class WasmJSPITests: XCTestCase { func testJSPI() throws { // We need to have the right arguments here and we need a shell that supports jspi. - let runner = try GetJavaScriptExecutorOrSkipTest(type: .user, withArguments: ["--wasm-staging", "--expose-gc"]) + let runner = try GetJavaScriptExecutorOrSkipTest( + type: .user, withArguments: ["--wasm-staging", "--expose-gc"]) let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) @@ -6642,7 +8148,9 @@ class WasmJSPITests: XCTestCase { let function = b.buildAsyncFunction(with: .parameters(n: 1)) { args in b.callFunction(b.createNamedVariable(forBuiltin: "gc")) let json = b.createNamedVariable(forBuiltin: "JSON") - b.callFunction(b.createNamedVariable(forBuiltin: "output"), withArgs: [b.callMethod("stringify", on: json, withArgs: [args[0]])]) + b.callFunction( + b.createNamedVariable(forBuiltin: "output"), + withArgs: [b.callMethod("stringify", on: json, withArgs: [args[0]])]) b.doReturn(b.loadInt(1)) } @@ -6653,7 +8161,11 @@ class WasmJSPITests: XCTestCase { // Now lets build the module let module = b.buildWasmModule { m in m.addWasmFunction(with: [.wasmExternRef()] => [.wasmi32]) { f, label, args in - [f.wasmJsCall(function: importFunction, withArgs: args, withWasmSignature: [.wasmExternRef()] => [.wasmi32])!] + [ + f.wasmJsCall( + function: importFunction, withArgs: args, + withWasmSignature: [.wasmExternRef()] => [.wasmi32])! + ] } } @@ -6692,7 +8204,11 @@ class WasmJSPITests: XCTestCase { let b = fuzzer.makeBuilder() let wasmGlobali64: Variable = b.createWasmGlobal(value: .wasmi64(1337), isMutable: true) - XCTAssertEqual(b.type(of: wasmGlobali64), .object(ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) + XCTAssertEqual( + b.type(of: wasmGlobali64), + .object( + ofGroup: "WasmGlobal", withProperties: ["value"], withMethods: ["valueOf"], + withWasmType: WasmGlobalType(valueType: ILType.wasmi64, isMutable: true))) let module = b.buildWasmModule { wasmModule in // Function 0, modifies the imported global. From 1d3e779b4732a62b50725e785ceb25b5e2deb7cd Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Tue, 31 Mar 2026 16:44:34 +0200 Subject: [PATCH 213/234] [format] Add formatting check to presubmit.py Bug: 430616180 Change-Id: I6784d3f4232e11b272cbb7a345713edff05c7426 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9156216 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Tools/presubmit.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) mode change 100644 => 100755 Tools/presubmit.py diff --git a/Tools/presubmit.py b/Tools/presubmit.py old mode 100644 new mode 100755 index 7c6efa58e..f9502c874 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -1,3 +1,19 @@ +#!/usr/bin/env python3 + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import os import shutil import subprocess @@ -13,7 +29,7 @@ "ast.proto" ] -def check_git_clean(): +def check_git_clean(info): """Check that the git repository does not have any uncommitted changes.""" result = subprocess.run( ["git", "diff", "--name-only"], @@ -23,7 +39,7 @@ def check_git_clean(): output = result.stdout.decode().strip() if output != "": diff_result = subprocess.run(["git", "diff"], cwd=BASE_DIR, capture_output=True, check=True) - assert False, f"Unexpected modified files: {output}\n== Diff ==\n{diff_result.stdout.decode()}" + assert False, f"Unexpected modified files {info}: {output}\n== Diff ==\n{diff_result.stdout.decode()}" def check_proto(): """Check that program.proto is up-to-date.""" @@ -31,7 +47,7 @@ def check_proto(): proto_dir = BASE_DIR / "Sources/Fuzzilli/Protobuf" subprocess.run(["python3", "./gen_programproto.py"], cwd=proto_dir, check=True) # gen_programproto.py should be a no-op. - check_git_clean() + check_git_clean("after running gen_programproto.py") if not shutil.which("protoc"): print("Skipping protobuf validation as protoc is not available.") @@ -48,12 +64,16 @@ def check_proto(): cmd = ["protoc", "--swift_opt=Visibility=Public", "--swift_out=."] + KNOWN_PROTO_FILES subprocess.run(cmd, cwd=proto_dir, check=True, env=env) # Regenerating the protobuf files should be a no-op. - check_git_clean() + check_git_clean("after regenerating protobuf files") + +def check_formatting(): + subprocess.run(["swift", "format", BASE_DIR, "--recursive", "--parallel", "--in-place"], check=True) + check_git_clean("after auto-formatting") def main(): - check_git_clean() + check_git_clean("before any checks") check_proto() - # TODO(mliedtke): Ensure formatting delta is zero once we enable automated formatting. + check_formatting() if __name__ == '__main__': From cbade79edaf1dae0c233890b7957f560008d2c63 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 8 Apr 2026 12:04:39 +0000 Subject: [PATCH 214/234] Add default parameters to generated functions This CL adds support for default parameters in generated functions. Methods with default parameters, and JS to FuzzIL compilation code will be added later. Change-Id: I5b3583a8656c72a4068c497677bd6f18c98badb8 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9176497 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 81 +++++++++++++++---- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 55 +++++++++---- Sources/Fuzzilli/FuzzIL/Instruction.swift | 5 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 32 ++++++-- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 9 ++- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 49 ++++++++--- Sources/Fuzzilli/Protobuf/operations.pb.swift | 9 ++- Sources/Fuzzilli/Protobuf/operations.proto | 1 + Tests/FuzzilliTests/LifterTest.swift | 74 +++++++++++++++++ 9 files changed, 264 insertions(+), 51 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 631f5a3f9..c6c701d4c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3324,11 +3324,46 @@ public class ProgramBuilder { return parameters.count } - public static func parameters(n: Int, hasRestParameter: Bool = false) - -> SubroutineDescriptor - { + public static func parameters( + n: Int, hasRestParameter: Bool = false, defaultParameterIndices: [Int] = [] + ) -> SubroutineDescriptor { return SubroutineDescriptor( - withParameters: Parameters(count: n, hasRestParameter: hasRestParameter)) + withParameters: Parameters( + count: n, hasRestParameter: hasRestParameter, + defaultParameterIndices: defaultParameterIndices)) + } + + /// Returns a copy of this SubroutineDescriptor but with some parameters turned into default parameters. + public func withRandomDefaultParameters( + probability chance: Double, randomVariable: () -> Variable + ) + -> (SubroutineDescriptor, [Variable]) + { + var defaultParameterIndices = [Int]() + var defaultValues = [Variable]() + if self.parameters.count > 0 { + for i in 0.. SubroutineDescriptor { @@ -3364,11 +3399,13 @@ public class ProgramBuilder { @discardableResult public func buildPlainFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginPlainFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndPlainFunction()) return instr.output @@ -3376,10 +3413,13 @@ public class ProgramBuilder { @discardableResult public func buildArrowFunction( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginArrowFunction(parameters: descriptor.parameters)) + let instr = emit( + BeginArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndArrowFunction()) return instr.output @@ -3388,11 +3428,13 @@ public class ProgramBuilder { @discardableResult public func buildGeneratorFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginGeneratorFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndGeneratorFunction()) return instr.output @@ -3401,11 +3443,13 @@ public class ProgramBuilder { @discardableResult public func buildAsyncFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( - BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName)) + BeginAsyncFunction(parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncFunction()) return instr.output @@ -3413,10 +3457,13 @@ public class ProgramBuilder { @discardableResult public func buildAsyncArrowFunction( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginAsyncArrowFunction(parameters: descriptor.parameters)) + let instr = emit( + BeginAsyncArrowFunction(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncArrowFunction()) return instr.output @@ -3425,12 +3472,14 @@ public class ProgramBuilder { @discardableResult public func buildAsyncGeneratorFunction( with descriptor: SubroutineDescriptor, named functionName: String? = nil, - _ body: ([Variable]) -> Void + defaultValues: [Variable] = [], _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = emit( BeginAsyncGeneratorFunction( - parameters: descriptor.parameters, functionName: functionName)) + parameters: descriptor.parameters, functionName: functionName), + withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndAsyncGeneratorFunction()) return instr.output diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index f759f51ff..93fd51a6f 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1504,11 +1504,15 @@ public let CodeGenerators: [CodeGenerator] = [ [ GeneratorStub("PlainFunctionBeginGenerator", provides: [.javascript, .subroutine]) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1532,11 +1536,15 @@ public let CodeGenerators: [CodeGenerator] = [ { b in // We could consider having a standalone DirectiveGenerator, but probably most of the time it won't do anything meaningful. // We could also consider keeping a list of known directives in the JavaScriptEnvironment, but currently we only use 'use strict'. - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginPlainFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1561,11 +1569,15 @@ public let CodeGenerators: [CodeGenerator] = [ "ArrowFunctionBeginGenerator", provides: [.subroutine, .javascript] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginArrowFunction(parameters: randomParameters.parameters)) + BeginArrowFunction(parameters: randomParameters.parameters), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1586,12 +1598,16 @@ public let CodeGenerators: [CodeGenerator] = [ "GeneratorFunctionBeginGenerator", provides: [.generatorFunction, .subroutine, .javascript] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) + parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1623,11 +1639,15 @@ public let CodeGenerators: [CodeGenerator] = [ GeneratorStub( "AsyncFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( - BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil)) + BeginAsyncFunction(parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1653,12 +1673,15 @@ public let CodeGenerators: [CodeGenerator] = [ "AsyncArrowFunctionBeginGenerator", provides: [.javascript, .asyncFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginAsyncArrowFunction( - parameters: randomParameters.parameters)) + parameters: randomParameters.parameters), withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } @@ -1689,12 +1712,16 @@ public let CodeGenerators: [CodeGenerator] = [ "AsyncGeneratorFunctionBeginGenerator", provides: [.javascript, .subroutine, .asyncFunction, .generatorFunction] ) { b in - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let instr = b.emit( BeginAsyncGeneratorFunction( - parameters: randomParameters.parameters, functionName: nil)) + parameters: randomParameters.parameters, functionName: nil), + withInputs: defaultValues) if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: instr.innerOutputs.last!) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index e40947e3b..8ccfd989e 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -329,6 +329,7 @@ extension Instruction: ProtobufConvertible { return Fuzzilli_Protobuf_Parameters.with { $0.count = UInt32(parameters.count) $0.hasRest_p = parameters.hasRestParameter + $0.defaultParameterIndices = parameters.defaultParameterIndices.map(UInt32.init) } } @@ -1754,7 +1755,9 @@ extension Instruction: ProtobufConvertible { } func convertParameters(_ parameters: Fuzzilli_Protobuf_Parameters) -> Parameters { - return Parameters(count: Int(parameters.count), hasRestParameter: parameters.hasRest_p) + return Parameters( + count: Int(parameters.count), hasRestParameter: parameters.hasRest_p, + defaultParameterIndices: parameters.defaultParameterIndices.map(Int.init)) } // Converts to the Wasm world global type diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 958602acf..8daeb1073 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1320,15 +1320,32 @@ public struct Parameters { private let numParameters: UInt32 /// Whether the last parameter is a rest parameter. let hasRestParameter: Bool + /// Indices of parameters that have a default value. + /// The n-th default parameter will be the n-th input to the BeginAnySubroutine instruction. + let defaultParameterIndices: [Int] /// The total number of parameters. This is equivalent to the number of inner outputs produced from the parameters. var count: Int { return Int(numParameters) } - init(count: Int, hasRestParameter: Bool = false) { + var numDefaultParameters: Int { + return defaultParameterIndices.count + } + + init(count: Int, hasRestParameter: Bool = false, defaultParameterIndices: [Int] = []) { + assert( + !hasRestParameter || !defaultParameterIndices.contains(count - 1), + "Rest parameter cannot have a default value") + assert( + defaultParameterIndices.allSatisfy({ $0 >= 0 && $0 < count }), + "Invalid default parameter index") + assert( + defaultParameterIndices == defaultParameterIndices.sorted(), + "Default parameter indices must be sorted") self.numParameters = UInt32(count) self.hasRestParameter = hasRestParameter + self.defaultParameterIndices = defaultParameterIndices } } @@ -1339,16 +1356,17 @@ class BeginAnySubroutine: JsOperation { let parameters: Parameters init( - parameters: Parameters, numInputs: Int = 0, numOutputs: Int = 0, numInnerOutputs: Int = 0, - attributes: Operation.Attributes = .isBlockStart, requiredContext: Context = .javascript, - contextOpened: Context + parameters: Parameters, numInputs: Int? = nil, numOutputs: Int = 0, + numInnerOutputs: Int = 0, attributes: Operation.Attributes = .isBlockStart, + requiredContext: Context = .javascript, contextOpened: Context ) { assert(contextOpened.contains(.subroutine)) assert(attributes.contains(.isBlockStart)) self.parameters = parameters super.init( - numInputs: numInputs, numOutputs: numOutputs, numInnerOutputs: numInnerOutputs, - attributes: attributes, requiredContext: requiredContext, contextOpened: contextOpened) + numInputs: numInputs ?? parameters.numDefaultParameters, numOutputs: numOutputs, + numInnerOutputs: numInnerOutputs, attributes: attributes, + requiredContext: requiredContext, contextOpened: contextOpened) } } @@ -1365,7 +1383,7 @@ class BeginAnyFunction: BeginAnySubroutine { init(parameters: Parameters, contextOpened: Context = [.javascript, .subroutine]) { super.init( parameters: parameters, - numInputs: 0, + numInputs: parameters.numDefaultParameters, numOutputs: 1, numInnerOutputs: parameters.count, contextOpened: contextOpened) diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 4dffd0123..a62659c93 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -408,7 +408,14 @@ public class FuzzILLifter: Lifter { .beginAsyncArrowFunction(let op as BeginAnyFunction), .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("\(output()) <- \(op.name) -> \(params)") + let inputs = + instr.inputs.isEmpty + ? "" + : " [" + + zip(op.parameters.defaultParameterIndices, instr.inputs).map { + "\($0): \(lift($1))" + }.joined(separator: ", ") + "]" + w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() case .endPlainFunction(let op as EndAnyFunction), diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 8f12d3f0e..b9a546761 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -833,32 +833,36 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .beginPlainFunction: - liftFunctionDefinitionBegin(instr, keyword: "function", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "function", withInputs: inputs, using: &w) case .beginArrowFunction(let op): guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } liftArrowFunctionDefinitionBegin( - instr, parameters: op.parameters, isAsync: false, using: &w, + instr, withInputs: inputs, parameters: op.parameters, isAsync: false, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginGeneratorFunction: - liftFunctionDefinitionBegin(instr, keyword: "function*", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "function*", withInputs: inputs, using: &w) case .beginAsyncFunction: - liftFunctionDefinitionBegin(instr, keyword: "async function", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "async function", withInputs: inputs, using: &w) case .beginAsyncArrowFunction(let op): guard let endIndex = blockEndIndices[instr.index] else { fatalError("Block analysis failed") } liftArrowFunctionDefinitionBegin( - instr, parameters: op.parameters, isAsync: true, using: &w, + instr, withInputs: inputs, parameters: op.parameters, isAsync: true, using: &w, functionEndIndex: endIndex, analyzer: analyzer) case .beginAsyncGeneratorFunction: - liftFunctionDefinitionBegin(instr, keyword: "async function*", using: &w) + liftFunctionDefinitionBegin( + instr, keyword: "async function*", withInputs: inputs, using: &w) case .endArrowFunction(_), .endAsyncArrowFunction: @@ -1934,12 +1938,21 @@ public class JavaScriptLifter: Lifter { return (isGuarded ? "?." : "") + "[" + safeName + "]" } - private func liftParameters(_ parameters: Parameters, as variables: [String]) -> String { + private func liftParameters( + _ parameters: Parameters, as variables: [String], defaultValues: [String?] = [] + ) -> String { assert(parameters.count == variables.count) + let actualDefaultValues = + defaultValues.isEmpty + ? [String?](repeating: nil, count: parameters.count) : defaultValues + assert(actualDefaultValues.count == parameters.count) var paramList = [String]() - for v in variables { + for (v, defaultValue) in zip(variables, actualDefaultValues) { if parameters.hasRestParameter && v == variables.last { + assert(defaultValue == nil) paramList.append("..." + v) + } else if let defaultValue { + paramList.append(v + " = " + defaultValue) } else { paramList.append(v) } @@ -1948,7 +1961,8 @@ public class JavaScriptLifter: Lifter { } private func liftFunctionDefinitionBegin( - _ instr: Instruction, keyword FUNCTION: String, using w: inout JavaScriptWriter + _ instr: Instruction, keyword FUNCTION: String, withInputs inputs: [Expression], + using w: inout JavaScriptWriter ) { // Function are lifted as `function f3(a4, a5, a6) { ...`. // This will produce functions with a recognizable .name property, which the JavaScriptExploreLifting code makes use of (see shouldTreatAsConstructor). @@ -1963,13 +1977,20 @@ public class JavaScriptLifter: Lifter { } let NAME = w.declare(instr.output, as: functionName) let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("\(FUNCTION) \(NAME)(\(PARAMS)) {") w.enterNewBlock() } private func liftArrowFunctionDefinitionBegin( _ instr: Instruction, + withInputs inputs: [Expression], parameters: Parameters, isAsync: Bool, using w: inout JavaScriptWriter, @@ -1984,7 +2005,13 @@ public class JavaScriptLifter: Lifter { ) let vars = w.declareAll(instr.innerOutputs, usePrefix: "a") - let params = liftParameters(parameters, as: vars) + + var defaultValues = [String?](repeating: nil, count: parameters.count) + for (inputIdx, paramIdx) in parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + + let params = liftParameters(parameters, as: vars, defaultValues: defaultValues) functionLiftingStack.push( FunctionLiftingState( diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 03dc972b5..322a6fe2e 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1606,6 +1606,8 @@ public struct Fuzzilli_Protobuf_Parameters: Sendable { public var hasRest_p: Bool = false + public var defaultParameterIndices: [UInt32] = [] + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -6101,7 +6103,7 @@ extension Fuzzilli_Protobuf_WasmAtomicCmpxchgType: SwiftProtobuf._ProtoNameProvi extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Parameters" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}count\0\u{1}hasRest\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}count\0\u{1}hasRest\0\u{1}defaultParameterIndices\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -6111,6 +6113,7 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me switch fieldNumber { case 1: try { try decoder.decodeSingularUInt32Field(value: &self.count) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.hasRest_p) }() + case 3: try { try decoder.decodeRepeatedUInt32Field(value: &self.defaultParameterIndices) }() default: break } } @@ -6123,12 +6126,16 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me if self.hasRest_p != false { try visitor.visitSingularBoolField(value: self.hasRest_p, fieldNumber: 2) } + if !self.defaultParameterIndices.isEmpty { + try visitor.visitPackedUInt32Field(value: self.defaultParameterIndices, fieldNumber: 3) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_Parameters, rhs: Fuzzilli_Protobuf_Parameters) -> Bool { if lhs.count != rhs.count {return false} if lhs.hasRest_p != rhs.hasRest_p {return false} + if lhs.defaultParameterIndices != rhs.defaultParameterIndices {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 9cfb20633..c48160805 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -19,6 +19,7 @@ package fuzzilli.protobuf; message Parameters { uint32 count = 1; bool hasRest = 2; + repeated uint32 defaultParameterIndices = 3; } message LoadInteger { diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 0840baf24..faf67c326 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -4356,4 +4356,78 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testPlainFunctionDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + let v1 = b.loadString("default") + + // function f(a, b = 42, c = "default") { return a; } + b.buildPlainFunction( + with: .parameters(n: 3, defaultParameterIndices: [1, 2]), defaultValues: [v0, v1] + ) { args in + b.doReturn(args[0]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function f2(a3, a4 = 42, a5 = "default") { + return a3; + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testArrowFunctionDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // (a, b = 42) => { return a; } + b.buildArrowFunction( + with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[0]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = "(a2, a3 = 42) => a2;\n" + + XCTAssertEqual(actual, expected) + } + + func testPlainFunctionMixedDefaultParametersLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // function f(a = 42, b) { return b; } + b.buildPlainFunction( + with: .parameters(n: 2, defaultParameterIndices: [0]), defaultValues: [v0] + ) { args in + b.doReturn(args[1]) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function f1(a2 = 42, a3) { + return a3; + } + + """ + + XCTAssertEqual(actual, expected) + } } From 4c88bcd50d37f9a752e701641175441826f51ac5 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 8 Apr 2026 15:00:39 +0000 Subject: [PATCH 215/234] Add JS-to-FuzzIL transpilation for default params This CL adds JS to FuzzIL transpilation support for default parameters in the context of functions. Change-Id: If3451444a6ef0ce032825039a92acbef340438ed Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182176 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Compiler/Compiler.swift | 28 +- Sources/Fuzzilli/Compiler/Parser/parser.js | 7 +- Sources/Fuzzilli/Protobuf/ast.pb.swift | 294 +++++++++++++----- Sources/Fuzzilli/Protobuf/ast.proto | 1 + .../function_with_default_parameters.js | 42 +++ 5 files changed, 292 insertions(+), 80 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 079d8673a..91b7dab1e 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -366,6 +366,7 @@ public class JavaScriptCompiler { } case .functionDeclaration(let functionDeclaration): + let defaultValues = try compileDefaultValues(for: functionDeclaration.parameters) let parameters = convertParameters(functionDeclaration.parameters) let functionBegin: Operation let functionEnd: Operation @@ -390,7 +391,7 @@ public class JavaScriptCompiler { throw CompilerError.invalidNodeError("invalid function declaration type \(type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) // The function may have been accessed before it was defined due to function hoisting, so // here we may overwrite an existing variable mapping. mapOrRemap(functionDeclaration.name, to: instr.output) @@ -1064,6 +1065,7 @@ public class JavaScriptCompiler { } case .functionExpression(let functionExpression): + let defaultValues = try compileDefaultValues(for: functionExpression.parameters) let parameters = convertParameters(functionExpression.parameters) let functionBegin: Operation let functionEnd: Operation @@ -1086,7 +1088,7 @@ public class JavaScriptCompiler { throw CompilerError.invalidNodeError("invalid function declaration type \(type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) try enterNewScope { mapParameters(functionExpression.parameters, to: instr.innerOutputs) for statement in functionExpression.body { @@ -1098,6 +1100,7 @@ public class JavaScriptCompiler { return instr.output case .arrowFunctionExpression(let arrowFunction): + let defaultValues = try compileDefaultValues(for: arrowFunction.parameters) let parameters = convertParameters(arrowFunction.parameters) let functionBegin: Operation let functionEnd: Operation @@ -1113,7 +1116,7 @@ public class JavaScriptCompiler { "invalid arrow function type \(arrowFunction.type)") } - let instr = emit(functionBegin) + let instr = emit(functionBegin, withInputs: defaultValues) try enterNewScope { mapParameters(arrowFunction.parameters, to: instr.innerOutputs) guard let body = arrowFunction.body else { @@ -1482,9 +1485,26 @@ public class JavaScriptCompiler { } } + private func compileDefaultValues(for parameters: Compiler_Protobuf_Parameters) throws + -> [Variable] + { + var defaultValues = [Variable]() + for param in parameters.parameters { + if param.hasDefaultValue { + defaultValues.append(try compileExpression(param.defaultValue)) + } + } + return defaultValues + } + private func convertParameters(_ parameters: Compiler_Protobuf_Parameters) -> Parameters { + let defaultParameterIndices = parameters.parameters.enumerated() + .filter { $0.element.hasDefaultValue } + .map { $0.offset } + return Parameters( - count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p) + count: parameters.parameters.count, hasRestParameter: parameters.hasRestElement_p, + defaultParameterIndices: defaultParameterIndices) } /// Convenience accessor for the currently active scope. diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index aa06d05ce..c1cba8b76 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -83,11 +83,16 @@ function parse(script, proto) { return Statement.create(statement); } - // TODO(bettscheider): Add support for default parameters. function visitParameter(param) { switch (param.type) { case 'Identifier': return make('Parameter', { name: param.name }); + case 'AssignmentPattern': + assert(param.left.type === 'Identifier', "Expected identifier in assignment pattern"); + return make('Parameter', { + name: param.left.name, + defaultValue: visitExpression(param.right) + }); case 'RestElement': return make('Parameter', { name: param.argument.name }); default: diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index c556a80e6..365d0c7bd 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -163,16 +163,30 @@ public struct Compiler_Protobuf_AST: Sendable { } /// A parameter in a function declaration. Not an expression on its own. -public struct Compiler_Protobuf_Parameter: Sendable { +public struct Compiler_Protobuf_Parameter: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var name: String = String() + public var name: String { + get {_storage._name} + set {_uniqueStorage()._name = newValue} + } + + public var defaultValue: Compiler_Protobuf_Expression { + get {_storage._defaultValue ?? Compiler_Protobuf_Expression()} + set {_uniqueStorage()._defaultValue = newValue} + } + /// Returns true if `defaultValue` has been explicitly set. + public var hasDefaultValue: Bool {_storage._defaultValue != nil} + /// Clears the value of `defaultValue`. Subsequent reads from it will return its default value. + public mutating func clearDefaultValue() {_uniqueStorage()._defaultValue = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_EmptyStatement: Sendable { @@ -964,28 +978,31 @@ public struct Compiler_Protobuf_ContinueStatement: Sendable { public init() {} } -public struct Compiler_Protobuf_CatchClause: Sendable { +public struct Compiler_Protobuf_CatchClause: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// The parameter is optional public var parameter: Compiler_Protobuf_Parameter { - get {_parameter ?? Compiler_Protobuf_Parameter()} - set {_parameter = newValue} + get {_storage._parameter ?? Compiler_Protobuf_Parameter()} + set {_uniqueStorage()._parameter = newValue} } /// Returns true if `parameter` has been explicitly set. - public var hasParameter: Bool {self._parameter != nil} + public var hasParameter: Bool {_storage._parameter != nil} /// Clears the value of `parameter`. Subsequent reads from it will return its default value. - public mutating func clearParameter() {self._parameter = nil} + public mutating func clearParameter() {_uniqueStorage()._parameter = nil} - public var body: [Compiler_Protobuf_Statement] = [] + public var body: [Compiler_Protobuf_Statement] { + get {_storage._body} + set {_uniqueStorage()._body = newValue} + } public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _parameter: Compiler_Protobuf_Parameter? = nil + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_FinallyClause: Sendable { @@ -1000,39 +1017,41 @@ public struct Compiler_Protobuf_FinallyClause: Sendable { public init() {} } -public struct Compiler_Protobuf_TryStatement: Sendable { +public struct Compiler_Protobuf_TryStatement: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var body: [Compiler_Protobuf_Statement] = [] + public var body: [Compiler_Protobuf_Statement] { + get {_storage._body} + set {_uniqueStorage()._body = newValue} + } /// The catch clause is optional public var `catch`: Compiler_Protobuf_CatchClause { - get {_catch ?? Compiler_Protobuf_CatchClause()} - set {_catch = newValue} + get {_storage._catch ?? Compiler_Protobuf_CatchClause()} + set {_uniqueStorage()._catch = newValue} } /// Returns true if ``catch`` has been explicitly set. - public var hasCatch: Bool {self._catch != nil} + public var hasCatch: Bool {_storage._catch != nil} /// Clears the value of ``catch``. Subsequent reads from it will return its default value. - public mutating func clearCatch() {self._catch = nil} + public mutating func clearCatch() {_uniqueStorage()._catch = nil} /// The finally clause is optional public var finally: Compiler_Protobuf_FinallyClause { - get {_finally ?? Compiler_Protobuf_FinallyClause()} - set {_finally = newValue} + get {_storage._finally ?? Compiler_Protobuf_FinallyClause()} + set {_uniqueStorage()._finally = newValue} } /// Returns true if `finally` has been explicitly set. - public var hasFinally: Bool {self._finally != nil} + public var hasFinally: Bool {_storage._finally != nil} /// Clears the value of `finally`. Subsequent reads from it will return its default value. - public mutating func clearFinally() {self._finally = nil} + public mutating func clearFinally() {_uniqueStorage()._finally = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _catch: Compiler_Protobuf_CatchClause? = nil - fileprivate var _finally: Compiler_Protobuf_FinallyClause? = nil + fileprivate var _storage = _StorageClass.defaultInstance } public struct Compiler_Protobuf_ThrowStatement: @unchecked Sendable { @@ -2501,29 +2520,76 @@ extension Compiler_Protobuf_AST: SwiftProtobuf.Message, SwiftProtobuf._MessageIm extension Compiler_Protobuf_Parameter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Parameter" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}name\0\u{1}defaultValue\0") + + fileprivate class _StorageClass { + var _name: String = String() + var _defaultValue: Compiler_Protobuf_Expression? = nil + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _name = source._name + _defaultValue = source._defaultValue + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &_storage._name) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._defaultValue) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if !_storage._name.isEmpty { + try visitor.visitSingularStringField(value: _storage._name, fieldNumber: 1) + } + try { if let v = _storage._defaultValue { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_Parameter, rhs: Compiler_Protobuf_Parameter) -> Bool { - if lhs.name != rhs.name {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._name != rhs_storage._name {return false} + if _storage._defaultValue != rhs_storage._defaultValue {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4183,36 +4249,74 @@ extension Compiler_Protobuf_CatchClause: SwiftProtobuf.Message, SwiftProtobuf._M public static let protoMessageName: String = _protobuf_package + ".CatchClause" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}parameter\0\u{1}body\0") + fileprivate class _StorageClass { + var _parameter: Compiler_Protobuf_Parameter? = nil + var _body: [Compiler_Protobuf_Statement] = [] + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _parameter = source._parameter + _body = source._body + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._parameter) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._parameter) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._body) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._parameter { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 2) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._parameter { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + if !_storage._body.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._body, fieldNumber: 2) + } } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_CatchClause, rhs: Compiler_Protobuf_CatchClause) -> Bool { - if lhs._parameter != rhs._parameter {return false} - if lhs.body != rhs.body {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._parameter != rhs_storage._parameter {return false} + if _storage._body != rhs_storage._body {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4252,41 +4356,81 @@ extension Compiler_Protobuf_TryStatement: SwiftProtobuf.Message, SwiftProtobuf._ public static let protoMessageName: String = _protobuf_package + ".TryStatement" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}body\0\u{1}catch\0\u{1}finally\0") + fileprivate class _StorageClass { + var _body: [Compiler_Protobuf_Statement] = [] + var _catch: Compiler_Protobuf_CatchClause? = nil + var _finally: Compiler_Protobuf_FinallyClause? = nil + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _body = source._body + _catch = source._catch + _finally = source._finally + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.body) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._catch) }() - case 3: try { try decoder.decodeSingularMessageField(value: &self._finally) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &_storage._body) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._catch) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._finally) }() + default: break + } } } } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.body.isEmpty { - try visitor.visitRepeatedMessageField(value: self.body, fieldNumber: 1) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if !_storage._body.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._body, fieldNumber: 1) + } + try { if let v = _storage._catch { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._finally { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() } - try { if let v = self._catch { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - try { if let v = self._finally { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_TryStatement, rhs: Compiler_Protobuf_TryStatement) -> Bool { - if lhs.body != rhs.body {return false} - if lhs._catch != rhs._catch {return false} - if lhs._finally != rhs._finally {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._body != rhs_storage._body {return false} + if _storage._catch != rhs_storage._catch {return false} + if _storage._finally != rhs_storage._finally {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index d53216273..b9ce69147 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -23,6 +23,7 @@ message AST { // A parameter in a function declaration. Not an expression on its own. message Parameter { string name = 1; + Expression defaultValue = 2; } message EmptyStatement { diff --git a/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js b/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js new file mode 100644 index 000000000..5c634769e --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/function_with_default_parameters.js @@ -0,0 +1,42 @@ +if (typeof output === 'undefined') output = console.log; + +// plain function +function f(v1, v2=42) { + return v1+v2; +} + +output(f(42)); +output(f(42,43)); + +// arrow function +const arrow = (v1, v2=10) => v1 + v2; +output(arrow(5)); +output(arrow(5, 15)); + + +// function expr +const expr = function(v1, v2="default") { + return v1 + v2; +}; +output(expr("hello ")); +output(expr("hello ", "world")); + + +// generator function +function* gen(v1, v2=1) { + yield v1; + yield v2; +} +for (let v of gen(100)) { + output(v); +} +for (let v of gen(100, 200)) { + output(v); +} + +// async function +async function asyncF(v1, v2=Promise.resolve(42)) { + return v1 + await v2; +} +asyncF(10).then(output); +asyncF(10, Promise.resolve(20)).then(output); From d13654f129ec9fac25d49dec051ce7b8b960a3f5 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 8 Apr 2026 22:55:08 +0200 Subject: [PATCH 216/234] [v8] Sometimes disable generic Wasm wrappers Change-Id: Id5d47cf3d566fbcd1d9e671220d9cdcc930b201a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182836 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 59ec66b44..8919b7511 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -1012,6 +1012,11 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { args.append("--wasm-inlining-ignore-call-counts") } + // Force compiled Wasm wrappers. + if probability(0.3) { + args.append("--no-wasm-generic-wrapper") + } + // // Future features that should sometimes be enabled. // From 7a578ff6e5899bb776689413b02410875aca84ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 9 Apr 2026 11:17:38 +0200 Subject: [PATCH 217/234] Fix compiler warning Change-Id: I8d4b9ee4f0648091b06262a0cbee6a65b311db92 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184556 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index c6c701d4c..55dcae720 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2422,7 +2422,7 @@ public class ProgramBuilder { // Check if we can produce it with findOrGenerateWasmVar let _ = currentWasmFunction.generateRandomWasmVar(ofType: type) } - if findVariable { requirement.fulfilled(by: self.type(of: $0)) } == nil { + if findVariable(satisfying: { requirement.fulfilled(by: self.type(of: $0)) }) == nil { // Check for other CodeGenerators that can produce the given type in this context. let usableGenerators = fuzzer.codeGenerators.filter { From 5ad6837e008eaf334510f28a839d302b4b942399 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Thu, 9 Apr 2026 14:09:20 +0000 Subject: [PATCH 218/234] Add default params to generated methods + ctors This CL adds support for default parameters in generated methods and constructors. JS to FuzzIL compilation code will be added in a subsequent CL. Change-Id: Idc8ba4b53be0373f5090e7b8f78db583e3eab0dd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184576 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 67 ++++++--- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 54 +++++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 6 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 43 ++++-- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 42 +++++- Tests/FuzzilliTests/LifterTest.swift | 142 ++++++++++++++++++ 6 files changed, 295 insertions(+), 59 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 55dcae720..5c363ae05 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2754,22 +2754,27 @@ public class ProgramBuilder { } public func addMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( - BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters)) + BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralMethod()) } public func addComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginObjectLiteralComputedMethod(parameters: descriptor.parameters), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndObjectLiteralComputedMethod()) } @@ -2868,10 +2873,13 @@ public class ProgramBuilder { } public func addConstructor( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = b.emit(BeginClassConstructor(parameters: descriptor.parameters)) + let instr = b.emit( + BeginClassConstructor(parameters: descriptor.parameters), withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassConstructor()) } @@ -2898,23 +2906,28 @@ public class ProgramBuilder { } public func addInstanceMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassMethod( - methodName: name, parameters: descriptor.parameters, isStatic: false)) + methodName: name, parameters: descriptor.parameters, isStatic: false), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } public func addInstanceComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: false), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } @@ -2977,23 +2990,28 @@ public class ProgramBuilder { } public func addStaticMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassMethod( - methodName: name, parameters: descriptor.parameters, isStatic: true)) + methodName: name, parameters: descriptor.parameters, isStatic: true), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassMethod()) } public func addStaticComputedMethod( - _ name: Variable, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: Variable, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassComputedMethod(parameters: descriptor.parameters, isStatic: true), - withInputs: [name]) + withInputs: [name] + defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassComputedMethod()) } @@ -3036,12 +3054,15 @@ public class ProgramBuilder { } public func addPrivateInstanceMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassPrivateMethod( - methodName: name, parameters: descriptor.parameters, isStatic: false)) + methodName: name, parameters: descriptor.parameters, isStatic: false), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } @@ -3054,12 +3075,15 @@ public class ProgramBuilder { } public func addPrivateStaticMethod( - _ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + _ name: String, with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) b.setParameterTypesForNextSubroutine(descriptor.parameterTypes) let instr = b.emit( BeginClassPrivateMethod( - methodName: name, parameters: descriptor.parameters, isStatic: true)) + methodName: name, parameters: descriptor.parameters, isStatic: true), + withInputs: defaultValues) body(Array(instr.innerOutputs)) b.emit(EndClassPrivateMethod()) } @@ -3487,10 +3511,13 @@ public class ProgramBuilder { @discardableResult public func buildConstructor( - with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> Void + with descriptor: SubroutineDescriptor, defaultValues: [Variable] = [], + _ body: ([Variable]) -> Void ) -> Variable { + assert(descriptor.parameters.numDefaultParameters == defaultValues.count) setParameterTypesForNextSubroutine(descriptor.parameterTypes) - let instr = emit(BeginConstructor(parameters: descriptor.parameters)) + let instr = emit( + BeginConstructor(parameters: descriptor.parameters), withInputs: defaultValues) bodyWithRecursionGuard(instr.output) { body(Array(instr.innerOutputs)) } emit(EndConstructor()) return instr.output diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 93fd51a6f..cdc4863d0 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -551,7 +551,11 @@ public let CodeGenerators: [CodeGenerator] = [ Int.random(in: 1...maxProperties))) // Define a constructor function... - let c = b.buildConstructor(with: b.randomParameters()) { args in + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) + let c = b.buildConstructor(with: randomParameters, defaultValues: defaultValues) { args in let this = args[0] // We don't want |this| to be used as property value, so hide it. @@ -809,13 +813,17 @@ public let CodeGenerators: [CodeGenerator] = [ b.randomCustomMethodName, notIn: b.currentObjectLiteral.methods) - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) b.emit( BeginObjectLiteralMethod( methodName: methodName, - parameters: randomParameters.parameters)) + parameters: randomParameters.parameters), + withInputs: defaultValues) }, GeneratorStub( "ObjectLiteralMethodEndGenerator", @@ -836,12 +844,15 @@ public let CodeGenerators: [CodeGenerator] = [ // Try to find a computed method name that hasn't already been added to this literal. let methodName = b.randomJsVariable( notIn: b.currentObjectLiteral.computedMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginObjectLiteralComputedMethod( parameters: parameters.parameters), - withInputs: [methodName]) + withInputs: [methodName] + defaultValues) }, GeneratorStub( "ObjectLiteralComputedMethodEndGenerator", @@ -954,21 +965,25 @@ public let CodeGenerators: [CodeGenerator] = [ return } - let randomParameters = b.randomParameters() + let (randomParameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine( randomParameters.parameterTypes) let args = b.emit( BeginClassConstructor( - parameters: randomParameters.parameters) + parameters: randomParameters.parameters), + withInputs: defaultValues ).innerOutputs if randomParameters.parameters.hasRestParameter && probability(0.2) { b.getProperty("length", of: args.last!) } - let this = args[0] + let this = args.first! // Derived classes must call `super()` before accessing this, but non-derived classes must not call `super()`. if b.currentClassDefinition.isDerivedClass { b.hide(this) // We need to hide |this| so it isn't used as argument for `super()` @@ -1039,13 +1054,17 @@ public let CodeGenerators: [CodeGenerator] = [ b.randomCustomMethodName, notIn: b.currentClassDefinition.instanceMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassMethod( methodName: methodName, parameters: parameters.parameters, - isStatic: false)) + isStatic: false), + withInputs: defaultValues) }, GeneratorStub( "ClassInstanceMethodEndGenerator", @@ -1067,13 +1086,16 @@ public let CodeGenerators: [CodeGenerator] = [ // Try to find a method that hasn't already been added to this class. let methodName = b.randomJsVariable( notIn: b.currentClassDefinition.instanceComputedMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassComputedMethod( parameters: parameters.parameters, isStatic: false), - withInputs: [methodName]) + withInputs: [methodName] + defaultValues) }, GeneratorStub( "ClassInstanceComputedMethodEndGenerator", @@ -1197,14 +1219,18 @@ public let CodeGenerators: [CodeGenerator] = [ let methodName = b.generateString( b.randomCustomMethodName, notIn: b.currentClassDefinition.staticMethods) - let parameters = b.randomParameters() + let (parameters, defaultValues) = b.randomParameters() + .withRandomDefaultParameters( + probability: 0.1, + randomVariable: { b.randomJsVariable() }) b.setParameterTypesForNextSubroutine(parameters.parameterTypes) b.emit( BeginClassMethod( methodName: methodName, parameters: parameters.parameters, - isStatic: true)) + isStatic: true), + withInputs: defaultValues) }, GeneratorStub( diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 8daeb1073..d02651787 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -605,7 +605,8 @@ final class BeginObjectLiteralComputedMethod: BeginAnySubroutine { init(parameters: Parameters) { // First inner output is the explicit |this| parameter super.init( - parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + parameters: parameters, numInputs: 1 + parameters.numDefaultParameters, + numInnerOutputs: parameters.count + 1, attributes: .isBlockStart, requiredContext: .objectLiteral, contextOpened: [.javascript, .subroutine, .method]) } @@ -854,7 +855,8 @@ final class BeginClassComputedMethod: BeginAnySubroutine { self.isStatic = isStatic // First inner output is the explicit |this| parameter super.init( - parameters: parameters, numInputs: 1, numInnerOutputs: parameters.count + 1, + parameters: parameters, numInputs: 1 + parameters.numDefaultParameters, + numInnerOutputs: parameters.count + 1, attributes: [.isBlockStart], requiredContext: .classDefinition, contextOpened: [.javascript, .subroutine, .method, .classMethod]) } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index a62659c93..2cc5d9465 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -36,6 +36,16 @@ public class FuzzILLifter: Lifter { return lift(instr.innerOutput) } + func liftDefaultParameters(_ parameters: Parameters, _ defaultValues: ArraySlice) + -> String + { + guard !defaultValues.isEmpty else { return "" } + let defaults = zip(parameters.defaultParameterIndices, defaultValues).map { + "\($0): \(lift($1))" + }.joined(separator: ", ") + return " [\(defaults)]" + } + switch instr.op.opcode { case .loadInteger(let op): w.emit("\(output()) <- LoadInteger '\(op.value)'") @@ -114,16 +124,18 @@ public class FuzzILLifter: Lifter { case .beginObjectLiteralMethod(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginObjectLiteralMethod `\(op.methodName)` -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginObjectLiteralMethod `\(op.methodName)`\(inputs) -> \(params)") w.increaseIndentionLevel() case .endObjectLiteralMethod: w.decreaseIndentionLevel() w.emit("EndObjectLiteralMethod") - case .beginObjectLiteralComputedMethod: + case .beginObjectLiteralComputedMethod(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginObjectLiteralComputedMethod \(input(0)) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs.dropFirst()) + w.emit("BeginObjectLiteralComputedMethod \(input(0))\(inputs) -> \(params)") w.increaseIndentionLevel() case .endObjectLiteralComputedMethod: @@ -182,9 +194,10 @@ public class FuzzILLifter: Lifter { w.emit(line) w.increaseIndentionLevel() - case .beginClassConstructor: + case .beginClassConstructor(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassConstructor -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassConstructor\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassConstructor: @@ -218,7 +231,8 @@ public class FuzzILLifter: Lifter { case .beginClassMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)' -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassMethod: @@ -228,7 +242,8 @@ public class FuzzILLifter: Lifter { case .beginClassComputedMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0)) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs.dropFirst()) + w.emit("BeginClassComputedMethod \(maybeStatic)\(input(0))\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassComputedMethod: @@ -294,7 +309,8 @@ public class FuzzILLifter: Lifter { case .beginClassPrivateMethod(let op): let maybeStatic = op.isStatic ? "static " : "" let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)' -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("BeginClassPrivateMethod '\(maybeStatic)\(op.methodName)'\(inputs) -> \(params)") w.increaseIndentionLevel() case .endClassPrivateMethod: @@ -408,13 +424,7 @@ public class FuzzILLifter: Lifter { .beginAsyncArrowFunction(let op as BeginAnyFunction), .beginAsyncGeneratorFunction(let op as BeginAnyFunction): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - let inputs = - instr.inputs.isEmpty - ? "" - : " [" - + zip(op.parameters.defaultParameterIndices, instr.inputs).map { - "\($0): \(lift($1))" - }.joined(separator: ", ") + "]" + let inputs = liftDefaultParameters(op.parameters, instr.inputs) w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() @@ -429,7 +439,8 @@ public class FuzzILLifter: Lifter { case .beginConstructor(let op): let params = instr.innerOutputs.map(lift).joined(separator: ", ") - w.emit("\(output()) <- \(op.name) -> \(params)") + let inputs = liftDefaultParameters(op.parameters, instr.inputs) + w.emit("\(output()) <- \(op.name)\(inputs) -> \(params)") w.increaseIndentionLevel() case .endConstructor(let op): diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index b9a546761..6a733fac2 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -424,7 +424,11 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = quoteIdentifierIfNeeded(op.methodName) currentObjectLiteral.beginMethod("\(METHOD)(\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -434,7 +438,11 @@ public class JavaScriptLifter: Lifter { case .beginObjectLiteralComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[1 + inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = input(0) currentObjectLiteral.beginMethod("[\(METHOD)](\(PARAMS)) {", &w) bindVariableToThis(instr.innerOutput(0)) @@ -519,7 +527,11 @@ public class JavaScriptLifter: Lifter { case .beginClassConstructor(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("constructor(\(PARAMS)) {") w.enterNewBlock() bindVariableToThis(instr.innerOutput(0)) @@ -569,7 +581,11 @@ public class JavaScriptLifter: Lifter { case .beginClassMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = quoteIdentifierIfNeeded(op.methodName) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)\(METHOD)(\(PARAMS)) {") @@ -578,7 +594,11 @@ public class JavaScriptLifter: Lifter { case .beginClassComputedMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[1 + inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = input(0) let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)[\(METHOD)](\(PARAMS)) {") @@ -639,7 +659,11 @@ public class JavaScriptLifter: Lifter { case .beginClassPrivateMethod(let op): let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) let METHOD = op.methodName let staticStr = op.isStatic ? "static " : "" w.emit("\(staticStr)#\(METHOD)(\(PARAMS)) {") @@ -910,7 +934,11 @@ public class JavaScriptLifter: Lifter { let NAME = "F\(instr.output.number)" w.declare(instr.output, as: NAME) let vars = w.declareAll(instr.innerOutputs.dropFirst(), usePrefix: "a") - let PARAMS = liftParameters(op.parameters, as: vars) + var defaultValues = [String?](repeating: nil, count: op.parameters.count) + for (inputIdx, paramIdx) in op.parameters.defaultParameterIndices.enumerated() { + defaultValues[paramIdx] = inputs[inputIdx].text + } + let PARAMS = liftParameters(op.parameters, as: vars, defaultValues: defaultValues) w.emit("function \(NAME)(\(PARAMS)) {") w.enterNewBlock() // Disallow invoking constructors without `new` (i.e. Construct in FuzzIL). diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index faf67c326..9033e9283 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -4430,4 +4430,146 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + + func testObjectLiteralMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildObjectLiteral { obj in + obj.addMethod( + "foo", with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v4 = { + foo(a2, a3 = 42) { + return a3; + }, + }; + + """ + + XCTAssertEqual(actual, expected) + } + + func testClassMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildClassDefinition { cls in + cls.addInstanceMethod( + "bar", with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C1 { + bar(a3, a4 = 42) { + return a4; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testClassConstructorDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + b.buildClassDefinition { cls in + cls.addConstructor( + with: .parameters(n: 1, defaultParameterIndices: [0]), defaultValues: [v0] + ) { args in + b.setProperty("foo", of: args[0], to: args[1]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + class C1 { + constructor(a3 = 42) { + this.foo = a3; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testObjectLiteralComputedMethodDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + let v1 = b.loadString("computed") + + b.buildObjectLiteral { obj in + obj.addComputedMethod( + v1, with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + b.doReturn(args[2]) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v5 = { + ["computed"](a3, a4 = 42) { + return a4; + }, + }; + + """ + + XCTAssertEqual(actual, expected) + } + + func testConstructorDefaultParameterLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + + // function F(a, b = 42) { if (!new.target) ... } + b.buildConstructor( + with: .parameters(n: 2, defaultParameterIndices: [1]), defaultValues: [v0] + ) { args in + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + function F1(a3, a4 = 42) { + if (!new.target) { throw 'must be called with new'; } + } + + """ + + XCTAssertEqual(actual, expected) + } } From 58f196f4537064676084a8760dffd311ec81ad99 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 10 Apr 2026 10:00:56 +0000 Subject: [PATCH 219/234] Add JS-to-FuzzIL transpilation for default params in methods This CL adds JS to FuzzIL transpilation support for default parameters in the context of methods. Change-Id: I92b72780e1e994b86d067f3239d87507afde15f7 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184577 Commit-Queue: Leon Bettscheider Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Compiler/Compiler.swift | 38 +++++++--- .../methods_with_default_parameters.js | 74 +++++++++++++++++++ 2 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 91b7dab1e..188868063 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -71,9 +71,10 @@ public class JavaScriptCompiler { private func compileClass( _ name: String, superClass: ExpressionNode?, fields: [ClassFieldNode], isExpression: Bool ) throws -> Variable { - // The expressions for property values and computed properties need to be emitted before the class declaration is opened. + // The expressions for property values, computed properties and method default parameters need to be emitted before the class declaration is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() + var defaultValuesPerSubroutine = [[Variable]]() for field in fields { guard let field = field.field else { throw CompilerError.invalidNodeError("missing concrete field in class declaration") @@ -87,12 +88,17 @@ public class JavaScriptCompiler { } key = property.key case .method(let method): + defaultValuesPerSubroutine.append(try compileDefaultValues(for: method.parameters)) key = method.key case .getter(let getter): key = getter.key case .setter(let setter): key = setter.key - case .ctor, .staticInitializer: + case .ctor(let constructor): + defaultValuesPerSubroutine.append( + try compileDefaultValues(for: constructor.parameters)) + key = nil + case .staticInitializer: key = nil } @@ -104,6 +110,7 @@ public class JavaScriptCompiler { // Reverse the arrays since we'll remove the elements in FIFO order. propertyValues.reverse() computedKeys.reverse() + defaultValuesPerSubroutine.reverse() let classDecl: Instruction if let superClass = superClass { @@ -146,8 +153,10 @@ public class JavaScriptCompiler { emit(op, withInputs: inputs) case .ctor(let constructor): + let defaultValues = defaultValuesPerSubroutine.removeLast() let parameters = convertParameters(constructor.parameters) - let head = emit(BeginClassConstructor(parameters: parameters)) + let head = emit( + BeginClassConstructor(parameters: parameters), withInputs: defaultValues) try enterNewScope { var parameters = head.innerOutputs @@ -161,6 +170,7 @@ public class JavaScriptCompiler { emit(EndClassConstructor()) case .method(let method): + let defaultValues = defaultValuesPerSubroutine.removeLast() let parameters = convertParameters(method.parameters) let head: Instruction @@ -171,16 +181,18 @@ public class JavaScriptCompiler { case .name(let name): head = emit( BeginClassMethod( - methodName: name, parameters: parameters, isStatic: method.isStatic)) + methodName: name, parameters: parameters, isStatic: method.isStatic), + withInputs: defaultValues) case .index(let index): head = emit( BeginClassMethod( methodName: String(index), parameters: parameters, - isStatic: method.isStatic)) + isStatic: method.isStatic), + withInputs: defaultValues) case .expression: head = emit( BeginClassComputedMethod(parameters: parameters, isStatic: method.isStatic), - withInputs: [computedKeys.removeLast()]) + withInputs: [computedKeys.removeLast()] + defaultValues) } try enterNewScope { @@ -886,9 +898,10 @@ public class JavaScriptCompiler { return rhs case .objectExpression(let objectExpression): - // The expressions for property values and computed properties need to be emitted before the object literal is opened. + // The expressions for property values, computed properties and method default parameters need to be emitted before the object literal is opened. var propertyValues = [Variable]() var computedKeys = [Variable]() + var methodDefaultValues = [[Variable]]() for field in objectExpression.fields { guard let field = field.field else { throw CompilerError.invalidNodeError( @@ -901,6 +914,7 @@ public class JavaScriptCompiler { propertyValues.append(try compileExpression(property.value)) key = property.key case .method(let method): + methodDefaultValues.append(try compileDefaultValues(for: method.parameters)) key = method.key case .getter(let getter): key = getter.key @@ -915,6 +929,7 @@ public class JavaScriptCompiler { // Reverse the arrays since we'll remove the elements in FIFO order. propertyValues.reverse() computedKeys.reverse() + methodDefaultValues.reverse() // Now build the object literal. emit(BeginObjectLiteral()) @@ -937,6 +952,7 @@ public class JavaScriptCompiler { withInputs: [computedKeys.removeLast()] + inputs) } case .method(let method): + let defaultValues = methodDefaultValues.removeLast() let parameters = convertParameters(method.parameters) let head: Instruction @@ -947,15 +963,17 @@ public class JavaScriptCompiler { switch key { case .name(let name): head = emit( - BeginObjectLiteralMethod(methodName: name, parameters: parameters)) + BeginObjectLiteralMethod(methodName: name, parameters: parameters), + withInputs: defaultValues) case .index(let index): head = emit( BeginObjectLiteralMethod( - methodName: String(index), parameters: parameters)) + methodName: String(index), parameters: parameters), + withInputs: defaultValues) case .expression: head = emit( BeginObjectLiteralComputedMethod(parameters: parameters), - withInputs: [computedKeys.removeLast()]) + withInputs: [computedKeys.removeLast()] + defaultValues) } try enterNewScope { diff --git a/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js b/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js new file mode 100644 index 000000000..8384dc3a7 --- /dev/null +++ b/Tests/FuzzilliTests/CompilerTests/methods_with_default_parameters.js @@ -0,0 +1,74 @@ +if (typeof output === 'undefined') output = console.log; + +// Object literal method +const propName = "computedMethod"; +const obj = { + method(v1, v2 = 42) { + return v1 + v2; + }, + [propName](v1, v2 = 10) { + return v1 + v2; + } +}; + +output(obj.method(5)); +output(obj.method(5, 15)); +output(obj.computedMethod(5)); +output(obj.computedMethod(5, 15)); + +// Class constructor +class C { + constructor(v1, v2 = "default") { + this.v1 = v1; + this.v2 = v2; + } + + method(v1, v2 = 100) { + return v1 + v2; + } + + method_with_multiple_default_params_1(v1 = -1, v2 = 2, v3 = 3) { + return -1 * v1 + v2 + v3; + } + + method_with_multiple_default_params_2(v1, v2 = 2, v3 = 3) { + return -1 * v1 + v2 + v3; + } + + static staticMethod(v1, v2 = 200) { + return v1 + v2; + } + + [propName](v1, v2 = 300) { + return v1 + v2; + } + + ["computedMethodWithMultipleDefaultParams"](v1, v2 = 300, v3=400) { + return -1 * v1 + v2 + v3; + } +} + +const instance = new C("hello"); +output(instance.v1); +output(instance.v2); + +output(instance.method(5)); +output(instance.method(5, 15)); + +output(instance.method_with_multiple_default_params_1()) +output(instance.method_with_multiple_default_params_1(10)) +output(instance.method_with_multiple_default_params_2(10)) +output(instance.method_with_multiple_default_params_2(-10, 20, 30)) + +output(instance.computedMethod(5)); +output(instance.computedMethod(5, 15)); + +output(instance.computedMethodWithMultipleDefaultParams(-1)); +output(instance.computedMethodWithMultipleDefaultParams(10, 2, 3)); + +const instance2 = new C("hello", "world"); +output(instance2.v1); +output(instance2.v2); + +output(C.staticMethod(10)); +output(C.staticMethod(10, 20)); From 7ad5f6c3c15caba036d53a50d0084a52c38c4e64 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Fri, 10 Apr 2026 12:44:18 +0200 Subject: [PATCH 220/234] [tools] Add --format and --regenerate-proto to presubmit helper Change-Id: I4e0f51c795d4d262c420b28cbc059e70b4060506 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9189336 Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- Tools/presubmit.py | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/Tools/presubmit.py b/Tools/presubmit.py index f9502c874..cf59ac292 100755 --- a/Tools/presubmit.py +++ b/Tools/presubmit.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import argparse import os import shutil import subprocess @@ -21,6 +22,7 @@ from pathlib import Path BASE_DIR = Path(__file__).parent.parent.resolve() +PROTO_DIR = BASE_DIR / "Sources/Fuzzilli/Protobuf" KNOWN_PROTO_FILES = [ "program.proto", @@ -41,14 +43,10 @@ def check_git_clean(info): diff_result = subprocess.run(["git", "diff"], cwd=BASE_DIR, capture_output=True, check=True) assert False, f"Unexpected modified files {info}: {output}\n== Diff ==\n{diff_result.stdout.decode()}" -def check_proto(): - """Check that program.proto is up-to-date.""" - print("Checking generated protobuf files...") - proto_dir = BASE_DIR / "Sources/Fuzzilli/Protobuf" - subprocess.run(["python3", "./gen_programproto.py"], cwd=proto_dir, check=True) - # gen_programproto.py should be a no-op. - check_git_clean("after running gen_programproto.py") +def regenerate_opcodes(): + subprocess.run(["python3", "./gen_programproto.py"], cwd=PROTO_DIR, check=True) +def regenerate_proto(): if not shutil.which("protoc"): print("Skipping protobuf validation as protoc is not available.") return @@ -62,18 +60,39 @@ def check_proto(): env = os.environ.copy() env["PATH"] = f"{swift_protobuf_path}/.build/debug:" + env["PATH"] cmd = ["protoc", "--swift_opt=Visibility=Public", "--swift_out=."] + KNOWN_PROTO_FILES - subprocess.run(cmd, cwd=proto_dir, check=True, env=env) - # Regenerating the protobuf files should be a no-op. + subprocess.run(cmd, cwd=PROTO_DIR, check=True, env=env) + +def check_proto(): + """Check that program.proto is up-to-date.""" + print("Checking generated protobuf files...") + regenerate_opcodes() + check_git_clean("after running gen_programproto.py") + regenerate_proto() check_git_clean("after regenerating protobuf files") -def check_formatting(): +def run_formatting(): subprocess.run(["swift", "format", BASE_DIR, "--recursive", "--parallel", "--in-place"], check=True) + +def check_formatting(): + run_formatting() check_git_clean("after auto-formatting") def main(): - check_git_clean("before any checks") - check_proto() - check_formatting() + parser = argparse.ArgumentParser() + parser.add_argument("--format", action="store_true", help="Run auto-formatting.") + parser.add_argument("--regenerate-proto", action="store_true", help="Regenerate OpCodes.swift protobuf files.") + args = parser.parse_args() + + if args.format or args.regenerate_proto: + if args.regenerate_proto: + regenerate_opcodes() + regenerate_proto() + if args.format: + run_formatting() + else: + check_git_clean("before any checks") + check_proto() + check_formatting() if __name__ == '__main__': From 17ac8a6f7826ac6d211419647931cd848774d408 Mon Sep 17 00:00:00 2001 From: Tigran Bantikyan Date: Fri, 10 Apr 2026 13:36:03 +0000 Subject: [PATCH 221/234] Add support for integer enumerations Fuzzilli currently only has support for enumerations with string values. Being able to represent integer enumerations through the Fuzzilli type system would reduce the amount of supporting code that profile authors need to write. For instance, if a method has an argument that is of an integer enumeration type, the current approach would be to mark the argument as a `integer` in the Fuzzilli profile and write a custom CodeGenerator that constains the argument's values to those of the enumeration. The author cannot rely on CodeGenerators such as `MethodCallGenerator`, since these will overwhelmingly provide incorrect integer values for this argument. This CL introduces the `intEnumeration` type to Fuzzilli to support integer enumerations. The changes follow the example set by the existing `enumeration`. Namely, the introduction of a `customName` field for integers allows Fuzzilli to reliably distinguish regular integer variabels from intEnumeration variables. Rather than complicating the `isEnumeration` and `isEnumerationOrNamedString` properties on `ILType`, this CL also introduces an `isEnumeration` parameter to the `TypeExtension` constructor to explicitly identify enumerations. Fixed: 500001059 Change-Id: Ia5b2c632864a0b9fa7e7d4c7357f0de3e0a5e23c Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9182892 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 13 +++-- .../Environment/JavaScriptEnvironment.swift | 4 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 10 +++- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 5 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 4 +- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 49 ++++++++++++++----- .../Fuzzilli/Mutators/OperationMutator.swift | 11 ++++- Sources/Fuzzilli/Protobuf/operations.pb.swift | 22 ++++++++- Sources/Fuzzilli/Protobuf/operations.proto | 1 + Tests/FuzzilliTests/JSTyperTests.swift | 22 +++++++++ Tests/FuzzilliTests/TypeSystemTest.swift | 34 +++++++++++++ 11 files changed, 150 insertions(+), 25 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 5c363ae05..e3bf101f0 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -769,7 +769,10 @@ public class ProgramBuilder { // We only need to check against all base types from TypeSystem.swift, this works because we use .MayBe // TODO: Not sure how we should handle merge types, e.g. .string + .object(...). let typeGenerators: [(ILType, () -> Variable)] = [ - (.integer, { return self.loadInt(self.randomInt()) }), + ( + .integer, + { type.isEnumeration ? self.loadEnum(type) : self.loadInt(self.randomInt()) } + ), ( .string, { @@ -2643,8 +2646,8 @@ public class ProgramBuilder { } @discardableResult - public func loadInt(_ value: Int64) -> Variable { - return emit(LoadInteger(value: value)).output + public func loadInt(_ value: Int64, customName: String? = nil) -> Variable { + return emit(LoadInteger(value: value, customName: customName)).output } @discardableResult @@ -2665,6 +2668,10 @@ public class ProgramBuilder { @discardableResult public func loadEnum(_ type: ILType) -> Variable { assert(type.isEnumeration) + if type.Is(.integer) { + let value = Int64(chooseUniform(from: type.enumValues))! + return loadInt(value, customName: type.group) + } return loadString(chooseUniform(from: type.enumValues), customName: type.group) } diff --git a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift index 05a1c753b..bb2429870 100644 --- a/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift +++ b/Sources/Fuzzilli/Environment/JavaScriptEnvironment.swift @@ -1022,7 +1022,7 @@ public class JavaScriptEnvironment: ComponentBase { if let signatures = group.methods[propertyName] { return .unboundFunction(signatures.first, receiver: baseType) } - } else if !baseType.isEnumerationOrNamedString { + } else if !(baseType.isEnumeration || baseType.isNamedString) { // This shouldn't happen, probably forgot to register the object group. logger.warning("No type information for object group \(groupName) available") } @@ -1037,7 +1037,7 @@ public class JavaScriptEnvironment: ComponentBase { if let signatures = group.methods[methodName] { return signatures } - } else if !baseType.isEnumerationOrNamedString { + } else if !(baseType.isEnumeration || baseType.isNamedString) { // This shouldn't happen, probably forgot to register the object group logger.warning("No type information for object group \(groupName) available") } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 8ccfd989e..be087fdc3 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -561,7 +561,12 @@ extension Instruction: ProtobufConvertible { case .nop: $0.nop = Fuzzilli_Protobuf_Nop() case .loadInteger(let op): - $0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { $0.value = op.value } + $0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { + $0.value = op.value + if let customName = op.customName { + $0.customName = customName + } + } case .loadBigInt(let op): $0.loadBigInt = Fuzzilli_Protobuf_LoadBigInt.with { $0.value = op.value } case .loadFloat(let op): @@ -1959,7 +1964,8 @@ extension Instruction: ProtobufConvertible { } op = cachedOp case .loadInteger(let p): - op = LoadInteger(value: p.value) + let customName = p.customName.isEmpty ? nil : p.customName + op = LoadInteger(value: p.value, customName: customName) case .loadBigInt(let p): op = LoadBigInt(value: p.value) case .loadFloat(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 8c49dcc19..f3519b16f 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -1676,8 +1676,9 @@ public struct JSTyper: Analyzer { } switch instr.op.opcode { - case .loadInteger: - set(instr.output, .integer) + case .loadInteger(let op): + // Set to enum type if en enum for `op.customName` is registered. + set(instr.output, op.customName.flatMap(environment.getEnum) ?? .integer) case .loadBigInt: set(instr.output, .bigint) diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index d02651787..be392b830 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -177,9 +177,11 @@ final class LoadInteger: JsOperation { override var opcode: Opcode { .loadInteger(self) } let value: Int64 + let customName: String? - init(value: Int64) { + init(value: Int64, customName: String? = nil) { self.value = value + self.customName = customName super.init(numOutputs: 1, attributes: [.isMutable]) } } diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index 2fc55cec3..e546fae6d 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -164,10 +164,20 @@ public struct ILType: Hashable { /// Constructs an enum type, which is a string with a limited set of allowed values. public static func enumeration(ofName name: String, withValues values: [String]) -> ILType { let ext = TypeExtension( - group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil) + group: name, properties: Set(values), methods: Set(), signature: nil, wasmExt: nil, + isEnumeration: true) return ILType(definiteType: .string, ext: ext) } + /// Constructs an enum type, which is an integer with a limited set of allowed values. + public static func intEnumeration(ofName name: String, withValues values: [Int64]) -> ILType { + let stringValues = values.map { String($0) } + let ext = TypeExtension( + group: name, properties: Set(stringValues), methods: Set(), signature: nil, + wasmExt: nil, isEnumeration: true) + return ILType(definiteType: .integer, ext: ext) + } + /// Constructs an named string: this is a string that typically has some complex format. /// /// Most code will treat these as strings, but the JavaScriptEnvironment can register @@ -597,11 +607,11 @@ public struct ILType: Hashable { } public var isEnumeration: Bool { - return Is(.string) && ext != nil && !ext!.properties.isEmpty + return ext?.isEnumeration ?? false } - public var isEnumerationOrNamedString: Bool { - return Is(.string) && ext != nil && group != nil + public var isNamedString: Bool { + return (Is(.string) && ext != nil && group != nil) } public var group: String? { @@ -819,12 +829,14 @@ public struct ILType: Hashable { if wasmExt == nil && (self.wasmType ?? other.wasmType) != nil { group = nil } + let isEnumeration = self.isEnumeration && other.isEnumeration && group != nil return ILType( definiteType: definiteType, possibleType: possibleType, ext: TypeExtension( group: group, properties: commonProperties, methods: commonMethods, - signature: signature, wasmExt: wasmExt, receiver: receiver)) + signature: signature, wasmExt: wasmExt, receiver: receiver, + isEnumeration: isEnumeration)) } public static func | (lhs: ILType, rhs: ILType) -> ILType { @@ -924,11 +936,13 @@ public struct ILType: Hashable { wasmExt = wasmIntersection } + let isEnumeration = self.isEnumeration || other.isEnumeration + return ILType( definiteType: definiteType, possibleType: possibleType, ext: TypeExtension( group: group, properties: properties, methods: methods, signature: signature, - wasmExt: wasmExt, receiver: receiver)) + wasmExt: wasmExt, receiver: receiver, isEnumeration: isEnumeration)) } public static func & (lhs: ILType, rhs: ILType) -> ILType { @@ -1001,11 +1015,13 @@ public struct ILType: Hashable { let wasmExt = self.wasmType ?? other.wasmType + let isEnumeration = self.isEnumeration || other.isEnumeration + // We just take the self.wasmExt as they have to be the same, see `canMerge`. let ext = TypeExtension( group: group, properties: self.properties.union(other.properties), methods: self.methods.union(other.methods), signature: signature, wasmExt: wasmExt, - receiver: receiver) + receiver: receiver, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: ext) } @@ -1032,7 +1048,7 @@ public struct ILType: Hashable { newProperties.insert(property) let newExt = TypeExtension( group: group, properties: newProperties, methods: methods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1054,7 +1070,7 @@ public struct ILType: Hashable { newMethods.remove(name) let newExt = TypeExtension( group: group, properties: newProperties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1067,7 +1083,7 @@ public struct ILType: Hashable { newMethods.insert(method) let newExt = TypeExtension( group: group, properties: properties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1085,7 +1101,7 @@ public struct ILType: Hashable { newMethods.remove(method) let newExt = TypeExtension( group: group, properties: properties, methods: newMethods, signature: signature, - wasmExt: wasmType) + wasmExt: wasmType, isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1094,7 +1110,8 @@ public struct ILType: Hashable { return self } let newExt = TypeExtension( - group: group, properties: properties, methods: methods, signature: signature) + group: group, properties: properties, methods: methods, signature: signature, + isEnumeration: isEnumeration) return ILType(definiteType: definiteType, possibleType: possibleType, ext: newExt) } @@ -1378,9 +1395,12 @@ class TypeExtension: Hashable { // The receiver type of a function (used for unbound functions). let receiver: ILType? + // Used to indentify whether a type is an enumeration + let isEnumeration: Bool + init?( group: String? = nil, properties: Set, methods: Set, signature: Signature?, - wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil + wasmExt: WasmTypeExtension? = nil, receiver: ILType? = nil, isEnumeration: Bool = false ) { if group == nil && properties.isEmpty && methods.isEmpty && signature == nil && wasmExt == nil && receiver == nil @@ -1394,6 +1414,7 @@ class TypeExtension: Hashable { self.signature = signature self.wasmExt = wasmExt self.receiver = receiver + self.isEnumeration = isEnumeration } static func == (lhs: TypeExtension, rhs: TypeExtension) -> Bool { @@ -1403,6 +1424,7 @@ class TypeExtension: Hashable { && lhs.signature == rhs.signature && lhs.wasmExt == rhs.wasmExt && lhs.receiver == rhs.receiver + && lhs.isEnumeration == rhs.isEnumeration } public func hash(into hasher: inout Hasher) { @@ -1412,6 +1434,7 @@ class TypeExtension: Hashable { hasher.combine(signature) hasher.combine(wasmExt) hasher.combine(receiver) + hasher.combine(isEnumeration) } } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index c7614ff25..1ce56d0c8 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -45,7 +45,16 @@ public class OperationMutator: BaseInstructionMutator { private func mutateOperation(_ instr: Instruction, _ b: ProgramBuilder) -> Instruction { let newOp: Operation switch instr.op.opcode { - case .loadInteger(_): + case .loadInteger(let op): + // Half the time we want to just hit the regular path + if Bool.random(), + let customName = op.customName, + let type = b.fuzzer.environment.getEnum(ofName: customName) + { + let value = Int64(chooseUniform(from: type.enumValues))! + newOp = LoadInteger(value: value, customName: customName) + break + } newOp = LoadInteger(value: b.randomInt()) case .loadBigInt(_): newOp = LoadBigInt(value: b.randomInt()) diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 322a6fe2e..cc4bafbf1 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1620,9 +1620,20 @@ public struct Fuzzilli_Protobuf_LoadInteger: Sendable { public var value: Int64 = 0 + public var customName: String { + get {_customName ?? String()} + set {_customName = newValue} + } + /// Returns true if `customName` has been explicitly set. + public var hasCustomName: Bool {self._customName != nil} + /// Clears the value of `customName`. Subsequent reads from it will return its default value. + public mutating func clearCustomName() {self._customName = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _customName: String? = nil } public struct Fuzzilli_Protobuf_LoadBigInt: Sendable { @@ -6143,7 +6154,7 @@ extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_LoadInteger: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".LoadInteger" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}value\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}value\0\u{1}customName\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -6152,20 +6163,29 @@ extension Fuzzilli_Protobuf_LoadInteger: SwiftProtobuf.Message, SwiftProtobuf._M // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularInt64Field(value: &self.value) }() + case 2: try { try decoder.decodeSingularStringField(value: &self._customName) }() default: break } } } public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 if self.value != 0 { try visitor.visitSingularInt64Field(value: self.value, fieldNumber: 1) } + try { if let v = self._customName { + try visitor.visitSingularStringField(value: v, fieldNumber: 2) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_LoadInteger, rhs: Fuzzilli_Protobuf_LoadInteger) -> Bool { if lhs.value != rhs.value {return false} + if lhs._customName != rhs._customName {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index c48160805..c654f8b6f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -24,6 +24,7 @@ message Parameters { message LoadInteger { int64 value = 1; + optional string customName = 2; } message LoadBigInt { diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index e41776ea4..bfb9afd4a 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -2262,4 +2262,26 @@ class JSTyperTests: XCTestCase { XCTAssertNil(unionType.group) } + + func testIntEnumerationCustomName() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let mockIntEnum = ILType.intEnumeration(ofName: "MockIntEnum", withValues: [1337, 42]) + fuzzer.environment.registerEnumeration(mockIntEnum) + + let v1 = b.loadInt(1337, customName: "MockIntEnum") + let v2 = b.loadInt(1337) + + // v1 should be typed as the enumeration + XCTAssertEqual(b.type(of: v1).group, "MockIntEnum") + XCTAssertTrue(b.type(of: v1).isEnumeration) + XCTAssert(b.type(of: v1).Is(mockIntEnum)) + XCTAssert(b.type(of: v1).Is(.integer)) + + // v2 should be typed as a generic integer + XCTAssertNil(b.type(of: v2).group) + XCTAssertFalse(b.type(of: v2).isEnumeration) + XCTAssert(b.type(of: v2).Is(.integer)) + } } diff --git a/Tests/FuzzilliTests/TypeSystemTest.swift b/Tests/FuzzilliTests/TypeSystemTest.swift index 91f17cdb2..5833233e6 100644 --- a/Tests/FuzzilliTests/TypeSystemTest.swift +++ b/Tests/FuzzilliTests/TypeSystemTest.swift @@ -1548,6 +1548,40 @@ class TypeSystemTests: XCTestCase { XCTAssertEqual(receiverObject.intersection(with: receiverNil), receiverObject) } + func testEnumerationTypeOperations() { + let enumA = ILType.enumeration(ofName: "EnumA", withValues: ["A", "B"]) + let enumB = ILType.intEnumeration(ofName: "EnumB", withValues: [1, 2]) + let genericString = ILType.string + let genericInt = ILType.integer + + XCTAssertTrue(enumA.isEnumeration) + XCTAssertTrue(enumB.isEnumeration) + XCTAssertFalse(genericString.isEnumeration) + XCTAssertFalse(genericInt.isEnumeration) + + // Union: enumA | genericString should be genericString, so not an enumeration. + XCTAssertFalse((enumA | genericString).isEnumeration) + // Union: enumB | genericInt should be genericInt, so not an enumeration. + XCTAssertFalse((enumB | genericInt).isEnumeration) + // Union: enumA (string) | enumB (int) should be number | string, so not an enumeration. + XCTAssertFalse((enumA | enumB).isEnumeration) + + // Intersection: enumA & genericString should be enumA, so it should be an enumeration. + XCTAssertTrue((enumA & genericString).isEnumeration) + // Intersection: enumB & genericInt should be enumB, so it should be an enumeration. + XCTAssertTrue((enumB & genericInt).isEnumeration) + + // Intersection of string enum and int enum should be .nothing, which is not an enumeration. + XCTAssertEqual(enumA & enumB, .nothing) + XCTAssertFalse((enumA & enumB).isEnumeration) + + // Merging: enumA + object should maintain the isEnumeration flag. + let obj = ILType.object(withProperties: ["foo"]) + XCTAssertFalse(obj.isEnumeration) + XCTAssertTrue((enumA + obj).isEnumeration) + XCTAssertTrue((enumB + obj).isEnumeration) + } + let primitiveTypes: [ILType] = [ .undefined, .integer, .float, .string, .boolean, .bigint, .regexp, ] From 6b80463cff7fa2a3eed591cbbb2c502ecb2a8b32 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 8 Apr 2026 17:51:50 +0200 Subject: [PATCH 222/234] [wasm] Try to finally fix the jsTyper.getWasmTypeDef() crash This change refactors the WasmTypeGroupReducer to not just remove unused type definitions from the WasmEndTypeGroup but to also remove the type definition itself. In general, the GenericInstructionReducer should take care of that, however, with a sufficiently large program it could happen that the minimization doesn't finish within its max iteration count and it removed the input-wiring but not the type definition. The CodeGenMutator can then perform a `buildIntoTypeGroup()` and add a new struct type that uses the "unexported" type definition as an element type. Subsequently, another run of the CodeGenMutator can add a WasmStructNew operation that will then call jsTyper.getWasmTypeDef() which relies on all typess inside a type group (including the element type) being exported by the WasmEndTypeGroup operation which isn't the case here causing the fatalError. Bug: 475996631 Change-Id: I269d7c9c2069c1b31e85a17e103c87f593a241f0 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9188577 Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke Reviewed-by: Michael Achenbach --- .../Minimization/WasmTypeGroupReducer.swift | 97 ++++++++++++------- Tests/FuzzilliTests/MinimizerTest.swift | 72 +++++++++++++- 2 files changed, 132 insertions(+), 37 deletions(-) diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 76b991b43..85f93525a 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -12,57 +12,82 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + +// The TypeGroupReducer removes unused type definition. A type definition is considered unused if it +// is not used by any other operation but the WasmEndTypeGroup and if the corresponding output +// of the WasmEndTypeGroup is not used anywhere inside the program. +// +// This reducer preserves the invariant that each type defined inside a type group is also exposed +// by the WasmEndTypeGroup operation. +// Note that a WasmResolveForwardReference(v0, v1) makes v1 used and prevents its removal by this +// reducer. However, the GenericInstructionReducer will try to remove the +// WasmResolveForwardReference, so this is not an issue. struct WasmTypeGroupReducer: Reducer { func reduce(with helper: MinimizationHelper) { - // Compute all candidates: intermediate operations in a data flow chain. - var candidates = [Int]() - var uses = VariableMap() + var useCount = VariableMap() + var definitions = VariableMap() + + // Count all usages of Wasm type definitions. for instr in helper.code { - for input in instr.inputs { - uses[input]? += 1 + if instr.op is WasmTypeOperation { + for output in instr.outputs { + useCount[output] = 0 + definitions[output] = instr.index + } } - guard instr.op is WasmTypeOperation else { continue } - // Define the usages for all WasmTypeOperation so that we also count usages of a type - // inside a type group (i.e. by other type operations). - for output in instr.outputs { - uses[output] = 0 + if instr.op is WasmEndTypeGroup { + // Propagate usage counts from the input to the output variables. Note that the + // WasmEndTypeGroup ends the scope in which the inputs are defined (meaning there) + // can't be any usages after the WasmEndTypeGroup instruction. + for (input, output) in zip(instr.inputs, instr.outputs) { + useCount[output] = useCount[input]! + } + } else { + // Any usage but the WasmEndTypeGroup should be tracked. + // (This includes WasmResolveForwardReference.) + for input in instr.inputs { + useCount[input]? += 1 + } } + } + + if definitions.isEmpty { + return + } - // For now, we only consider EndTypeGroup instructions. + // Create replacements for WasmEndTypeGroup and collect type definitions to remove. + var toRemove = IndexSet() + var endTypeGroupReplacements = [Int: Instruction]() + + for instr in helper.code { guard case .wasmEndTypeGroup = instr.op.opcode else { continue } - candidates.append(instr.index) - for (input, output) in zip(instr.inputs, instr.outputs) { - // Subtract 1 as the input in the WasmEndTypeGroup itself is not a reason to keep - // the type. However, if the type is used inside the type group, it also needs to be - // exposed by the type group. Right now the JSTyper requires that all types defined - // in a type group are exposed by their WasmEndTypeGroup instruction. - uses[output]! += uses[input]! - 1 + let keptInoutsMap = zip(instr.inputs, instr.outputs).filter { useCount[$0.1]! > 0 } + if keptInoutsMap.count == instr.inputs.count { continue } + + let unusedInputs = + zip(instr.inputs, instr.outputs).filter { useCount[$0.1]! == 0 }.map { $0.0 } + for input in unusedInputs { + toRemove.insert(definitions[input]!) } - } - // Remove those candidates whose outputs are all used. - candidates = candidates.filter { - helper.code[$0].allOutputs.map({ uses[$0]! }).contains { $0 == 0 } + let newInouts = keptInoutsMap.map { $0.0 } + keptInoutsMap.map { $0.1 } + endTypeGroupReplacements[instr.index] = Instruction( + WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts, flags: .empty) } - if candidates.isEmpty { + if toRemove.isEmpty { return } - // Simplify each remaining candidate. - var replacements = [(Int, Instruction)]() - for candidate in candidates { - let instr = helper.code[candidate] - assert(instr.op is WasmEndTypeGroup) - assert(instr.inputs.count == instr.outputs.count) - let newInoutsMap = zip(instr.inputs, instr.outputs).filter { uses[$0.1]! > 0 } - let newInouts = newInoutsMap.map { $0.0 } + newInoutsMap.map { $0.1 } - let newInstr = Instruction( - WasmEndTypeGroup(typesCount: newInoutsMap.count), inouts: newInouts, flags: .empty) - replacements.append((candidate, newInstr)) - } - helper.tryReplacements(replacements, renumberVariables: true) + var newCode = Code( + helper.code + .filter { !toRemove.contains($0.index) } + .map { endTypeGroupReplacements[$0.index] ?? $0 }) + + newCode.renumberVariables() + helper.testAndCommit(newCode) } } diff --git a/Tests/FuzzilliTests/MinimizerTest.swift b/Tests/FuzzilliTests/MinimizerTest.swift index 7ecaf6dbe..bdd149207 100644 --- a/Tests/FuzzilliTests/MinimizerTest.swift +++ b/Tests/FuzzilliTests/MinimizerTest.swift @@ -2521,7 +2521,7 @@ class MinimizerTests: XCTestCase { var numReturnsAfter = 0 var numFunctionsBefore = 0 var numFunctionsAfter = 0 - var numImportantInstructionsBefore = importantInstructions.count + let numImportantInstructionsBefore = importantInstructions.count var numImportantInstructionsAfter = 0 for instr in referenceProgram.code { @@ -2616,4 +2616,74 @@ class MinimizerTests: XCTestCase { program, withAspects: dummyAspects, limit: limit, performPostprocessing: performPostprocessing) } + + func testWasmTypeGroupMinimization() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + evaluator.nextInstructionIsImportant(in: b) + b.wasmDefineTypeGroup { + let v0 = b.wasmDefineArrayType(elementType: .wasmi32, mutability: true) + return [v0] + } + let originalProgram = b.finalize() + + // Build expected output program: an empty type group. + b.reset() + b.wasmDefineTypeGroup { [] } + let expectedProgram = b.finalize() + + // Perform minimization with only the WasmTypeGroupReducer. + let reducer = WasmTypeGroupReducer() + evaluator.setOriginalProgram(originalProgram) + let helper = MinimizationHelper( + for: ProgramAspects(outcome: .succeeded), forCode: originalProgram.code, of: fuzzer, + runningOnFuzzerQueue: true) + reducer.reduce(with: helper) + + let actualProgram = Program(code: helper.code) + + XCTAssertEqual( + expectedProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(expectedProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + } + + // Removing WasmResolveForwardReference is done by another reducer. The WasmTypeGroupReducer + // should not change the semantics when reducing the types exposed by the WasmEndTypeGroup. + func testWasmTypeGroupReducerDoesntRemoveForwardReferenceResolving() { + let evaluator = EvaluatorForMinimizationTests() + let fuzzer = makeMockFuzzer(evaluator: evaluator) + let b = fuzzer.makeBuilder() + + // Build input program to be minimized. + b.wasmDefineTypeGroup { + let fwd = b.wasmDefineForwardOrSelfReference() + evaluator.nextInstructionIsImportant(in: b) + let arrayType = b.wasmDefineArrayType( + elementType: .wasmRef(.Index(), nullability: true), mutability: true, indexType: fwd + ) + let structType = b.wasmDefineStructType( + fields: [.init(type: .wasmi32, mutability: true)], indexTypes: []) + b.wasmResolveForwardReference(fwd, to: structType) + return [structType, arrayType] + } + let originalProgram = b.finalize() + + // Perform minimization and check that the two programs are equal. + let reducer = WasmTypeGroupReducer() + evaluator.setOriginalProgram(originalProgram) + let helper = MinimizationHelper( + for: ProgramAspects(outcome: .succeeded), forCode: originalProgram.code, of: fuzzer, + runningOnFuzzerQueue: true) + reducer.reduce(with: helper) + let actualProgram = Program(code: helper.code) + + XCTAssertEqual( + originalProgram, actualProgram, + "Expected:\n\(FuzzILLifter().lift(originalProgram.code))\n\n" + + "Actual:\n\(FuzzILLifter().lift(actualProgram.code))") + } } From bc511f1bb5a85fbbf0f1e0332f736850745048b3 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 12:07:22 +0200 Subject: [PATCH 223/234] [lifting] Remove invalid assert There isn't any escaping that prevents having property names containing new-lines and we do not escape them e.g. in the FuzzILLifter. This should be fine, the indentation might be ugly for it and in the JavaScriptLifter in the worst case we might create syntax errors but consistently and properly escaping string literals is not something that Fuzzilli seems to do (as of now). Change-Id: I974d10ecbe5d919b898e418815d8f72c199d0178 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206257 Reviewed-by: Michael Achenbach Commit-Queue: Michael Achenbach Auto-Submit: Matthias Liedtke --- Sources/Fuzzilli/Lifting/ScriptWriter.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Fuzzilli/Lifting/ScriptWriter.swift b/Sources/Fuzzilli/Lifting/ScriptWriter.swift index f9c029856..ec84c02b3 100644 --- a/Sources/Fuzzilli/Lifting/ScriptWriter.swift +++ b/Sources/Fuzzilli/Lifting/ScriptWriter.swift @@ -57,7 +57,6 @@ struct ScriptWriter { mutating func emit(_ line: S) { assert(maxLineLength > currentIndention.count) let splitAt = maxLineLength - currentIndention.count - assert(!line.contains("\n")) var line = line.prefix(line.count) while line.count > splitAt { var lineToPrint = line.prefix(splitAt + 1) From 31c547c7162255839c3e2484c3476457d35f4ab1 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 14:53:15 +0200 Subject: [PATCH 224/234] [v8] Remove wasm-in-js-inlining flag This feature isn't usable standalone any more, only as part of the turbolev pipeline. As such we'll be testing this implicitly via --turbolev-future (and eventually --turbolev once it's stable enough). Bug: 353475584, 455524488 Change-Id: I1f7566952c7fb33b20f59a58fd0795b5fa0bee16 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206258 Auto-Submit: Matthias Liedtke Reviewed-by: Daniel Lehmann Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Profiles/V8CommonProfile.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift index 8919b7511..68478c62f 100644 --- a/Sources/Fuzzilli/Profiles/V8CommonProfile.swift +++ b/Sources/Fuzzilli/Profiles/V8CommonProfile.swift @@ -1069,10 +1069,6 @@ public func v8ProcessArgs(randomize: Bool, forSandbox: Bool) -> [String] { } } - if probability(0.1) { - args.append("--turboshaft-wasm-in-js-inlining") - } - if probability(0.1) { args.append("--harmony-struct") } From 91f2dda2d39b430fe5204fa0f4d2a3a66287c198 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Wed, 15 Apr 2026 16:14:53 +0000 Subject: [PATCH 225/234] Add FuzzilliCLI flag corpusGenerationIterations This allows to specify, e.g., --corpusGenerationIterations=1 such that the main fuzzing phase is triggered earlier. This can be helpful for quickly checking if a change causes a problem in the main fuzzing phase. Change-Id: Iedee6175b7fe15f677bb5a015aeeea555f7ce16b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9207316 Reviewed-by: Matthias Liedtke Commit-Queue: Leon Bettscheider --- Sources/Fuzzilli/Configuration.swift | 6 ++++++ Sources/Fuzzilli/Fuzzer.swift | 2 +- Sources/FuzzilliCli/main.swift | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index d6fa2d311..4aa0f7b4a 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -97,6 +97,10 @@ public struct Configuration { // The directory in which the corpus and additional diagnostics files are stored. public let storagePath: String? + // The number of iterations without finding a new interesting program after which + // the fuzzer switches from corpus generation to the main fuzzing phase. + public let corpusGenerationIterations: Int + // Advises the fuzzer to generate cases that are more suitable for differential fuzzing. // Right now this only leads to the JavaScriptLifter emitting more local variables which // differential fuzzers can inspect (via mutating the JS program to print defined variables). @@ -121,6 +125,7 @@ public struct Configuration { tag: String? = nil, isWasmEnabled: Bool = false, storagePath: String? = nil, + corpusGenerationIterations: Int = 100, forDifferentialFuzzing: Bool = false, instanceId: Int = -1, dumplingEnabled: Bool = false @@ -138,6 +143,7 @@ public struct Configuration { self.tag = tag self.isWasmEnabled = isWasmEnabled self.storagePath = storagePath + self.corpusGenerationIterations = corpusGenerationIterations self.forDifferentialFuzzing = forDifferentialFuzzing self.diffConfig = dumplingEnabled diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 09b1ce265..4fb4f00cb 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -1069,7 +1069,7 @@ public class Fuzzer { // iterations. The rough order of magnitude of N has been determined experimentally: run two instances with // different values (e.g. 10 and 100) for roughly the same number of iterations (approximately until both // have finished the initial corpus generation), then compare the corpus size and coverage. - if iterationsSinceLastInterestingProgram > 100 { + if iterationsSinceLastInterestingProgram > config.corpusGenerationIterations { guard !corpus.isEmpty else { logger.fatal( "Initial corpus generation failed, corpus is still empty. Is the evaluator working correctly?" diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 8a95f081a..615825f21 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -48,6 +48,8 @@ if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != per round of sample selection. Used to ensure diversity between fuzzer instances (default: 0.10) --consecutiveMutations=n : Perform this many consecutive mutations on each sample (default: 5). + --corpusGenerationIterations=n : Switch from corpus generation to the main fuzzing phase after this many + iterations without finding a new interesting sample (default: 100). --minimizationLimit=p : When minimizing interesting programs, keep at least this percentage of the original instructions regardless of whether they are needed to trigger the interesting behaviour or not. See Minimizer.swift for an overview of this feature (default: 0.0). @@ -142,6 +144,7 @@ let minCorpusSize = args.int(for: "--minCorpusSize") ?? 1000 let maxCorpusSize = args.int(for: "--maxCorpusSize") ?? Int.max let markovDropoutRate = args.double(for: "--markovDropoutRate") ?? 0.10 let consecutiveMutations = args.int(for: "--consecutiveMutations") ?? 5 +let corpusGenerationIterations = args.int(for: "--corpusGenerationIterations") ?? 100 let minimizationLimit = args.double(for: "--minimizationLimit") ?? 0.0 let storagePath = args["--storagePath"] var resume = args.has("--resume") @@ -615,6 +618,7 @@ let mainConfig = Configuration( tag: tag, isWasmEnabled: enableWasm, storagePath: storagePath, + corpusGenerationIterations: corpusGenerationIterations, forDifferentialFuzzing: forDifferentialFuzzing, instanceId: 0, dumplingEnabled: profile.isDifferential) @@ -794,6 +798,7 @@ for i in 1.. Date: Wed, 15 Apr 2026 15:19:06 +0200 Subject: [PATCH 226/234] RuntimeAssistedMutator: Improve error message on failed transpilation The fuzzer should report whether node.js wasn't available or whether the npm dependencies were missing. This commit also changes the order of the two warnings, so we first print: > Mutated program did not crash, reporting original crash of the > instrumented program and then print any failures for trying to transpile the instrumented program. Bug: 488963988 Change-Id: I30fd95b8a0eaa10fb0050866cf5099e356086dd6 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206260 Reviewed-by: Leon Bettscheider Commit-Queue: Matthias Liedtke --- .../Mutators/RuntimeAssistedMutator.swift | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index 89845ff39..c9d3c383f 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -85,6 +85,43 @@ public class RuntimeAssistedMutator: Mutator { // May be overwritten by child classes } + // Lift the instrumented program to JS and try to transpile it back to FuzzIL. + // If we can convert the instrumented program including its additional JS code to IL, the crash + // reporting can perform proper minimization on it. + private func tryRoundtripTranspileInstrumentedProgramToFuzzIL( + _ fuzzer: Fuzzer, _ instrumentedProgram: Program + ) + -> Program? + { + let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) + var maybeProgramToMinimize: Program? = nil + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( + UUID().uuidString + ".js") + let errorPrefix = "Unable to compile instrumented JS program to FuzzIL because" + guard + let nodejs = JavaScriptExecutor( + type: .nodejs, withArguments: ["--allow-natives-syntax"]) + else { + logger.warning("\(errorPrefix) node.js is not available") + return nil + } + guard let parser = JavaScriptParser(executor: nodejs) else { + logger.warning("\(errorPrefix) the needed npm dependencies are not installed") + return nil + } + do { + try instrumentedJavaScriptProgram.write( + to: tempFile, atomically: true, encoding: .utf8) + let ast = try parser.parse(tempFile.path) + maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program to FuzzIL") + } catch { + logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + } + try? FileManager.default.removeItem(at: tempFile) + return maybeProgramToMinimize + } + override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) -> Program? { @@ -155,38 +192,16 @@ public class RuntimeAssistedMutator: Mutator { } } - // If we reach here, the process()'d program did not crash, so we need to report the instrumented program. - // First, get the instrumented JS program and try to compile it back to FuzzIL, so it can be minimized more effectively. - // We need this because instrumentation adds boilerplate JS code. - let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) - var maybeProgramToMinimize: Program? = nil - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( - UUID().uuidString + ".js") - if let nodejs = JavaScriptExecutor( - type: .nodejs, withArguments: ["--allow-natives-syntax"]), - let parser = JavaScriptParser(executor: nodejs) - { - do { - try instrumentedJavaScriptProgram.write( - to: tempFile, atomically: true, encoding: .utf8) - let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") - } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") - } - try? FileManager.default.removeItem(at: tempFile) - } else { - logger.warning( - "Unable to compile instrumented JS program to FuzzIL because node.js is not available" - ) - } - + // If we reach here, the process()'d program did not crash, so we need to report the + // instrumented program. logger.warning( "Mutated program did not crash, reporting original crash of the instrumented program" ) + let programToReport = + tryRoundtripTranspileInstrumentedProgramToFuzzIL(fuzzer, instrumentedProgram) + ?? instrumentedProgram fuzzer.processCrash( - maybeProgramToMinimize ?? instrumentedProgram, withSignal: signal, + programToReport, withSignal: signal, withStderr: oldStderr, withStdout: stdout, origin: .local, withExectime: execution.execTime) case .succeeded: From d4c70b087cc3570c6233401e6f8ec8883691bc5d Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Wed, 15 Apr 2026 16:26:39 +0200 Subject: [PATCH 227/234] RuntimeAssistedMutator: Verify that the transpiled program still crashes There isn't any guarantee for that, in the worst case, removing comments can be enough to not encounter a crash any more (mostly in cases of moving gc-intervals as the JS code itself is part of the JS heap and therefore its size can affect reproducability.) Bug: 488963988 Change-Id: Id41eb32cc7517965c1de425e1d1be76ddd9f4370 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9206261 Reviewed-by: Leon Bettscheider Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- .../Mutators/RuntimeAssistedMutator.swift | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift index c9d3c383f..6dbf6e2c0 100644 --- a/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift +++ b/Sources/Fuzzilli/Mutators/RuntimeAssistedMutator.swift @@ -89,14 +89,14 @@ public class RuntimeAssistedMutator: Mutator { // If we can convert the instrumented program including its additional JS code to IL, the crash // reporting can perform proper minimization on it. private func tryRoundtripTranspileInstrumentedProgramToFuzzIL( - _ fuzzer: Fuzzer, _ instrumentedProgram: Program + _ fuzzer: Fuzzer, _ instrumentedProgram: Program, expectedSignal: Int ) -> Program? { let instrumentedJavaScriptProgram = fuzzer.lifter.lift(instrumentedProgram) - var maybeProgramToMinimize: Program? = nil let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent( UUID().uuidString + ".js") + defer { try? FileManager.default.removeItem(at: tempFile) } let errorPrefix = "Unable to compile instrumented JS program to FuzzIL because" guard let nodejs = JavaScriptExecutor( @@ -113,13 +113,25 @@ public class RuntimeAssistedMutator: Mutator { try instrumentedJavaScriptProgram.write( to: tempFile, atomically: true, encoding: .utf8) let ast = try parser.parse(tempFile.path) - maybeProgramToMinimize = try JavaScriptCompiler().compile(ast) - logger.warning("Successfully compiled instrumented JS program to FuzzIL") + let transpiledProgram = try JavaScriptCompiler().compile(ast) + logger.warning("Successfully compiled instrumented JS program back to FuzzIL") + let execution = fuzzer.execute( + transpiledProgram, withTimeout: fuzzer.config.timeout, + purpose: .runtimeAssistedMutation) + guard case .crashed(let signal) = execution.outcome else { + logger.warning("Transpiled program doesn't crash any more.") + return nil + } + guard signal == expectedSignal else { + logger.warning( + "Transpiled program crashes with signal \(signal) instead of \(expectedSignal)") + return nil + } + return transpiledProgram } catch { - logger.warning("Failed to compile instrumented JS program to FuzzIL: \(error)") + logger.warning("Failed to compile instrumented JS program back to FuzzIL: \(error)") + return nil } - try? FileManager.default.removeItem(at: tempFile) - return maybeProgramToMinimize } override final func mutate(_ program: Program, using b: ProgramBuilder, for fuzzer: Fuzzer) @@ -198,7 +210,8 @@ public class RuntimeAssistedMutator: Mutator { "Mutated program did not crash, reporting original crash of the instrumented program" ) let programToReport = - tryRoundtripTranspileInstrumentedProgramToFuzzIL(fuzzer, instrumentedProgram) + tryRoundtripTranspileInstrumentedProgramToFuzzIL( + fuzzer, instrumentedProgram, expectedSignal: signal) ?? instrumentedProgram fuzzer.processCrash( programToReport, withSignal: signal, From 267a742869730c92284be5be0b944136b44ab07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Thu, 16 Apr 2026 13:11:58 +0200 Subject: [PATCH 228/234] [js] Add bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bundles can contain multiple scripts which will be executed sequentially. Modules will be added as a follow up. Bug: 342521422 Change-Id: Icedae3b6805bf6db0359bb6fbdff69cfb2f0d48a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9184296 Reviewed-by: Matthias Liedtke Commit-Queue: Marja Hölttä --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 39 +++++++++-- .../CodeGen/CodeGeneratorWeights.swift | 4 ++ Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 20 ++++++ Sources/Fuzzilli/Compiler/Compiler.swift | 6 +- Sources/Fuzzilli/Configuration.swift | 5 ++ Sources/Fuzzilli/Corpus/MarkovCorpus.swift | 3 +- .../Fuzzilli/Engines/GenerativeEngine.swift | 12 +++- .../Evaluation/ProgramCoverageEvaluator.swift | 2 +- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 13 +++- Sources/Fuzzilli/FuzzIL/Code.swift | 12 +++- Sources/Fuzzilli/FuzzIL/Context.swift | 6 ++ Sources/Fuzzilli/FuzzIL/Instruction.swift | 8 +++ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 14 ++-- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 17 +++++ Sources/Fuzzilli/FuzzIL/Opcodes.swift | 2 + Sources/Fuzzilli/FuzzIL/Program.swift | 7 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 2 + Sources/Fuzzilli/Fuzzer.swift | 57 +++++++++++----- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 8 +++ .../Fuzzilli/Lifting/JavaScriptLifter.swift | 20 ++++-- Sources/Fuzzilli/Lifting/WasmLifter.swift | 2 +- .../Fuzzilli/Minimization/BlockReducer.swift | 9 +-- .../Minimization/DataFlowSimplifier.swift | 4 +- .../Minimization/InliningReducer.swift | 2 +- .../Minimization/InstructionSimplifier.swift | 2 +- .../Minimization/MinimizationHelper.swift | 2 +- .../MinimizationPostProcessor.swift | 2 +- .../Minimization/ReassignReducer.swift | 2 +- .../Minimization/WasmTypeGroupReducer.swift | 2 +- Sources/Fuzzilli/Modules/Sync.swift | 10 +++ .../Fuzzilli/Mutators/OperationMutator.swift | 2 + Sources/Fuzzilli/Protobuf/gen_programproto.py | 1 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 58 ++++++++++++++++ Sources/Fuzzilli/Protobuf/operations.proto | 6 ++ Sources/Fuzzilli/Protobuf/program.pb.swift | 68 ++++++++++++++++++- Sources/Fuzzilli/Protobuf/program.proto | 3 + Sources/Fuzzilli/Protobuf/sync.pb.swift | 9 ++- Sources/Fuzzilli/Protobuf/sync.proto | 1 + Sources/FuzzilliCli/main.swift | 14 +++- Tests/FuzzilliTests/ContextGraphTest.swift | 21 +++++- Tests/FuzzilliTests/LifterTest.swift | 30 ++++++++ Tests/FuzzilliTests/MinimizerTest.swift | 42 +++++++++++- Tests/FuzzilliTests/ProgramBuilderTest.swift | 39 +++++++++++ 43 files changed, 520 insertions(+), 68 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index e3bf101f0..44cc8f64a 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -58,7 +58,7 @@ public class ProgramBuilder { private let logger = Logger(withLabel: "ProgramBuilder") /// The code and type information of the program that is being constructed. - private var code = Code() + private var code: Code /// Comments for the program that is being constructed. private var comments = ProgramComments() @@ -77,7 +77,7 @@ public class ProgramBuilder { private var numVariables = 0 /// Context analyzer to keep track of the currently active IL context. - private var contextAnalyzer = ContextAnalyzer() + private var contextAnalyzer: ContextAnalyzer /// Visible variables management. /// The `scopes` stack contains one entry per currently open scope containing all variables created in that scope. @@ -191,15 +191,20 @@ public class ProgramBuilder { } } + public let isBundle: Bool + /// Constructs a new program builder for the given fuzzer. - init(for fuzzer: Fuzzer, parent: Program?) { + init(for fuzzer: Fuzzer, parent: Program?, isBundle: Bool) { self.fuzzer = fuzzer - self.jsTyper = JSTyper(for: fuzzer.environment) + self.jsTyper = JSTyper(for: fuzzer.environment, isBundle: isBundle) self.parent = parent + self.isBundle = isBundle if fuzzer.config.logLevel.isAtLeast(.verbose) { self.buildLog = BuildLog() } + code = Code(isBundle: isBundle) + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) } /// Resets this builder. @@ -212,7 +217,7 @@ public class ProgramBuilder { variablesInScope.removeAll() hiddenVariables.removeAll() numberOfHiddenVariables = 0 - contextAnalyzer = ContextAnalyzer() + contextAnalyzer = ContextAnalyzer(isBundle: isBundle) jsTyper.reset() activeObjectLiterals.removeAll() activeClassDefinitions.removeAll() @@ -1106,6 +1111,10 @@ public class ProgramBuilder { /// Returns a random variable satisfying the given constraints or nil if none is found. public func findVariable(satisfying filter: ((Variable) -> Bool) = { _ in true }) -> Variable? { + if isBundle && !hasVisibleVariables { + // Bundles don't have visible variables before we've started generating the bundle items. + return nil + } assert(hasVisibleVariables) // TODO: we should implement some kind of fast lookup data structure to speed up the lookup of variables by type. @@ -1730,7 +1739,7 @@ public class ProgramBuilder { // Step (2): determine which instructions can be part of the slice and attempt to find replacement variables for the outputs of instructions that cannot be included. // // We need a typer to be able to find compatible replacement variables if we are merging the dataflows of the two programs. - var typer = JSTyper(for: fuzzer.environment) + var typer = JSTyper(for: fuzzer.environment, isBundle: program.code.isBundle) // The set of variables that are available for a slice. A variable is available either because the instruction that outputs // it can be part of the slice or because the variable has been remapped to a host variable. var availableVariables = VariableSet() @@ -2097,8 +2106,9 @@ public class ProgramBuilder { case .generating: // This requirement might seem somewhat arbitrary but our JavaScript code generators make use of `b.randomVariable` and as such rely on the availability of // visible Variables. Therefore we should always have some Variables visible if we want to use them. + assert( - hasVisibleVariables, + isBundle || hasVisibleVariables, "CodeGenerators assume that there are visible variables to use. Use buildPrefix() to generate some initial variables in a new program" ) @@ -2244,6 +2254,11 @@ public class ProgramBuilder { /// of prefix code is controlled in the same way as other generated code through the /// generator's respective weights. public func buildPrefix() { + if contextAnalyzer.context == .bundle { + // Don't emit a prefix into the bundle context. The items inside the bundle will emit their own prefixes. + return + } + // Each value generators should generate at least 3 variables, and we probably want to run at least a // few of them (maybe roughly >= 3), so the number of variables to build shouldn't be set too low. assert(GeneratorStub.numberOfValuesToGenerateByValueGenerators == 3) @@ -4060,6 +4075,16 @@ public class ProgramBuilder { emit(EndBlockStatement()) } + public func maybeWrapInsideBundleScript(_ body: () -> Void) { + if isBundle { + emit(BeginBundleScript()) + } + body() + if isBundle { + emit(EndBundleScript()) + } + } + public func doPrint(_ value: Variable) { emit(Print(), withInputs: [value]) } diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 69a29a2ef..f607ba62d 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -236,6 +236,10 @@ public let codeGeneratorWeights = [ "WasmTagGenerator": 4, "WasmLegacyTryCatchComplexGenerator": 5, + // For generating bundles + // TODO(marja): Add modules. + "BundleScriptGenerator": 1, + // // Wasm generators // diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index cdc4863d0..8bc94f6db 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -3394,4 +3394,24 @@ public let CodeGenerators: [CodeGenerator] = [ let newSize = b.binary(currentByteLength, delta, with: .Add) b.callMethod("grow", on: buffer, withArgs: [newSize], guard: true) }, + + CodeGenerator( + "BundleScriptGenerator", + [ + GeneratorStub( + "BundleScriptBeginGenerator", + inContext: .single(.bundle), + provides: [.javascript] + ) { b in + b.emit(BeginBundleScript()) + // TODO(marja): Make variables created to scripts visible to other scripts. + b.buildPrefix() + }, + GeneratorStub( + "BundleScriptEndGenerator", + inContext: .single([.javascript]), + ) { b in + b.emit(EndBundleScript()) + }, + ]), ] diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 188868063..1ecdf89e6 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -31,7 +31,8 @@ public class JavaScriptCompiler { public init() {} /// The compiled code. - private var code = Code() + // TODO(marja): Make JavaScriptCompiler understand bundles. + private var code = Code(isBundle: false) /// The environment is used to determine if an identifier identifies a builtin object. /// TODO we should probably use the correct target environment, with any additional builtins etc. here. But for now, we just manually add `gc` since that's relatively common. @@ -1559,7 +1560,8 @@ public class JavaScriptCompiler { } private func reset() { - code = Code() + // TODO(marja): Make JavaScriptCompiler understand bundles. + code = Code(isBundle: false) scopes.removeAll() nextVariable = 0 } diff --git a/Sources/Fuzzilli/Configuration.swift b/Sources/Fuzzilli/Configuration.swift index 4aa0f7b4a..efd048ddf 100644 --- a/Sources/Fuzzilli/Configuration.swift +++ b/Sources/Fuzzilli/Configuration.swift @@ -110,6 +110,9 @@ public struct Configuration { // be imported due to disabled wasm capabilities in the fuzzer. public static let excludedWasmDirectory = "excluded_wasm_programs" + // Whether the fuzzer generates bundles containing multiple JavaScript scripts or modules. + public let generateBundle: Bool + public init( arguments: [String] = [], timeout: UInt32 = 250, @@ -124,6 +127,7 @@ public struct Configuration { staticCorpus: Bool = false, tag: String? = nil, isWasmEnabled: Bool = false, + generateBundle: Bool = false, storagePath: String? = nil, corpusGenerationIterations: Int = 100, forDifferentialFuzzing: Bool = false, @@ -142,6 +146,7 @@ public struct Configuration { self.staticCorpus = staticCorpus self.tag = tag self.isWasmEnabled = isWasmEnabled + self.generateBundle = generateBundle self.storagePath = storagePath self.corpusGenerationIterations = corpusGenerationIterations self.forDifferentialFuzzing = forDifferentialFuzzing diff --git a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift index bbc069983..2224f593c 100644 --- a/Sources/Fuzzilli/Corpus/MarkovCorpus.swift +++ b/Sources/Fuzzilli/Corpus/MarkovCorpus.swift @@ -51,7 +51,8 @@ public class MarkovCorpus: ComponentBase, Corpus { self.dropoutRate = dropoutRate covEvaluator.enableEdgeTracking() self.covEvaluator = covEvaluator - self.currentProg = Program() + // TODO(marja): Support bundles. + self.currentProg = Program(isBundle: false) super.init(name: "MarkovCorpus") } diff --git a/Sources/Fuzzilli/Engines/GenerativeEngine.swift b/Sources/Fuzzilli/Engines/GenerativeEngine.swift index f2a5115ee..a0c21aadf 100644 --- a/Sources/Fuzzilli/Engines/GenerativeEngine.swift +++ b/Sources/Fuzzilli/Engines/GenerativeEngine.swift @@ -17,9 +17,12 @@ import Foundation /// Purely generative fuzzing engine, mostly used for initial corpus generation when starting without an existing corpus. public class GenerativeEngine: FuzzEngine { /// Approximate number of instructions to generate in additional to any prefix code. - private let numInstructionsToGenerate = 10 + private var numInstructionsToGenerate = 10 - public init() { + private let generateBundle: Bool + + public init(generateBundle: Bool) { + self.generateBundle = generateBundle super.init(name: "GenerativeEngine") } @@ -27,6 +30,11 @@ public class GenerativeEngine: FuzzEngine { public override func fuzzOne(_ group: DispatchGroup) { let b = fuzzer.makeBuilder() + if generateBundle { + // Increase the budget so that we are more likely to generate more items inside a bundle. + numInstructionsToGenerate = 50 + } + // Start by building a prefix that creates some variables (of known types) that the following CodeGenerators can then make use of. b.buildPrefix() // Then generate the actual code. diff --git a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift index 4decc2812..447db8043 100644 --- a/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift +++ b/Sources/Fuzzilli/Evaluation/ProgramCoverageEvaluator.swift @@ -150,7 +150,7 @@ public class ProgramCoverageEvaluator: ComponentBase, ProgramEvaluator { libcoverage.cov_shutdown(&self.context) } - let _ = fuzzer.execute(Program(), purpose: .startup) + let _ = fuzzer.execute(Program(isBundle: false), purpose: .startup) libcoverage.cov_finish_initialization(&context, shouldTrackEdgeCounts ? 1 : 0) logger.info("Initialized, \(context.num_edges) edges") } diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index aabce9662..ce6edb562 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -37,7 +37,7 @@ extension Analyzer { struct DefUseAnalyzer: Analyzer { private var assignments = VariableMap<[Int]>() private var uses = VariableMap<[Int]>() - private var code = Code() + private var code: Code private var isRunning = true private var analysisDone = false @@ -46,7 +46,9 @@ struct DefUseAnalyzer: Analyzer { self.isRunning = false } - init() {} + init(isBundle: Bool) { + self.code = Code(isBundle: isBundle) + } mutating func finishAnalysis() { analysisDone = true @@ -161,12 +163,17 @@ struct VariableAnalyzer: Analyzer { /// Keeps track of the current context during program construction. struct ContextAnalyzer: Analyzer { - private var contextStack = Stack([Context.javascript]) + private var contextStack: Stack var context: Context { return contextStack.top } + public init(isBundle: Bool = false) { + let startingContext = isBundle ? Context.bundle : Context.javascript + contextStack = Stack([startingContext]) + } + mutating func analyze(_ instr: Instruction) { if instr.isBlockEnd { contextStack.pop() diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index b0229396c..199ec341a 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -22,11 +22,17 @@ public struct Code: Collection { /// Code is just a linear sequence of instructions. private var instructions = [Instruction]() + public let isBundle: Bool + /// Creates an empty code instance. - public init() {} + public init(isBundle: Bool) { + self.isBundle = isBundle + } /// Creates a code instance containing the given instructions. - public init(_ instructions: S) where S.Element == Instruction { + public init(_ instructions: S, isBundle: Bool) + where S.Element == Instruction { + self.isBundle = isBundle for instr in instructions { append(instr) } @@ -205,7 +211,7 @@ public struct Code: Collection { /// Checks if this code is statically valid, i.e. can be used as a Program. public func check() throws { var definedVariables = VariableMap() - var contextAnalyzer = ContextAnalyzer() + var contextAnalyzer = ContextAnalyzer(isBundle: isBundle) var scopeCounter = 0 // Per-block information is stored in this struct and kept in a stack of active blocks. struct Block { diff --git a/Sources/Fuzzilli/FuzzIL/Context.swift b/Sources/Fuzzilli/FuzzIL/Context.swift index 080c3d5e8..3bf4dd5b4 100644 --- a/Sources/Fuzzilli/FuzzIL/Context.swift +++ b/Sources/Fuzzilli/FuzzIL/Context.swift @@ -30,6 +30,7 @@ public struct Context: OptionSet, Hashable, CaseIterable { .wasmFunction, .wasmTypeGroup, .empty, + .bundle, ] public let rawValue: UInt32 @@ -71,6 +72,8 @@ public struct Context: OptionSet, Hashable, CaseIterable { public static let wasmFunction = Context(rawValue: 1 << 12) // Inside a wasm recursive type group definition. public static let wasmTypeGroup = Context(rawValue: 1 << 13) + // Inside a bundle containing multiple scripts / modules + public static let bundle = Context(rawValue: 1 << 14) public static let empty = Context([]) @@ -115,6 +118,9 @@ extension Context: CustomStringConvertible { if self.contains(.switchCase) { strings.append(".switchCase") } + if self.contains(.bundle) { + strings.append(".bundle") + } if self.contains(.wasm) { strings.append(".wasm") } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index be087fdc3..3cc539e93 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1194,6 +1194,10 @@ extension Instruction: ProtobufConvertible { $0.bindMethod = Fuzzilli_Protobuf_BindMethod.with { $0.methodName = op.methodName } case .bindFunction(_): $0.bindFunction = Fuzzilli_Protobuf_BindFunction() + case .beginBundleScript: + $0.beginBundleScript = Fuzzilli_Protobuf_BeginBundleScript() + case .endBundleScript: + $0.endBundleScript = Fuzzilli_Protobuf_EndBundleScript() case .print(_): fatalError("Print operations should not be serialized") // Wasm Operations @@ -2378,6 +2382,10 @@ extension Instruction: ProtobufConvertible { op = BeginBlockStatement() case .endBlockStatement: op = EndBlockStatement() + case .beginBundleScript: + op = BeginBundleScript() + case .endBundleScript: + op = EndBundleScript() case .loadNewTarget: op = LoadNewTarget() case .nop: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index f3519b16f..078e34378 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -25,7 +25,7 @@ public struct JSTyper: Analyzer { // The current state private var state = AnalyzerState() - private var defUseAnalyzer = DefUseAnalyzer() + private var defUseAnalyzer: DefUseAnalyzer // Parameter types for subroutines defined in the analyzed program. // These are keyed by the index of the start of the subroutine definition. @@ -441,8 +441,12 @@ public struct JSTyper: Analyzer { // The index of the last instruction that was processed. Just used for debug assertions. private var indexOfLastInstruction = -1 - init(for environ: JavaScriptEnvironment) { + private let isBundle: Bool + + init(for environ: JavaScriptEnvironment, isBundle: Bool) { self.environment = environ + self.isBundle = isBundle + self.defUseAnalyzer = DefUseAnalyzer(isBundle: isBundle) } public mutating func reset() { @@ -451,7 +455,7 @@ public struct JSTyper: Analyzer { signatures.removeAll() typeGroups.removeAll() wasmTypeDefMap.removeAll() - defUseAnalyzer = DefUseAnalyzer() + defUseAnalyzer = DefUseAnalyzer(isBundle: isBundle) isWithinTypeGroup = false dynamicObjectGroupManager = ObjectGroupManager() assert(activeFunctionDefinitions.isEmpty) @@ -1379,7 +1383,9 @@ public struct JSTyper: Analyzer { .beginClassStaticInitializer, .endClassStaticInitializer, .beginWasmModule, - .endWasmModule: + .endWasmModule, + .beginBundleScript, + .endBundleScript: // Object literals and class definitions don't create any conditional branches, only methods and accessors inside of them. These are handled further below. break case .beginIf: diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index be392b830..14e74f42d 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -2624,6 +2624,23 @@ final class LoadNewTarget: JsOperation { } } +final class BeginBundleScript: JsOperation { + override var opcode: Opcode { .beginBundleScript(self) } + + init() { + super.init( + attributes: .isBlockStart, requiredContext: [.bundle], contextOpened: .javascript) + } +} + +final class EndBundleScript: JsOperation { + override var opcode: Opcode { .endBundleScript(self) } + + init() { + super.init(attributes: .isBlockEnd, requiredContext: .javascript) + } +} + final class BeginWasmModule: JsOperation { override var opcode: Opcode { .beginWasmModule(self) } init() { diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 3a55fc4cb..deb4011bc 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -363,4 +363,6 @@ enum Opcode { case endClassComputedGetter(EndClassComputedGetter) case beginClassComputedSetter(BeginClassComputedSetter) case endClassComputedSetter(EndClassComputedSetter) + case beginBundleScript(BeginBundleScript) + case endBundleScript(EndBundleScript) } diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index 9b2c81122..f7e4e4b58 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -47,8 +47,8 @@ public final class Program: CustomStringConvertible { public private(set) lazy var id = UUID() /// Constructs an empty program. - public init() { - self.code = Code() + public init(isBundle: Bool) { + self.code = Code(isBundle: isBundle) self.parent = nil } @@ -141,6 +141,7 @@ extension Program: ProtobufConvertible { if let parent = parent { $0.parent = parent.asProtobuf(opCache: opCache) } + $0.isBundle = code.isBundle } } @@ -149,7 +150,7 @@ extension Program: ProtobufConvertible { } convenience init(from proto: ProtobufType, opCache: OperationCache? = nil) throws { - var code = Code() + var code = Code(isBundle: proto.isBundle) for (i, protoInstr) in proto.code.enumerated() { do { code.append(try Instruction(from: protoInstr, with: opCache)) diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index f8a60233c..325524ca3 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -221,6 +221,8 @@ extension Operation { return endOp is EndCodeString case .beginBlockStatement: return endOp is EndBlockStatement + case .beginBundleScript: + return endOp is EndBundleScript case .beginWasmModule: return endOp is EndWasmModule case .beginWasmFunction: diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 4fb4f00cb..7a2d93ab5 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -87,7 +87,7 @@ public class Fuzzer { public let minimizer: Minimizer /// The engine used for initial corpus generation (if performed). - public let corpusGenerationEngine = GenerativeEngine() + public let corpusGenerationEngine: GenerativeEngine /// The possible states of a fuzzer. public enum State { @@ -212,6 +212,7 @@ public class Fuzzer { self.logger = Logger(withLabel: "Fuzzer") self.contextGraph = ContextGraph(for: codeGenerators, withLogger: self.logger) + self.corpusGenerationEngine = GenerativeEngine(generateBundle: configuration.generateBundle) // Pass-through any postprocessor to the generative engine. if let postProcessor = engine.postProcessor { corpusGenerationEngine.registerPostProcessor(postProcessor) @@ -449,6 +450,7 @@ public class Fuzzer { case imported case dropped case needsWasm + case needsBundles case failed(ExecutionOutcome) } @@ -487,6 +489,10 @@ public class Fuzzer { return .needsWasm } + if !config.generateBundle && program.code.isBundle { + return .needsBundles + } + let execution = execute(program, purpose: .programImport) var wasImported = false @@ -622,7 +628,7 @@ public class Fuzzer { // Only attempt fixup if the program failed to execute successfully. In particular, ignore timeouts and // crashes here, but also take into account that not all successfully executing programs will be imported. switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 0) case .failed(_): break @@ -646,7 +652,7 @@ public class Fuzzer { program = removeCallsTo(filteredFunctions, from: program) result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 1) case .failed(_): break @@ -667,7 +673,7 @@ public class Fuzzer { } result = importProgram(program, origin: origin) switch result { - case .dropped, .needsWasm, .imported: + case .dropped, .needsWasm, .needsBundles, .imported: return (result, 2) case .failed(_): break @@ -949,7 +955,7 @@ public class Fuzzer { dispatchPrecondition(condition: .onQueue(queue)) // Program ancestor chains are only constructed if inspection mode is enabled let parent = config.enableInspection ? parent : nil - return ProgramBuilder(for: self, parent: parent) + return ProgramBuilder(for: self, parent: parent, isBundle: config.generateBundle) } /// Performs one round of fuzzing. @@ -1038,6 +1044,11 @@ public class Fuzzer { ) } } + if !config.generateBundle { + logger.info( + "\(currentCorpusImportJob.numberOfProgramsRequiringBundlesButDisabled)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs require bundles which are disabled" + ) + } let successRatio = Double( @@ -1048,7 +1059,7 @@ public class Fuzzer { let reason = config.isWasmEnabled ? "execute successfully" - : "execute successfully or require currently disabled wasm" + : "execute successfully or require currently disabled wasm or bundles" logger.warning( "\(String(format: "%.2f", failureRatio * 100))% of imported programs failed to \(reason) and therefore couldn't be imported." ) @@ -1093,9 +1104,7 @@ public class Fuzzer { } /// Constructs a non-trivial program. Useful to measure program execution speed. - private func makeComplexProgram() -> Program { - let b = makeBuilder() - + private func makeComplexProgram(builder b: ProgramBuilder) { let f = b.buildPlainFunction(with: .parameters(n: 2)) { params in let x = b.getProperty("x", of: params[0]) let y = b.getProperty("y", of: params[0]) @@ -1111,8 +1120,6 @@ public class Fuzzer { let arg2 = i b.callFunction(f, withArgs: [arg1, arg2]) } - - return b.finalize() } /// Runs a number of startup tests to check whether everything is configured correctly. @@ -1121,7 +1128,7 @@ public class Fuzzer { assert(isInitialized) // Check if we can execute programs - var execution = execute(Program(), purpose: .startup) + var execution = execute(Program(isBundle: false), purpose: .startup) guard case .succeeded = execution.outcome else { logger.fatal( "Cannot execute programs (exit code must be zero when no exception was thrown, but execution outcome was \(execution.outcome)). Are the command line flags valid?" @@ -1130,8 +1137,10 @@ public class Fuzzer { // Check if we can detect failed executions (i.e. an exception was thrown) var b = makeBuilder() - let exception = b.loadInt(42) - b.throwException(exception) + b.maybeWrapInsideBundleScript { + let exception = b.loadInt(42) + b.throwException(exception) + } execution = execute(b.finalize(), purpose: .startup) guard case .failed = execution.outcome else { logger.fatal( @@ -1141,7 +1150,10 @@ public class Fuzzer { var maxExecutionTime: TimeInterval = 0 // Dispatch a non-trivial program and measure its execution time - let complexProgram = makeComplexProgram() + b.maybeWrapInsideBundleScript { + makeComplexProgram(builder: b) + } + let complexProgram = b.finalize() for _ in 0..<5 { let execution = execute(complexProgram, purpose: .startup) maxExecutionTime = max(maxExecutionTime, execution.execTime) @@ -1151,7 +1163,9 @@ public class Fuzzer { var hasAnyCrashTests = false for (test, expectedResult) in config.startupTests { b = makeBuilder() - b.eval(test) + b.maybeWrapInsideBundleScript { + b.eval(test) + } execution = execute(b.finalize(), purpose: .startup) if execution.outcome == .timedOut { @@ -1184,6 +1198,8 @@ public class Fuzzer { } } + // TODO(marja): when we have modules, add a "bundles" startup test which asserts that bundles are handled correctly. + if !hasAnyCrashTests { logger.warning( "Cannot check if crashes are detected as there are no startup tests that should cause a crash" @@ -1216,8 +1232,10 @@ public class Fuzzer { // Check if we can receive program output b = makeBuilder() - let str = b.loadString("Hello World!") - b.doPrint(str) + b.maybeWrapInsideBundleScript { + let str = b.loadString("Hello World!") + b.doPrint(str) + } let output = execute(b.finalize(), purpose: .startup).fuzzout.trimmingCharacters( in: .whitespacesAndNewlines) if output != "Hello World!" { @@ -1312,6 +1330,7 @@ public class Fuzzer { private(set) var numberOfProgramsThatNeededTwoFixupAttempts = 0 private(set) var numberOfProgramsThatNeededThreeFixupAttempts = 0 private(set) var numberOfProgramsRequiringWasmButDisabled = 0 + private(set) var numberOfProgramsRequiringBundlesButDisabled = 0 var numberOfProgramsThatNeededFixup: Int { assert(Fuzzer.maxProgramImportFixupAttempts == 3) @@ -1354,6 +1373,8 @@ public class Fuzzer { break case .needsWasm: numberOfProgramsRequiringWasmButDisabled += 1 + case .needsBundles: + numberOfProgramsRequiringBundlesButDisabled += 1 case .failed(let outcome): switch outcome { case .crashed, .succeeded, .differential: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 2cc5d9465..dc7d7af68 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -817,6 +817,14 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndBlockStatement") + case .beginBundleScript: + w.emit("BeginBundleScript") + w.increaseIndentionLevel() + + case .endBundleScript: + w.decreaseIndentionLevel() + w.emit("EndBundleScript") + case .loadNewTarget: w.emit("\(output()) <- LoadNewTarget") diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 6a733fac2..858c62af5 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -113,7 +113,7 @@ public class JavaScriptLifter: Lifter { // This typer is shared across WasmLifters and a WasmLifter is only valid for a single WasmModule. var typer: JSTyper? = nil // The currently active WasmLifter, we can only have one of them. - var wasmInstructions = Code() + var wasmInstructions = Code(isBundle: false) // Map block start index to end index. let blockEndIndices = program.code.reduce( @@ -139,7 +139,7 @@ public class JavaScriptLifter: Lifter { if needToSupportWasm { // If we need to support Wasm we need to type all instructions outside of Wasm such that the WasmLifter can access extra type information during lifting. - typer = JSTyper(for: environment) + typer = JSTyper(for: environment, isBundle: program.code.isBundle) } var w = JavaScriptWriter( @@ -235,7 +235,8 @@ public class JavaScriptLifter: Lifter { wasmTypeGroupStarts = instr.index } else if instr.op is WasmEndTypeGroup { w.emitComment("Wasm type group:") - let code = Code(program.code[wasmTypeGroupStarts!...instr.index]) + let code = Code( + program.code[wasmTypeGroupStarts!...instr.index], isBundle: false) wasmTypeGroupStarts = nil w.emitComment(FuzzILLifter().lift(code)) } @@ -1514,6 +1515,12 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") + case .beginBundleScript: + w.emitRaw("// JS_BUNDLE_SCRIPT") + + case .endBundleScript: + break + case .loadNewTarget: w.assign(Identifier.new("new.target"), to: instr.output) @@ -1579,7 +1586,7 @@ public class JavaScriptLifter: Lifter { case .endWasmModule: // Lift the FuzzILCode of this Block first. w.emitComment("WasmModule Code:") - let code = Code(program.code[wasmCodeStarts!...instr.index]) + let code = Code(program.code[wasmCodeStarts!...instr.index], isBundle: false) wasmCodeStarts = nil w.emitComment(FuzzILLifter().lift(code)) @@ -2474,6 +2481,11 @@ public class JavaScriptLifter: Lifter { writer.emitBlock(line) } + mutating func emitRaw(_ line: String) { + emitPendingExpressions() + writer.emit(line) + } + /// Emit a (potentially multi-line) comment. mutating func emitComment(_ comment: String) { writer.emitComment(comment) diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index 13f91758d..a5a0232f3 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -257,7 +257,7 @@ public class WasmLifter { private var typer: JSTyper // This contains the instructions that we need to lift. - private var instructionBuffer: Code = Code() + private var instructionBuffer: Code = Code(isBundle: false) // TODO(cffsmith): we could do some checking here that the function is actually defined, at that point it would not be static anymore though. private static func nameOfFunction(_ idx: Int) -> String { diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 39f27e327..5af1d5e3e 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -90,7 +90,8 @@ struct BlockReducer: Reducer { .beginWasmFunction, .beginWasmModule, .wasmBeginTryDelegate, - .wasmBeginTryTable: + .wasmBeginTryTable, + .beginBundleScript: reduceGenericBlockGroup(group, with: helper) case .wasmBeginBlock, @@ -347,7 +348,7 @@ struct BlockReducer: Reducer { varReplacements.merge( zip(endInstr.outputs, endInstrInputs.map { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == group.head || i == group.tail { continue // Skip the block begin and end. @@ -542,7 +543,7 @@ struct BlockReducer: Reducer { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == ifBlock.head || (i >= elseBlock.head && i <= elseBlock.tail) { continue // Skip the WasmBeginIf and the else block. @@ -572,7 +573,7 @@ struct BlockReducer: Reducer { varReplacements[$0] ?? $0 }), uniquingKeysWith: { _, _ in fatalError("duplicate variables") }) - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) for (i, instr) in helper.code.enumerated() { if i == elseBlock.tail || (i >= ifBlock.head && i <= ifBlock.tail) { continue // Skip the WasmBeginIf and the if true block. diff --git a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift index c1a4357c4..5263ef11d 100644 --- a/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/DataFlowSimplifier.swift @@ -31,7 +31,7 @@ /// roughly the right type. struct DataFlowSimplifier: Reducer { func reduce(with helper: MinimizationHelper) { - var typer = JSTyper(for: helper.fuzzer.environment) + var typer = JSTyper(for: helper.fuzzer.environment, isBundle: helper.code.isBundle) var candidates = [Int]() var uses = VariableMap() for instr in helper.code { @@ -83,7 +83,7 @@ struct DataFlowSimplifier: Reducer { // Finally try to remove each remaining candidate. for candidate in candidates { - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var replacements = VariableMap() for instr in helper.code { if instr.index == candidate { diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 731478c45..94f81e904 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -145,7 +145,7 @@ struct InliningReducer: Reducer { assert(index < code.count) assert(code[index].op is BeginAnyFunction) - var c = Code() + var c = Code(isBundle: code.isBundle) var i = 0 // Append all code prior to the function that we're inlining. diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index da9d32ad3..2126359d7 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -127,7 +127,7 @@ struct InstructionSimplifier: Reducer { // All simplifications are performed at once to keep this logic simple. // This logic needs to be somewhat careful not to perform no-op replacements as // these would cause the fixpoint iteration to not terminate. - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var numCopiedInstructions = 0 for instr in helper.code { var keepInstruction = true diff --git a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift index 440a98ae5..80691a669 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift @@ -195,7 +195,7 @@ class MinimizationHelper { assert(newInstr.flags.isEmpty) // For simplicity, just build a copy of the input code here. This logic is not particularly performance sensitive. - var newCode = Code() + var newCode = Code(isBundle: code.isBundle) for instr in code { if instr.index == index { newCode.append(newInstr) diff --git a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift index 45180278c..594c621bb 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationPostProcessor.swift @@ -25,7 +25,7 @@ struct MinimizationPostProcessor { func process(with helper: MinimizationHelper) -> Bool { // Step 1: Generate all changes that we'd like to perform and record them. var changes = [(index: Int, newInstruction: Instruction)]() - var codeWithNops = Code() + var codeWithNops = Code(isBundle: helper.code.isBundle) // This must happen on the fuzzer's queue as it requires a ProgramBuilder to obtain input variables. helper.performOnFuzzerQueue { diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index c6a290d08..e473f28c1 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -45,7 +45,7 @@ struct ReassignmentReducer: Reducer { func reduce(with helper: MinimizationHelper) { var reassignedVariables = VariableMap() var reassignedVariableStack: [[Variable]] = [[]] - var newCode = Code() + var newCode = Code(isBundle: helper.code.isBundle) var didChangeCode = false for instr in helper.code { diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 85f93525a..50f2c5eac 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -85,7 +85,7 @@ struct WasmTypeGroupReducer: Reducer { var newCode = Code( helper.code .filter { !toRemove.contains($0.index) } - .map { endTypeGroupReplacements[$0.index] ?? $0 }) + .map { endTypeGroupReplacements[$0.index] ?? $0 }, isBundle: helper.code.isBundle) newCode.renumberVariables() helper.testAndCommit(newCode) diff --git a/Sources/Fuzzilli/Modules/Sync.swift b/Sources/Fuzzilli/Modules/Sync.swift index d21b68d8c..e45507e61 100644 --- a/Sources/Fuzzilli/Modules/Sync.swift +++ b/Sources/Fuzzilli/Modules/Sync.swift @@ -137,6 +137,7 @@ public class DistributedFuzzingNode { $0.corpus = try fuzzer.corpus.exportState() $0.evaluatorState = fuzzer.evaluator.exportState() $0.isWasmEnabled = fuzzer.config.isWasmEnabled + $0.areBundlesEnabled = fuzzer.config.generateBundle } return try state.serializedData() } else { @@ -166,6 +167,15 @@ public class DistributedFuzzingNode { ) } + if state.areBundlesEnabled != fuzzer.config.generateBundle { + // Ditto for bundles. + let parentState = fuzzer.config.generateBundle ? "enabled" : "disabled" + let selfState = state.areBundlesEnabled ? "enabled" : "disabled" + throw FuzzilliError.corpusImportError( + "Inconsistent state between distributed nodes: The parent has bundles \(parentState) while the current fuzzer has wasm \(selfState)!" + ) + } + try fuzzer.corpus.importState(state.corpus) try fuzzer.evaluator.importState(state.evaluatorState) } else { diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 1ce56d0c8..613b68e1a 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -748,6 +748,8 @@ public class OperationMutator: BaseInstructionMutator { .wrapSuspending(_), .bindMethod(_), .bindFunction(_), + .beginBundleScript(_), + .endBundleScript(_), // Wasm instructions .beginWasmModule(_), .endWasmModule(_), diff --git a/Sources/Fuzzilli/Protobuf/gen_programproto.py b/Sources/Fuzzilli/Protobuf/gen_programproto.py index 7447d6caf..2055904e9 100644 --- a/Sources/Fuzzilli/Protobuf/gen_programproto.py +++ b/Sources/Fuzzilli/Protobuf/gen_programproto.py @@ -48,6 +48,7 @@ repeated Instruction code = 2; map comments = 3; Program parent = 4; + bool isBundle = 5; } """ diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index cc4bafbf1..97800aa14 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -6008,6 +6008,26 @@ public struct Fuzzilli_Protobuf_WasmTableCopy: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_BeginBundleScript: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_EndBundleScript: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "fuzzilli.protobuf" @@ -15547,3 +15567,41 @@ extension Fuzzilli_Protobuf_WasmTableCopy: SwiftProtobuf.Message, SwiftProtobuf. return true } } + +extension Fuzzilli_Protobuf_BeginBundleScript: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginBundleScript" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginBundleScript, rhs: Fuzzilli_Protobuf_BeginBundleScript) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_EndBundleScript: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".EndBundleScript" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_EndBundleScript, rhs: Fuzzilli_Protobuf_EndBundleScript) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index c654f8b6f..cdb4eb12f 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1672,3 +1672,9 @@ message WasmTableInit { message WasmTableCopy { } + +message BeginBundleScript { +} + +message EndBundleScript { +} \ No newline at end of file diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index a610786ae..a84249e86 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2721,6 +2721,22 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endClassComputedSetter(newValue)} } + public var beginBundleScript: Fuzzilli_Protobuf_BeginBundleScript { + get { + if case .beginBundleScript(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginBundleScript() + } + set {operation = .beginBundleScript(newValue)} + } + + public var endBundleScript: Fuzzilli_Protobuf_EndBundleScript { + get { + if case .endBundleScript(let v)? = operation {return v} + return Fuzzilli_Protobuf_EndBundleScript() + } + set {operation = .endBundleScript(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -3058,6 +3074,8 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case endClassComputedGetter(Fuzzilli_Protobuf_EndClassComputedGetter) case beginClassComputedSetter(Fuzzilli_Protobuf_BeginClassComputedSetter) case endClassComputedSetter(Fuzzilli_Protobuf_EndClassComputedSetter) + case beginBundleScript(Fuzzilli_Protobuf_BeginBundleScript) + case endBundleScript(Fuzzilli_Protobuf_EndBundleScript) } @@ -3093,6 +3111,11 @@ public struct Fuzzilli_Protobuf_Program: @unchecked Sendable { /// Clears the value of `parent`. Subsequent reads from it will return its default value. public mutating func clearParent() {_uniqueStorage()._parent = nil} + public var isBundle: Bool { + get {_storage._isBundle} + set {_uniqueStorage()._isBundle = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -3106,7 +3129,7 @@ fileprivate let _protobuf_package = "fuzzilli.protobuf" extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Instruction" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}inouts\0\u{1}opIdx\0\u{1}nop\0\u{1}loadInteger\0\u{1}loadBigInt\0\u{1}loadFloat\0\u{1}loadString\0\u{1}loadBoolean\0\u{1}loadUndefined\0\u{1}loadNull\0\u{1}loadThis\0\u{1}loadArguments\0\u{1}createNamedVariable\0\u{1}loadDisposableVariable\0\u{1}loadAsyncDisposableVariable\0\u{1}loadRegExp\0\u{1}beginObjectLiteral\0\u{1}objectLiteralAddProperty\0\u{1}objectLiteralAddElement\0\u{1}objectLiteralAddComputedProperty\0\u{1}objectLiteralCopyProperties\0\u{1}objectLiteralSetPrototype\0\u{1}beginObjectLiteralMethod\0\u{1}endObjectLiteralMethod\0\u{1}beginObjectLiteralComputedMethod\0\u{1}endObjectLiteralComputedMethod\0\u{1}beginObjectLiteralGetter\0\u{1}endObjectLiteralGetter\0\u{1}beginObjectLiteralSetter\0\u{1}endObjectLiteralSetter\0\u{1}endObjectLiteral\0\u{1}beginClassDefinition\0\u{1}beginClassConstructor\0\u{1}endClassConstructor\0\u{1}classAddProperty\0\u{1}classAddElement\0\u{1}classAddComputedProperty\0\u{1}beginClassMethod\0\u{1}endClassMethod\0\u{1}beginClassComputedMethod\0\u{1}endClassComputedMethod\0\u{1}beginClassGetter\0\u{1}endClassGetter\0\u{1}beginClassSetter\0\u{1}endClassSetter\0\u{1}beginClassStaticInitializer\0\u{1}endClassStaticInitializer\0\u{1}classAddPrivateProperty\0\u{1}beginClassPrivateMethod\0\u{1}endClassPrivateMethod\0\u{1}endClassDefinition\0\u{1}createArray\0\u{1}createIntArray\0\u{1}createFloatArray\0\u{1}createArrayWithSpread\0\u{1}createTemplateString\0\u{1}getProperty\0\u{1}setProperty\0\u{1}updateProperty\0\u{1}deleteProperty\0\u{1}configureProperty\0\u{1}getElement\0\u{1}setElement\0\u{1}updateElement\0\u{1}deleteElement\0\u{1}configureElement\0\u{1}getComputedProperty\0\u{1}setComputedProperty\0\u{1}updateComputedProperty\0\u{1}deleteComputedProperty\0\u{1}configureComputedProperty\0\u{1}typeOf\0\u{1}void\0\u{1}testInstanceOf\0\u{1}testIn\0\u{1}beginPlainFunction\0\u{1}endPlainFunction\0\u{1}beginArrowFunction\0\u{1}endArrowFunction\0\u{1}beginGeneratorFunction\0\u{1}endGeneratorFunction\0\u{1}beginAsyncFunction\0\u{1}endAsyncFunction\0\u{1}beginAsyncArrowFunction\0\u{1}endAsyncArrowFunction\0\u{1}beginAsyncGeneratorFunction\0\u{1}endAsyncGeneratorFunction\0\u{1}beginConstructor\0\u{1}endConstructor\0\u{1}directive\0\u{1}return\0\u{1}yield\0\u{1}yieldEach\0\u{1}await\0\u{1}callFunction\0\u{1}callFunctionWithSpread\0\u{1}construct\0\u{1}constructWithSpread\0\u{1}callMethod\0\u{1}callMethodWithSpread\0\u{1}callComputedMethod\0\u{1}callComputedMethodWithSpread\0\u{1}unaryOperation\0\u{1}binaryOperation\0\u{1}ternaryOperation\0\u{1}update\0\u{1}dup\0\u{1}reassign\0\u{1}destructArray\0\u{1}destructArrayAndReassign\0\u{1}destructObject\0\u{1}destructObjectAndReassign\0\u{1}compare\0\u{1}eval\0\u{1}beginWith\0\u{1}endWith\0\u{1}callSuperConstructor\0\u{1}callSuperMethod\0\u{1}getPrivateProperty\0\u{1}setPrivateProperty\0\u{1}updatePrivateProperty\0\u{1}callPrivateMethod\0\u{1}getSuperProperty\0\u{1}setSuperProperty\0\u{1}getComputedSuperProperty\0\u{1}setComputedSuperProperty\0\u{1}updateSuperProperty\0\u{1}beginIf\0\u{1}beginElse\0\u{1}endIf\0\u{1}beginWhileLoopHeader\0\u{1}beginWhileLoopBody\0\u{1}endWhileLoop\0\u{1}beginDoWhileLoopBody\0\u{1}beginDoWhileLoopHeader\0\u{1}endDoWhileLoop\0\u{1}beginForLoopInitializer\0\u{1}beginForLoopCondition\0\u{1}beginForLoopAfterthought\0\u{1}beginForLoopBody\0\u{1}endForLoop\0\u{1}beginForInLoop\0\u{1}endForInLoop\0\u{1}beginForOfLoop\0\u{1}beginForOfLoopWithDestruct\0\u{1}endForOfLoop\0\u{1}beginRepeatLoop\0\u{1}endRepeatLoop\0\u{1}loopBreak\0\u{1}loopContinue\0\u{1}beginTry\0\u{1}beginCatch\0\u{1}beginFinally\0\u{1}endTryCatchFinally\0\u{1}throwException\0\u{1}beginCodeString\0\u{1}endCodeString\0\u{1}beginBlockStatement\0\u{1}endBlockStatement\0\u{1}beginSwitch\0\u{1}beginSwitchCase\0\u{1}beginSwitchDefaultCase\0\u{1}endSwitchCase\0\u{1}endSwitch\0\u{1}switchBreak\0\u{1}loadNewTarget\0\u{1}print\0\u{1}explore\0\u{1}probe\0\u{1}fixup\0\u{1}beginWasmModule\0\u{1}endWasmModule\0\u{1}createWasmGlobal\0\u{1}createWasmMemory\0\u{1}createWasmTable\0\u{1}createWasmJSTag\0\u{1}createWasmTag\0\u{1}wrapPromising\0\u{1}wrapSuspending\0\u{1}bindMethod\0\u{1}bindFunction\0\u{1}consti64\0\u{1}consti32\0\u{1}constf32\0\u{1}constf64\0\u{1}wasmReturn\0\u{1}wasmJsCall\0\u{1}wasmi32CompareOp\0\u{1}wasmi64CompareOp\0\u{1}wasmf32CompareOp\0\u{1}wasmf64CompareOp\0\u{1}wasmi32EqualZero\0\u{1}wasmi64EqualZero\0\u{1}wasmi32BinOp\0\u{1}wasmi64BinOp\0\u{1}wasmi32UnOp\0\u{1}wasmi64UnOp\0\u{1}wasmf32BinOp\0\u{1}wasmf64BinOp\0\u{1}wasmf32UnOp\0\u{1}wasmf64UnOp\0\u{1}wasmWrapi64Toi32\0\u{1}wasmTruncatef32Toi32\0\u{1}wasmTruncatef64Toi32\0\u{1}wasmExtendi32Toi64\0\u{1}wasmTruncatef32Toi64\0\u{1}wasmTruncatef64Toi64\0\u{1}wasmConverti32Tof32\0\u{1}wasmConverti64Tof32\0\u{1}wasmDemotef64Tof32\0\u{1}wasmConverti32Tof64\0\u{1}wasmConverti64Tof64\0\u{1}wasmPromotef32Tof64\0\u{1}wasmReinterpretf32Asi32\0\u{1}wasmReinterpretf64Asi64\0\u{1}wasmReinterpreti32Asf32\0\u{1}wasmReinterpreti64Asf64\0\u{1}wasmSignExtend8Intoi32\0\u{1}wasmSignExtend16Intoi32\0\u{1}wasmSignExtend8Intoi64\0\u{1}wasmSignExtend16Intoi64\0\u{1}wasmSignExtend32Intoi64\0\u{1}wasmTruncateSatf32Toi32\0\u{1}wasmTruncateSatf64Toi32\0\u{1}wasmTruncateSatf32Toi64\0\u{1}wasmTruncateSatf64Toi64\0\u{1}wasmReassign\0\u{1}wasmDefineGlobal\0\u{1}wasmDefineTable\0\u{1}wasmDefineMemory\0\u{1}wasmDefineDataSegment\0\u{1}wasmLoadGlobal\0\u{1}wasmStoreGlobal\0\u{1}wasmTableGet\0\u{1}wasmTableSet\0\u{1}wasmTableSize\0\u{1}wasmTableGrow\0\u{1}wasmCallIndirect\0\u{1}wasmCallDirect\0\u{1}wasmReturnCallDirect\0\u{1}wasmReturnCallIndirect\0\u{1}wasmMemoryLoad\0\u{1}wasmMemoryStore\0\u{1}wasmAtomicLoad\0\u{1}wasmAtomicStore\0\u{1}wasmAtomicRMW\0\u{1}wasmAtomicCmpxchg\0\u{1}wasmMemorySize\0\u{1}wasmMemoryGrow\0\u{1}wasmMemoryFill\0\u{1}wasmMemoryInit\0\u{1}wasmDropDataSegment\0\u{1}beginWasmFunction\0\u{1}endWasmFunction\0\u{1}wasmBeginBlock\0\u{1}wasmEndBlock\0\u{1}wasmBeginLoop\0\u{1}wasmEndLoop\0\u{1}wasmBranch\0\u{1}wasmBranchIf\0\u{1}wasmBranchTable\0\u{1}wasmNop\0\u{1}wasmBeginIf\0\u{1}wasmBeginElse\0\u{1}wasmEndIf\0\u{1}wasmBeginTryTable\0\u{1}wasmEndTryTable\0\u{1}wasmBeginTry\0\u{1}wasmBeginCatchAll\0\u{1}wasmBeginCatch\0\u{1}wasmEndTry\0\u{1}wasmBeginTryDelegate\0\u{1}wasmEndTryDelegate\0\u{1}wasmThrow\0\u{1}wasmRethrow\0\u{1}wasmThrowRef\0\u{1}wasmDefineTag\0\u{1}constSimd128\0\u{1}wasmSimd128Compare\0\u{1}wasmSimd128IntegerUnOp\0\u{1}wasmSimd128IntegerBinOp\0\u{1}wasmSimd128IntegerTernaryOp\0\u{1}wasmSimd128FloatUnOp\0\u{1}wasmSimd128FloatBinOp\0\u{1}wasmSimd128FloatTernaryOp\0\u{1}wasmSimdSplat\0\u{1}wasmSimdExtractLane\0\u{1}wasmSimdReplaceLane\0\u{1}wasmSimdStoreLane\0\u{1}wasmSimdLoadLane\0\u{1}wasmSimdLoad\0\u{1}wasmUnreachable\0\u{1}wasmSelect\0\u{1}wasmBeginTypeGroup\0\u{1}wasmEndTypeGroup\0\u{1}wasmDefineArrayType\0\u{1}wasmDefineStructType\0\u{1}wasmDefineForwardOrSelfReference\0\u{1}wasmResolveForwardReference\0\u{1}wasmArrayNewFixed\0\u{1}wasmArrayNewDefault\0\u{1}wasmArrayLen\0\u{1}wasmArrayGet\0\u{1}wasmArraySet\0\u{1}wasmStructNewDefault\0\u{1}wasmStructGet\0\u{1}wasmStructSet\0\u{1}wasmRefNull\0\u{1}wasmRefIsNull\0\u{1}wasmRefI31\0\u{1}wasmI31Get\0\u{1}wasmAnyConvertExtern\0\u{1}wasmExternConvertAny\0\u{1}wasmMemoryCopy\0\u{1}wasmDefineElementSegment\0\u{1}wasmTableInit\0\u{1}wasmDropElementSegment\0\u{1}wasmTableCopy\0\u{1}wasmDefineSignatureType\0\u{1}createNamedDisposableVariable\0\u{1}createNamedAsyncDisposableVariable\0\u{1}wasmDefineAdHocSignatureType\0\u{1}wasmStructNew\0\u{1}wasmRefEq\0\u{1}wasmRefTest\0\u{1}wasmDefineAdHocModuleSignatureType\0\u{1}wasmRefCast\0\u{1}beginObjectLiteralComputedGetter\0\u{1}endObjectLiteralComputedGetter\0\u{1}beginObjectLiteralComputedSetter\0\u{1}endObjectLiteralComputedSetter\0\u{1}beginClassComputedGetter\0\u{1}endClassComputedGetter\0\u{1}beginClassComputedSetter\0\u{1}endClassComputedSetter\0\u{1}beginBundleScript\0\u{1}endBundleScript\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -7452,6 +7475,32 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endClassComputedSetter(v) } }() + case 336: try { + var v: Fuzzilli_Protobuf_BeginBundleScript? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginBundleScript(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginBundleScript(v) + } + }() + case 337: try { + var v: Fuzzilli_Protobuf_EndBundleScript? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .endBundleScript(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .endBundleScript(v) + } + }() default: break } } @@ -8802,6 +8851,14 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endClassComputedSetter(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 335) }() + case .beginBundleScript?: try { + guard case .beginBundleScript(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 336) + }() + case .endBundleScript?: try { + guard case .endBundleScript(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 337) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -8817,13 +8874,14 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Program" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}uuid\0\u{1}code\0\u{1}comments\0\u{1}parent\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}uuid\0\u{1}code\0\u{1}comments\0\u{1}parent\0\u{1}isBundle\0") fileprivate class _StorageClass { var _uuid: Data = Data() var _code: [Fuzzilli_Protobuf_Instruction] = [] var _comments: Dictionary = [:] var _parent: Fuzzilli_Protobuf_Program? = nil + var _isBundle: Bool = false // This property is used as the initial default value for new instances of the type. // The type itself is protecting the reference to its storage via CoW semantics. @@ -8838,6 +8896,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa _code = source._code _comments = source._comments _parent = source._parent + _isBundle = source._isBundle } } @@ -8860,6 +8919,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._code) }() case 3: try { try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap.self, value: &_storage._comments) }() case 4: try { try decoder.decodeSingularMessageField(value: &_storage._parent) }() + case 5: try { try decoder.decodeSingularBoolField(value: &_storage._isBundle) }() default: break } } @@ -8884,6 +8944,9 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa try { if let v = _storage._parent { try visitor.visitSingularMessageField(value: v, fieldNumber: 4) } }() + if _storage._isBundle != false { + try visitor.visitSingularBoolField(value: _storage._isBundle, fieldNumber: 5) + } } try unknownFields.traverse(visitor: &visitor) } @@ -8897,6 +8960,7 @@ extension Fuzzilli_Protobuf_Program: SwiftProtobuf.Message, SwiftProtobuf._Messa if _storage._code != rhs_storage._code {return false} if _storage._comments != rhs_storage._comments {return false} if _storage._parent != rhs_storage._parent {return false} + if _storage._isBundle != rhs_storage._isBundle {return false} return true } if !storagesAreEqual {return false} diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index bdea24d6c..1a7c830c6 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -359,6 +359,8 @@ message Instruction { EndClassComputedGetter endClassComputedGetter = 333; BeginClassComputedSetter beginClassComputedSetter = 334; EndClassComputedSetter endClassComputedSetter = 335; + BeginBundleScript beginBundleScript = 336; + EndBundleScript endBundleScript = 337; } } @@ -367,4 +369,5 @@ message Program { repeated Instruction code = 2; map comments = 3; Program parent = 4; + bool isBundle = 5; } diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift index f17c236ce..c18e2b3e2 100644 --- a/Sources/Fuzzilli/Protobuf/sync.pb.swift +++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift @@ -65,6 +65,8 @@ public struct Fuzzilli_Protobuf_FuzzerState: Sendable { public var isWasmEnabled: Bool = false + public var areBundlesEnabled: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -241,7 +243,7 @@ extension Fuzzilli_Protobuf_LogMessage: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".FuzzerState" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}corpus\0\u{1}evaluatorState\0\u{1}isWasmEnabled\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}corpus\0\u{1}evaluatorState\0\u{1}isWasmEnabled\0\u{1}areBundlesEnabled\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -252,6 +254,7 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M case 1: try { try decoder.decodeSingularBytesField(value: &self.corpus) }() case 2: try { try decoder.decodeSingularBytesField(value: &self.evaluatorState) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.isWasmEnabled) }() + case 4: try { try decoder.decodeSingularBoolField(value: &self.areBundlesEnabled) }() default: break } } @@ -267,6 +270,9 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M if self.isWasmEnabled != false { try visitor.visitSingularBoolField(value: self.isWasmEnabled, fieldNumber: 3) } + if self.areBundlesEnabled != false { + try visitor.visitSingularBoolField(value: self.areBundlesEnabled, fieldNumber: 4) + } try unknownFields.traverse(visitor: &visitor) } @@ -274,6 +280,7 @@ extension Fuzzilli_Protobuf_FuzzerState: SwiftProtobuf.Message, SwiftProtobuf._M if lhs.corpus != rhs.corpus {return false} if lhs.evaluatorState != rhs.evaluatorState {return false} if lhs.isWasmEnabled != rhs.isWasmEnabled {return false} + if lhs.areBundlesEnabled != rhs.areBundlesEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/sync.proto b/Sources/Fuzzilli/Protobuf/sync.proto index 39a18a115..4f3b134ab 100644 --- a/Sources/Fuzzilli/Protobuf/sync.proto +++ b/Sources/Fuzzilli/Protobuf/sync.proto @@ -29,6 +29,7 @@ message FuzzerState { bytes corpus = 1; bytes evaluatorState = 2; bool isWasmEnabled = 3; + bool areBundlesEnabled = 4; } message Statistics { diff --git a/Sources/FuzzilliCli/main.swift b/Sources/FuzzilliCli/main.swift index 615825f21..ccc1a60c3 100644 --- a/Sources/FuzzilliCli/main.swift +++ b/Sources/FuzzilliCli/main.swift @@ -104,6 +104,7 @@ if args["-h"] != nil || args["--help"] != nil || args.numPositionalArguments != This can for example be used to remember the target revision that is being fuzzed. --wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift). --forDifferentialFuzzing : Enable additional features for better support of external differential fuzzing. + --bundle : Generate bundles containing multiple JS scripts and modules """) exit(0) @@ -163,6 +164,7 @@ let argumentRandomization = args.has("--argumentRandomization") let additionalArguments = args["--additionalArguments"] ?? "" let tag = args["--tag"] let enableWasm = args.has("--wasm") +let generateBundle = args.has("--bundle") let forDifferentialFuzzing = args.has("--forDifferentialFuzzing") var timeout: Timeout @@ -441,6 +443,8 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { let finalArgs = baseArgs + configuration.getInstanceSpecificArguments(forReferenceRunner: forReferenceRunner) + // TODO(mliedtke): The flag should be controllable via the profile. + + (configuration.generateBundle ? ["--bundle"] : []) return REPRL( executable: jsShellPath, processArguments: finalArgs, @@ -461,7 +465,13 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer { }() /// The mutation fuzzer responsible for mutating programs from the corpus and evaluating the outcome. - let disabledMutators = Set(profile.disabledMutators) + var disabledMutators = Set(profile.disabledMutators) + + if configuration.generateBundle { + // TODO(marja): enable combining bundles. + disabledMutators.insert("CombineMutator") + } + var mutators = WeightedList([ (ExplorationMutator(), 3), (CodeGenMutator(), 2), @@ -617,6 +627,7 @@ let mainConfig = Configuration( staticCorpus: staticCorpus, tag: tag, isWasmEnabled: enableWasm, + generateBundle: generateBundle, storagePath: storagePath, corpusGenerationIterations: corpusGenerationIterations, forDifferentialFuzzing: forDifferentialFuzzing, @@ -797,6 +808,7 @@ for i in 1.. Date: Thu, 16 Apr 2026 12:13:08 +0200 Subject: [PATCH 229/234] Improve error messages in cases of invalid code objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I2d86a3970a67ac92c9a2c8690b255b18b8d71bee Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210757 Commit-Queue: Matthias Liedtke Reviewed-by: Marja Hölttä --- Sources/Fuzzilli/FuzzIL/Analyzer.swift | 2 +- Sources/Fuzzilli/FuzzIL/Code.swift | 19 +++++++++++++++++-- Sources/Fuzzilli/FuzzIL/Program.swift | 2 +- .../Minimization/InliningReducer.swift | 2 +- .../Minimization/MinimizationHelper.swift | 6 +++++- Sources/Fuzzilli/Minimization/Minimizer.swift | 4 ++-- .../Minimization/ReassignReducer.swift | 2 +- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Analyzer.swift b/Sources/Fuzzilli/FuzzIL/Analyzer.swift index ce6edb562..6e6a392b0 100644 --- a/Sources/Fuzzilli/FuzzIL/Analyzer.swift +++ b/Sources/Fuzzilli/FuzzIL/Analyzer.swift @@ -26,7 +26,7 @@ extension Analyzer { } mutating func analyze(_ code: Code) { - assert(code.isStaticallyValid()) + code.assertIsStaticallyValid() for instr in code { analyze(instr) } diff --git a/Sources/Fuzzilli/FuzzIL/Code.swift b/Sources/Fuzzilli/FuzzIL/Code.swift index 199ec341a..1118a7073 100644 --- a/Sources/Fuzzilli/FuzzIL/Code.swift +++ b/Sources/Fuzzilli/FuzzIL/Code.swift @@ -148,7 +148,7 @@ public struct Code: Collection { /// Computes the last variable (which will have the highest number) in this code or nil if there are no variables. public func lastVariable() -> Variable? { - assert(isStaticallyValid()) + assertIsStaticallyValid() for instr in instructions.reversed() { if let v = instr.allOutputs.max() { return v @@ -159,7 +159,7 @@ public struct Code: Collection { /// Computes the next free variable in this code. public func nextFreeVariable() -> Variable { - assert(isStaticallyValid()) + assertIsStaticallyValid() if let lastVar = lastVariable() { return Variable(number: lastVar.number + 1) } @@ -321,6 +321,21 @@ public struct Code: Collection { } } + // Helper function for asserting that the Code object is valid. Use this over + // assert(code.isValid()) to get more useful error messages if the assert triggers. + public func assertIsStaticallyValid() { + #if DEBUG + do { + try check() + } catch { + // This assumes that even if the code is invalid, the FuzzILLifter will be able to + // handle it without crashing. If that is not the case, it might be better to not print + // the code at all. + fatalError("Code is invalid: \(error)\n\(FuzzILLifter().lift(self))") + } + #endif + } + public func countIntructionsWith(flags: Instruction.Flags) -> Int { self.filter { instr in instr.flags.contains(flags) diff --git a/Sources/Fuzzilli/FuzzIL/Program.swift b/Sources/Fuzzilli/FuzzIL/Program.swift index f7e4e4b58..7b151998d 100644 --- a/Sources/Fuzzilli/FuzzIL/Program.swift +++ b/Sources/Fuzzilli/FuzzIL/Program.swift @@ -54,7 +54,7 @@ public final class Program: CustomStringConvertible { /// Constructs a program with the given code. The code must be statically valid. public init(with code: Code) { - assert(code.isStaticallyValid()) + code.assertIsStaticallyValid() self.code = code } diff --git a/Sources/Fuzzilli/Minimization/InliningReducer.swift b/Sources/Fuzzilli/Minimization/InliningReducer.swift index 94f81e904..f6af53318 100644 --- a/Sources/Fuzzilli/Minimization/InliningReducer.swift +++ b/Sources/Fuzzilli/Minimization/InliningReducer.swift @@ -258,7 +258,7 @@ struct InliningReducer: Reducer { c.renumberVariables() // The code must now be valid. - assert(c.isStaticallyValid()) + c.assertIsStaticallyValid() return c } } diff --git a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift index 80691a669..fa90ab0fe 100644 --- a/Sources/Fuzzilli/Minimization/MinimizationHelper.swift +++ b/Sources/Fuzzilli/Minimization/MinimizationHelper.swift @@ -123,7 +123,11 @@ class MinimizationHelper { ) -> Bool { assert(!self.finalized) assert(numExecutions > 0) - assert(!expectCodeToBeValid || newCode.isStaticallyValid()) + #if DEBUG + if expectCodeToBeValid { + newCode.assertIsStaticallyValid() + } + #endif // Reducers are allowed to nop instructions without verifying whether their outputs are used. // They are also allowed to remove blocks without verifying whether their opened contexts are required. diff --git a/Sources/Fuzzilli/Minimization/Minimizer.swift b/Sources/Fuzzilli/Minimization/Minimizer.swift index 6bdf91ce4..e759f9eb3 100644 --- a/Sources/Fuzzilli/Minimization/Minimizer.swift +++ b/Sources/Fuzzilli/Minimization/Minimizer.swift @@ -118,7 +118,7 @@ public class Minimizer: ComponentBase { assert( helper.code.countIntructionsWith(flags: .notRemovable) >= helper.numKeptInstructions) - assert(helper.code.isStaticallyValid()) + helper.code.assertIsStaticallyValid() } iterations += 1 guard iterations < 100 else { @@ -145,7 +145,7 @@ public class Minimizer: ComponentBase { postProcessor.process(with: helper) } - assert(helper.code.isStaticallyValid()) + helper.code.assertIsStaticallyValid() assert(!helper.code.contains(where: { $0.isNop })) return helper.finalize() diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index e473f28c1..8226089a5 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -86,7 +86,7 @@ struct ReassignmentReducer: Reducer { } } - assert(newCode.isStaticallyValid()) + newCode.assertIsStaticallyValid() if didChangeCode { helper.testAndCommit(newCode) } From fc8ac822074e92d4868ae1af1111d24cf3eedd18 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 16 Apr 2026 17:20:44 +0200 Subject: [PATCH 230/234] [test] Skip flaky test case for --bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I04428445c2feae6749a74f71a63ce4e3363f3f3a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211138 Reviewed-by: Marja Hölttä Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Tests/FuzzilliTests/ProgramBuilderTest.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 76c604c0c..14a2bb9f8 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3291,7 +3291,10 @@ class ProgramBuilderTests: XCTestCase { } } - func testThatBundleGeneratorsAreBuildableFromBundle() { + func testThatBundleGeneratorsAreBuildableFromBundle() throws { + // TODO(mliedtke,marja): Investigate how we can make the code generator scheduling more + // reliable. + if true { throw XCTSkip("Test case is flaky") } let config = Configuration(generateBundle: true) let fuzzer = makeMockFuzzer(config: config) let tries: Int = 10 @@ -3309,7 +3312,7 @@ class ProgramBuilderTests: XCTestCase { if generatedInstructions == 0 { failures[generator.name, default: 0] += 1 } - XCTAssertLessThan(syntheticGenerator.parts.count, 10) + XCTAssertLessThan(syntheticGenerator.parts.count, 10, "for \(generator.name)") } else { XCTFail( "Unable to generate synthetic CodeGenerator for \(generator.name) from a bundle." From 2cfe7c3d61bee425dc32810579bf46609c99384a Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Thu, 16 Apr 2026 14:27:25 +0200 Subject: [PATCH 231/234] [wasm] Make it easier to generate any.convert_extern Change-Id: Ifa582d369584dc6ba774112f5f7dba6f1b7663fb Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210758 Reviewed-by: Michael Achenbach Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift | 5 +++-- Tests/FuzzilliTests/ProgramBuilderTest.swift | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index eb5c1c514..65275e1db 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -344,7 +344,8 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(pawkra): add shared variant. CodeGenerator( - "WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32) + "WasmRefI31Generator", inContext: .single(.wasmFunction), inputs: .required(.wasmi32), + produces: [.wasmI31Ref()] ) { b, value in b.currentWasmModule.currentWasmFunction.wasmRefI31(value, shared: false) }, @@ -367,7 +368,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // TODO(pawkra): add shared variant. CodeGenerator( "WasmExternConvertAnyGenerator", inContext: .single(.wasmFunction), - inputs: .required(.wasmAnyRef()) + inputs: .required(.wasmAnyRef()), produces: [.wasmExternRef()] ) { b, ref in b.currentWasmModule.currentWasmFunction.wasmExternConvertAny(ref) }, diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 14a2bb9f8..6ed19b068 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -3253,6 +3253,8 @@ class ProgramBuilderTests: XCTestCase { test("WasmArrayGetGenerator", expectAny: WasmArrayGet.self, requiresTypes: true) test("WasmStructGetGenerator", expectAny: WasmStructGet.self, requiresTypes: true) test("WasmThrowRefGenerator", expectAny: WasmThrowRef.self) + test("WasmExternConvertAnyGenerator", expectAny: WasmExternConvertAny.self) + test("WasmAnyConvertExternGenerator", expectAny: WasmAnyConvertExtern.self) } func testThatGeneratorsExistAndAreBuildableFromJs() { From 79f9aa85045ebcb5325f2637a3d9d2766363aab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Fri, 17 Apr 2026 08:09:24 +0200 Subject: [PATCH 232/234] [js, bundles] Don't warn about BundleScriptGenerator if we're not generating bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 342521422 Change-Id: I5b40c6c2e97ed1e52a48d987d96cb00bbbdf82c9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211116 Auto-Submit: Marja Hölttä Reviewed-by: Matthias Liedtke Commit-Queue: Marja Hölttä --- Sources/Fuzzilli/Base/ContextGraph.swift | 15 ++++++++++----- Sources/Fuzzilli/Fuzzer.swift | 6 ++++-- Tests/FuzzilliTests/ContextGraphTest.swift | 6 +++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Sources/Fuzzilli/Base/ContextGraph.swift b/Sources/Fuzzilli/Base/ContextGraph.swift index 722801e64..6d706e0cb 100644 --- a/Sources/Fuzzilli/Base/ContextGraph.swift +++ b/Sources/Fuzzilli/Base/ContextGraph.swift @@ -54,9 +54,11 @@ public class ContextGraph { // This is the Graph, each pair of from and to, maps to a `GeneratorEdge`. var edges: [EdgeKey: GeneratorEdge] = [:] - public init(for generators: WeightedList, withLogger logger: Logger) { + public init( + for generators: WeightedList, isBundle: Bool, withLogger logger: Logger + ) { assertBasicConsistency(in: generators) - warnOfSuspiciousContexts(in: generators, withLogger: logger) + warnOfSuspiciousContexts(in: generators, isBundle: isBundle, withLogger: logger) // One can still try to build in a context that doesn't have generators, this will be caught in the build function, if we fail to find any suitable generator. // Otherwise we could assert here that the sets are equal. @@ -96,10 +98,10 @@ public class ContextGraph { } private func warnOfSuspiciousContexts( - in generators: WeightedList, withLogger logger: Logger + in generators: WeightedList, isBundle: Bool, withLogger logger: Logger ) { - // Technically we don't need any generator to emit the .javascript context, as this is provided by the toplevel. - var providedContexts = Set([.javascript]) + // Technically we don't need any generator to emit the .bundle or .javascript context, as they are provided by the toplevel. + var providedContexts = Set([isBundle ? .bundle : .javascript]) var requiredContexts = Set() for generator in generators { @@ -112,6 +114,9 @@ public class ContextGraph { for generator in generators { // Now check which generators don't have providers if !providedContexts.contains(generator.requiredContext) { + if !isBundle && generator.requiredContext == .bundle { + continue + } logger.warning( "Generator \(generator.name) cannot be run as it doesn't have a Generator that can provide this context." ) diff --git a/Sources/Fuzzilli/Fuzzer.swift b/Sources/Fuzzilli/Fuzzer.swift index 7a2d93ab5..6ab97c135 100644 --- a/Sources/Fuzzilli/Fuzzer.swift +++ b/Sources/Fuzzilli/Fuzzer.swift @@ -210,7 +210,8 @@ public class Fuzzer { self.referenceRunner = referenceScriptRunner self.minimizer = minimizer self.logger = Logger(withLabel: "Fuzzer") - self.contextGraph = ContextGraph(for: codeGenerators, withLogger: self.logger) + self.contextGraph = ContextGraph( + for: codeGenerators, isBundle: configuration.generateBundle, withLogger: self.logger) self.corpusGenerationEngine = GenerativeEngine(generateBundle: configuration.generateBundle) // Pass-through any postprocessor to the generative engine. @@ -252,7 +253,8 @@ public class Fuzzer { fatalError("Code generators must contain at least one value generator") } // This builds a graph that we need later for scheduling generators. - self.contextGraph = ContextGraph(for: generators, withLogger: self.logger) + self.contextGraph = ContextGraph( + for: generators, isBundle: self.config.generateBundle, withLogger: self.logger) self.codeGenerators = generators } diff --git a/Tests/FuzzilliTests/ContextGraphTest.swift b/Tests/FuzzilliTests/ContextGraphTest.swift index 60bec3eec..97aec8fa2 100644 --- a/Tests/FuzzilliTests/ContextGraphTest.swift +++ b/Tests/FuzzilliTests/ContextGraphTest.swift @@ -20,7 +20,7 @@ class ContextGraphTests: XCTestCase { func testReachabilityCalculationForJS() { let fuzzer = makeMockFuzzer() let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: false, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .javascript)) @@ -39,7 +39,7 @@ class ContextGraphTests: XCTestCase { let config = Configuration(generateBundle: true) let fuzzer = makeMockFuzzer(config: config) let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: true, withLogger: Logger(withLabel: "Test")) let reachableContexts = Set(contextGraph.getReachableContexts(from: .bundle)) @@ -55,7 +55,7 @@ class ContextGraphTests: XCTestCase { func testSubsetReachabilityCalculation() { let fuzzer = makeMockFuzzer() let contextGraph = ContextGraph( - for: fuzzer.codeGenerators, withLogger: Logger(withLabel: "Test")) + for: fuzzer.codeGenerators, isBundle: false, withLogger: Logger(withLabel: "Test")) let reachableContextsWasm = Set(contextGraph.getReachableContexts(from: .wasm)) let reachableContextsWasm2 = Set(contextGraph.getReachableContexts(from: .wasm)) From d5a995ec7f3a51d867f6d88c6d0bcb39bbd73cb8 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 17 Apr 2026 11:30:25 +0000 Subject: [PATCH 233/234] Rename wasm-related labels This CL renames wasm-related labels to better distinguish them from js-related labels, which we're currently adding. Change-Id: I9682b4a30e18c0d4f5704a49a2890c4647def159 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9210958 Commit-Queue: Matthias Liedtke Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 12 +++++----- .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 14 +++++------ Sources/Fuzzilli/FuzzIL/JSTyper.swift | 10 ++++---- Sources/Fuzzilli/FuzzIL/TypeSystem.swift | 24 +++++++++---------- Sources/Fuzzilli/FuzzIL/WasmOperations.swift | 2 +- Sources/Fuzzilli/Lifting/WasmLifter.swift | 6 ++--- Tests/FuzzilliTests/WasmTests.swift | 16 ++++++------- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 44cc8f64a..8e2dc2443 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -4932,7 +4932,7 @@ public class ProgramBuilder { #if DEBUG var argIndex = signature.parameterTypes.count let assertLabelTypeData: (ILType) -> Void = { labelType in - assert(labelType.Is(.anyLabel)) + assert(labelType.Is(.anyWasmLabel)) assert(labelType.wasmLabelType!.parameters.last!.Is(.wasmExnRef())) } for catchKind in catches { @@ -4944,14 +4944,14 @@ public class ProgramBuilder { argIndex += 2 case .NoRef: assert(b.type(of: args[argIndex]).Is(.object(ofGroup: "WasmTag"))) - assert(b.type(of: args[argIndex + 1]).Is(.anyLabel)) + assert(b.type(of: args[argIndex + 1]).Is(.anyWasmLabel)) argIndex += 2 case .AllRef: let labelType = b.type(of: args[argIndex]) assertLabelTypeData(labelType) argIndex += 1 case .AllNoRef: - assert(b.type(of: args[argIndex]).Is(.anyLabel)) + assert(b.type(of: args[argIndex]).Is(.anyWasmLabel)) argIndex += 1 } } @@ -5087,8 +5087,8 @@ public class ProgramBuilder { b.emit(WasmThrowRef(), withInputs: [exception], types: [.wasmExnRef()]) } - public func wasmBuildLegacyRethrow(_ exceptionLabel: Variable) { - b.emit(WasmRethrow(), withInputs: [exceptionLabel], types: [.exceptionLabel]) + public func wasmBuildLegacyRethrow(_ wasmExceptionLabel: Variable) { + b.emit(WasmRethrow(), withInputs: [wasmExceptionLabel], types: [.wasmExceptionLabel]) } public func wasmBuildLegacyTryDelegate( @@ -5120,7 +5120,7 @@ public class ProgramBuilder { b.emit( WasmEndTryDelegate(outputCount: signature.outputTypes.count), withInputs: [signatureDef, delegate] + results, - types: [.wasmTypeDef(), .anyLabel] + signature.outputTypes + types: [.wasmTypeDef(), .anyWasmLabel] + signature.outputTypes ).outputs) } diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index 65275e1db..e0676a9fc 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -1609,7 +1609,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmLegacyTryDelegateGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel) + inputs: .required(.anyWasmLabel) ) { b, label in let function = b.currentWasmModule.currentWasmFunction // Choose a few random wasm values as arguments if available. @@ -1734,7 +1734,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmLegacyRethrowGenerator", inContext: .single(.wasmFunction), - inputs: .required(.exceptionLabel) + inputs: .required(.wasmExceptionLabel) ) { b, exception in let function = b.currentWasmModule.currentWasmFunction function.wasmBuildLegacyRethrow(exception) @@ -1800,7 +1800,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmBranchGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel) + inputs: .required(.anyWasmLabel) ) { b, label in let function = b.currentWasmModule.currentWasmFunction let args = b.type(of: label).wasmLabelType!.parameters.map( @@ -1810,7 +1810,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator( "WasmBranchIfGenerator", inContext: .single(.wasmFunction), - inputs: .required(.anyLabel, .wasmi32) + inputs: .required(.anyWasmLabel, .wasmi32) ) { b, label, conditionVar in let function = b.currentWasmModule.currentWasmFunction let args = b.type(of: label).wasmLabelType!.parameters.map( @@ -1828,7 +1828,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // Choose parameter types for the br_table. If we can find an existing label, just use that // label types as it allows use to reuse existing (and therefore more interesting) blocks. let parameterTypes = - if let label = b.randomVariable(ofType: .anyLabel) { + if let label = b.randomVariable(ofType: .anyWasmLabel) { b.type(of: label).wasmLabelType!.parameters } else { b.randomWasmBlockOutputTypes(upTo: 3) @@ -1841,7 +1841,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ b.emit(WasmBeginBlock(parameterCount: 0), withInputs: [signatureDef]) } let labels = (0...valueCount).map { _ in - b.randomVariable(ofType: .label(parameterTypes))! + b.randomVariable(ofType: .wasmLabel(parameterTypes))! } let args = parameterTypes.map(function.findOrGenerateWasmVar) function.wasmBranchTable(on: value, labels: labels, args: args) @@ -1897,7 +1897,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ // same parameter types could also be mapped to the same block.) let labels = signatureDefs.map { signatureDef in b.randomVariable( - ofType: .label( + ofType: .wasmLabel( b.type(of: signatureDef).wasmFunctionSignatureDefSignature.outputTypes))! } let catches = zip(tags, withExnRef).map { diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 078e34378..c7992206c 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -710,7 +710,7 @@ public struct JSTyper: Analyzer { // Helper function to type a "regular" wasm begin block (block, if, try). mutating func wasmTypeBeginBlock(_ instr: Instruction, _ signature: WasmSignature) { - setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.outputTypes)) for (innerOutput, paramType) in zip( instr.innerOutputs.dropFirst(), signature.parameterTypes) { @@ -971,7 +971,7 @@ public struct JSTyper: Analyzer { // of the block, not the result types (because a branch to a loop label jumps to the // beginning of the loop block instead of the end.) let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.innerOutputs.first!, to: .label(signature.parameterTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.parameterTypes)) for (innerOutput, paramType) in zip( instr.innerOutputs.dropFirst(), signature.parameterTypes) { @@ -999,11 +999,11 @@ public struct JSTyper: Analyzer { wasmTypeBeginBlock(instr, signature) case .wasmBeginCatchAll(_): let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature - setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes)) + setType(of: instr.innerOutputs.first!, to: .wasmLabel(signature.outputTypes)) case .wasmBeginCatch(_): let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature // Type the label (used for branch instructions). - setType(of: instr.innerOutput(0), to: .label(blockSignature.outputTypes)) + setType(of: instr.innerOutput(0), to: .wasmLabel(blockSignature.outputTypes)) // Register the tag (Wasm exception) in the dynamicObjectGroupManager as being used // by this Wasm module. let tag = instr.input(1) @@ -1014,7 +1014,7 @@ public struct JSTyper: Analyzer { // The second inner output is the exception label which is used for rethrowing the // exception with the legacy exception handling proposal. (This is similar to the // exnref in the standard exception handling spec.) - setType(of: instr.innerOutput(1), to: .exceptionLabel) + setType(of: instr.innerOutput(1), to: .wasmExceptionLabel) // Type the tag parameters based on the tag's signature definition. // This guarantees that the inner outputs are properly typed, even if a mutator // changed the tag variable to something that's not typed as a Wasm tag anymore. diff --git a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift index e546fae6d..a19b294c1 100644 --- a/Sources/Fuzzilli/FuzzIL/TypeSystem.swift +++ b/Sources/Fuzzilli/FuzzIL/TypeSystem.swift @@ -222,21 +222,21 @@ public struct ILType: Hashable { // Internal types // This type is used to indicate block labels in wasm. - public static func label(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { + public static func wasmLabel(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType { return ILType( - definiteType: .label, + definiteType: .wasmLabel, ext: TypeExtension( group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch))) } - public static let anyLabel: ILType = ILType( - definiteType: .label, + public static let anyWasmLabel: ILType = ILType( + definiteType: .wasmLabel, ext: TypeExtension( group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil)) /// A label that allows rethrowing the caught exception of a catch block. - public static let exceptionLabel: ILType = ILType(definiteType: .exceptionLabel) + public static let wasmExceptionLabel: ILType = ILType(definiteType: .wasmExceptionLabel) public static func wasmMemory(limits: Limits, isShared: Bool = false, isMemory64: Bool = false) -> ILType @@ -1245,11 +1245,11 @@ extension ILType: CustomStringConvertible { return ".wasmPackedI8" case .wasmPackedI16: return ".wasmPackedI16" - case .label: + case .wasmLabel: if let labelType = self.wasmLabelType { - return ".label(\(labelType.parameters))" + return ".wasmLabel(\(labelType.parameters))" } - return ".label" + return ".wasmLabel" case .wasmRef: guard let refType = self.wasmReferenceType else { return ".wasmGenericRef" @@ -1276,8 +1276,8 @@ extension ILType: CustomStringConvertible { return ".wasmTypeDef(\(desc))" } return ".wasmTypeDef(nil)" - case .exceptionLabel: - return ".exceptionLabel" + case .wasmExceptionLabel: + return ".wasmExceptionLabel" case .wasmDataSegment: return ".wasmDataSegment" case .wasmElementSegment: @@ -1336,11 +1336,11 @@ struct BaseType: OptionSet, Hashable { static let wasmf64 = BaseType(rawValue: 1 << 15) // These are wasm internal types, these are never lifted as such and are only used to glue together dataflow in wasm. - static let label = BaseType(rawValue: 1 << 16) + static let wasmLabel = BaseType(rawValue: 1 << 16) // Any catch block exposes such a label now to rethrow the exception caught by that catch. // Note that in wasm the label is actually the try block's label but as rethrows are only possible inside a catch // block, semantically having a label on the catch makes more sense. - static let exceptionLabel = BaseType(rawValue: 1 << 17) + static let wasmExceptionLabel = BaseType(rawValue: 1 << 17) // This is a reference to a table, which can be passed around to table instructions // The lifter will resolve this to the proper index when lifting. static let wasmSimd128 = BaseType(rawValue: 1 << 18) diff --git a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift index ef8e416b6..113cd8e3f 100644 --- a/Sources/Fuzzilli/FuzzIL/WasmOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/WasmOperations.swift @@ -1452,7 +1452,7 @@ final class WasmBeginCatch: WasmOperation { // branching as well as for rethrowing the exception. However, rethrows may only use labels // from catch blocks and branches may use any label but need to be very precise on the type // of the label parameters, so typing the label would require different subtyping based on - // the usage. For now, we just emit a label for branching and the ".exceptionLabel" for + // the usage. For now, we just emit a label for branching and the ".wasmExceptionLabel" for // rethrows. super.init( // Inputs: The block signature, the tag, the tag signature, and the outputs of the preceding try or catch diff --git a/Sources/Fuzzilli/Lifting/WasmLifter.swift b/Sources/Fuzzilli/Lifting/WasmLifter.swift index a5a0232f3..e9e35cc1c 100644 --- a/Sources/Fuzzilli/Lifting/WasmLifter.swift +++ b/Sources/Fuzzilli/Lifting/WasmLifter.swift @@ -1408,7 +1408,7 @@ public class WasmLifter { for input in instr.inputs { // Skip "internal" inputs, i.e. ones that don't map to a slot, such as .label variables let inputType = typer.type(of: input) - if inputType.Is(.anyLabel) || inputType.Is(.exceptionLabel) { + if inputType.Is(.anyWasmLabel) || inputType.Is(.wasmExceptionLabel) { continue } @@ -1444,7 +1444,7 @@ public class WasmLifter { // If we have an output, make sure we store it on the stack as this is a "complex" instruction, i.e. has inputs and outputs. if instr.numOutputs > 0 { - assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyLabel) }) + assert(instr.outputs.allSatisfy { !typer.type(of: $0).Is(.anyWasmLabel) }) for output in instr.outputs.reversed() { // Also spill the instruction currentFunction!.spillLocal(forVariable: output) @@ -1460,7 +1460,7 @@ public class WasmLifter { // As the parameters are pushed "in order" to the stack, they need to be popped in reverse order. for innerOutput in instr.innerOutputs.reversed() { let t = typer.type(of: innerOutput) - if !t.Is(.anyLabel) && !t.Is(.exceptionLabel) { + if !t.Is(.anyWasmLabel) && !t.Is(.wasmExceptionLabel) { currentFunction!.spillLocal(forVariable: innerOutput) } } diff --git a/Tests/FuzzilliTests/WasmTests.swift b/Tests/FuzzilliTests/WasmTests.swift index 5006e0c91..d18ecef71 100644 --- a/Tests/FuzzilliTests/WasmTests.swift +++ b/Tests/FuzzilliTests/WasmTests.swift @@ -412,7 +412,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, _, _ in let ctr = function.consti32(10) function.wasmBuildLoop(with: [] => [], args: []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let result = function.wasmi32BinOp(ctr, function.consti32(1), binOpKind: .Sub) function.wasmReassign(variable: ctr, to: result) // The backedge, loop if we are not at zero yet. @@ -3742,7 +3742,7 @@ class WasmFoundationTests: XCTestCase { let one = function.consti32(1) function.wasmBuildLoop(with: [] => [], args: []) { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let result = function.wasmi32BinOp(ctr, one, binOpKind: .Add) let varUpdate = function.wasmi64BinOp( variable, function.consti64(2), binOpKind: .Add) @@ -4023,7 +4023,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) function.wasmReturn(function.consti64(42)) } return [function.consti64(-1)] @@ -4056,7 +4056,7 @@ class WasmFoundationTests: XCTestCase { let module = b.buildWasmModule { wasmModule in wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) // Manually set the availableTypes here for testing. let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( b.type(of: functionA).signature!, availableTypes: WeightedList([])) @@ -4102,7 +4102,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid( body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) let wasmSignature = ProgramBuilder.convertJsSignatureToWasmSignature( b.type(of: functionA).signature!, availableTypes: WeightedList([])) function.wasmJsCall( @@ -4167,7 +4167,7 @@ class WasmFoundationTests: XCTestCase { wasmModule.addWasmFunction(with: [] => [.wasmi64]) { function, _, _ in function.wasmBuildLegacyTryVoid( body: { label in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) function.WasmBuildThrow( tag: throwTag, inputs: [function.consti64(123), function.consti32(234)]) function.wasmUnreachable() @@ -4221,7 +4221,7 @@ class WasmFoundationTests: XCTestCase { catchClauses: [ ( tag: tag, - body: { catchLabel, exceptionLabel, args in + body: { catchLabel, wasmExceptionLabel, args in function.wasmBranch(to: catchLabel) } ) @@ -4374,7 +4374,7 @@ class WasmFoundationTests: XCTestCase { signature: signature, signatureDef: signatureDef, args: [argI64, argI32], body: { label, args in - XCTAssert(b.type(of: label).Is(.anyLabel)) + XCTAssert(b.type(of: label).Is(.anyWasmLabel)) XCTAssertEqual(b.type(of: args[0]), .wasmi64) XCTAssertEqual(b.type(of: args[1]), .wasmi32) function.WasmBuildThrow(tag: tag, inputs: args) From afc490749f693c2a5a4dbdde8330231719c51021 Mon Sep 17 00:00:00 2001 From: Leon Bettscheider Date: Fri, 17 Apr 2026 11:44:16 +0000 Subject: [PATCH 234/234] Have Instruction ctor use .empty flags by default This cleans up the code a bit. Change-Id: I12c467936fbfaceec025922aee407e00ce82c545 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/9211219 Reviewed-by: Matthias Liedtke Commit-Queue: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 2 +- Sources/Fuzzilli/Compiler/Compiler.swift | 2 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 14 +++++++------- Sources/Fuzzilli/Minimization/BlockReducer.swift | 10 +++++----- .../Minimization/InstructionSimplifier.swift | 8 ++++---- Sources/Fuzzilli/Minimization/LoopSimplifier.swift | 14 +++++++------- .../Fuzzilli/Minimization/MinimizationHelper.swift | 3 +-- .../Fuzzilli/Minimization/ReassignReducer.swift | 2 +- .../Minimization/WasmTypeGroupReducer.swift | 2 +- Sources/Fuzzilli/Mutators/InputMutator.swift | 2 +- Sources/Fuzzilli/Mutators/OperationMutator.swift | 4 ++-- Tests/FuzzilliTests/LifterTest.swift | 2 +- 12 files changed, 32 insertions(+), 33 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 8e2dc2443..2ca4a0d0b 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2657,7 +2657,7 @@ public class ProgramBuilder { } } - return internalAppend(Instruction(op, inouts: inouts, flags: .empty)) + return internalAppend(Instruction(op, inouts: inouts)) } @discardableResult diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 1ecdf89e6..f5168eacd 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -1470,7 +1470,7 @@ public class JavaScriptCompiler { let outputs = (0..( - _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags + _ op: Operation, inouts: Variables, index: Int? = nil, flags: Self.Flags = .empty ) where Variables.Element == Variable { assert(op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count) self.op = op @@ -263,33 +263,33 @@ public struct Instruction { public init(_ op: Operation, output: Variable) { assert(op.numInputs == 0 && op.numOutputs == 1 && op.numInnerOutputs == 0) - self.init(op, inouts: [output], flags: .empty) + self.init(op, inouts: [output]) } public init(_ op: Operation, output: Variable, inputs: [Variable]) { assert(op.numOutputs == 1) assert(op.numInnerOutputs == 0) assert(op.numInputs == inputs.count) - self.init(op, inouts: inputs + [output], flags: .empty) + self.init(op, inouts: inputs + [output]) } public init(_ op: Operation, inputs: [Variable]) { assert(op.numOutputs + op.numInnerOutputs == 0) assert(op.numInputs == inputs.count) - self.init(op, inouts: inputs, flags: .empty) + self.init(op, inouts: inputs) } public init(_ op: Operation, innerOutput: Variable) { assert(op.numInnerOutputs == 1) assert(op.numOutputs == 0) assert(op.numInputs == 0) - self.init(op, inouts: [innerOutput], flags: .empty) + self.init(op, inouts: [innerOutput]) } public init(_ op: Operation) { assert(op.numOutputs + op.numInnerOutputs == 0) assert(op.numInputs == 0) - self.init(op, inouts: [], flags: .empty) + self.init(op, inouts: []) } /// Flags associated with an Instruction. @@ -2812,7 +2812,7 @@ extension Instruction: ProtobufConvertible { opCache?.add(op) - self.init(op, inouts: inouts, flags: .empty) + self.init(op, inouts: inouts) } init(from proto: ProtobufType) throws { diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 5af1d5e3e..1de029dcc 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -272,7 +272,7 @@ struct BlockReducer: Reducer { replacements.append( ( ifBlock.head, - Instruction(invertedIf, inouts: helper.code[ifBlock.head].inouts, flags: .empty) + Instruction(invertedIf, inouts: helper.code[ifBlock.head].inouts) )) // The rest of the if body is nopped ... for instr in helper.code.body(of: ifBlock) { @@ -354,7 +354,7 @@ struct BlockReducer: Reducer { continue // Skip the block begin and end. } let newInouts = instr.inouts.map({ varReplacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() return helper.testAndCommit(newCode) @@ -503,7 +503,7 @@ struct BlockReducer: Reducer { // of the original WasmBeginElse block, so that users of them are rewired correctly. let inouts = helper.code[ifBlock.head].inputs + helper.code[elseBlock.head].allOutputs replacements.append( - (ifBlock.head, Instruction(invertedIf, inouts: inouts, flags: .empty))) + (ifBlock.head, Instruction(invertedIf, inouts: inouts))) // The rest of the if body is nopped ... for instr in helper.code.body(of: ifBlock) { replacements.append((instr.index, helper.nop(for: instr))) @@ -549,7 +549,7 @@ struct BlockReducer: Reducer { continue // Skip the WasmBeginIf and the else block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() if helper.testAndCommit(newCode) { @@ -579,7 +579,7 @@ struct BlockReducer: Reducer { continue // Skip the WasmBeginIf and the if true block. } let newInouts = instr.inouts.map { varReplacements[$0] ?? $0 } - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } newCode.renumberVariables() if helper.testAndCommit(newCode) { diff --git a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift index 2126359d7..cc4c8b79a 100644 --- a/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/InstructionSimplifier.swift @@ -32,7 +32,7 @@ struct InstructionSimplifier: Reducer { let functionName = (begin as? BeginAnyNamedFunction)?.functionName ?? nil let newBegin = Instruction( BeginPlainFunction(parameters: begin.parameters, functionName: functionName), - inouts: helper.code[group.head].inouts, flags: .empty) + inouts: helper.code[group.head].inouts) let newEnd = Instruction(EndPlainFunction()) // The resulting code may be invalid as we may be changing the context inside the body (e.g. turning an async function into a plain one). @@ -61,7 +61,7 @@ struct InstructionSimplifier: Reducer { if let op = newOp { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(op, inouts: instr.inouts, flags: .empty)) + with: Instruction(op, inouts: instr.inouts)) } } } @@ -100,7 +100,7 @@ struct InstructionSimplifier: Reducer { if let op = newOp { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(op, inouts: instr.inouts, flags: .empty)) + with: Instruction(op, inouts: instr.inouts)) } } } @@ -114,7 +114,7 @@ struct InstructionSimplifier: Reducer { if newOp !== op { helper.tryReplacing( instructionAt: instr.index, - with: Instruction(newOp, inouts: instr.inouts, flags: .empty)) + with: Instruction(newOp, inouts: instr.inouts)) } } } diff --git a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index edf76df0c..6acce260b 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -101,14 +101,14 @@ struct LoopSimplifier: Reducer { newCode.append( Instruction( BeginRepeatLoop(iterations: 1, exposesLoopCounter: needLoopVariable), - inouts: needLoopVariable ? [loopVar!] : [], flags: .empty)) + inouts: needLoopVariable ? [loopVar!] : [])) // Append condition, body, and afterthought code var replacements = [Variable: Variable]( uniqueKeysWithValues: beginConditionBlock.innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: conditionBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } let bodyBlock = group.block(3) @@ -117,7 +117,7 @@ struct LoopSimplifier: Reducer { uniqueKeysWithValues: helper.code[bodyBlock.head].innerOutputs.map({ ($0, loopVar!) })) for instr in helper.code.body(of: bodyBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } let afterthoughtBlock = group.block(2) @@ -128,7 +128,7 @@ struct LoopSimplifier: Reducer { })) for instr in helper.code.body(of: afterthoughtBlock) { let newInouts = instr.inouts.map({ replacements[$0] ?? $0 }) - newCode.append(Instruction(instr.op, inouts: newInouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: newInouts)) } // Append loop footer @@ -244,7 +244,7 @@ struct LoopSimplifier: Reducer { if originalLoopHeader.exposesLoopCounter { replacement = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: helper.code[group.head].inouts, flags: .empty) + inouts: helper.code[group.head].inouts) } else { replacement = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) @@ -267,7 +267,7 @@ struct LoopSimplifier: Reducer { if newCode[headerIndex].numInnerOutputs > 0 { newCode[headerIndex] = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: true), - inouts: newCode[headerIndex].inouts, flags: .empty) + inouts: newCode[headerIndex].inouts) } else { newCode[headerIndex] = Instruction( BeginRepeatLoop(iterations: numIterations, exposesLoopCounter: false)) @@ -370,7 +370,7 @@ struct LoopSimplifier: Reducer { for instr in helper.code[innerHead.. Instruction { // We must preserve outputs here to keep variable number contiguous. return Instruction( - Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs, - flags: .empty) + Nop(numOutputs: instr.numOutputs + instr.numInnerOutputs), inouts: instr.allOutputs) } } diff --git a/Sources/Fuzzilli/Minimization/ReassignReducer.swift b/Sources/Fuzzilli/Minimization/ReassignReducer.swift index 8226089a5..c69cb0128 100644 --- a/Sources/Fuzzilli/Minimization/ReassignReducer.swift +++ b/Sources/Fuzzilli/Minimization/ReassignReducer.swift @@ -82,7 +82,7 @@ struct ReassignmentReducer: Reducer { } else { let inouts = instr.inouts.map({ reassignedVariables[$0] ?? $0 }) if inouts[...] != instr.inouts { didChangeCode = true } - newCode.append(Instruction(instr.op, inouts: inouts, flags: .empty)) + newCode.append(Instruction(instr.op, inouts: inouts)) } } diff --git a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift index 50f2c5eac..aeeaf7b37 100644 --- a/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift +++ b/Sources/Fuzzilli/Minimization/WasmTypeGroupReducer.swift @@ -75,7 +75,7 @@ struct WasmTypeGroupReducer: Reducer { let newInouts = keptInoutsMap.map { $0.0 } + keptInoutsMap.map { $0.1 } endTypeGroupReplacements[instr.index] = Instruction( - WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts, flags: .empty) + WasmEndTypeGroup(typesCount: keptInoutsMap.count), inouts: newInouts) } if toRemove.isEmpty { diff --git a/Sources/Fuzzilli/Mutators/InputMutator.swift b/Sources/Fuzzilli/Mutators/InputMutator.swift index 01c214a89..1fdcee1ed 100644 --- a/Sources/Fuzzilli/Mutators/InputMutator.swift +++ b/Sources/Fuzzilli/Mutators/InputMutator.swift @@ -91,7 +91,7 @@ public class InputMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - b.append(Instruction(instr.op, inouts: inouts, flags: .empty)) + b.append(Instruction(instr.op, inouts: inouts)) } } } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 613b68e1a..8f24ce7d3 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -848,7 +848,7 @@ public class OperationMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - return Instruction(newOp, inouts: instr.inouts, flags: .empty) + return Instruction(newOp, inouts: instr.inouts) } private func extendVariadicOperation(_ instr: Instruction, _ b: ProgramBuilder) -> Instruction { @@ -945,7 +945,7 @@ public class OperationMutator: BaseInstructionMutator { // This assert is here to prevent subtle bugs if we ever decide to add flags that are "alive" during program building / mutation. // If we add flags, remove this assert and change the code below. assert(instr.flags == .empty) - return Instruction(newOp, inouts: inouts, flags: .empty) + return Instruction(newOp, inouts: inouts) } private func replaceRandomElement( diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 1869265d4..03b73e48d 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3990,7 +3990,7 @@ class LifterTests: XCTestCase { var newInouts = oldInstr.inouts // This is the mutation newInouts[1] = f - let instr = Instruction(oldInstr.op, inouts: newInouts, flags: .empty) + let instr = Instruction(oldInstr.op, inouts: newInouts) // Append the mutated instruction now. b.append(instr) // Adopt the rest of the Program.