Commit cbe42346 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm][fuzzer] Test combinations of Turbofan and Liftoff

Currently the fuzzer only tests Turbofan and Liftoff in isolation. In
order to test that both tiers use the same ABI, it should also test
calls from one tier to the other.
This CL introduces a new flag which controls which function will be
compiled by which tier, and uses that in the fuzzer.

R=ahaas@chromium.org

Bug: chromium:862931, v8:6600
Change-Id: I450b906700972cfdb496b1734faed9f8208d652f
Reviewed-on: https://chromium-review.googlesource.com/1134775
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54409}
parent a0dbaf59
...@@ -567,6 +567,10 @@ DEFINE_DEBUG_BOOL(wasm_break_on_decoder_error, false, ...@@ -567,6 +567,10 @@ DEFINE_DEBUG_BOOL(wasm_break_on_decoder_error, false,
"debug break when wasm decoder encounters an error") "debug break when wasm decoder encounters an error")
DEFINE_BOOL(wasm_trace_memory, false, DEFINE_BOOL(wasm_trace_memory, false,
"print all memory updates performed in wasm code") "print all memory updates performed in wasm code")
// Fuzzers use {wasm_tier_mask_for_testing} together with {liftoff} and
// {no_wasm_tier_up} to force some functions to be compiled with Turbofan.
DEFINE_INT(wasm_tier_mask_for_testing, 0,
"bitmask of functions to compile with TurboFan instead of Liftoff")
DEFINE_BOOL(validate_asm, true, "validate asm.js modules before compiling") DEFINE_BOOL(validate_asm, true, "validate asm.js modules before compiling")
DEFINE_BOOL(suppress_asm_messages, false, DEFINE_BOOL(suppress_asm_messages, false,
......
...@@ -54,6 +54,10 @@ WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate, ModuleEnv* env, ...@@ -54,6 +54,10 @@ WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate, ModuleEnv* env,
// 1) asm-specific opcodes are not implemented, and // 1) asm-specific opcodes are not implemented, and
// 2) tier-up does not work with lazy compilation. // 2) tier-up does not work with lazy compilation.
if (env->module->origin == kAsmJsOrigin) mode = CompilationMode::kTurbofan; if (env->module->origin == kAsmJsOrigin) mode = CompilationMode::kTurbofan;
if (V8_UNLIKELY(FLAG_wasm_tier_mask_for_testing) && index < 32 &&
(FLAG_wasm_tier_mask_for_testing & (1 << index))) {
mode = CompilationMode::kTurbofan;
}
SwitchMode(mode); SwitchMode(mode);
} }
......
...@@ -269,6 +269,10 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data, ...@@ -269,6 +269,10 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
int32_t num_args = 0; int32_t num_args = 0;
std::unique_ptr<WasmValue[]> interpreter_args; std::unique_ptr<WasmValue[]> interpreter_args;
std::unique_ptr<Handle<Object>[]> compiler_args; std::unique_ptr<Handle<Object>[]> compiler_args;
// The first byte builds the bitmask to control which function will be
// compiled with Turbofan and which one with Liftoff.
uint8_t tier_mask = data.is_empty() ? 0 : data[0];
if (!data.is_empty()) data += 1;
if (!GenerateModule(i_isolate, &zone, data, buffer, num_args, if (!GenerateModule(i_isolate, &zone, data, buffer, num_args,
interpreter_args, compiler_args)) { interpreter_args, compiler_args)) {
return 0; return 0;
...@@ -282,7 +286,11 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data, ...@@ -282,7 +286,11 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
// Compile with Turbofan here. Liftoff will be tested later. // Compile with Turbofan here. Liftoff will be tested later.
MaybeHandle<WasmModuleObject> compiled_module; MaybeHandle<WasmModuleObject> compiled_module;
{ {
FlagScope<bool> no_liftoff(&FLAG_liftoff, false); // Explicitly enable Liftoff, disable tiering and set the tier_mask. This
// way, we deterministically test a combination of Liftoff and Turbofan.
FlagScope<bool> liftoff(&FLAG_liftoff, true);
FlagScope<bool> no_tier_up(&FLAG_wasm_tier_up, false);
FlagScope<int> tier_mask_scope(&FLAG_wasm_tier_mask_for_testing, tier_mask);
compiled_module = i_isolate->wasm_engine()->SyncCompile( compiled_module = i_isolate->wasm_engine()->SyncCompile(
i_isolate, &interpreter_thrower, wire_bytes); i_isolate, &interpreter_thrower, wire_bytes);
} }
...@@ -327,59 +335,32 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data, ...@@ -327,59 +335,32 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
bool expect_exception = bool expect_exception =
result_interpreter == static_cast<int32_t>(0xDEADBEEF); result_interpreter == static_cast<int32_t>(0xDEADBEEF);
int32_t result_turbofan; int32_t result_compiled;
{ {
ErrorThrower compiler_thrower(i_isolate, "Turbofan"); ErrorThrower compiler_thrower(i_isolate, "Compile");
MaybeHandle<WasmInstanceObject> compiled_instance = MaybeHandle<WasmInstanceObject> compiled_instance =
i_isolate->wasm_engine()->SyncInstantiate( i_isolate->wasm_engine()->SyncInstantiate(
i_isolate, &compiler_thrower, compiled_module.ToHandleChecked(), i_isolate, &compiler_thrower, compiled_module.ToHandleChecked(),
MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>()); MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>());
DCHECK(!compiler_thrower.error()); DCHECK(!compiler_thrower.error());
result_turbofan = testing::CallWasmFunctionForTesting( result_compiled = testing::CallWasmFunctionForTesting(
i_isolate, compiled_instance.ToHandleChecked(), &compiler_thrower, i_isolate, compiled_instance.ToHandleChecked(), &compiler_thrower,
"main", num_args, compiler_args.get()); "main", num_args, compiler_args.get());
} }
// The WebAssembly spec allows the sign bit of NaN to be non-deterministic. // The WebAssembly spec allows the sign bit of NaN to be non-deterministic.
// This sign bit may cause result_interpreter to be different than // This sign bit may cause result_interpreter to be different than
// result_turbofan. Therefore we do not check the equality of the results // result_compiled. Therefore we do not check the equality of the results
// if the execution may have produced a NaN at some point. // if the execution may have produced a NaN at some point.
if (!possible_nondeterminism) { if (!possible_nondeterminism) {
if (expect_exception != i_isolate->has_pending_exception()) { if (expect_exception != i_isolate->has_pending_exception()) {
const char* exception_text[] = {"no exception", "exception"}; const char* exception_text[] = {"no exception", "exception"};
FATAL("interpreter: %s; turbofan: %s", exception_text[expect_exception], FATAL("interpreter: %s; compiled: %s", exception_text[expect_exception],
exception_text[i_isolate->has_pending_exception()]);
}
if (!expect_exception) CHECK_EQ(result_interpreter, result_turbofan);
}
// Clear any pending exceptions for the next run.
i_isolate->clear_pending_exception();
int32_t result_liftoff;
{
FlagScope<bool> liftoff(&FLAG_liftoff, true);
FlagScope<bool> no_tier_up(&FLAG_wasm_tier_up, false);
ErrorThrower compiler_thrower(i_isolate, "Liftoff");
// Re-compile with Liftoff.
MaybeHandle<WasmInstanceObject> compiled_instance =
testing::CompileAndInstantiateForTesting(i_isolate, &compiler_thrower,
wire_bytes);
DCHECK(!compiler_thrower.error());
result_liftoff = testing::CallWasmFunctionForTesting(
i_isolate, compiled_instance.ToHandleChecked(), &compiler_thrower,
"main", num_args, compiler_args.get());
}
if (!possible_nondeterminism) {
if (expect_exception != i_isolate->has_pending_exception()) {
const char* exception_text[] = {"no exception", "exception"};
FATAL("interpreter: %s; liftoff: %s", exception_text[expect_exception],
exception_text[i_isolate->has_pending_exception()]); exception_text[i_isolate->has_pending_exception()]);
} }
if (!expect_exception) CHECK_EQ(result_interpreter, result_liftoff); if (!expect_exception) CHECK_EQ(result_interpreter, result_compiled);
} }
// Cleanup any pending exception. // Cleanup any pending exception.
......
...@@ -825,6 +825,7 @@ ...@@ -825,6 +825,7 @@
# TODO(clemensh): Implement on all other platforms (crbug.com/v8/6600). # TODO(clemensh): Implement on all other platforms (crbug.com/v8/6600).
['arch != x64 and arch != ia32', { ['arch != x64 and arch != ia32', {
'wasm/liftoff': [SKIP], 'wasm/liftoff': [SKIP],
'wasm/tier-up-testing-flag': [SKIP],
}], # arch != x64 and arch != ia32 }], # arch != x64 and arch != ia32
############################################################################## ##############################################################################
......
// 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.
// Flags: --allow-natives-syntax --liftoff --no-future --no-wasm-tier-up
// Compile functions 0 and 2 with Turbofan, the rest with Liftoff:
// Flags: --wasm-tier-mask-for-testing=5
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
const num_functions = 5;
function create_builder() {
const builder = new WasmModuleBuilder();
for (let i = 0; i < num_functions; ++i) {
builder.addFunction('f' + i, kSig_i_v)
.addBody(wasmI32Const(i))
.exportFunc();
}
return builder;
}
function check(instance) {
for (let i = 0; i < num_functions; ++i) {
const expect_liftoff = i != 0 && i != 2;
assertEquals(
expect_liftoff, %IsLiftoffFunction(instance.exports['f' + i]),
'function ' + i);
}
}
(function testTierTestingFlag() {
print(arguments.callee.name);
const instance = create_builder().instantiate();
check(instance);
})();
async function testTierTestingFlag() {
print(arguments.callee.name);
const instance = await create_builder().asyncInstantiate();
check(instance);
}
assertPromiseResult(testTierTestingFlag());
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