Merge pull request #976 from FEX-Emu/skmp/aotir-mmap

AOTIR: Switch over to mmap-based loading
This commit is contained in:
Ryan Houdek authored and GitHub committed 2021-04-30 18:24:54 -07:00
commit a30866a886
6 files changed
+258 -157

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2 -2
View File
@@ -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) {