Commit 1f06229f authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[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/+/2656259Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72423}
parent 31d2bb86
...@@ -874,11 +874,13 @@ void NativeModule::LogWasmCodes(Isolate* isolate, Script script) { ...@@ -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 // Log all owned code, not just the current entries in the code table. This
// will also include import wrappers. // will also include import wrappers.
WasmCodeRefScope code_ref_scope;
base::MutexGuard lock(&allocation_mutex_); base::MutexGuard lock(&allocation_mutex_);
for (auto& owned_entry : owned_code_) { for (auto& owned_entry : owned_code_) {
owned_entry.second->LogCode(isolate, source_url.get(), script.id()); 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 { CompilationEnv NativeModule::CreateCompilationEnv() const {
...@@ -1189,7 +1191,7 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) { ...@@ -1189,7 +1191,7 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
} }
} }
WasmCode* result = code.get(); WasmCode* result = code.get();
owned_code_.emplace(result->instruction_start(), std::move(code)); new_owned_code_.emplace_back(std::move(code));
return result; return result;
} }
...@@ -1461,8 +1463,34 @@ void NativeModule::SetWireBytes(OwnedVector<const uint8_t> wire_bytes) { ...@@ -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 { WasmCode* NativeModule::Lookup(Address pc) const {
base::MutexGuard lock(&allocation_mutex_); base::MutexGuard lock(&allocation_mutex_);
if (!new_owned_code_.empty()) TransferNewOwnedCodeLocked();
auto iter = owned_code_.upper_bound(pc); auto iter = owned_code_.upper_bound(pc);
if (iter == owned_code_.begin()) return nullptr; if (iter == owned_code_.begin()) return nullptr;
--iter; --iter;
...@@ -2004,6 +2032,7 @@ void NativeModule::FreeCode(Vector<WasmCode* const> codes) { ...@@ -2004,6 +2032,7 @@ void NativeModule::FreeCode(Vector<WasmCode* const> codes) {
DebugInfo* debug_info = nullptr; DebugInfo* debug_info = nullptr;
{ {
base::MutexGuard guard(&allocation_mutex_); base::MutexGuard guard(&allocation_mutex_);
if (!new_owned_code_.empty()) TransferNewOwnedCodeLocked();
debug_info = debug_info_.get(); debug_info = debug_info_.get();
// Free the {WasmCode} objects. This will also unregister trap handler data. // Free the {WasmCode} objects. This will also unregister trap handler data.
for (WasmCode* code : codes) { for (WasmCode* code : codes) {
......
...@@ -730,6 +730,9 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -730,6 +730,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// Hold the {allocation_mutex_} when calling {PublishCodeLocked}. // Hold the {allocation_mutex_} when calling {PublishCodeLocked}.
WasmCode* PublishCodeLocked(std::unique_ptr<WasmCode>); WasmCode* PublishCodeLocked(std::unique_ptr<WasmCode>);
// Transfer owned code from {new_owned_code_} to {owned_code_}.
void TransferNewOwnedCodeLocked() const;
// -- Fields of {NativeModule} start here. // -- Fields of {NativeModule} start here.
WasmEngine* const engine_; WasmEngine* const engine_;
...@@ -788,9 +791,15 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -788,9 +791,15 @@ class V8_EXPORT_PRIVATE NativeModule final {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Protected by {allocation_mutex_}: // Protected by {allocation_mutex_}:
// Holds all allocated code objects. For lookup based on pc, the key is the // Holds allocated code objects for fast lookup and deletion. For lookup based
// instruction start address of the value. // on pc, the key is the instruction start address of the value. Filled lazily
std::map<Address, std::unique_ptr<WasmCode>> owned_code_; // 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 // Table of the latest code object per function, updated on initial
// compilation and tier up. The number of entries is // compilation and tier up. The number of entries is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment