[wasm] Wait until top tier finished before serializing
We only want to serialize TurboFan code, because Liftoff code could contain breakpoints, and we start thinking about embedding other non-relocatable constants. Thus, wait until top-tier compilation finished before triggering serialization. A follow-up CL will make serialization fail if any Liftoff code is encountered. R=ahaas@chromium.org Bug: v8:10777 Change-Id: I73d6c2d868545fcd4069a8cf9850ca7fca375ecb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2349293 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#69332}
This commit is contained in:
parent
5ec483c38e
commit
8d3ababba4
@ -1326,30 +1326,29 @@ RUNTIME_FUNCTION(Runtime_SerializeDeserializeNow) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
// Take a compiled wasm module and serialize it into an array buffer, which is
|
||||
// then returned.
|
||||
// Wait until the given module is fully tiered up, then serialize it into an
|
||||
// array buffer.
|
||||
RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
|
||||
|
||||
wasm::NativeModule* native_module = module_obj->native_module();
|
||||
native_module->compilation_state()->WaitForTopTierFinished();
|
||||
DCHECK(!native_module->compilation_state()->failed());
|
||||
|
||||
wasm::WasmSerializer wasm_serializer(native_module);
|
||||
size_t byte_length = wasm_serializer.GetSerializedNativeModuleSize();
|
||||
|
||||
MaybeHandle<JSArrayBuffer> result =
|
||||
isolate->factory()->NewJSArrayBufferAndBackingStore(
|
||||
byte_length, InitializedFlag::kUninitialized);
|
||||
Handle<JSArrayBuffer> array_buffer =
|
||||
isolate->factory()
|
||||
->NewJSArrayBufferAndBackingStore(byte_length,
|
||||
InitializedFlag::kUninitialized)
|
||||
.ToHandleChecked();
|
||||
|
||||
Handle<JSArrayBuffer> array_buffer;
|
||||
if (result.ToHandle(&array_buffer) &&
|
||||
wasm_serializer.SerializeNativeModule(
|
||||
{reinterpret_cast<uint8_t*>(array_buffer->backing_store()),
|
||||
byte_length})) {
|
||||
return *array_buffer;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
CHECK(wasm_serializer.SerializeNativeModule(
|
||||
{static_cast<uint8_t*>(array_buffer->backing_store()), byte_length}));
|
||||
return *array_buffer;
|
||||
}
|
||||
|
||||
// Take an array buffer and attempt to reconstruct a compiled wasm module.
|
||||
|
@ -1035,6 +1035,8 @@ auto Module::serialize() const -> vec<byte_t> {
|
||||
impl(this)->v8_object()->native_module();
|
||||
i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
|
||||
size_t binary_size = wire_bytes.size();
|
||||
// We can only serialize after top-tier compilation (TurboFan) finished.
|
||||
native_module->compilation_state()->WaitForTopTierFinished();
|
||||
i::wasm::WasmSerializer serializer(native_module);
|
||||
size_t serial_size = serializer.GetSerializedNativeModuleSize();
|
||||
size_t size_size = i::wasm::LEBHelper::sizeof_u64v(binary_size);
|
||||
|
@ -101,7 +101,7 @@ enum class CompilationEvent : uint8_t {
|
||||
|
||||
// The implementation of {CompilationState} lives in module-compiler.cc.
|
||||
// This is the PIMPL interface to that private class.
|
||||
class CompilationState {
|
||||
class V8_EXPORT_PRIVATE CompilationState {
|
||||
public:
|
||||
using callback_t = std::function<void(CompilationEvent)>;
|
||||
|
||||
@ -113,15 +113,17 @@ class CompilationState {
|
||||
|
||||
void SetWireBytesStorage(std::shared_ptr<WireBytesStorage>);
|
||||
|
||||
V8_EXPORT_PRIVATE std::shared_ptr<WireBytesStorage> GetWireBytesStorage()
|
||||
const;
|
||||
std::shared_ptr<WireBytesStorage> GetWireBytesStorage() const;
|
||||
|
||||
void AddCallback(callback_t);
|
||||
|
||||
// Wait until top tier finished, or compilation failed (to avoid deadlocks).
|
||||
void WaitForTopTierFinished();
|
||||
|
||||
bool failed() const;
|
||||
V8_EXPORT_PRIVATE bool baseline_compilation_finished() const;
|
||||
V8_EXPORT_PRIVATE bool top_tier_compilation_finished() const;
|
||||
V8_EXPORT_PRIVATE bool recompilation_finished() const;
|
||||
bool baseline_compilation_finished() const;
|
||||
bool top_tier_compilation_finished() const;
|
||||
bool recompilation_finished() const;
|
||||
|
||||
// Override {operator delete} to avoid implicit instantiation of {operator
|
||||
// delete} with {size_t} argument. The {size_t} argument would be incorrect.
|
||||
|
@ -688,6 +688,17 @@ void CompilationState::AddCallback(CompilationState::callback_t callback) {
|
||||
return Impl(this)->AddCallback(std::move(callback));
|
||||
}
|
||||
|
||||
void CompilationState::WaitForTopTierFinished() {
|
||||
auto top_tier_finished_semaphore = std::make_shared<base::Semaphore>(0);
|
||||
AddCallback([top_tier_finished_semaphore](CompilationEvent event) {
|
||||
if (event == CompilationEvent::kFailedCompilation ||
|
||||
event == CompilationEvent::kFinishedTopTierCompilation) {
|
||||
top_tier_finished_semaphore->Signal();
|
||||
}
|
||||
});
|
||||
top_tier_finished_semaphore->Wait();
|
||||
}
|
||||
|
||||
bool CompilationState::failed() const { return Impl(this)->failed(); }
|
||||
|
||||
bool CompilationState::baseline_compilation_finished() const {
|
||||
|
@ -268,10 +268,11 @@ ZoneBuffer GetValidCompiledModuleBytes(Zone* zone, ZoneBuffer wire_bytes) {
|
||||
// Serialize the NativeModule.
|
||||
std::shared_ptr<NativeModule> native_module = tester.native_module();
|
||||
CHECK(native_module);
|
||||
native_module->compilation_state()->WaitForTopTierFinished();
|
||||
i::wasm::WasmSerializer serializer(native_module.get());
|
||||
size_t size = serializer.GetSerializedNativeModuleSize();
|
||||
std::vector<byte> buffer(size);
|
||||
CHECK(serializer.SerializeNativeModule({buffer.data(), size}));
|
||||
CHECK(serializer.SerializeNativeModule(VectorOf(buffer)));
|
||||
ZoneBuffer result(zone, size);
|
||||
result.write(buffer.data(), size);
|
||||
return result;
|
||||
|
@ -148,6 +148,10 @@ class WasmSerializationTest {
|
||||
// Check that the native module exists at this point.
|
||||
CHECK(weak_native_module.lock());
|
||||
|
||||
auto* native_module = module_object->native_module();
|
||||
native_module->compilation_state()->WaitForTopTierFinished();
|
||||
DCHECK(!native_module->compilation_state()->failed());
|
||||
|
||||
v8::Local<v8::Object> v8_module_obj =
|
||||
v8::Utils::ToLocal(Handle<JSObject>::cast(module_object));
|
||||
CHECK(v8_module_obj->IsWasmModuleObject());
|
||||
@ -163,6 +167,7 @@ class WasmSerializationTest {
|
||||
wire_bytes_ = {bytes_copy, uncompiled_bytes.size()};
|
||||
// keep alive data_ until the end
|
||||
data_ = compiled_module.Serialize();
|
||||
CHECK_LT(0, data_.size);
|
||||
}
|
||||
// Dispose of serialization isolate to destroy the reference to the
|
||||
// NativeModule, which removes it from the module cache in the wasm engine
|
||||
|
Loading…
Reference in New Issue
Block a user