Commit 838a220c authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

[wasm] AdaptiveMap for DecodedNameSection

This is a performance improvement; no change in functional
behavior is intended.
AdaptiveMap is an abstraction over a std::map or a std::vector:
after being initialized iteratively with a set of entries, it
can switch to dense vector-based storage if that would be more
efficient.
The motivation is that we expect most name sections, if they
are present at all, to give fairly complete information, so the
dense mode will likely be the typical case. However, it's easy
enough to support sparse mode as well, and parsing the name
section into a std::map at first is particularly convenient for
cases where we can't guess the expected number of entries, such
as for function locals.

Change-Id: Ia17f27576a3061eb05c912f7081411d6f38137e6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3726150Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81474}
parent c651551f
...@@ -2563,7 +2563,7 @@ bool FindNameSection(Decoder* decoder) { ...@@ -2563,7 +2563,7 @@ bool FindNameSection(Decoder* decoder) {
} // namespace } // namespace
void DecodeFunctionNames(const byte* module_start, const byte* module_end, void DecodeFunctionNames(const byte* module_start, const byte* module_end,
std::unordered_map<uint32_t, WireBytesRef>& names) { NameMap& names) {
Decoder decoder(module_start, module_end); Decoder decoder(module_start, module_end);
if (FindNameSection(&decoder)) { if (FindNameSection(&decoder)) {
while (decoder.ok() && decoder.more()) { while (decoder.ok() && decoder.more()) {
...@@ -2588,19 +2588,18 @@ void DecodeFunctionNames(const byte* module_start, const byte* module_end, ...@@ -2588,19 +2588,18 @@ void DecodeFunctionNames(const byte* module_start, const byte* module_end,
// You can even assign to the same function multiple times (last valid // You can even assign to the same function multiple times (last valid
// one wins). // one wins).
if (decoder.ok() && validate_utf8(&decoder, name)) { if (decoder.ok() && validate_utf8(&decoder, name)) {
names.insert(std::make_pair(function_index, name)); names.Put(function_index, name);
} }
} }
} }
} }
names.FinishInitialization();
} }
namespace { namespace {
void DecodeNameMap(NameMap& target, Decoder& decoder) { void DecodeNameMap(NameMap& target, Decoder& decoder) {
std::vector<NameAssoc> names;
uint32_t count = decoder.consume_u32v("names count"); uint32_t count = decoder.consume_u32v("names count");
names.reserve(count);
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
uint32_t index = decoder.consume_u32v("index"); uint32_t index = decoder.consume_u32v("index");
WireBytesRef name = WireBytesRef name =
...@@ -2609,22 +2608,18 @@ void DecodeNameMap(NameMap& target, Decoder& decoder) { ...@@ -2609,22 +2608,18 @@ void DecodeNameMap(NameMap& target, Decoder& decoder) {
if (index > kMaxInt) continue; if (index > kMaxInt) continue;
if (name.is_empty()) continue; // Empty names are useless. if (name.is_empty()) continue; // Empty names are useless.
if (!validate_utf8(&decoder, name)) continue; if (!validate_utf8(&decoder, name)) continue;
names.emplace_back(static_cast<int>(index), name); target.Put(index, name);
} }
std::stable_sort(names.begin(), names.end(), NameAssoc::IndexLess{}); target.FinishInitialization();
target = NameMap{std::move(names)};
} }
void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder) { void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder) {
std::vector<IndirectNameMapEntry> entries;
uint32_t outer_count = decoder.consume_u32v("outer count"); uint32_t outer_count = decoder.consume_u32v("outer count");
entries.reserve(outer_count);
for (uint32_t i = 0; i < outer_count; ++i) { for (uint32_t i = 0; i < outer_count; ++i) {
uint32_t outer_index = decoder.consume_u32v("outer index"); uint32_t outer_index = decoder.consume_u32v("outer index");
if (outer_index > kMaxInt) continue; if (outer_index > kMaxInt) continue;
std::vector<NameAssoc> names; NameMap names;
uint32_t inner_count = decoder.consume_u32v("inner count"); uint32_t inner_count = decoder.consume_u32v("inner count");
names.reserve(inner_count);
for (uint32_t k = 0; k < inner_count; ++k) { for (uint32_t k = 0; k < inner_count; ++k) {
uint32_t inner_index = decoder.consume_u32v("inner index"); uint32_t inner_index = decoder.consume_u32v("inner index");
WireBytesRef name = WireBytesRef name =
...@@ -2633,16 +2628,12 @@ void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder) { ...@@ -2633,16 +2628,12 @@ void DecodeIndirectNameMap(IndirectNameMap& target, Decoder& decoder) {
if (inner_index > kMaxInt) continue; if (inner_index > kMaxInt) continue;
if (name.is_empty()) continue; // Empty names are useless. if (name.is_empty()) continue; // Empty names are useless.
if (!validate_utf8(&decoder, name)) continue; if (!validate_utf8(&decoder, name)) continue;
names.emplace_back(static_cast<int>(inner_index), name); names.Put(inner_index, name);
} }
// Use stable sort to get deterministic names (the first one declared) names.FinishInitialization();
// even in the presence of duplicates. target.Put(outer_index, std::move(names));
std::stable_sort(names.begin(), names.end(), NameAssoc::IndexLess{});
entries.emplace_back(static_cast<int>(outer_index), std::move(names));
} }
std::stable_sort(entries.begin(), entries.end(), target.FinishInitialization();
IndirectNameMapEntry::IndexLess{});
target = IndirectNameMap{std::move(entries)};
} }
} // namespace } // namespace
......
...@@ -56,94 +56,6 @@ struct AsmJsOffsets { ...@@ -56,94 +56,6 @@ struct AsmJsOffsets {
}; };
using AsmJsOffsetsResult = Result<AsmJsOffsets>; using AsmJsOffsetsResult = Result<AsmJsOffsets>;
// The class names "NameAssoc", "NameMap", and "IndirectNameMap" match
// the terms used by the spec:
// https://webassembly.github.io/spec/core/bikeshed/index.html#name-section%E2%91%A0
class NameAssoc {
public:
NameAssoc(int index, WireBytesRef name) : index_(index), name_(name) {}
int index() const { return index_; }
WireBytesRef name() const { return name_; }
struct IndexLess {
bool operator()(const NameAssoc& a, const NameAssoc& b) const {
return a.index() < b.index();
}
};
private:
int index_;
WireBytesRef name_;
};
class NameMap {
public:
// For performance reasons, {NameMap} should not be copied.
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(NameMap);
explicit NameMap(std::vector<NameAssoc> names) : names_(std::move(names)) {
DCHECK(
std::is_sorted(names_.begin(), names_.end(), NameAssoc::IndexLess{}));
}
WireBytesRef GetName(int index) {
auto it = std::lower_bound(names_.begin(), names_.end(),
NameAssoc{index, {}}, NameAssoc::IndexLess{});
if (it == names_.end()) return {};
if (it->index() != index) return {};
return it->name();
}
private:
std::vector<NameAssoc> names_;
};
class IndirectNameMapEntry : public NameMap {
public:
// For performance reasons, {IndirectNameMapEntry} should not be copied.
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(IndirectNameMapEntry);
IndirectNameMapEntry(int index, std::vector<NameAssoc> names)
: NameMap(std::move(names)), index_(index) {}
int index() const { return index_; }
struct IndexLess {
bool operator()(const IndirectNameMapEntry& a,
const IndirectNameMapEntry& b) const {
return a.index() < b.index();
}
};
private:
int index_;
};
class IndirectNameMap {
public:
// For performance reasons, {IndirectNameMap} should not be copied.
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(IndirectNameMap);
explicit IndirectNameMap(std::vector<IndirectNameMapEntry> functions)
: functions_(std::move(functions)) {
DCHECK(std::is_sorted(functions_.begin(), functions_.end(),
IndirectNameMapEntry::IndexLess{}));
}
WireBytesRef GetName(int function_index, int local_index) {
auto it = std::lower_bound(functions_.begin(), functions_.end(),
IndirectNameMapEntry{function_index, {}},
IndirectNameMapEntry::IndexLess{});
if (it == functions_.end()) return {};
if (it->index() != function_index) return {};
return it->GetName(local_index);
}
private:
std::vector<IndirectNameMapEntry> functions_;
};
class DecodedNameSection { class DecodedNameSection {
public: public:
explicit DecodedNameSection(base::Vector<const uint8_t> wire_bytes, explicit DecodedNameSection(base::Vector<const uint8_t> wire_bytes,
...@@ -215,7 +127,7 @@ AsmJsOffsetsResult DecodeAsmJsOffsets( ...@@ -215,7 +127,7 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(
// unordered map. Only names with valid utf8 encoding are stored and conflicts // unordered map. Only names with valid utf8 encoding are stored and conflicts
// are resolved by choosing the last name read. // are resolved by choosing the last name read.
void DecodeFunctionNames(const byte* module_start, const byte* module_end, void DecodeFunctionNames(const byte* module_start, const byte* module_end,
std::unordered_map<uint32_t, WireBytesRef>& names); NameMap& names);
class ModuleDecoderImpl; class ModuleDecoderImpl;
......
...@@ -55,27 +55,19 @@ void NamesProvider::ComputeNamesFromImportsExports() { ...@@ -55,27 +55,19 @@ void NamesProvider::ComputeNamesFromImportsExports() {
case kExternalFunction: case kExternalFunction:
continue; // Functions are handled separately. continue; // Functions are handled separately.
case kExternalTable: case kExternalTable:
if (name_section_names_->table_names_.GetName(import.index).is_set()) { if (name_section_names_->table_names_.Has(import.index)) continue;
continue;
}
ComputeImportName(import, import_export_table_names_); ComputeImportName(import, import_export_table_names_);
break; break;
case kExternalMemory: case kExternalMemory:
if (name_section_names_->memory_names_.GetName(import.index).is_set()) { if (name_section_names_->memory_names_.Has(import.index)) continue;
continue;
}
ComputeImportName(import, import_export_memory_names_); ComputeImportName(import, import_export_memory_names_);
break; break;
case kExternalGlobal: case kExternalGlobal:
if (name_section_names_->global_names_.GetName(import.index).is_set()) { if (name_section_names_->global_names_.Has(import.index)) continue;
continue;
}
ComputeImportName(import, import_export_global_names_); ComputeImportName(import, import_export_global_names_);
break; break;
case kExternalTag: case kExternalTag:
if (name_section_names_->tag_names_.GetName(import.index).is_set()) { if (name_section_names_->tag_names_.Has(import.index)) continue;
continue;
}
ComputeImportName(import, import_export_tag_names_); ComputeImportName(import, import_export_tag_names_);
break; break;
} }
...@@ -85,27 +77,19 @@ void NamesProvider::ComputeNamesFromImportsExports() { ...@@ -85,27 +77,19 @@ void NamesProvider::ComputeNamesFromImportsExports() {
case kExternalFunction: case kExternalFunction:
continue; // Functions are handled separately. continue; // Functions are handled separately.
case kExternalTable: case kExternalTable:
if (name_section_names_->table_names_.GetName(ex.index).is_set()) { if (name_section_names_->table_names_.Has(ex.index)) continue;
continue;
}
ComputeExportName(ex, import_export_table_names_); ComputeExportName(ex, import_export_table_names_);
break; break;
case kExternalMemory: case kExternalMemory:
if (name_section_names_->memory_names_.GetName(ex.index).is_set()) { if (name_section_names_->memory_names_.Has(ex.index)) continue;
continue;
}
ComputeExportName(ex, import_export_memory_names_); ComputeExportName(ex, import_export_memory_names_);
break; break;
case kExternalGlobal: case kExternalGlobal:
if (name_section_names_->global_names_.GetName(ex.index).is_set()) { if (name_section_names_->global_names_.Has(ex.index)) continue;
continue;
}
ComputeExportName(ex, import_export_global_names_); ComputeExportName(ex, import_export_global_names_);
break; break;
case kExternalTag: case kExternalTag:
if (name_section_names_->tag_names_.GetName(ex.index).is_set()) { if (name_section_names_->tag_names_.Has(ex.index)) continue;
continue;
}
ComputeExportName(ex, import_export_tag_names_); ComputeExportName(ex, import_export_tag_names_);
break; break;
} }
...@@ -224,12 +208,25 @@ void NamesProvider::PrintFunctionName(StringBuilder& out, ...@@ -224,12 +208,25 @@ void NamesProvider::PrintFunctionName(StringBuilder& out,
} }
} }
WireBytesRef Get(const NameMap& map, uint32_t index) {
const WireBytesRef* result = map.Get(index);
if (!result) return {};
return *result;
}
WireBytesRef Get(const IndirectNameMap& map, uint32_t outer_index,
uint32_t inner_index) {
const NameMap* inner = map.Get(outer_index);
if (!inner) return {};
return Get(*inner, inner_index);
}
void NamesProvider::PrintLocalName(StringBuilder& out, uint32_t function_index, void NamesProvider::PrintLocalName(StringBuilder& out, uint32_t function_index,
uint32_t local_index, uint32_t local_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = WireBytesRef ref =
name_section_names_->local_names_.GetName(function_index, local_index); Get(name_section_names_->local_names_, function_index, local_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -244,7 +241,7 @@ void NamesProvider::PrintLabelName(StringBuilder& out, uint32_t function_index, ...@@ -244,7 +241,7 @@ void NamesProvider::PrintLabelName(StringBuilder& out, uint32_t function_index,
uint32_t fallback_index) { uint32_t fallback_index) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = WireBytesRef ref =
name_section_names_->label_names_.GetName(function_index, label_index); Get(name_section_names_->label_names_, function_index, label_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -256,7 +253,7 @@ void NamesProvider::PrintLabelName(StringBuilder& out, uint32_t function_index, ...@@ -256,7 +253,7 @@ void NamesProvider::PrintLabelName(StringBuilder& out, uint32_t function_index,
void NamesProvider::PrintTypeName(StringBuilder& out, uint32_t type_index, void NamesProvider::PrintTypeName(StringBuilder& out, uint32_t type_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->type_names_.GetName(type_index); WireBytesRef ref = Get(name_section_names_->type_names_, type_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -268,7 +265,7 @@ void NamesProvider::PrintTypeName(StringBuilder& out, uint32_t type_index, ...@@ -268,7 +265,7 @@ void NamesProvider::PrintTypeName(StringBuilder& out, uint32_t type_index,
void NamesProvider::PrintTableName(StringBuilder& out, uint32_t table_index, void NamesProvider::PrintTableName(StringBuilder& out, uint32_t table_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->table_names_.GetName(table_index); WireBytesRef ref = Get(name_section_names_->table_names_, table_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -286,7 +283,7 @@ void NamesProvider::PrintTableName(StringBuilder& out, uint32_t table_index, ...@@ -286,7 +283,7 @@ void NamesProvider::PrintTableName(StringBuilder& out, uint32_t table_index,
void NamesProvider::PrintMemoryName(StringBuilder& out, uint32_t memory_index, void NamesProvider::PrintMemoryName(StringBuilder& out, uint32_t memory_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->memory_names_.GetName(memory_index); WireBytesRef ref = Get(name_section_names_->memory_names_, memory_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -305,7 +302,7 @@ void NamesProvider::PrintMemoryName(StringBuilder& out, uint32_t memory_index, ...@@ -305,7 +302,7 @@ void NamesProvider::PrintMemoryName(StringBuilder& out, uint32_t memory_index,
void NamesProvider::PrintGlobalName(StringBuilder& out, uint32_t global_index, void NamesProvider::PrintGlobalName(StringBuilder& out, uint32_t global_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->global_names_.GetName(global_index); WireBytesRef ref = Get(name_section_names_->global_names_, global_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -324,8 +321,8 @@ void NamesProvider::PrintGlobalName(StringBuilder& out, uint32_t global_index, ...@@ -324,8 +321,8 @@ void NamesProvider::PrintGlobalName(StringBuilder& out, uint32_t global_index,
void NamesProvider::PrintElementSegmentName(StringBuilder& out, void NamesProvider::PrintElementSegmentName(StringBuilder& out,
uint32_t element_segment_index) { uint32_t element_segment_index) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->element_segment_names_.GetName( WireBytesRef ref =
element_segment_index); Get(name_section_names_->element_segment_names_, element_segment_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -338,7 +335,7 @@ void NamesProvider::PrintDataSegmentName(StringBuilder& out, ...@@ -338,7 +335,7 @@ void NamesProvider::PrintDataSegmentName(StringBuilder& out,
uint32_t data_segment_index) { uint32_t data_segment_index) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = WireBytesRef ref =
name_section_names_->data_segment_names_.GetName(data_segment_index); Get(name_section_names_->data_segment_names_, data_segment_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -352,7 +349,7 @@ void NamesProvider::PrintFieldName(StringBuilder& out, uint32_t struct_index, ...@@ -352,7 +349,7 @@ void NamesProvider::PrintFieldName(StringBuilder& out, uint32_t struct_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = WireBytesRef ref =
name_section_names_->field_names_.GetName(struct_index, field_index); Get(name_section_names_->field_names_, struct_index, field_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
...@@ -364,7 +361,7 @@ void NamesProvider::PrintFieldName(StringBuilder& out, uint32_t struct_index, ...@@ -364,7 +361,7 @@ void NamesProvider::PrintFieldName(StringBuilder& out, uint32_t struct_index,
void NamesProvider::PrintTagName(StringBuilder& out, uint32_t tag_index, void NamesProvider::PrintTagName(StringBuilder& out, uint32_t tag_index,
IndexAsComment index_as_comment) { IndexAsComment index_as_comment) {
DecodeNamesIfNotYetDone(); DecodeNamesIfNotYetDone();
WireBytesRef ref = name_section_names_->tag_names_.GetName(tag_index); WireBytesRef ref = Get(name_section_names_->tag_names_, tag_index);
if (ref.is_set()) { if (ref.is_set()) {
out << '$'; out << '$';
WriteRef(out, ref); WriteRef(out, ref);
......
...@@ -30,7 +30,6 @@ class WasmFrame; ...@@ -30,7 +30,6 @@ class WasmFrame;
namespace wasm { namespace wasm {
class DebugInfoImpl; class DebugInfoImpl;
class IndirectNameMap;
class NativeModule; class NativeModule;
class WasmCode; class WasmCode;
class WireBytesRef; class WireBytesRef;
......
...@@ -23,6 +23,29 @@ namespace v8 { ...@@ -23,6 +23,29 @@ namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
template <class Value>
void AdaptiveMap<Value>::FinishInitialization() {
uint32_t count = 0;
uint32_t max = 0;
DCHECK_EQ(mode_, kInitializing);
for (const auto& entry : *map_) {
count++;
max = std::max(max, entry.first);
}
if (count >= (max + 1) / kLoadFactor) {
mode_ = kDense;
vector_.resize(max + 1);
for (auto& entry : *map_) {
vector_[entry.first] = std::move(entry.second);
}
map_.reset();
} else {
mode_ = kSparse;
}
}
template void NameMap::FinishInitialization();
template void IndirectNameMap::FinishInitialization();
WireBytesRef LazilyGeneratedNames::LookupFunctionName( WireBytesRef LazilyGeneratedNames::LookupFunctionName(
const ModuleWireBytes& wire_bytes, uint32_t function_index) { const ModuleWireBytes& wire_bytes, uint32_t function_index) {
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
...@@ -30,15 +53,15 @@ WireBytesRef LazilyGeneratedNames::LookupFunctionName( ...@@ -30,15 +53,15 @@ WireBytesRef LazilyGeneratedNames::LookupFunctionName(
has_functions_ = true; has_functions_ = true;
DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(), function_names_); DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(), function_names_);
} }
auto it = function_names_.find(function_index); const WireBytesRef* result = function_names_.Get(function_index);
if (it == function_names_.end()) return WireBytesRef(); if (!result) return WireBytesRef();
return it->second; return *result;
} }
bool LazilyGeneratedNames::Has(uint32_t function_index) { bool LazilyGeneratedNames::Has(uint32_t function_index) {
DCHECK(has_functions_); DCHECK(has_functions_);
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
return function_names_.find(function_index) != function_names_.end(); return function_names_.Get(function_index) != nullptr;
} }
// static // static
...@@ -127,7 +150,7 @@ int GetSubtypingDepth(const WasmModule* module, uint32_t type_index) { ...@@ -127,7 +150,7 @@ int GetSubtypingDepth(const WasmModule* module, uint32_t type_index) {
void LazilyGeneratedNames::AddForTesting(int function_index, void LazilyGeneratedNames::AddForTesting(int function_index,
WireBytesRef name) { WireBytesRef name) {
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
function_names_.insert(std::make_pair(function_index, name)); function_names_.Put(function_index, name);
} }
AsmJsOffsetInformation::AsmJsOffsetInformation( AsmJsOffsetInformation::AsmJsOffsetInformation(
......
...@@ -212,6 +212,74 @@ enum ModuleOrigin : uint8_t { ...@@ -212,6 +212,74 @@ enum ModuleOrigin : uint8_t {
((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \ ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
: (counters)->prefix##_asm_##suffix()) : (counters)->prefix##_asm_##suffix())
// Uses a map as backing storage when sparsely, or a vector when densely
// populated. Requires {Value} to implement `bool is_set()` to identify
// uninitialized objects.
template <class Value>
class AdaptiveMap {
public:
AdaptiveMap() : map_(new MapType()) {}
explicit AdaptiveMap(const AdaptiveMap&) = delete;
AdaptiveMap& operator=(const AdaptiveMap&) = delete;
AdaptiveMap(AdaptiveMap&& other) V8_NOEXCEPT { *this = std::move(other); }
AdaptiveMap& operator=(AdaptiveMap&& other) V8_NOEXCEPT {
mode_ = other.mode_;
vector_.swap(other.vector_);
map_.swap(other.map_);
return *this;
}
void FinishInitialization();
bool is_set() const { return mode_ != kInitializing; }
void Put(uint32_t key, const Value& value) {
DCHECK(mode_ == kInitializing);
map_->insert(std::make_pair(key, value));
}
void Put(uint32_t key, Value&& value) {
DCHECK(mode_ == kInitializing);
map_->insert(std::make_pair(key, std::move(value)));
}
const Value* Get(uint32_t key) const {
if (mode_ == kDense) {
if (key >= vector_.size()) return nullptr;
if (!vector_[key].is_set()) return nullptr;
return &vector_[key];
} else {
DCHECK(mode_ == kSparse || mode_ == kInitializing);
auto it = map_->find(key);
if (it == map_->end()) return nullptr;
return &it->second;
}
}
bool Has(uint32_t key) const {
if (mode_ == kDense) {
return key < vector_.size() && vector_[key].is_set();
} else {
DCHECK(mode_ == kSparse || mode_ == kInitializing);
return map_->find(key) != map_->end();
}
}
private:
static constexpr uint32_t kLoadFactor = 4;
using MapType = std::map<uint32_t, Value>;
enum Mode { kDense, kSparse, kInitializing };
Mode mode_{kInitializing};
std::vector<Value> vector_;
std::unique_ptr<MapType> map_;
};
using NameMap = AdaptiveMap<WireBytesRef>;
using IndirectNameMap = AdaptiveMap<AdaptiveMap<WireBytesRef>>;
struct ModuleWireBytes; struct ModuleWireBytes;
class V8_EXPORT_PRIVATE LazilyGeneratedNames { class V8_EXPORT_PRIVATE LazilyGeneratedNames {
...@@ -227,7 +295,7 @@ class V8_EXPORT_PRIVATE LazilyGeneratedNames { ...@@ -227,7 +295,7 @@ class V8_EXPORT_PRIVATE LazilyGeneratedNames {
// {WasmModuleObject}s. // {WasmModuleObject}s.
base::Mutex mutex_; base::Mutex mutex_;
bool has_functions_{false}; bool has_functions_{false};
std::unordered_map<uint32_t, WireBytesRef> function_names_; NameMap function_names_;
}; };
class V8_EXPORT_PRIVATE AsmJsOffsetInformation { class V8_EXPORT_PRIVATE AsmJsOffsetInformation {
......
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