[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:
parent
31d2bb8670
commit
1f06229f22
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user