#include "src/wasm/wasm-code-pointer-table.h"
#include "src/sandbox/external-entity-table-inl.h"
#include "src/wasm/wasm-code-pointer-table-inl.h"
namespace v8::internal::wasm {
void WasmCodePointerTable::Initialize() { Base::Initialize(); }
void WasmCodePointerTable::TearDown() {
FreeNativeFunctionHandles();
SweepSegments(0);
DCHECK(freelist_head_.load().is_empty());
Base::TearDown();
}
DEFINE_LAZY_LEAKY_OBJECT_GETTER(WasmCodePointerTable,
GetProcessWideWasmCodePointerTable)
std::vector<uint32_t> WasmCodePointerTable::FreelistToVector(
WasmCodePointerTable::FreelistHead freelist) {
DCHECK(!freelist.is_empty());
std::vector<uint32_t> entries(freelist.length());
uint32_t entry = freelist.next();
for (uint32_t i = 0; i < freelist.length(); i++) {
entries[i] = entry;
entry = at(entry).GetNextFreelistEntryIndex();
}
return entries;
}
WasmCodePointerTable::FreelistHead WasmCodePointerTable::VectorToFreelist(
std::vector<uint32_t> entries) {
if (entries.empty()) {
return FreelistHead();
}
FreelistHead new_freelist =
FreelistHead(entries[0], static_cast<uint32_t>(entries.size()));
WriteScope write_scope("Freelist write");
for (size_t i = 0; i < entries.size() - 1; i++) {
uint32_t entry = entries[i];
uint32_t next_entry = entries[i + 1];
at(entry).MakeFreelistEntry(next_entry);
}
return new_freelist;
}
void WasmCodePointerTable::SweepSegments(size_t threshold) {
if (threshold < kEntriesPerSegment) {
threshold = kEntriesPerSegment;
}
FreelistHead initial_head, empty_freelist;
do {
initial_head = ReadFreelistHead();
if (initial_head.length() < threshold) {
return;
}
} while (
!freelist_head_.compare_exchange_strong(initial_head, empty_freelist));
std::vector<uint32_t> freelist_entries = FreelistToVector(initial_head);
std::sort(freelist_entries.begin(), freelist_entries.end());
DCHECK_GE(freelist_entries.size(), kEntriesPerSegment);
std::vector<uint32_t> new_freelist_entries;
for (size_t i = 0; i < freelist_entries.size(); i++) {
uint32_t entry = freelist_entries[i];
Segment segment = Segment::Containing(entry);
if (segment.first_entry() == entry &&
i + kEntriesPerSegment - 1 < freelist_entries.size()) {
uint32_t last_entry = freelist_entries[i + kEntriesPerSegment - 1];
if (segment.last_entry() == last_entry) {
FreeTableSegment(segment);
i += kEntriesPerSegment - 1;
continue;
}
}
new_freelist_entries.push_back(entry);
}
DCHECK_LE(new_freelist_entries.size(), freelist_entries.size());
DCHECK(IsAligned(freelist_entries.size() - new_freelist_entries.size(),
kEntriesPerSegment));
if (new_freelist_entries.empty()) {
return;
}
uint32_t last_element = new_freelist_entries.back();
FreelistHead new_freelist = VectorToFreelist(new_freelist_entries);
LinkFreelist(new_freelist, last_element);
}
WasmCodePointer WasmCodePointerTable::GetOrCreateHandleForNativeFunction(
Address addr) {
base::MutexGuard guard(&native_function_map_mutex_);
auto it = native_function_map_.find(addr);
if (it != native_function_map_.end()) {
return it->second;
}
WasmCodePointer handle = AllocateAndInitializeEntry(addr, -1);
native_function_map_.insert({addr, handle});
return handle;
}
bool WasmCodePointerTable::EntrypointEqualTo(WasmCodePointer index,
Address address) {
return at(index.value()).GetEntrypointWithoutSignatureCheck() == address;
}
void WasmCodePointerTable::FreeNativeFunctionHandles() {
base::MutexGuard guard(&native_function_map_mutex_);
for (auto const& [address, handle] : native_function_map_) {
FreeEntry(handle);
}
native_function_map_.clear();
}
}