mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 17:00:19 +02:00
Merge pull request #976 from FEX-Emu/skmp/aotir-mmap
AOTIR: Switch over to mmap-based loading
This commit is contained in:
6 files changed
+258
-157
No files matched your search
+1
-1
@@ -142,7 +142,7 @@ namespace FEXCore::Context {
|
||||
return CTX->CPUID.RunFunction(Function, Leaf);
|
||||
}
|
||||
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader) {
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader) {
|
||||
CTX->AOTIRLoader = CacheReader;
|
||||
}
|
||||
|
||||
|
||||
+40
-8
@@ -52,6 +52,39 @@ namespace FEXCore::Context {
|
||||
MODE_SINGLESTEP = 1,
|
||||
};
|
||||
|
||||
struct AOTIRCaptureCacheEntry {
|
||||
uint64_t start;
|
||||
uint64_t len;
|
||||
uint64_t crc;
|
||||
IR::IRListView *IR;
|
||||
IR::RegisterAllocationData *RAData;
|
||||
};
|
||||
|
||||
struct AOTIRInlineEntry {
|
||||
uint64_t GuestHash;
|
||||
uint64_t GuestLength;
|
||||
|
||||
/* RAData followed by IRData */
|
||||
uint8_t InlineData[0];
|
||||
|
||||
IR::RegisterAllocationData *GetRAData();
|
||||
IR::IRListView *GetIRData();
|
||||
};
|
||||
|
||||
struct AOTIRInlineIndexEntry {
|
||||
uint64_t GuestStart;
|
||||
uint64_t DataOffset;
|
||||
};
|
||||
|
||||
struct AOTIRInlineIndex {
|
||||
uint64_t Count;
|
||||
uint64_t DataBase;
|
||||
AOTIRInlineIndexEntry Entries[0];
|
||||
|
||||
AOTIRInlineEntry *Find(uint64_t GuestStart);
|
||||
AOTIRInlineEntry *GetInlineEntry(uint64_t DataOffset);
|
||||
};
|
||||
|
||||
struct Context {
|
||||
friend class FEXCore::HLE::SyscallHandler;
|
||||
#ifdef JIT_ARM64
|
||||
@@ -113,15 +146,14 @@ namespace FEXCore::Context {
|
||||
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
|
||||
|
||||
struct AOTIRCacheEntry {
|
||||
uint64_t start;
|
||||
uint64_t len;
|
||||
uint64_t crc;
|
||||
IR::IRListView *IR;
|
||||
IR::RegisterAllocationData *RAData;
|
||||
AOTIRInlineIndex *Array;
|
||||
void *mapping;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
std::function<std::unique_ptr<std::istream>(const std::string&)> AOTIRLoader;
|
||||
std::unordered_map<std::string, std::map<uint64_t, AOTIRCacheEntry>> AOTIRCache;
|
||||
std::unordered_map<std::string, AOTIRCacheEntry> AOTIRCache;
|
||||
std::function<int(const std::string&)> AOTIRLoader;
|
||||
std::unordered_map<std::string, std::map<uint64_t, AOTIRCaptureCacheEntry>> AOTIRCaptureCache;
|
||||
|
||||
struct AddrToFileEntry {
|
||||
uint64_t Start;
|
||||
@@ -183,7 +215,7 @@ namespace FEXCore::Context {
|
||||
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP);
|
||||
|
||||
bool LoadAOTIRCache(std::istream &stream);
|
||||
bool LoadAOTIRCache(int streamfd);
|
||||
bool WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
// Used for thread creation from syscalls
|
||||
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
|
||||
|
||||
+148
-100
@@ -30,12 +30,16 @@ $end_info$
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
#include "FEXCore/Utils/Allocator.h"
|
||||
|
||||
#include <xxh3.h>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Interface/Core/GdbServer.h"
|
||||
|
||||
@@ -172,13 +176,17 @@ namespace FEXCore::Context {
|
||||
Threads.clear();
|
||||
}
|
||||
|
||||
// AOTIRCache needs manual clear
|
||||
for (auto &Mod: AOTIRCache) {
|
||||
// AOTIRCaptureCache needs manual clear
|
||||
for (auto &Mod: AOTIRCaptureCache) {
|
||||
for (auto &Entry: Mod.second) {
|
||||
delete Entry.second.IR;
|
||||
free(Entry.second.RAData);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &Mod: AOTIRCache) {
|
||||
FEXCore::Allocator::munmap(Mod.second.mapping, Mod.second.size);
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::InitCore(FEXCore::CodeLoader *Loader) {
|
||||
@@ -776,6 +784,41 @@ namespace FEXCore::Context {
|
||||
return {IRList, RAData.release(), TotalInstructions, TotalInstructionsLength, Thread->FrontendDecoder->DecodedMinAddress, Thread->FrontendDecoder->DecodedMaxAddress - Thread->FrontendDecoder->DecodedMinAddress };
|
||||
}
|
||||
|
||||
AOTIRInlineEntry *AOTIRInlineIndex::GetInlineEntry(uint64_t DataOffset) {
|
||||
uintptr_t This = (uintptr_t)this;
|
||||
|
||||
return (AOTIRInlineEntry*)(This + DataBase + DataOffset);
|
||||
}
|
||||
|
||||
AOTIRInlineEntry *AOTIRInlineIndex::Find(uint64_t GuestStart) {
|
||||
ssize_t l = 0;
|
||||
ssize_t r = Count - 1;
|
||||
|
||||
while (l <= r) {
|
||||
size_t m = l + (r - l) / 2;
|
||||
|
||||
if (Entries[m].GuestStart == GuestStart)
|
||||
return GetInlineEntry(Entries[m].DataOffset);
|
||||
else if (Entries[m].GuestStart < GuestStart)
|
||||
l = m + 1;
|
||||
else
|
||||
r = m - 1;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IR::RegisterAllocationData *AOTIRInlineEntry::GetRAData() {
|
||||
return (IR::RegisterAllocationData *)InlineData;
|
||||
}
|
||||
|
||||
IR::IRListView *AOTIRInlineEntry::GetIRData() {
|
||||
auto RAData = GetRAData();
|
||||
auto Offset = RAData->Size(RAData->MapCount);
|
||||
|
||||
return (IR::IRListView *)&InlineData[Offset];
|
||||
}
|
||||
|
||||
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> Context::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||
FEXCore::IR::IRListView *IRList {};
|
||||
FEXCore::Core::DebugData *DebugData {};
|
||||
@@ -804,28 +847,36 @@ namespace FEXCore::Context {
|
||||
auto file = AddrToFile.lower_bound(GuestRIP);
|
||||
if (file != AddrToFile.begin()) {
|
||||
--file;
|
||||
auto Mod = (decltype(AOTIRCache)::value_type::second_type*) file->second.CachedFileEntry;
|
||||
auto Mod = (AOTIRInlineIndex*)file->second.CachedFileEntry;
|
||||
|
||||
if (Mod == nullptr) {
|
||||
file->second.CachedFileEntry = Mod = &AOTIRCache[file->second.fileid];
|
||||
file->second.CachedFileEntry = Mod = AOTIRCache[file->second.fileid].Array;
|
||||
}
|
||||
|
||||
auto AOTEntry = Mod->find(GuestRIP - file->second.Start + file->second.Offset);
|
||||
if (Mod != nullptr)
|
||||
{
|
||||
auto AOTEntry = Mod->Find(GuestRIP - file->second.Start + file->second.Offset);
|
||||
|
||||
if (AOTEntry != Mod->end()) {
|
||||
// verify hash
|
||||
auto MappedStart = AOTEntry->second.start + file->second.Start - file->second.Offset;
|
||||
auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->second.len);
|
||||
if (hash == AOTEntry->second.crc) {
|
||||
IRList = AOTEntry->second.IR;
|
||||
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
|
||||
if (AOTEntry) {
|
||||
// verify hash
|
||||
auto MappedStart = GuestRIP;
|
||||
auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->GuestLength);
|
||||
if (hash == AOTEntry->GuestHash) {
|
||||
IRList = AOTEntry->GetIRData();
|
||||
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
|
||||
|
||||
RAData = AOTEntry->second.RAData;
|
||||
DebugData = new FEXCore::Core::DebugData();
|
||||
StartAddr = MappedStart;
|
||||
Length = AOTEntry->second.len;
|
||||
|
||||
GeneratedIR = true;
|
||||
RAData = AOTEntry->GetRAData();;
|
||||
DebugData = new FEXCore::Core::DebugData();
|
||||
StartAddr = MappedStart;
|
||||
Length = AOTEntry->GuestLength;
|
||||
|
||||
GeneratedIR = true;
|
||||
} else {
|
||||
LogMan::Msg::I("AOTIR: hash check failed %lx\n", MappedStart);
|
||||
}
|
||||
} else {
|
||||
//LogMan::Msg::I("AOTIR: Failed to find %lx, %lx, %s\n", GuestRIP, GuestRIP - file->second.Start + file->second.Offset, file->second.fileid.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,87 +908,49 @@ namespace FEXCore::Context {
|
||||
return { Thread->CPUBackend->CompileCode(GuestRIP, IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR, StartAddr, Length};
|
||||
}
|
||||
|
||||
bool Context::LoadAOTIRCache(std::istream &stream) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
static bool readAll(int fd, void *data, size_t size) {
|
||||
int rv = read(fd, data, size);
|
||||
|
||||
if (rv != size)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::LoadAOTIRCache(int streamfd) {
|
||||
uint64_t tag;
|
||||
stream.read((char*)&tag, sizeof(tag));
|
||||
if (!stream || tag != 0xDEADBEEFC0D30002)
|
||||
|
||||
if (!readAll(streamfd, (char*)&tag, sizeof(tag)) || tag != 0xDEADBEEFC0D30003)
|
||||
return false;
|
||||
|
||||
std::string Module;
|
||||
uint64_t ModSize;
|
||||
|
||||
if (!readAll(streamfd, (char*)&ModSize, sizeof(ModSize)))
|
||||
return false;
|
||||
|
||||
uint64_t ModCount;
|
||||
stream.read((char*)&ModCount, sizeof(ModCount));
|
||||
if (!stream)
|
||||
Module.resize(ModSize);
|
||||
if (!readAll(streamfd, (char*)&Module[0], Module.size()))
|
||||
return false;
|
||||
|
||||
for (int ModIndex = 0; ModIndex < ModCount; ModIndex++) {
|
||||
std::string Module;
|
||||
uint64_t ModSize;
|
||||
stream.read((char*)&ModSize, sizeof(ModSize));
|
||||
if (!stream)
|
||||
return false;
|
||||
struct stat fileinfo;
|
||||
if (fstat(streamfd, &fileinfo) < 0)
|
||||
return false;
|
||||
size_t Size = (fileinfo.st_size + 4095) & ~4095;
|
||||
|
||||
Module.resize(ModSize);
|
||||
stream.read((char*)&Module[0], Module.size());
|
||||
if (!stream)
|
||||
return false;
|
||||
void *FilePtr = FEXCore::Allocator::mmap(nullptr, Size, PROT_READ, MAP_SHARED, streamfd, 0);
|
||||
|
||||
auto &Mod = AOTIRCache[Module];
|
||||
if (FilePtr == MAP_FAILED)
|
||||
return false;
|
||||
|
||||
uint64_t FnCount;
|
||||
stream.read((char*)&FnCount, sizeof(FnCount));
|
||||
if (!stream)
|
||||
return false;
|
||||
auto Array = (AOTIRInlineIndex *)((char*)FilePtr + sizeof(tag) + sizeof(ModSize) + ((ModSize+31) & ~31));
|
||||
|
||||
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), FnCount);
|
||||
for (int FnIndex = 0; FnIndex < FnCount; FnIndex++) {
|
||||
uint64_t addr, start, crc, len;
|
||||
stream.read((char*)&addr, sizeof(addr));
|
||||
if (!stream)
|
||||
return false;
|
||||
AOTIRCache.insert({Module, {Array, FilePtr, Size}});
|
||||
|
||||
stream.read((char*)&start, sizeof(start));
|
||||
if (!stream)
|
||||
return false;
|
||||
stream.read((char*)&len, sizeof(len));
|
||||
if (!stream)
|
||||
return false;
|
||||
stream.read((char*)&crc, sizeof(crc));
|
||||
if (!stream)
|
||||
return false;
|
||||
auto IR = new IR::IRListView(stream);
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
uint64_t RASize;
|
||||
stream.read((char*)&RASize, sizeof(RASize));
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
IR::RegisterAllocationData *RAData = (IR::RegisterAllocationData *)malloc(IR::RegisterAllocationData::Size(RASize));
|
||||
RAData->MapCount = RASize;
|
||||
|
||||
stream.read((char*)&RAData->Map[0], sizeof(RAData->Map[0]) * RASize);
|
||||
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
stream.read((char*)&RAData->SpillSlotCount, sizeof(RAData->SpillSlotCount));
|
||||
if (!stream) {
|
||||
delete IR;
|
||||
return false;
|
||||
}
|
||||
|
||||
IR->SetShared(true);
|
||||
RAData->IsShared = true;
|
||||
|
||||
Mod.insert({addr, {start, len, crc, IR, RAData}});
|
||||
}
|
||||
}
|
||||
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), Array->Count);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Context::WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter) {
|
||||
@@ -945,7 +958,7 @@ namespace FEXCore::Context {
|
||||
|
||||
bool rv = true;
|
||||
|
||||
for (auto AOTModule: AOTIRCache) {
|
||||
for (auto AOTModule: AOTIRCaptureCache) {
|
||||
if (AOTModule.second.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -954,28 +967,59 @@ namespace FEXCore::Context {
|
||||
if (!*stream) {
|
||||
rv = false;
|
||||
}
|
||||
uint64_t tag = 0xDEADBEEFC0D30002;
|
||||
uint64_t tag = 0xDEADBEEFC0D30003;
|
||||
stream->write((char*)&tag, sizeof(tag));
|
||||
|
||||
uint64_t ModCount = 1;
|
||||
stream->write((char*)&ModCount, sizeof(ModCount));
|
||||
auto ModSize = AOTModule.first.size();
|
||||
stream->write((char*)&ModSize, sizeof(ModSize));
|
||||
stream->write((char*)&AOTModule.first[0], ModSize);
|
||||
|
||||
auto Skip = ((ModSize + 31) & ~31) - ModSize;
|
||||
char Zero = 0;
|
||||
for (int i = 0; i < Skip; i++)
|
||||
stream->write(&Zero, 1);
|
||||
|
||||
// AOTIRInlineIndex
|
||||
|
||||
|
||||
auto FnCount = AOTModule.second.size();
|
||||
stream->write((char*)&FnCount, sizeof(FnCount));
|
||||
|
||||
size_t DataBase = sizeof(FnCount) + sizeof(DataBase) + FnCount * sizeof(AOTIRInlineIndexEntry);
|
||||
stream->write((char*)&DataBase, sizeof(DataBase));
|
||||
|
||||
size_t DataOffset = 0;
|
||||
for (auto entry: AOTModule.second) {
|
||||
//AOTIRInlineIndexEntry
|
||||
|
||||
// GuestStart
|
||||
stream->write((char*)&entry.first, sizeof(entry.first));
|
||||
stream->write((char*)&entry.second.start, sizeof(entry.second.start));
|
||||
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
|
||||
|
||||
// DataOffset
|
||||
stream->write((char*)&DataOffset, sizeof(DataOffset));
|
||||
|
||||
|
||||
DataOffset += sizeof(entry.second.crc);
|
||||
DataOffset += sizeof(entry.second.len);
|
||||
|
||||
DataOffset += entry.second.RAData->Size(entry.second.RAData->MapCount);
|
||||
|
||||
DataOffset += entry.second.IR->GetInlineSize();
|
||||
}
|
||||
|
||||
// AOTIRInlineEntry
|
||||
for (auto entry: AOTModule.second) {
|
||||
//GuestHash
|
||||
stream->write((char*)&entry.second.crc, sizeof(entry.second.crc));
|
||||
|
||||
//GuestLength
|
||||
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
|
||||
|
||||
// RAData (inline)
|
||||
stream->write((char*)entry.second.RAData, entry.second.RAData->Size(entry.second.RAData->MapCount));
|
||||
|
||||
// IRData (inline)
|
||||
entry.second.IR->Serialize(*stream);
|
||||
uint64_t RASize = entry.second.RAData->MapCount;
|
||||
stream->write((char*)&RASize, sizeof(RASize));
|
||||
stream->write((char*)&entry.second.RAData->Map[0], sizeof(entry.second.RAData->Map[0]) * RASize);
|
||||
stream->write((char*)&entry.second.RAData->SpillSlotCount, sizeof(entry.second.RAData->SpillSlotCount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1068,7 +1112,7 @@ namespace FEXCore::Context {
|
||||
if (file != AddrToFile.begin()) {
|
||||
--file;
|
||||
if (file->second.Start <= StartAddr && (file->second.Start + file->second.Len) >= (StartAddr + Length)) {
|
||||
AOTIRCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
|
||||
AOTIRCaptureCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1220,18 +1264,22 @@ namespace FEXCore::Context {
|
||||
fileid += Config.ABILocalFlags ? "L" : "l";
|
||||
fileid += Config.ABINoPF ? "p" : "P";
|
||||
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
|
||||
AddrToFile.insert({ Base, { Base, Size, Offset, fileid, nullptr } });
|
||||
|
||||
if (Config.AOTIRLoad && !AOTIRCache.contains(fileid) && AOTIRLoader) {
|
||||
auto stream = AOTIRLoader(fileid);
|
||||
if (*stream) {
|
||||
LoadAOTIRCache(*stream);
|
||||
auto streamfd = AOTIRLoader(fileid);
|
||||
if (streamfd != -1) {
|
||||
LoadAOTIRCache(streamfd);
|
||||
close(streamfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::RemoveNamedRegion(uintptr_t Base, uintptr_t Size) {
|
||||
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
|
||||
// TODO: Support partial removing
|
||||
AddrToFile.erase(Base);
|
||||
}
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ namespace FEXCore::Context {
|
||||
|
||||
__attribute__((visibility("default"))) void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name);
|
||||
__attribute__((visibility("default"))) void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
|
||||
__attribute__((visibility("default"))) void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader);
|
||||
__attribute__((visibility("default"))) void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader);
|
||||
__attribute__((visibility("default"))) bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
__attribute__((visibility("default"))) void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
|
||||
}
|
||||
+66
-45
@@ -89,77 +89,90 @@ class DualIntrusiveAllocator final {
|
||||
|
||||
|
||||
class IRListView final {
|
||||
enum Flags {
|
||||
FLAG_IsCopy = 1,
|
||||
FLAG_Shared = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
IRListView() = delete;
|
||||
IRListView(IRListView &&) = delete;
|
||||
|
||||
IRListView(DualIntrusiveAllocator *Data, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||
IRListView(DualIntrusiveAllocator *Data, bool _IsCopy) {
|
||||
SetCopy(_IsCopy);
|
||||
DataSize = Data->DataSize();
|
||||
ListSize = Data->ListSize();
|
||||
|
||||
if (IsCopy) {
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
memcpy(IRData, reinterpret_cast<void*>(Data->DataBegin()), DataSize);
|
||||
memcpy(ListData, reinterpret_cast<void*>(Data->ListBegin()), ListSize);
|
||||
if (_IsCopy) {
|
||||
IRDataInternal = malloc(DataSize + ListSize);
|
||||
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
|
||||
memcpy(IRDataInternal, reinterpret_cast<void*>(Data->DataBegin()), DataSize);
|
||||
memcpy(ListDataInternal, reinterpret_cast<void*>(Data->ListBegin()), ListSize);
|
||||
}
|
||||
else {
|
||||
// We are just pointing to the data
|
||||
IRData = reinterpret_cast<void*>(Data->DataBegin());
|
||||
ListData = reinterpret_cast<void*>(Data->ListBegin());
|
||||
IRDataInternal = reinterpret_cast<void*>(Data->DataBegin());
|
||||
ListDataInternal = reinterpret_cast<void*>(Data->ListBegin());
|
||||
}
|
||||
}
|
||||
|
||||
IRListView(IRListView *Old, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||
IRListView(IRListView *Old, bool _IsCopy) {
|
||||
SetCopy(_IsCopy);
|
||||
DataSize = Old->DataSize;
|
||||
ListSize = Old->ListSize;
|
||||
if (IsCopy) {
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
memcpy(IRData, Old->IRData, DataSize);
|
||||
memcpy(ListData, Old->ListData, ListSize);
|
||||
if (_IsCopy) {
|
||||
IRDataInternal = malloc(DataSize + ListSize);
|
||||
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
|
||||
memcpy(IRDataInternal, Old->IRDataInternal, DataSize);
|
||||
memcpy(ListDataInternal, Old->ListDataInternal, ListSize);
|
||||
} else {
|
||||
IRData = Old->IRData;
|
||||
ListData = Old->ListData;
|
||||
IRDataInternal = Old->IRDataInternal;
|
||||
ListDataInternal = Old->ListDataInternal;
|
||||
}
|
||||
}
|
||||
|
||||
IRListView(std::istream& stream) : IsCopy(true) {
|
||||
stream.read((char*)&DataSize, sizeof(DataSize));
|
||||
stream.read((char*)&ListSize, sizeof(ListSize));
|
||||
|
||||
IRData = malloc(DataSize + ListSize);
|
||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||
stream.read((char*)IRData, DataSize);
|
||||
stream.read((char*)ListData, ListSize);
|
||||
}
|
||||
|
||||
~IRListView() {
|
||||
if (IsCopy) {
|
||||
free (IRData);
|
||||
if (IsCopy()) {
|
||||
free (IRDataInternal);
|
||||
// ListData is just offset from IRData
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(std::ostream& stream) {
|
||||
void *nul = nullptr;
|
||||
//void *IRDataInternal;
|
||||
stream.write((char*)&nul, sizeof(nul));
|
||||
//void *ListDataInternal;
|
||||
stream.write((char*)&nul, sizeof(nul));
|
||||
//size_t DataSize;
|
||||
stream.write((char*)&DataSize, sizeof(DataSize));
|
||||
//size_t ListSize;
|
||||
stream.write((char*)&ListSize, sizeof(ListSize));
|
||||
stream.write((char*)IRData, DataSize);
|
||||
stream.write((char*)ListData, ListSize);
|
||||
//uint64_t Flags;
|
||||
uint64_t WrittenFlags = Flags | FLAG_Shared; //on disk format always has the Shared flag
|
||||
stream.write((char*)&WrittenFlags, sizeof(WrittenFlags));
|
||||
|
||||
// inline data
|
||||
stream.write((char*)GetData(), DataSize);
|
||||
stream.write((char*)GetListData(), ListSize);
|
||||
}
|
||||
|
||||
size_t GetInlineSize() {
|
||||
static_assert(sizeof(*this) == 40);
|
||||
return sizeof(*this) + DataSize + ListSize;
|
||||
}
|
||||
|
||||
IRListView *CreateCopy() {
|
||||
return new IRListView(this, true);
|
||||
}
|
||||
|
||||
uintptr_t const GetData() const { return reinterpret_cast<uintptr_t>(IRData); }
|
||||
uintptr_t const GetListData() const { return reinterpret_cast<uintptr_t>(ListData); }
|
||||
|
||||
size_t GetDataSize() const { return DataSize; }
|
||||
size_t GetListSize() const { return ListSize; }
|
||||
size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); }
|
||||
bool IsShared() const { return _IsShared; }
|
||||
void SetShared(bool Set) { _IsShared = Set; }
|
||||
bool IsCopy() const { return Flags & FLAG_IsCopy; }
|
||||
void SetCopy(bool Set) { if (Set) Flags |= FLAG_IsCopy; else Flags &= ~FLAG_IsCopy; }
|
||||
bool IsShared() const { return Flags & FLAG_Shared; }
|
||||
void SetShared(bool Set) { if (Set) Flags |= FLAG_Shared; else Flags &= ~FLAG_Shared; }
|
||||
|
||||
uint32_t GetID(OrderedNode *Node) const {
|
||||
return Node->Wrapped(GetListData()).ID();
|
||||
@@ -268,7 +281,7 @@ public:
|
||||
{
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = sizeof(OrderedNode);
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,7 +293,7 @@ public:
|
||||
{
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = 0;
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,27 +301,35 @@ public:
|
||||
* @return Iterator for this op
|
||||
*/
|
||||
iterator at(OrderedNodeWrapper Wrapped) const noexcept {
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
iterator at(uint32_t ID) const noexcept {
|
||||
OrderedNodeWrapper Wrapped;
|
||||
Wrapped.NodeOffset = ID * sizeof(OrderedNode);
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
iterator at(OrderedNode *Node) const noexcept {
|
||||
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(ListData));
|
||||
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
|
||||
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(GetListData()));
|
||||
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
|
||||
}
|
||||
|
||||
uintptr_t const GetData() const {
|
||||
return reinterpret_cast<uintptr_t>(IRDataInternal ? IRDataInternal : InlineData);
|
||||
}
|
||||
|
||||
uintptr_t const GetListData() const {
|
||||
return reinterpret_cast<uintptr_t>(ListDataInternal ? ListDataInternal : &InlineData[DataSize]);
|
||||
}
|
||||
|
||||
private:
|
||||
void *IRData;
|
||||
void *ListData;
|
||||
void *IRDataInternal;
|
||||
void *ListDataInternal;
|
||||
size_t DataSize;
|
||||
size_t ListSize;
|
||||
bool IsCopy;
|
||||
bool _IsShared {false};
|
||||
uint64_t Flags {0};
|
||||
uint8_t InlineData[0];
|
||||
};
|
||||
|
||||
struct IRListViewDeleter {
|
||||
|
||||
@@ -320,10 +320,10 @@ int main(int argc, char **argv, char **const envp) {
|
||||
LogMan::Msg::I("Warning: AOTIR is experimental, and might lead to crashes. Capture doesn't work with programs that fork.");
|
||||
}
|
||||
|
||||
FEXCore::Context::SetAOTIRLoader(CTX, [](const std::string &fileid) -> std::unique_ptr<std::istream> {
|
||||
FEXCore::Context::SetAOTIRLoader(CTX, [](const std::string &fileid) -> int {
|
||||
auto filepath = std::filesystem::path(FEXCore::Config::GetDataDirectory()) / "aotir" / fileid;
|
||||
|
||||
return std::make_unique<std::ifstream>(filepath, std::ios::in | std::ios::binary);
|
||||
return open(filepath.c_str(), O_RDONLY);
|
||||
});
|
||||
|
||||
for(auto handler: Loader.AOTMappers) {
|
||||
|
||||
Reference in new issue
Block a user