[wasm] Implementation of code flushing with explicit call

This CL introduces an initial implementation of code flushing, which
can be triggered from JavaScript with an explicit runtime call. The
runtime call allows easier testing. So far all Liftoff code gets
deallocated at a code flushing event. Experiments will show if this is
a good strategy.

Bug: chromium:1407659
Change-Id: I2c19a25ab5da1cf3b6d027d14cc6e719f33e300b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4171627
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85365}
This commit is contained in:
Andreas Haas 2023-01-18 13:21:16 +01:00 committed by V8 LUCI CQ
parent b0cd98500d
commit 10f3039bdb
8 changed files with 76 additions and 0 deletions

View File

@ -489,6 +489,19 @@ RUNTIME_FUNCTION(Runtime_IsTurboFanFunction) {
return isolate->heap()->ToBoolean(code && code->is_turbofan());
}
RUNTIME_FUNCTION(Runtime_IsUncompiledWasmFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
Handle<JSFunction> function = args.at<JSFunction>(0);
CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
Handle<WasmExportedFunction> exp_fun =
Handle<WasmExportedFunction>::cast(function);
wasm::NativeModule* native_module =
exp_fun->instance().module_object().native_module();
uint32_t func_index = exp_fun->function_index();
return isolate->heap()->ToBoolean(!native_module->HasCode(func_index));
}
RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
DCHECK_EQ(1, args.length());
DisallowGarbageCollection no_gc;
@ -510,5 +523,10 @@ RUNTIME_FUNCTION(Runtime_SetWasmGCEnabled) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_FlushWasmCode) {
wasm::GetWasmEngine()->FlushCode();
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8

View File

@ -654,6 +654,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_WASM_TEST(F, I) \
F(DeserializeWasmModule, 2, 1) \
F(DisallowWasmCodegen, 1, 1) \
F(FlushWasmCode, 0, 1) \
F(FreezeWasmLazyCompilation, 1, 1) \
F(GetWasmExceptionTagId, 2, 1) \
F(GetWasmExceptionValues, 1, 1) \
@ -662,6 +663,7 @@ namespace internal {
F(IsLiftoffFunction, 1, 1) \
F(IsTurboFanFunction, 1, 1) \
F(IsWasmDebugFunction, 1, 1) \
F(IsUncompiledWasmFunction, 1, 1) \
F(IsThreadInWasm, 0, 1) \
F(IsWasmCode, 1, 1) \
F(IsWasmTrapHandlerEnabled, 0, 1) \

View File

@ -2230,6 +2230,10 @@ bool ShouldRemoveCode(WasmCode* code, NativeModule::RemoveFilter filter) {
code->for_debugging()) {
return false;
}
if (filter == NativeModule::RemoveFilter::kRemoveLiftoffCode &&
!code->is_liftoff()) {
return false;
}
return true;
}
} // namespace

View File

@ -794,6 +794,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
enum class RemoveFilter {
kRemoveDebugCode,
kRemoveNonDebugCode,
kRemoveLiftoffCode,
kRemoveAllCode,
};
// Remove all compiled code from the {NativeModule} and replace it with

View File

@ -893,6 +893,14 @@ Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
return module_object;
}
void WasmEngine::FlushCode() {
for (auto& entry : native_modules_) {
NativeModule* native_module = entry.first;
native_module->RemoveCompiledCode(
NativeModule::RemoveFilter::kRemoveLiftoffCode);
}
}
std::shared_ptr<CompilationStatistics>
WasmEngine::GetOrCreateTurboStatistics() {
base::MutexGuard guard(&mutex_);

View File

@ -220,6 +220,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
Isolate* isolate, std::shared_ptr<NativeModule> shared_module,
base::Vector<const char> source_url);
void FlushCode();
AccountingAllocator* allocator() { return &allocator_; }
// Compilation statistics for TurboFan compilations. Returns a shared_ptr

View File

@ -989,6 +989,7 @@
# multiple isolates, as dynamic tiering relies on a array shared
# in the module, that can be modified by all instances.
'wasm/wasm-dynamic-tiering': [SKIP],
'wasm/code-flushing': [SKIP],
# The test relies on precise switching of code kinds of wasm functions. With
# multiple isolates that share the wasm functions, the precise switching is

View File

@ -0,0 +1,40 @@
// Copyright 2023 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: --expose-wasm --allow-natives-syntax --wasm-lazy-compilation
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
const builder = new WasmModuleBuilder();
builder.addFunction('f1', kSig_i_i).addBody([kExprLocalGet, 0]).exportFunc();
builder.addFunction('f2', kSig_i_i).addBody([kExprLocalGet, 0]).exportFunc();
builder.addFunction('f3', kSig_i_i).addBody([kExprLocalGet, 0]).exportFunc();
const instance = builder.instantiate();
instance.exports.f1(1);
instance.exports.f2(2);
instance.exports.f3(3);
assertTrue(%IsLiftoffFunction(instance.exports.f1));
assertTrue(%IsLiftoffFunction(instance.exports.f2));
assertTrue(%IsLiftoffFunction(instance.exports.f3));
%FlushWasmCode();
assertTrue(%IsUncompiledWasmFunction(instance.exports.f1));
assertTrue(%IsUncompiledWasmFunction(instance.exports.f2));
assertTrue(%IsUncompiledWasmFunction(instance.exports.f3));
instance.exports.f1(1);
instance.exports.f2(2);
instance.exports.f3(3);
%WasmTierUpFunction(instance.exports.f3);
%FlushWasmCode();
assertTrue(%IsUncompiledWasmFunction(instance.exports.f1));
assertTrue(%IsUncompiledWasmFunction(instance.exports.f2));
assertTrue(%IsTurboFanFunction(instance.exports.f3));