[wasm] Delay creation of {owned_code_} map

Insertion into the map is expensive, hence avoid inserting every single
code object. Instead, collect them in a {std::vector}, and only insert
them when the {owned_code_} map is being used. By sorting the vector
before inserting into the map, we can make most insertions constant time
instead of logarithmic in the size of the map, by using the previous
insert position as a hint for the next one.

Drive-by: Remove an unneeded {WasmCodeRefScope}.

R=thibaudm@chromium.org

Bug: v8:11164
Change-Id: I3cc47f627eca40ea747d3e8388f93094650bbe19
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2656259
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72423}
This commit is contained in:
Clemens Backes 2021-01-28 16:43:37 +01:00 committed by Commit Bot
parent 31d2bb8670
commit 1f06229f22
2 changed files with 43 additions and 5 deletions

View File

@ -874,11 +874,13 @@ void NativeModule::LogWasmCodes(Isolate* isolate, Script script) {
// Log all owned code, not just the current entries in the code table. This
// will also include import wrappers.
WasmCodeRefScope code_ref_scope;
base::MutexGuard lock(&allocation_mutex_);
for (auto& owned_entry : owned_code_) {
owned_entry.second->LogCode(isolate, source_url.get(), script.id());
}
for (auto& owned_entry : new_owned_code_) {
owned_entry->LogCode(isolate, source_url.get(), script.id());
}
}
CompilationEnv NativeModule::CreateCompilationEnv() const {
@ -1189,7 +1191,7 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
}
}
WasmCode* result = code.get();
owned_code_.emplace(result->instruction_start(), std::move(code));
new_owned_code_.emplace_back(std::move(code));
return result;
}
@ -1461,8 +1463,34 @@ void NativeModule::SetWireBytes(OwnedVector<const uint8_t> wire_bytes) {
}
}
void NativeModule::TransferNewOwnedCodeLocked() const {
// The caller holds the allocation mutex.
DCHECK(!allocation_mutex_.TryLock());
DCHECK(!new_owned_code_.empty());
// Sort the {new_owned_code_} vector reversed, such that the position of the
// previously inserted element can be used as a hint for the next element. If
// elements in {new_owned_code_} are adjacent, this will guarantee
// constant-time insertion into the map.
std::sort(new_owned_code_.begin(), new_owned_code_.end(),
[](const std::unique_ptr<WasmCode>& a,
const std::unique_ptr<WasmCode>& b) {
return a->instruction_start() > b->instruction_start();
});
auto insertion_hint = owned_code_.end();
for (auto& code : new_owned_code_) {
DCHECK_EQ(0, owned_code_.count(code->instruction_start()));
// Check plausibility of the insertion hint.
DCHECK(insertion_hint == owned_code_.end() ||
insertion_hint->first > code->instruction_start());
insertion_hint = owned_code_.emplace_hint(
insertion_hint, code->instruction_start(), std::move(code));
}
new_owned_code_.clear();
}
WasmCode* NativeModule::Lookup(Address pc) const {
base::MutexGuard lock(&allocation_mutex_);
if (!new_owned_code_.empty()) TransferNewOwnedCodeLocked();
auto iter = owned_code_.upper_bound(pc);
if (iter == owned_code_.begin()) return nullptr;
--iter;
@ -2004,6 +2032,7 @@ void NativeModule::FreeCode(Vector<WasmCode* const> codes) {
DebugInfo* debug_info = nullptr;
{
base::MutexGuard guard(&allocation_mutex_);
if (!new_owned_code_.empty()) TransferNewOwnedCodeLocked();
debug_info = debug_info_.get();
// Free the {WasmCode} objects. This will also unregister trap handler data.
for (WasmCode* code : codes) {

View File

@ -730,6 +730,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// Hold the {allocation_mutex_} when calling {PublishCodeLocked}.
WasmCode* PublishCodeLocked(std::unique_ptr<WasmCode>);
// Transfer owned code from {new_owned_code_} to {owned_code_}.
void TransferNewOwnedCodeLocked() const;
// -- Fields of {NativeModule} start here.
WasmEngine* const engine_;
@ -788,9 +791,15 @@ class V8_EXPORT_PRIVATE NativeModule final {
//////////////////////////////////////////////////////////////////////////////
// Protected by {allocation_mutex_}:
// Holds all allocated code objects. For lookup based on pc, the key is the
// instruction start address of the value.
std::map<Address, std::unique_ptr<WasmCode>> owned_code_;
// Holds allocated code objects for fast lookup and deletion. For lookup based
// on pc, the key is the instruction start address of the value. Filled lazily
// from {new_owned_code_} (below).
mutable std::map<Address, std::unique_ptr<WasmCode>> owned_code_;
// Holds owned code which is not inserted into {owned_code_} yet. It will be
// inserted on demand. This has much better performance than inserting
// individual code objects.
mutable std::vector<std::unique_ptr<WasmCode>> new_owned_code_;
// Table of the latest code object per function, updated on initial
// compilation and tier up. The number of entries is