Commit 633b70b1 authored by jgruber's avatar jgruber Committed by Commit Bot

[regexp] Initial go at a builtins fuzzer

This fuzzer randomly generates calls to regexp builtins, runs each on
the slow and fast path, and verifies that their result is the same.

Change-Id: Ia91b0c8afcdaf64835a9bb7b9a470610fbb75fc8
Reviewed-on: https://chromium-review.googlesource.com/833922
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50670}
parent 8d2ab930
......@@ -2842,6 +2842,7 @@ group("v8_fuzzers") {
":v8_simple_json_fuzzer",
":v8_simple_multi_return_fuzzer",
":v8_simple_parser_fuzzer",
":v8_simple_regexp_builtins_fuzzer",
":v8_simple_regexp_fuzzer",
":v8_simple_wasm_async_fuzzer",
":v8_simple_wasm_call_fuzzer",
......@@ -3127,6 +3128,25 @@ v8_source_set("parser_fuzzer") {
v8_fuzzer("parser_fuzzer") {
}
v8_source_set("regexp_builtins_fuzzer") {
sources = [
"test/fuzzer/regexp-builtins.cc",
"test/fuzzer/regexp_builtins/mjsunit.js.h",
]
deps = [
":fuzzer_support",
]
configs = [
":external_config",
":internal_config_base",
]
}
v8_fuzzer("regexp_builtins_fuzzer") {
}
v8_source_set("regexp_fuzzer") {
sources = [
"test/fuzzer/regexp.cc",
......
......@@ -1176,8 +1176,8 @@ class Isolate {
void* stress_deopt_count_address() { return &stress_deopt_count_; }
bool force_slow_path() { return force_slow_path_; }
void set_force_slow_path(bool v) { force_slow_path_ = v; }
bool force_slow_path() const { return force_slow_path_; }
bool* force_slow_path_address() { return &force_slow_path_; }
V8_EXPORT_PRIVATE base::RandomNumberGenerator* random_number_generator();
......
......@@ -48,7 +48,7 @@ class JSRegExp : public JSObject {
};
typedef base::Flags<Flag> Flags;
static int FlagCount() { return 6; }
static constexpr int FlagCount() { return 6; }
DECL_ACCESSORS(data, Object)
DECL_ACCESSORS(flags, Object)
......
......@@ -755,6 +755,18 @@ RUNTIME_FUNCTION(Runtime_SetFlags) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetForceSlowPath) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, arg, 0);
if (arg->IsTrue(isolate)) {
isolate->set_force_slow_path(true);
} else {
DCHECK(arg->IsFalse(isolate));
isolate->set_force_slow_path(false);
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_Abort) {
SealHandleScope shs(isolate);
......
......@@ -560,81 +560,82 @@ namespace internal {
F(SymbolIsPrivate, 1, 1)
#define FOR_EACH_INTRINSIC_TEST(F) \
F(ConstructDouble, 2, 1) \
F(ConstructConsString, 2, 1) \
F(DeoptimizeFunction, 1, 1) \
F(DeoptimizeNow, 0, 1) \
F(RunningInSimulator, 0, 1) \
F(IsConcurrentRecompilationSupported, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(TypeProfile, 1, 1) \
F(OptimizeOsr, -1, 1) \
F(NeverOptimizeFunction, 1, 1) \
F(GetOptimizationStatus, -1, 1) \
F(UnblockConcurrentRecompilation, 0, 1) \
F(GetDeoptCount, 1, 1) \
F(GetUndetectable, 0, 1) \
F(GetCallable, 0, 1) \
F(ClearFunctionFeedback, 1, 1) \
F(Abort, 1, 1) \
F(AbortJS, 1, 1) \
F(CheckWasmWrapperElision, 2, 1) \
F(NotifyContextDisposed, 0, 1) \
F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \
F(ClearFunctionFeedback, 1, 1) \
F(CompleteInobjectSlackTracking, 1, 1) \
F(ConstructConsString, 2, 1) \
F(ConstructDouble, 2, 1) \
F(DebugPrint, 1, 1) \
F(DebugTrace, 0, 1) \
F(DebugTrackRetainingPath, -1, 1) \
F(PrintWithNameForAssert, 2, 1) \
F(DeoptimizeFunction, 1, 1) \
F(DeoptimizeNow, 0, 1) \
F(DeserializeWasmModule, 2, 1) \
F(DisallowCodegenFromStrings, 1, 1) \
F(DisallowWasmCodegen, 1, 1) \
F(DisassembleFunction, 1, 1) \
F(FreezeWasmLazyCompilation, 1, 1) \
F(GetCallable, 0, 1) \
F(GetDeoptCount, 1, 1) \
F(GetExceptionDetails, 1, 1) \
F(GetOptimizationStatus, -1, 1) \
F(GetUndetectable, 0, 1) \
F(GetWasmRecoveredTrapCount, 0, 1) \
F(GlobalPrint, 1, 1) \
F(SystemBreak, 0, 1) \
F(SetFlags, 1, 1) \
F(Abort, 1, 1) \
F(AbortJS, 1, 1) \
F(NativeScriptsCount, 0, 1) \
F(DisassembleFunction, 1, 1) \
F(TraceEnter, 0, 1) \
F(TraceExit, 1, 1) \
F(HaveSameMap, 2, 1) \
F(InNewSpace, 1, 1) \
F(HasFastElements, 1, 1) \
F(HasSmiElements, 1, 1) \
F(HasObjectElements, 1, 1) \
F(HasSmiOrObjectElements, 1, 1) \
F(HasDoubleElements, 1, 1) \
F(HasHoleyElements, 1, 1) \
F(HasDictionaryElements, 1, 1) \
F(HasSloppyArgumentsElements, 1, 1) \
F(HasFixedTypedArrayElements, 1, 1) \
F(HasDoubleElements, 1, 1) \
F(HasFastElements, 1, 1) \
F(HasFastProperties, 1, 1) \
F(HasFixedUint8Elements, 1, 1) \
F(HasFixedFloat32Elements, 1, 1) \
F(HasFixedFloat64Elements, 1, 1) \
F(HasFixedInt16Elements, 1, 1) \
F(HasFixedInt32Elements, 1, 1) \
F(HasFixedInt8Elements, 1, 1) \
F(HasFixedTypedArrayElements, 1, 1) \
F(HasFixedUint16Elements, 1, 1) \
F(HasFixedInt16Elements, 1, 1) \
F(HasFixedUint32Elements, 1, 1) \
F(HasFixedInt32Elements, 1, 1) \
F(HasFixedFloat32Elements, 1, 1) \
F(HasFixedFloat64Elements, 1, 1) \
F(HasFixedUint8ClampedElements, 1, 1) \
F(SpeciesProtector, 0, 1) \
F(SerializeWasmModule, 1, 1) \
F(DeserializeWasmModule, 2, 1) \
F(HasFixedUint8Elements, 1, 1) \
F(HasHoleyElements, 1, 1) \
F(HasObjectElements, 1, 1) \
F(HasSloppyArgumentsElements, 1, 1) \
F(HasSmiElements, 1, 1) \
F(HasSmiOrObjectElements, 1, 1) \
F(HaveSameMap, 2, 1) \
F(HeapObjectVerify, 1, 1) \
F(InNewSpace, 1, 1) \
F(IsAsmWasmCode, 1, 1) \
F(IsConcurrentRecompilationSupported, 0, 1) \
F(IsLiftoffFunction, 1, 1) \
F(IsWasmCode, 1, 1) \
F(IsWasmTrapHandlerEnabled, 0, 1) \
F(GetWasmRecoveredTrapCount, 0, 1) \
F(DisallowCodegenFromStrings, 1, 1) \
F(DisallowWasmCodegen, 1, 1) \
F(NativeScriptsCount, 0, 1) \
F(NeverOptimizeFunction, 1, 1) \
F(NotifyContextDisposed, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(OptimizeOsr, -1, 1) \
F(PrintWithNameForAssert, 2, 1) \
F(RedirectToWasmInterpreter, 2, 1) \
F(RunningInSimulator, 0, 1) \
F(SerializeWasmModule, 1, 1) \
F(SetAllocationTimeout, -1 /* 2 || 3 */, 1) \
F(SetFlags, 1, 1) \
F(SetForceSlowPath, 1, 1) \
F(SetWasmCompileControls, 2, 1) \
F(SetWasmInstantiateControls, 0, 1) \
F(SpeciesProtector, 0, 1) \
F(SystemBreak, 0, 1) \
F(TraceEnter, 0, 1) \
F(TraceExit, 1, 1) \
F(TypeProfile, 1, 1) \
F(UnblockConcurrentRecompilation, 0, 1) \
F(ValidateWasmInstancesChain, 2, 1) \
F(ValidateWasmModuleState, 1, 1) \
F(ValidateWasmOrphanedInstance, 1, 1) \
F(SetWasmCompileControls, 2, 1) \
F(SetWasmInstantiateControls, 0, 1) \
F(HeapObjectVerify, 1, 1) \
F(WasmNumInterpretedCalls, 1, 1) \
F(RedirectToWasmInterpreter, 2, 1) \
F(WasmTraceMemory, 1, 1) \
F(CompleteInobjectSlackTracking, 1, 1) \
F(IsLiftoffFunction, 1, 1) \
F(FreezeWasmLazyCompilation, 1, 1)
F(WasmTraceMemory, 1, 1)
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
F(ArrayBufferGetByteLength, 1, 1) \
......
......@@ -62,6 +62,34 @@
'parser.cc',
],
},
{
'target_name': 'v8_simple_regexp_builtins_fuzzer',
'type': 'executable',
'dependencies': [
'regexp_builtins_fuzzer_lib',
],
'include_dirs': [
'../..',
],
'sources': [
'fuzzer.cc',
],
},
{
'target_name': 'regexp_builtins_fuzzer_lib',
'type': 'static_library',
'dependencies': [
'../../src/v8.gyp:v8_libplatform',
'fuzzer_support',
],
'include_dirs': [
'../..',
],
'sources': [ ### gcmole(all) ###
'regexp-builtins.cc',
'regexp_builtins/mjsunit.js.h',
],
},
{
'target_name': 'v8_simple_regexp_fuzzer',
'type': 'executable',
......@@ -528,6 +556,7 @@
'dependencies': [
'v8_simple_json_fuzzer',
'v8_simple_parser_fuzzer',
'v8_simple_regexp_builtins_fuzzer',
'v8_simple_regexp_fuzzer',
'v8_simple_wasm_fuzzer',
],
......
......@@ -7,6 +7,7 @@
'files': [
'<(PRODUCT_DIR)/v8_simple_json_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_parser_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_regexp_builtins_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_regexp_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_multi_return_fuzzer<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/v8_simple_wasm_fuzzer<(EXECUTABLE_SUFFIX)',
......@@ -26,6 +27,7 @@
'./json/',
'./parser/',
'./regexp/',
'./regexp_builtins/',
'./multi_return/',
'./wasm/',
'./wasm_async/',
......
This diff is collapsed.
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Stripped-down version of test/mjsunit/mjsunit.js that only contains
// assertEquals.S
var assertEquals;
(function () {
var ObjectPrototypeToString = Object.prototype.toString;
var NumberPrototypeValueOf = Number.prototype.valueOf;
var BooleanPrototypeValueOf = Boolean.prototype.valueOf;
var StringPrototypeValueOf = String.prototype.valueOf;
var DatePrototypeValueOf = Date.prototype.valueOf;
var RegExpPrototypeToString = RegExp.prototype.toString;
var ArrayPrototypeForEach = Array.prototype.forEach;
var ArrayPrototypeJoin = Array.prototype.join;
var ArrayPrototypeMap = Array.prototype.map;
var ArrayPrototypePush = Array.prototype.push;
var BigIntPrototypeValueOf;
try {
BigIntPrototypeValueOf = BigInt.prototype.valueOf;
} catch(e) {}
function classOf(object) {
var string = ObjectPrototypeToString.call(object);
return string.substring(8, string.length - 1);
}
function ValueOf(value) {
switch (classOf(value)) {
case "Number":
return NumberPrototypeValueOf.call(value);
case "BigInt":
return BigIntPrototypeValueOf.call(value);
case "String":
return StringPrototypeValueOf.call(value);
case "Boolean":
return BooleanPrototypeValueOf.call(value);
case "Date":
return DatePrototypeValueOf.call(value);
default:
return value;
}
}
function PrettyPrint(value) {
switch (typeof value) {
case "string":
return JSON.stringify(value);
case "bigint":
return String(value) + "n";
case "number":
if (value === 0 && (1 / value) < 0) return "-0";
// FALLTHROUGH.
case "boolean":
case "undefined":
case "function":
case "symbol":
return String(value);
case "object":
if (value === null) return "null";
var objectClass = classOf(value);
switch (objectClass) {
case "Number":
case "BigInt":
case "String":
case "Boolean":
case "Date":
return objectClass + "(" + PrettyPrint(ValueOf(value)) + ")";
case "RegExp":
return RegExpPrototypeToString.call(value);
case "Array":
var mapped = ArrayPrototypeMap.call(value, PrettyPrintArrayElement);
var joined = ArrayPrototypeJoin.call(mapped, ",");
return "[" + joined + "]";
case "Uint8Array":
case "Int8Array":
case "Int16Array":
case "Uint16Array":
case "Uint32Array":
case "Int32Array":
case "Float32Array":
case "Float64Array":
var joined = ArrayPrototypeJoin.call(value, ",");
return objectClass + "([" + joined + "])";
case "Object":
break;
default:
return objectClass + "()";
}
var name = value.constructor.name;
if (name) return name + "()";
return "Object()";
default:
return "-- unknown value --";
}
}
function PrettyPrintArrayElement(value, index, array) {
if (value === undefined && !(index in array)) return "";
return PrettyPrint(value);
}
failWithMessage = function failWithMessage(message) {
throw new Error(message);
}
function formatFailureText(expectedText, found, name_opt) {
var message = "Fail" + "ure";
if (name_opt) {
message += " (" + name_opt + ")";
}
var foundText = PrettyPrint(found);
if (expectedText.length <= 40 && foundText.length <= 40) {
message += ": expected <" + expectedText + "> found <" + foundText + ">";
} else {
message += ":\nexpected:\n" + expectedText + "\nfound:\n" + foundText;
}
return message;
}
function fail(expectedText, found, name_opt) {
return failWithMessage(formatFailureText(expectedText, found, name_opt));
}
function deepObjectEquals(a, b) {
var aProps = Object.keys(a);
aProps.sort();
var bProps = Object.keys(b);
bProps.sort();
if (!deepEquals(aProps, bProps)) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
if (!deepEquals(a[aProps[i]], b[aProps[i]])) {
return false;
}
}
return true;
}
function deepEquals(a, b) {
if (a === b) {
// Check for -0.
if (a === 0) return (1 / a) === (1 / b);
return true;
}
if (typeof a !== typeof b) return false;
if (typeof a === "number") return isNaN(a) && isNaN(b);
if (typeof a !== "object" && typeof a !== "function") return false;
// Neither a nor b is primitive.
var objectClass = classOf(a);
if (objectClass !== classOf(b)) return false;
if (objectClass === "RegExp") {
// For RegExp, just compare pattern and flags using its toString.
return RegExpPrototypeToString.call(a) ===
RegExpPrototypeToString.call(b);
}
// Functions are only identical to themselves.
if (objectClass === "Function") return false;
if (objectClass === "Array") {
var elementCount = 0;
if (a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; i++) {
if (!deepEquals(a[i], b[i])) return false;
}
return true;
}
if (objectClass === "String" || objectClass === "Number" ||
objectClass === "BigInt" || objectClass === "Boolean" ||
objectClass === "Date") {
if (ValueOf(a) !== ValueOf(b)) return false;
}
return deepObjectEquals(a, b);
}
assertEquals = function assertEquals(expected, found, name_opt) {
if (!deepEquals(found, expected)) {
fail(PrettyPrint(expected), found, name_opt);
}
};
})();
This diff is collapsed.
......@@ -14,7 +14,7 @@ class VariantsGenerator(testsuite.VariantsGenerator):
class TestSuite(testsuite.TestSuite):
SUB_TESTS = ( 'json', 'parser', 'regexp', 'multi_return', 'wasm',
SUB_TESTS = ( 'json', 'parser', 'regexp_builtins', 'regexp', 'multi_return', 'wasm',
'wasm_async', 'wasm_call', 'wasm_code', 'wasm_compile',
'wasm_data_section', 'wasm_function_sigs_section',
'wasm_globals_section', 'wasm_imports_section', 'wasm_memory_section',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment