[wasm] Add support to tier down/up Wasm NativeModule

This is the first part of switching between Liftoff and Turbofan in
debugging Wasm. In this CL, we implemented the logic to tier down/up all
functions in module.

Bug: v8:9654
Change-Id: Ia25103ca29963afa103c124ff5f159f197c2b2b0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1970470
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65529}
This commit is contained in:
Z Nguyen-Huu 2019-12-19 10:13:23 -08:00 committed by Commit Bot
parent 2e7eb2f108
commit 6ce3046e2b
6 changed files with 119 additions and 3 deletions

View File

@ -1377,6 +1377,26 @@ RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierDownModule) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
auto* native_module = instance->module_object().native_module();
native_module->TierDown(isolate);
CHECK(!native_module->compilation_state()->failed());
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierUpModule) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
auto* native_module = instance->module_object().native_module();
native_module->TierUp(isolate);
CHECK(!native_module->compilation_state()->failed());
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());

View File

@ -536,7 +536,9 @@ namespace internal {
F(WasmGetNumberOfInstances, 1, 1) \
F(WasmNumInterpretedCalls, 1, 1) \
F(WasmNumCodeSpaces, 1, 1) \
F(WasmTierDownModule, 1, 1) \
F(WasmTierUpFunction, 2, 1) \
F(WasmTierUpModule, 1, 1) \
F(WasmTraceMemory, 1, 1) \
I(DeoptimizeNow, 0, 1)

View File

@ -1046,11 +1046,14 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
ExecutionTier::kLiftoff < ExecutionTier::kTurbofan,
"Assume an order on execution tiers");
// Update code table but avoid to fall back to less optimized code. We use
// the new code if it was compiled with a higher tier.
// Unless tier down to Liftoff: update code table but avoid to fall back to
// less optimized code. We use the new code if it was compiled with a higher
// tier.
uint32_t slot_idx = code->index() - module_->num_imported_functions;
WasmCode* prior_code = code_table_[slot_idx];
bool update_code_table = !prior_code || prior_code->tier() < code->tier();
bool update_code_table =
tier_down_ ? !prior_code || code->tier() == ExecutionTier::kLiftoff
: !prior_code || prior_code->tier() < code->tier();
if (update_code_table) {
code_table_[slot_idx] = code.get();
if (prior_code) {
@ -1807,6 +1810,34 @@ bool NativeModule::IsRedirectedToInterpreter(uint32_t func_index) {
return has_interpreter_redirection(func_index);
}
void NativeModule::TierDown(Isolate* isolate) {
// Set the flag.
tier_down_ = true;
// Tier down all functions.
// TODO(duongn): parallelize this eventually.
for (uint32_t index = module_->num_imported_functions;
index < num_functions(); index++) {
isolate->wasm_engine()->CompileFunction(isolate, this, index,
ExecutionTier::kLiftoff);
DCHECK(!compilation_state()->failed());
}
}
void NativeModule::TierUp(Isolate* isolate) {
// Set the flag.
tier_down_ = false;
// Tier up all functions.
// TODO(duongn): parallelize this eventually.
for (uint32_t index = module_->num_imported_functions;
index < num_functions(); index++) {
isolate->wasm_engine()->CompileFunction(isolate, this, index,
ExecutionTier::kTurbofan);
DCHECK(!compilation_state()->failed());
}
}
void NativeModule::FreeCode(Vector<WasmCode* const> codes) {
// Free the code space.
code_allocator_.FreeCode(codes);

View File

@ -551,6 +551,11 @@ class V8_EXPORT_PRIVATE NativeModule final {
// by publishing an entry stub with the {Kind::kInterpreterEntry} code kind.
bool IsRedirectedToInterpreter(uint32_t func_index);
// Sets the flag, triggers recompilation of all methods to tier down or up,
// waits for that to complete.
void TierDown(Isolate* isolate);
void TierUp(Isolate* isolate);
// Free a set of functions of this module. Uncommits whole pages if possible.
// The given vector must be ordered by the instruction start address, and all
// {WasmCode} objects must not be used any more.
@ -686,6 +691,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
// Data (especially jump table) per code space.
std::vector<CodeSpaceData> code_space_data_;
bool tier_down_ = false;
// End of fields protected by {allocation_mutex_}.
//////////////////////////////////////////////////////////////////////////////

View File

@ -1096,6 +1096,7 @@
['arch != x64 and arch != ia32 and arch != arm64 and arch != arm', {
'wasm/liftoff': [SKIP],
'wasm/tier-up-testing-flag': [SKIP],
'wasm/tier-down-to-liftoff': [SKIP],
}], # arch != x64 and arch != ia32 and arch != arm64 and arch != arm
##############################################################################

View File

@ -0,0 +1,56 @@
// Copyright 2019 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 --wasm-tier-up
load('test/mjsunit/wasm/wasm-module-builder.js');
const num_functions = 2;
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) {
%WasmTierUpFunction(instance, i);
assertFalse(%IsLiftoffFunction(instance.exports['f' + i]));
}
%WasmTierDownModule(instance);
for (let i = 0; i < num_functions; ++i) {
assertTrue(%IsLiftoffFunction(instance.exports['f' + i]));
}
for (let i = 0; i < num_functions; ++i) {
%WasmTierUpFunction(instance, i);
assertTrue(%IsLiftoffFunction(instance.exports['f' + i]));
}
%WasmTierUpModule(instance);
for (let i = 0; i < num_functions; ++i) {
assertFalse(%IsLiftoffFunction(instance.exports['f' + i]));
}
}
(function testTierDownToLiftoff() {
print(arguments.callee.name);
const instance = create_builder().instantiate();
check(instance);
})();
async function testTierDownToLiftoffAsync() {
print(arguments.callee.name);
const instance = await create_builder().asyncInstantiate();
check(instance);
}
assertPromiseResult(testTierDownToLiftoffAsync());