// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import Fuzzilli
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)
}
fileprivate let TurbofanVerifyTypeGenerator = CodeGenerator("TurbofanVerifyTypeGenerator", inputs: .one) { b, v in
b.eval("%VerifyType(%@)", with: [v])
}
// 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])])
}
public extension ILType {
{% for enum in database.enumerations %}
static let js{{enum.identifier}} = ILType.string
{% endfor %}
{% for interface in database.interfaces %}
{% set inter = interface|parse_interface -%}
static let js{{interface.identifier}} = {{inter[0].fuzzilli_repr()}}
{% endfor %}
{% for d in database.dictionaries %}
{% set dictionary = d|parse_dictionary -%}
static let js{{d.identifier}} = {{dictionary[0].fuzzilli_repr()}}
{% endfor %}
{% for interface in database.interfaces -%}
{% set constructor = interface|parse_constructors -%}
{% if constructor[0] %}
static let js{{interface.identifier}}Constructor = {{constructor[0].fuzzilli_repr()}}
{% endif %}
{%- endfor %}
{% for t in database.typedefs %}
{% set il_type = t.idl_type|idl_type_to_iltype -%}
static let js{{t.identifier}} = {{il_type.fuzzilli_repr()}}
{% endfor %}
{% for interface in database.callback_interfaces %}
{% set inter = interface|parse_interface -%}
static let js{{interface.identifier}} = {{inter[0].fuzzilli_repr()}}
{% endfor %}
{% for c in database.callback_functions %}
{% set op = c|parse_operation -%}
static let js{{c.identifier}} = ILType.function({{op.fuzzilli_repr()}})
{% endfor %}
}
{%- macro define_group(identifier, group) %}
let js{{identifier}} = ObjectGroup(
name: "{{group.name}}",
instanceType: {{group.instanceType.fuzzilli_repr()}},
properties: [
{%- for k, v in group.properties.items() %}
"{{k}}" : {{v.fuzzilli_repr()}},
{% else %}
:
{% endfor -%}
],
methods: [
{%- for k, v in group.methods.items() %}
"{{k}}" : {{v.fuzzilli_repr()}},
{% else %}
:
{% endfor -%}
]
)
{%- endmacro -%}
{% for interface in database.interfaces %}
{%- set inter = interface|parse_interface -%}
{{define_group(interface.identifier, inter[1])}}
{% endfor %}
{% for interface in database.interfaces %}
{%- set constructor = interface|parse_constructors -%}
{% if constructor[1] %}
{{define_group(interface.identifier+"Constructor", constructor[1])}}
{% endif %}
{%- endfor %}
{% for d in database.dictionaries %}
{%- set dictionary = d|parse_dictionary -%}
{{define_group(d.identifier, dictionary[1])}}
{% endfor -%}
{% for interface in database.callback_interfaces %}
{%- set inter = interface|parse_interface -%}
{{define_group(interface.identifier, inter[1])}}
{% endfor -%}
let chromiumProfile = Profile(
processArgs: { _ in
var args: [String] = []
return args
},
processEnv: ["ASAN_OPTIONS":"detect_odr_violation=0", "DISPLAY":":20"],
maxExecsBeforeRespawn: 100,
timeout: 8000,
codePrefix: """
""",
codeSuffix: """
""",
ecmaVersion: ECMAScriptVersion.es6,
startupTests: [
("fuzzilli('FUZZILLI_CRASH', 0)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 1)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 2)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 3)", .shouldCrash),
],
additionalCodeGenerators: [
(ForceJITCompilationThroughLoopGenerator, 5),
(ForceTurboFanCompilationGenerator, 5),
(ForceMaglevCompilationGenerator, 5),
(TurbofanVerifyTypeGenerator, 10),
(GcGenerator, 10),
],
additionalProgramTemplates: WeightedList<ProgramTemplate>([
]),
disabledCodeGenerators: [],
disabledMutators: [],
additionalBuiltins: [
{%- for interface in database.interfaces -%}
{% set constructor = interface|parse_constructors -%}
{% if constructor[0] %}
"{{interface.identifier}}": ILType.js{{interface.identifier}}Constructor,
{% endif %}
{%- endfor %}
"window": .jsWindow,
"document": .jsDocument,
"gc" : .function([] => (.undefined | .jsPromise)),
"d8": .object(),
],
additionalObjectGroups: [
{%- for interface in database.interfaces %}
js{{interface.identifier}},
{% endfor -%}
{% for interface in database.interfaces -%}
{% set constructor = interface|parse_constructors -%}
{% if constructor[1] %}
js{{interface.identifier}}Constructor,
{% endif %}
{%- endfor -%}
{% for d in database.dictionaries %}
js{{d.identifier}},
{% endfor -%}
{% for interface in database.callback_interfaces %}
js{{interface.identifier}},
{% endfor -%}
],
optionalPostProcessor: nil
)