Skip to content

Commit 69fa5f7

Browse files
MayaLekovaCommit Bot
authored andcommitted
Revert "[wasm] Share native modules compiled from the same bytes"
This reverts commit c509bb8. Reason for revert: Breaks arm64 - sim - MSAN, see https://ci.chromium.org/p/v8/builders/ci/V8%20Linux%20-%20arm64%20-%20sim%20-%20MSAN/30050 Original change's description: > [wasm] Share native modules compiled from the same bytes > > Cache native modules in the wasm engine by their wire bytes. This is to > prepare for sharing {Script} objects between multiple {WasmModuleObject} > created from the same bytes. This also saves unnecessary compilation > time and memory. > > R=​clemensb@chromium.org > > Bug: v8:6847 > Change-Id: Iad5f70efbfe3f0f134dcb851edbcec50691677e0 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1916603 > Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> > Reviewed-by: Clemens Backes <clemensb@chromium.org> > Cr-Commit-Position: refs/heads/master@{#65296} TBR=clemensb@chromium.org,thibaudm@chromium.org Change-Id: I908b0f59bce26678d0b5d7fddc986384c40b4709 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: v8:6847 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1946334 Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#65297}
1 parent c509bb8 commit 69fa5f7

10 files changed

Lines changed: 59 additions & 178 deletions

src/wasm/module-compiler.cc

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,22 +1356,15 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
13561356
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
13571357
Handle<FixedArray>* export_wrappers_out) {
13581358
const WasmModule* wasm_module = module.get();
1359-
std::shared_ptr<NativeModule> native_module =
1360-
isolate->wasm_engine()->MaybeGetNativeModule(wasm_module->origin,
1361-
wire_bytes.module_bytes());
1362-
if (native_module) {
1363-
// TODO(thibaudm): Look into sharing export wrappers.
1364-
CompileJsToWasmWrappers(isolate, wasm_module, export_wrappers_out);
1365-
return native_module;
1366-
}
1367-
13681359
TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
13691360
isolate->counters(), wasm_module->origin, wasm_compile, module_time));
13701361

13711362
// Embedder usage count for declared shared memories.
13721363
if (wasm_module->has_shared_memory) {
13731364
isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
13741365
}
1366+
// TODO(wasm): only save the sections necessary to deserialize a
1367+
// {WasmModule}. E.g. function bodies could be omitted.
13751368
OwnedVector<uint8_t> wire_bytes_copy =
13761369
OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
13771370

@@ -1380,13 +1373,11 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
13801373
size_t code_size_estimate =
13811374
wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get(),
13821375
uses_liftoff);
1383-
native_module = isolate->wasm_engine()->NewNativeModule(
1376+
auto native_module = isolate->wasm_engine()->NewNativeModule(
13841377
isolate, enabled, std::move(module), code_size_estimate);
13851378
native_module->SetWireBytes(std::move(wire_bytes_copy));
13861379

13871380
CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
1388-
isolate->wasm_engine()->UpdateNativeModuleCache(native_module,
1389-
thrower->error());
13901381
if (thrower->error()) return {};
13911382

13921383
Impl(native_module->compilation_state())
@@ -2227,7 +2218,9 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
22272218
job_->module_object_ =
22282219
job_->isolate_->global_handles()->Create(*result.ToHandleChecked());
22292220
job_->native_module_ = job_->module_object_->shared_native_module();
2230-
job_->wire_bytes_ = ModuleWireBytes(job_->native_module_->wire_bytes());
2221+
auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
2222+
job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
2223+
job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
22312224
job_->FinishCompile();
22322225
return true;
22332226
}

src/wasm/wasm-engine.cc

Lines changed: 5 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "src/objects/heap-number.h"
1414
#include "src/objects/js-promise.h"
1515
#include "src/objects/objects-inl.h"
16-
#include "src/strings/string-hasher-inl.h"
1716
#include "src/utils/ostreams.h"
1817
#include "src/wasm/function-compiler.h"
1918
#include "src/wasm/module-compiler.h"
@@ -307,6 +306,11 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
307306
CreateWasmScript(isolate, bytes, native_module->module()->source_map_url,
308307
native_module->module()->name);
309308

309+
// Create the module object.
310+
// TODO(clemensb): For the same module (same bytes / same hash), we should
311+
// only have one WasmModuleObject. Otherwise, we might only set
312+
// breakpoints on a (potentially empty) subset of the instances.
313+
310314
// Create the compiled module object and populate with compiled functions
311315
// and information needed at instantiation time. This object needs to be
312316
// serializable. Instantiation may occur off a deserialized version of this
@@ -691,42 +695,6 @@ std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
691695
return native_module;
692696
}
693697

694-
std::shared_ptr<NativeModule> WasmEngine::MaybeGetNativeModule(
695-
ModuleOrigin origin, Vector<const uint8_t> wire_bytes) {
696-
if (origin != kWasmOrigin) return nullptr;
697-
base::MutexGuard lock(&mutex_);
698-
while (true) {
699-
auto it = native_module_cache_.find(wire_bytes);
700-
if (it == native_module_cache_.end()) {
701-
// Insert an empty entry to let other threads know that this
702-
// {NativeModule} is already being created on another thread.
703-
native_module_cache_.emplace(wire_bytes, std::weak_ptr<NativeModule>());
704-
return nullptr;
705-
}
706-
if (auto shared_native_module = it->second.lock()) {
707-
return shared_native_module;
708-
}
709-
cache_cv_.Wait(&mutex_);
710-
}
711-
}
712-
713-
void WasmEngine::UpdateNativeModuleCache(
714-
std::shared_ptr<NativeModule> native_module, bool error) {
715-
DCHECK_NOT_NULL(native_module);
716-
if (native_module->module()->origin != kWasmOrigin) return;
717-
Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
718-
base::MutexGuard lock(&mutex_);
719-
auto it = native_module_cache_.find(wire_bytes);
720-
DCHECK_NE(it, native_module_cache_.end());
721-
DCHECK_NULL(it->second.lock());
722-
// The lifetime of the temporary entry's bytes is unknown. Use the new native
723-
// module's owned copy of the bytes for the key instead.
724-
native_module_cache_.erase(it);
725-
native_module_cache_.emplace(wire_bytes,
726-
error ? nullptr : std::move(native_module));
727-
cache_cv_.NotifyAll();
728-
}
729-
730698
void WasmEngine::FreeNativeModule(NativeModule* native_module) {
731699
base::MutexGuard guard(&mutex_);
732700
auto it = native_modules_.find(native_module);
@@ -767,14 +735,6 @@ void WasmEngine::FreeNativeModule(NativeModule* native_module) {
767735
TRACE_CODE_GC("Native module %p died, reducing dead code objects to %zu.\n",
768736
native_module, current_gc_info_->dead_code.size());
769737
}
770-
auto cache_it = native_module_cache_.find(native_module->wire_bytes());
771-
// Not all native modules are stored in the cache currently. In particular
772-
// asynchronous compilation and asmjs compilation results are not. So make
773-
// sure that we only delete existing and expired entries.
774-
if (cache_it != native_module_cache_.end() && cache_it->second.expired()) {
775-
native_module_cache_.erase(cache_it);
776-
cache_cv_.NotifyAll();
777-
}
778738
native_modules_.erase(it);
779739
}
780740

@@ -1012,13 +972,6 @@ std::shared_ptr<WasmEngine> WasmEngine::GetWasmEngine() {
1012972
return *GetSharedWasmEngine();
1013973
}
1014974

1015-
size_t WasmEngine::WireBytesHasher::operator()(
1016-
const Vector<const uint8_t>& bytes) const {
1017-
return StringHasher::HashSequentialString(
1018-
reinterpret_cast<const char*>(bytes.begin()), bytes.length(),
1019-
kZeroHashSeed);
1020-
}
1021-
1022975
// {max_mem_pages} is declared in wasm-limits.h.
1023976
uint32_t max_mem_pages() {
1024977
STATIC_ASSERT(kV8MaxWasmMemoryPages <= kMaxUInt32);

src/wasm/wasm-engine.h

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
#define V8_WASM_WASM_ENGINE_H_
77

88
#include <memory>
9-
#include <unordered_map>
109
#include <unordered_set>
1110

12-
#include "src/base/platform/condition-variable.h"
13-
#include "src/base/platform/mutex.h"
1411
#include "src/tasks/cancelable-task.h"
1512
#include "src/wasm/wasm-code-manager.h"
1613
#include "src/wasm/wasm-tier.h"
@@ -185,22 +182,6 @@ class V8_EXPORT_PRIVATE WasmEngine {
185182
Isolate* isolate, const WasmFeatures& enabled_features,
186183
std::shared_ptr<const WasmModule> module, size_t code_size_estimate);
187184

188-
// Try getting a cached {NativeModule}. The {wire_bytes}' underlying array
189-
// should be valid at least until the next call to {UpdateNativeModuleCache}.
190-
// Return nullptr if no {NativeModule} exists for these bytes. In this case,
191-
// an empty entry is added to let other threads know that a {NativeModule} for
192-
// these bytes is currently being created. The caller should eventually call
193-
// {UpdateNativeModuleCache} to update the entry and wake up other threads.
194-
std::shared_ptr<NativeModule> MaybeGetNativeModule(
195-
ModuleOrigin origin, Vector<const uint8_t> wire_bytes);
196-
197-
// Update the temporary cache entry inserted by {MaybeGetNativeModule}.
198-
// Replace the key so that it uses the native module's owned copy of the
199-
// bytes, and set the value to the new native module, or {nullptr} if {error}
200-
// is true. Wake up the threads waiting for this {NativeModule}.
201-
void UpdateNativeModuleCache(std::shared_ptr<NativeModule> native_module,
202-
bool error);
203-
204185
void FreeNativeModule(NativeModule*);
205186

206187
// Sample the code size of the given {NativeModule} in all isolates that have
@@ -294,26 +275,6 @@ class V8_EXPORT_PRIVATE WasmEngine {
294275
// about that.
295276
std::unique_ptr<CurrentGCInfo> current_gc_info_;
296277

297-
struct WireBytesHasher {
298-
size_t operator()(const Vector<const uint8_t>& bytes) const;
299-
};
300-
301-
// Native modules cached by their wire bytes.
302-
// Each key points to the corresponding native module's wire bytes, so they
303-
// should always be valid as long as the native module is alive. When
304-
// the native module dies, {FreeNativeModule} deletes the entry from the
305-
// map, so that we do not leave any dangling key pointing to an expired
306-
// weak_ptr. This also serves as a way to regularly clean up the map, which
307-
// would otherwise accumulate expired entries.
308-
std::unordered_map<Vector<const uint8_t>, std::weak_ptr<NativeModule>,
309-
WireBytesHasher>
310-
native_module_cache_;
311-
312-
// This condition variable is used to synchronize threads compiling the same
313-
// module. Only one thread will create the {NativeModule}. The other threads
314-
// will wait on this variable until the first thread wakes them up.
315-
base::ConditionVariable cache_cv_;
316-
317278
// End of fields protected by {mutex_}.
318279
//////////////////////////////////////////////////////////////////////////////
319280

src/wasm/wasm-serialization.cc

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -608,47 +608,41 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
608608

609609
ModuleWireBytes wire_bytes(wire_bytes_vec);
610610
// TODO(titzer): module features should be part of the serialization format.
611-
WasmEngine* wasm_engine = isolate->wasm_engine();
612611
WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
613-
ModuleResult decode_result = DecodeWasmModule(
614-
enabled_features, wire_bytes.start(), wire_bytes.end(), false,
615-
i::wasm::kWasmOrigin, isolate->counters(), wasm_engine->allocator());
612+
ModuleResult decode_result =
613+
DecodeWasmModule(enabled_features, wire_bytes.start(), wire_bytes.end(),
614+
false, i::wasm::kWasmOrigin, isolate->counters(),
615+
isolate->wasm_engine()->allocator());
616616
if (decode_result.failed()) return {};
617617
std::shared_ptr<WasmModule> module = std::move(decode_result.value());
618618
CHECK_NOT_NULL(module);
619619
Handle<Script> script = CreateWasmScript(
620620
isolate, wire_bytes, module->source_map_url, module->name);
621621

622-
auto shared_native_module =
623-
wasm_engine->MaybeGetNativeModule(module->origin, wire_bytes_vec);
624-
if (shared_native_module == nullptr) {
625-
const bool kIncludeLiftoff = false;
626-
size_t code_size_estimate =
627-
wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get(),
628-
kIncludeLiftoff);
629-
shared_native_module = wasm_engine->NewNativeModule(
630-
isolate, enabled_features, std::move(module), code_size_estimate);
631-
shared_native_module->SetWireBytes(
632-
OwnedVector<uint8_t>::Of(wire_bytes_vec));
633-
634-
NativeModuleDeserializer deserializer(shared_native_module.get());
635-
WasmCodeRefScope wasm_code_ref_scope;
636-
637-
Reader reader(data + kVersionSize);
638-
bool error = !deserializer.Read(&reader);
639-
wasm_engine->UpdateNativeModuleCache(shared_native_module, error);
640-
if (error) return {};
641-
}
642-
643-
// Log the code within the generated module for profiling.
644-
shared_native_module->LogWasmCodes(isolate);
622+
const bool kIncludeLiftoff = false;
623+
size_t code_size_estimate =
624+
wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get(),
625+
kIncludeLiftoff);
626+
auto shared_native_module = isolate->wasm_engine()->NewNativeModule(
627+
isolate, enabled_features, std::move(module), code_size_estimate);
628+
shared_native_module->SetWireBytes(OwnedVector<uint8_t>::Of(wire_bytes_vec));
645629

646630
Handle<FixedArray> export_wrappers;
647631
CompileJsToWasmWrappers(isolate, shared_native_module->module(),
648632
&export_wrappers);
649633

650634
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
651635
isolate, std::move(shared_native_module), script, export_wrappers);
636+
NativeModule* native_module = module_object->native_module();
637+
638+
NativeModuleDeserializer deserializer(native_module);
639+
WasmCodeRefScope wasm_code_ref_scope;
640+
641+
Reader reader(data + kVersionSize);
642+
if (!deserializer.Read(&reader)) return {};
643+
644+
// Log the code within the generated module for profiling.
645+
native_module->LogWasmCodes(isolate);
652646

653647
// Finish the Wasm script now and make it public to the debugger.
654648
isolate->debug()->OnAfterCompile(script);

test/cctest/compiler/test-multiple-return.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,8 @@ std::shared_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
125125
// We have to add the code object to a NativeModule, because the
126126
// WasmCallDescriptor assumes that code is on the native heap and not
127127
// within a code object.
128-
auto native_module = isolate->wasm_engine()->NewNativeModule(
128+
return isolate->wasm_engine()->NewNativeModule(
129129
isolate, wasm::WasmFeatures::All(), std::move(module), code_size);
130-
native_module->SetWireBytes({});
131-
return native_module;
132130
}
133131

134132
void TestReturnMultipleValues(MachineType type) {

test/cctest/wasm/test-wasm-import-wrapper-cache.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ namespace test_wasm_import_wrapper_cache {
2121
std::shared_ptr<NativeModule> NewModule(Isolate* isolate) {
2222
std::shared_ptr<WasmModule> module(new WasmModule);
2323
constexpr size_t kCodeSizeEstimate = 16384;
24-
auto native_module = isolate->wasm_engine()->NewNativeModule(
24+
return isolate->wasm_engine()->NewNativeModule(
2525
isolate, WasmFeatures::All(), std::move(module), kCodeSizeEstimate);
26-
native_module->SetWireBytes({});
27-
return native_module;
2826
}
2927

3028
TEST(CacheHit) {

test/fuzzer/multi-return.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,8 @@ std::shared_ptr<wasm::NativeModule> AllocateNativeModule(i::Isolate* isolate,
142142
// We have to add the code object to a NativeModule, because the
143143
// WasmCallDescriptor assumes that code is on the native heap and not
144144
// within a code object.
145-
auto native_module = isolate->wasm_engine()->NewNativeModule(
145+
return isolate->wasm_engine()->NewNativeModule(
146146
isolate, i::wasm::WasmFeatures::All(), std::move(module), code_size);
147-
native_module->SetWireBytes({});
148-
return native_module;
149147
}
150148

151149
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

test/mjsunit/mjsunit.status

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,10 +817,6 @@
817817
# trigger a GC, but only in the isolate allocating the new memory.
818818
'wasm/module-memory': [SKIP],
819819
'wasm/shared-memory-gc-stress': [SKIP],
820-
821-
# Redirection to the interpreter is non-deterministic with multiple isolates.
822-
'wasm/interpreter-mixed': [SKIP],
823-
'wasm/worker-interpreter': [SKIP],
824820
}], # 'isolates'
825821

826822
##############################################################################

test/mjsunit/wasm/interpreter-mixed.js

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// Flags: --allow-natives-syntax --expose-gc
5+
// Flags: --allow-natives-syntax
66

77
load('test/mjsunit/wasm/wasm-module-builder.js');
88

@@ -144,32 +144,28 @@ function redirectToInterpreter(
144144
// Three runs: Break in instance 1, break in instance 2, or both.
145145
for (let run = 0; run < 3; ++run) {
146146
print(" - run " + run);
147-
(() => {
148-
// Trigger a GC to ensure that the underlying native module is not a cached
149-
// one from a previous run, with functions already redirected to the
150-
// interpreter. This is not observable from pure JavaScript, but this is
151-
// observable with the internal runtime functions used in this test.
152-
// Run in a local scope to ensure previous native modules are
153-
// unreachable.
154-
gc();
155-
let [instance1, instance2] = createTwoInstancesCallingEachOther();
156-
let interpreted_before_1 = %WasmNumInterpretedCalls(instance1);
157-
let interpreted_before_2 = %WasmNumInterpretedCalls(instance2);
158-
// Call plus_two, which calls plus_one.
159-
assertEquals(9, instance2.exports.plus_two(7));
160-
// Nothing interpreted:
161-
assertEquals(interpreted_before_1, %WasmNumInterpretedCalls(instance1));
162-
assertEquals(interpreted_before_2, %WasmNumInterpretedCalls(instance2));
163-
// Now redirect functions to the interpreter.
164-
redirectToInterpreter(instance1, instance2, run != 1, run != 0);
165-
// Call plus_two, which calls plus_one.
166-
assertEquals(9, instance2.exports.plus_two(7));
167-
// TODO(6668): Fix patching of instances which imported others' code.
168-
//assertEquals(interpreted_before_1 + (run == 1 ? 0 : 1),
169-
// %WasmNumInterpretedCalls(instance1));
170-
assertEquals(interpreted_before_2 + (run == 0 ? 0 : 1),
171-
%WasmNumInterpretedCalls(instance2))
172-
})();
147+
let [instance1, instance2] = createTwoInstancesCallingEachOther();
148+
149+
let interpreted_before_1 = %WasmNumInterpretedCalls(instance1);
150+
let interpreted_before_2 = %WasmNumInterpretedCalls(instance2);
151+
// Call plus_two, which calls plus_one.
152+
assertEquals(9, instance2.exports.plus_two(7));
153+
154+
// Nothing interpreted:
155+
assertEquals(interpreted_before_1, %WasmNumInterpretedCalls(instance1));
156+
assertEquals(interpreted_before_2, %WasmNumInterpretedCalls(instance2));
157+
158+
// Now redirect functions to the interpreter.
159+
redirectToInterpreter(instance1, instance2, run != 1, run != 0);
160+
161+
// Call plus_two, which calls plus_one.
162+
assertEquals(9, instance2.exports.plus_two(7));
163+
164+
// TODO(6668): Fix patching of instances which imported others' code.
165+
//assertEquals(interpreted_before_1 + (run == 1 ? 0 : 1),
166+
// %WasmNumInterpretedCalls(instance1));
167+
assertEquals(interpreted_before_2 + (run == 0 ? 0 : 1),
168+
%WasmNumInterpretedCalls(instance2));
173169
}
174170
})();
175171

0 commit comments

Comments
 (0)