Merge pull request #2549 from Sonicadvance1/glibc_remaining_allocations

Move FEX away from the remaining glibc allocations that we can
This commit is contained in:
Ryan Houdek 2023-04-01 09:46:29 -07:00 committed by GitHub
commit aac4e25ca4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 1293 additions and 485 deletions

2
.gitmodules vendored
View File

@ -3,7 +3,7 @@
path = External/vixl
url = https://github.com/FEX-Emu/vixl.git
[submodule "External/cpp-optparse"]
path = External/cpp-optparse
path = Source/Common/cpp-optparse
url = https://github.com/Sonicadvance1/cpp-optparse
[submodule "External/imgui"]
path = External/imgui

View File

@ -33,6 +33,7 @@ option(ENABLE_VIXL_DISASSEMBLER "Enables debug disassembler output with VIXL" FA
option(COMPILE_VIXL_DISASSEMBLER "Compiles the vixl disassembler in to vixl" FALSE)
option(ENABLE_FEXCORE_PROFILER "Enables use of the FEXCore timeline profiling capabilities" FALSE)
set (FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend you want to use for the FEXCore profiler")
option(ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT "Enables glibc memory allocation hooking with fault for CI testing")
set (X86_32_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/toolchain_x86_32.cmake" CACHE FILEPATH "Toolchain file for the (cross-)compiler targeting i686")
set (X86_64_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/toolchain_x86_64.cmake" CACHE FILEPATH "Toolchain file for the (cross-)compiler targeting x86_64")
@ -56,6 +57,10 @@ if (ENABLE_FEXCORE_PROFILER)
endif()
endif()
if (ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT)
add_definitions(-DGLIBC_ALLOCATOR_FAULT=1)
endif()
# uninstall target
if(NOT TARGET uninstall)
configure_file(
@ -237,9 +242,6 @@ if (BUILD_TESTS)
include(Catch)
endif()
add_subdirectory(External/cpp-optparse/)
include_directories(External/cpp-optparse/)
add_subdirectory(External/fmt/)
add_subdirectory(External/imgui/)

View File

@ -387,7 +387,7 @@ def print_parse_argloader_options(options):
output_argloader.write("\t}\n")
else:
if (NeedsString):
output_argloader.write("\tfextl::string UserValue = fextl::string_from_string(Options[\"{0}\"]);\n".format(op_key))
output_argloader.write("\tfextl::string UserValue = Options[\"{0}\"];\n".format(op_key))
else:
output_argloader.write("\t{0} UserValue = Options.get(\"{1}\");\n".format(value_type, op_key))

View File

@ -146,6 +146,11 @@ set (SRCS
Utils/Profiler.cpp
)
if (ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT)
list(APPEND FEXCORE_BASE_SRCS
Utils/AllocatorOverride.cpp)
endif()
if (ENABLE_INTERPRETER)
list(APPEND SRCS
Interface/Core/Interpreter/InterpreterCore.cpp

View File

@ -1,17 +1,21 @@
#include "Common/Paths.h"
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <cstdlib>
#include <filesystem>
#include <memory>
#include <pwd.h>
#include <system_error>
#include <sys/stat.h>
#include <unistd.h>
namespace FEXCore::Paths {
std::unique_ptr<fextl::string> CachePath;
std::unique_ptr<fextl::string> EntryCache;
fextl::string CachePath{};
fextl::string EntryCache{};
char const* FindUserHomeThroughUID() {
auto passwd = getpwuid(geteuid());
@ -43,9 +47,6 @@ namespace FEXCore::Paths {
}
void InitializePaths() {
CachePath = std::make_unique<fextl::string>();
EntryCache = std::make_unique<fextl::string>();
char const *HomeDir = getenv("HOME");
if (!HomeDir) {
@ -58,35 +59,29 @@ namespace FEXCore::Paths {
char *XDGDataDir = getenv("XDG_DATA_DIR");
if (XDGDataDir) {
*CachePath = XDGDataDir;
CachePath = XDGDataDir;
}
else {
if (HomeDir) {
*CachePath = HomeDir;
CachePath = HomeDir;
}
}
*CachePath += "/.fex-emu/";
*EntryCache = *CachePath + "/EntryCache/";
CachePath += "/.fex-emu/";
EntryCache = CachePath + "/EntryCache/";
std::error_code ec{};
// Ensure the folder structure is created for our Data
if (!std::filesystem::exists(*EntryCache, ec) &&
!std::filesystem::create_directories(*EntryCache, ec)) {
LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", *EntryCache);
if (!FHU::Filesystem::Exists(EntryCache) &&
!FHU::Filesystem::CreateDirectories(EntryCache)) {
LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", EntryCache);
}
}
void ShutdownPaths() {
CachePath.reset();
EntryCache.reset();
}
fextl::string GetCachePath() {
return *CachePath;
return CachePath;
}
fextl::string GetEntryCachePath() {
return *EntryCache;
return EntryCache;
}
}

View File

@ -4,13 +4,16 @@
#include "Utils/FileLoading.h"
#include <FEXCore/Config/Config.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/CPUInfo.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/unordered_map.h>
#include <FEXCore/fextl/vector.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <array>
#include <assert.h>
@ -18,7 +21,7 @@
#include <filesystem>
#include <fstream>
#include <functional>
#include <memory>
#include <linux/limits.h>
#include <optional>
#include <stddef.h>
#include <stdint.h>
@ -45,13 +48,13 @@ namespace DefaultValues {
namespace JSON {
struct JsonAllocator {
jsonPool_t PoolObject;
std::unique_ptr<fextl::list<json_t>> json_objects;
fextl::unique_ptr<fextl::list<json_t>> json_objects;
};
static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero");
json_t* PoolInit(jsonPool_t* Pool) {
JsonAllocator* alloc = reinterpret_cast<JsonAllocator*>(Pool);
alloc->json_objects = std::make_unique<fextl::list<json_t>>();
alloc->json_objects = fextl::make_unique<fextl::list<json_t>>();
return &*alloc->json_objects->emplace(alloc->json_objects->end());
}
@ -143,9 +146,8 @@ namespace JSON {
}
// Ensure the folder structure is created for our configuration
std::error_code ec{};
if (!std::filesystem::exists(ConfigDir, ec) &&
!std::filesystem::create_directories(ConfigDir, ec)) {
if (!FHU::Filesystem::Exists(ConfigDir) &&
!FHU::Filesystem::CreateDirectories(ConfigDir)) {
// Let's go local in this case
return "./";
}
@ -175,10 +177,9 @@ namespace JSON {
fextl::string GetApplicationConfig(const fextl::string &Filename, bool Global) {
fextl::string ConfigFile = GetConfigDirectory(Global);
std::error_code ec{};
if (!Global &&
!std::filesystem::exists(ConfigFile, ec) &&
!std::filesystem::create_directories(ConfigFile, ec)) {
!FHU::Filesystem::Exists(ConfigFile) &&
!FHU::Filesystem::CreateDirectories(ConfigFile)) {
LogMan::Msg::DFmt("Couldn't create config directory: '{}'", ConfigFile);
// Let's go local in this case
return "./" + Filename + ".json";
@ -188,8 +189,8 @@ namespace JSON {
// Attempt to create the local folder if it doesn't exist
if (!Global &&
!std::filesystem::exists(ConfigFile, ec) &&
!std::filesystem::create_directories(ConfigFile, ec)) {
!FHU::Filesystem::Exists(ConfigFile) &&
!FHU::Filesystem::CreateDirectories(ConfigFile)) {
// Let's go local in this case
return "./" + Filename + ".json";
}
@ -208,7 +209,7 @@ namespace JSON {
return 0;
}
static fextl::map<FEXCore::Config::LayerType, std::unique_ptr<FEXCore::Config::Layer>> ConfigLayers;
static fextl::map<FEXCore::Config::LayerType, fextl::unique_ptr<FEXCore::Config::Layer>> ConfigLayers;
static FEXCore::Config::Layer *Meta{};
constexpr std::array<FEXCore::Config::LayerType, 9> LoadOrder = {
@ -311,7 +312,7 @@ namespace JSON {
}
void Initialize() {
AddLayer(std::make_unique<MetaLayer>(FEXCore::Config::LayerType::LAYER_TOP));
AddLayer(fextl::make_unique<MetaLayer>(FEXCore::Config::LayerType::LAYER_TOP));
Meta = ConfigLayers.begin()->second.get();
}
@ -334,10 +335,9 @@ namespace JSON {
return {};
}
std::filesystem::path Path{PathName};
// Expand home if it exists
if (Path.is_relative()) {
if (FHU::Filesystem::IsRelative(PathName)) {
fextl::string Home = getenv("HOME") ?: "";
// Home expansion only works if it is the first character
// This matches bash behaviour
@ -347,12 +347,15 @@ namespace JSON {
}
// Expand relative path to absolute
Path = std::filesystem::absolute(Path);
char ExistsTempPath[PATH_MAX];
char *RealPath = realpath(PathName.c_str(), ExistsTempPath);
if (RealPath) {
PathName = RealPath;
}
// Only return if it exists
std::error_code ec{};
if (std::filesystem::exists(Path, ec)) {
return fextl::string_from_path(Path);
if (FHU::Filesystem::Exists(PathName)) {
return PathName;
}
}
else {
@ -368,9 +371,9 @@ namespace JSON {
// HostThunks: $CMAKE_INSTALL_PREFIX/lib/fex-emu/HostThunks/
// GuestThunks: $CMAKE_INSTALL_PREFIX/share/fex-emu/GuestThunks/
if (!ContainerPrefix.empty() && !PathName.empty()) {
if (!std::filesystem::exists(PathName)) {
if (!FHU::Filesystem::Exists(PathName)) {
auto ContainerPath = ContainerPrefix + PathName;
if (std::filesystem::exists(ContainerPath)) {
if (FHU::Filesystem::Exists(ContainerPath)) {
return ContainerPath;
}
}
@ -379,11 +382,11 @@ namespace JSON {
return {};
}
constexpr char ContainerManager[] = "/run/host/container-manager";
fextl::string FindContainer() {
// We only support pressure-vessel at the moment
const static fextl::string ContainerManager = "/run/host/container-manager";
if (std::filesystem::exists(ContainerManager)) {
if (FHU::Filesystem::Exists(ContainerManager)) {
fextl::vector<char> Manager{};
if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) {
// Trim the whitespace, may contain a newline
@ -397,8 +400,7 @@ namespace JSON {
fextl::string FindContainerPrefix() {
// We only support pressure-vessel at the moment
const static fextl::string ContainerManager = "/run/host/container-manager";
if (std::filesystem::exists(ContainerManager)) {
if (FHU::Filesystem::Exists(ContainerManager)) {
fextl::vector<char> Manager{};
if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) {
// Trim the whitespace, may contain a newline
@ -467,7 +469,7 @@ namespace JSON {
if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_ROOTFS)) {
FEX_CONFIG_OPT(PathName, ROOTFS);
auto ExpandedString = ExpandPath(ContainerPrefix, PathName());
auto ExpandedString = ExpandPath(ContainerPrefix,PathName());
if (!ExpandedString.empty()) {
// Adjust the path if it ended up being relative
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, ExpandedString);
@ -518,7 +520,7 @@ namespace JSON {
}
}
void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer) {
void AddLayer(fextl::unique_ptr<FEXCore::Config::Layer> _Layer) {
ConfigLayers.emplace(_Layer->GetLayerType(), std::move(_Layer));
}
@ -705,7 +707,8 @@ namespace JSON {
}
void EnvLoader::Load() {
fextl::unordered_map<std::string_view, std::string_view> EnvMap;
using EnvMapType = fextl::unordered_map<std::string_view, std::string_view>;
EnvMapType EnvMap;
for(const char *const *pvar=envp; pvar && *pvar; pvar++) {
std::string_view Var(*pvar);
@ -719,10 +722,10 @@ namespace JSON {
#define ENVLOADER
#include <FEXCore/Config/ConfigOptions.inl>
EnvMap[Key]=Value;
EnvMap[Key] = Value;
}
std::function GetVar = [=](const std::string_view id) -> std::optional<std::string_view> {
auto GetVar = [](EnvMapType &EnvMap, const std::string_view id) -> std::optional<std::string_view> {
if (EnvMap.find(id) != EnvMap.end())
return EnvMap.at(id);
@ -739,31 +742,31 @@ namespace JSON {
std::optional<std::string_view> Value;
for (auto &it : EnvConfigLookup) {
if ((Value = GetVar(it.first)).has_value()) {
if ((Value = GetVar(EnvMap, it.first)).has_value()) {
Set(it.second, fextl::string(*Value));
}
}
}
std::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer() {
return std::make_unique<FEXCore::Config::MainLoader>(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN);
fextl::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer() {
return fextl::make_unique<FEXCore::Config::MainLoader>(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN);
}
std::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(fextl::string const *File) {
fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(fextl::string const *File) {
if (File) {
return std::make_unique<FEXCore::Config::MainLoader>(*File);
return fextl::make_unique<FEXCore::Config::MainLoader>(*File);
}
else {
return std::make_unique<FEXCore::Config::MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN);
return fextl::make_unique<FEXCore::Config::MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN);
}
}
std::unique_ptr<FEXCore::Config::Layer> CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) {
return std::make_unique<FEXCore::Config::AppLoader>(Filename, Type);
fextl::unique_ptr<FEXCore::Config::Layer> CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) {
return fextl::make_unique<FEXCore::Config::AppLoader>(Filename, Type);
}
std::unique_ptr<FEXCore::Config::Layer> CreateEnvironmentLayer(char *const _envp[]) {
return std::make_unique<FEXCore::Config::EnvLoader>(_envp);
fextl::unique_ptr<FEXCore::Config::Layer> CreateEnvironmentLayer(char *const _envp[]) {
return fextl::make_unique<FEXCore::Config::EnvLoader>(_envp);
}
}

View File

@ -24,10 +24,6 @@ namespace FEXCore::Context {
IR::InstallOpcodeHandlers(Mode);
}
void ShutdownStaticTables() {
FEXCore::Paths::ShutdownPaths();
}
FEXCore::Context::Context *FEXCore::Context::Context::CreateNewContext() {
return new FEXCore::Context::ContextImpl{};
}

View File

@ -15,6 +15,7 @@
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/Event.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/set.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/unordered_map.h>
@ -261,14 +262,14 @@ namespace FEXCore::Context {
FEXCore::CPUIDEmu CPUID;
FEXCore::HLE::SyscallHandler *SyscallHandler{};
FEXCore::HLE::SourcecodeResolver *SourcecodeResolver{};
std::unique_ptr<FEXCore::ThunkHandler> ThunkHandler;
std::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
fextl::unique_ptr<FEXCore::ThunkHandler> ThunkHandler;
fextl::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
CustomCPUFactoryType CustomCPUFactory;
FEXCore::Context::ExitHandler CustomExitHandler;
#ifdef BLOCKSTATS
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
fextl::unique_ptr<FEXCore::BlockSamplingData> BlockData;
#endif
SignalDelegator *SignalDelegation{};
@ -405,10 +406,10 @@ namespace FEXCore::Context {
// Entry Cache
std::mutex ExitMutex;
std::unique_ptr<GdbServer> DebugServer;
fextl::unique_ptr<GdbServer> DebugServer;
IR::AOTIRCaptureCache IRCaptureCache;
std::unique_ptr<FEXCore::CodeSerialize::CodeObjectSerializeService> CodeObjectCacheService;
fextl::unique_ptr<FEXCore::CodeSerialize::CodeObjectSerializeService> CodeObjectCacheService;
bool StartPaused = false;
bool IsMemoryShared = false;

View File

@ -45,6 +45,7 @@ $end_info$
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Threads.h>
#include <FEXCore/Utils/Profiler.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/set.h>
#include <FEXCore/fextl/sstream.h>
#include <FEXCore/fextl/vector.h>
@ -59,7 +60,6 @@ $end_info$
#include <filesystem>
#include <functional>
#include <fstream>
#include <memory>
#include <mutex>
#include <queue>
#include <shared_mutex>
@ -151,7 +151,7 @@ namespace FEXCore::Context {
BlockData = std::make_unique<FEXCore::BlockSamplingData>();
#endif
if (Config.CacheObjectCodeCompilation() != FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) {
CodeObjectCacheService = std::make_unique<FEXCore::CodeSerialize::CodeObjectSerializeService>(this);
CodeObjectCacheService = fextl::make_unique<FEXCore::CodeSerialize::CodeObjectSerializeService>(this);
}
if (!Config.EnableAVX) {
HostFeatures.SupportsAVX = false;
@ -275,7 +275,7 @@ namespace FEXCore::Context {
StopGdbServer();
}
ThunkHandler.reset(FEXCore::ThunkHandler::Create());
ThunkHandler = FEXCore::ThunkHandler::Create();
using namespace FEXCore::Core;
@ -295,7 +295,7 @@ namespace FEXCore::Context {
void ContextImpl::StartGdbServer() {
if (!DebugServer) {
DebugServer = std::make_unique<GdbServer>(this);
DebugServer = fextl::make_unique<GdbServer>(this);
StartPaused = true;
}
}
@ -557,11 +557,11 @@ namespace FEXCore::Context {
}
void ContextImpl::InitializeCompiler(FEXCore::Core::InternalThreadState* Thread) {
Thread->OpDispatcher = std::make_unique<FEXCore::IR::OpDispatchBuilder>(this);
Thread->OpDispatcher = fextl::make_unique<FEXCore::IR::OpDispatchBuilder>(this);
Thread->OpDispatcher->SetMultiblock(Config.Multiblock);
Thread->LookupCache = std::make_unique<FEXCore::LookupCache>(this);
Thread->FrontendDecoder = std::make_unique<FEXCore::Frontend::Decoder>(this);
Thread->PassManager = std::make_unique<FEXCore::IR::PassManager>();
Thread->LookupCache = fextl::make_unique<FEXCore::LookupCache>(this);
Thread->FrontendDecoder = fextl::make_unique<FEXCore::Frontend::Decoder>(this);
Thread->PassManager = fextl::make_unique<FEXCore::IR::PassManager>();
Thread->PassManager->RegisterExitHandler([this]() {
Stop(false /* Ignore current thread */);
});

View File

@ -12,6 +12,7 @@
#include <FEXCore/Core/CoreState.h>
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/fextl/memory.h>
#include <FEXHeaderUtils/Syscalls.h>
#include <array>
@ -672,8 +673,8 @@ void Arm64Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Thr
}
}
std::unique_ptr<Dispatcher> Dispatcher::CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) {
return std::make_unique<Arm64Dispatcher>(CTX, Config);
fextl::unique_ptr<Dispatcher> Dispatcher::CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) {
return fextl::make_unique<Arm64Dispatcher>(CTX, Config);
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/fextl/memory.h>
#include "Interface/Core/ArchHelpers/MContext.h"
#include <cstdint>
@ -73,8 +74,8 @@ public:
virtual size_t GenerateGDBPauseCheck(uint8_t *CodeBuffer, uint64_t GuestRIP) = 0;
virtual size_t GenerateInterpreterTrampoline(uint8_t *CodeBuffer) = 0;
static std::unique_ptr<Dispatcher> CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config);
static std::unique_ptr<Dispatcher> CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config);
static fextl::unique_ptr<Dispatcher> CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config);
static fextl::unique_ptr<Dispatcher> CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config);
virtual void ExecuteDispatch(FEXCore::Core::CpuStateFrame *Frame) {
DispatchPtr(Frame);

View File

@ -11,6 +11,7 @@
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXHeaderUtils/Syscalls.h>
@ -19,7 +20,6 @@
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
#include <xbyak/xbyak.h>
#define STATE_PTR(STATE_TYPE, FIELD) \
[STATE + offsetof(FEXCore::Core::STATE_TYPE, FIELD)]
@ -417,13 +417,11 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::ContextImpl *ctx, const Dispatche
}
// Used by GenerateGDBPauseCheck, GenerateInterpreterTrampoline
static thread_local Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer
size_t X86Dispatcher::GenerateGDBPauseCheck(uint8_t *CodeBuffer, uint64_t GuestRIP) {
using namespace Xbyak;
using namespace Xbyak::util;
Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer
emit.setNewBuffer(CodeBuffer, MaxGDBPauseCheckSize);
Label RunBlock;
@ -458,6 +456,7 @@ size_t X86Dispatcher::GenerateInterpreterTrampoline(uint8_t *CodeBuffer) {
using namespace Xbyak;
using namespace Xbyak::util;
Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer
emit.setNewBuffer(CodeBuffer, MaxInterpreterTrampolineSize);
Label InlineIRData;
@ -500,8 +499,8 @@ void X86Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Threa
}
}
std::unique_ptr<Dispatcher> Dispatcher::CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) {
return std::make_unique<X86Dispatcher>(CTX, Config);
fextl::unique_ptr<Dispatcher> Dispatcher::CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) {
return fextl::make_unique<X86Dispatcher>(CTX, Config);
}
}

View File

@ -1,9 +1,23 @@
#pragma once
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/unordered_map.h>
#include <FEXCore/fextl/unordered_set.h>
#include "Interface/Core/Dispatcher/Dispatcher.h"
#define XBYAK64
#define XBYAK_CUSTOM_ALLOC
#define XBYAK_CUSTOM_MALLOC FEXCore::Allocator::malloc
#define XBYAK_CUSTOM_FREE FEXCore::Allocator::free
#define XBYAK_CUSTOM_SETS
#define XBYAK_STD_UNORDERED_SET fextl::unordered_set
#define XBYAK_STD_UNORDERED_MAP fextl::unordered_map
#define XBYAK_STD_UNORDERED_MULTIMAP fextl::unordered_multimap
#define XBYAK_STD_LIST fextl::list
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
namespace FEXCore::Core {
struct InternalThreadState;

View File

@ -9,7 +9,7 @@
#endif
#ifdef _M_X86_64
#include <xbyak/xbyak_util.h>
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#endif
namespace FEXCore {

View File

@ -10,8 +10,8 @@
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/MathUtils.h>
#include <FEXCore/fextl/memory.h>
#include <memory>
#include <signal.h>
#include <stdint.h>
#include <utility>
@ -103,8 +103,8 @@ void InterpreterCore::ClearCache() {
BufferUsed = 0;
}
std::unique_ptr<CPUBackend> CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return std::make_unique<InterpreterCore>(ctx->Dispatcher.get(), Thread);
fextl::unique_ptr<CPUBackend> CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return fextl::make_unique<InterpreterCore>(ctx->Dispatcher.get(), Thread);
}
void InitializeInterpreterSignalHandlers(FEXCore::Context::ContextImpl *CTX) {

View File

@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/fextl/memory.h>
namespace FEXCore::Context {
class ContextImpl;
@ -14,7 +15,7 @@ namespace FEXCore::CPU {
class CPUBackend;
struct DispatcherConfig;
[[nodiscard]] std::unique_ptr<CPUBackend> CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx,
[[nodiscard]] fextl::unique_ptr<CPUBackend> CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx,
FEXCore::Core::InternalThreadState *Thread);
void InitializeInterpreterSignalHandlers(FEXCore::Context::ContextImpl *CTX);
CPUBackendFeatures GetInterpreterBackendFeatures();

View File

@ -1087,8 +1087,8 @@ void Arm64JITCore::ResetStack() {
}
}
std::unique_ptr<CPUBackend> CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return std::make_unique<Arm64JITCore>(ctx, Thread);
fextl::unique_ptr<CPUBackend> CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return fextl::make_unique<Arm64JITCore>(ctx, Thread);
}
void InitializeArm64JITSignalHandlers(FEXCore::Context::ContextImpl *CTX) {

View File

@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/fextl/memory.h>
namespace FEXCore::Context {
class ContextImpl;
@ -13,12 +14,12 @@ struct InternalThreadState;
namespace FEXCore::CPU {
class CPUBackend;
[[nodiscard]] std::unique_ptr<CPUBackend> CreateX86JITCore(FEXCore::Context::ContextImpl *ctx,
[[nodiscard]] fextl::unique_ptr<CPUBackend> CreateX86JITCore(FEXCore::Context::ContextImpl *ctx,
FEXCore::Core::InternalThreadState *Thread);
void InitializeX86JITSignalHandlers(FEXCore::Context::ContextImpl *CTX);
CPUBackendFeatures GetX86JITBackendFeatures();
[[nodiscard]] std::unique_ptr<CPUBackend> CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx,
[[nodiscard]] fextl::unique_ptr<CPUBackend> CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx,
FEXCore::Core::InternalThreadState *Thread);
void InitializeArm64JITSignalHandlers(FEXCore::Context::ContextImpl *CTX);
CPUBackendFeatures GetArm64JITBackendFeatures();

View File

@ -5,6 +5,7 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/LogManager.h>
@ -12,7 +13,6 @@ $end_info$
#include <array>
#include <stdint.h>
#include <utility>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {

View File

@ -5,6 +5,7 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/LogManager.h>
@ -12,7 +13,6 @@ $end_info$
#include <array>
#include <stdint.h>
#include <utility>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {
#define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node)

View File

@ -7,6 +7,7 @@ $end_info$
#include "Interface/Context/Context.h"
#include "Interface/Core/CPUID.h"
#include "Interface/Core/Dispatcher/Dispatcher.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include "Interface/Core/LookupCache.h"
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/HLE/Thunks/Thunks.h"
@ -25,7 +26,6 @@ $end_info$
#include <stdint.h>
#include <unordered_map>
#include <utility>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {
#define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node)

View File

@ -5,13 +5,12 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/LogManager.h>
#include <array>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {

View File

@ -5,12 +5,11 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <array>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {
#define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node)

View File

@ -5,12 +5,12 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <array>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {

View File

@ -40,7 +40,6 @@ $end_info$
#include <tuple>
#include <unordered_map>
#include <utility>
#include <xbyak/xbyak.h>
// #define DEBUG_RA 1
// #define DEBUG_CYCLES
@ -788,8 +787,8 @@ CPUBackend::CompiledCode X86JITCore::CompileCode(uint64_t Entry, [[maybe_unused]
return CodeData;
}
std::unique_ptr<CPUBackend> CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return std::make_unique<X86JITCore>(ctx, Thread);
fextl::unique_ptr<CPUBackend> CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) {
return fextl::make_unique<X86JITCore>(ctx, Thread);
}
CPUBackendFeatures GetX86JITBackendFeatures() {

View File

@ -9,12 +9,9 @@ $end_info$
#include <FEXCore/IR/RegisterAllocationData.h>
#include "Interface/Core/BlockSamplingData.h"
#include "Interface/Core/Dispatcher/Dispatcher.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include "Interface/Core/ObjectCache/Relocations.h"
#define XBYAK64
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
using namespace Xbyak;
#include <FEXCore/Core/CPUBackend.h>

View File

@ -6,7 +6,7 @@ $end_info$
#include "Interface/Core/CPUID.h"
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/Core/CoreState.h>
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/LogManager.h>
@ -14,7 +14,6 @@ $end_info$
#include <array>
#include <stddef.h>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {

View File

@ -6,6 +6,7 @@ $end_info$
#include "Interface/Context/Context.h"
#include "Interface/Core/Dispatcher/Dispatcher.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "FEXCore/Debug/InternalThreadState.h"
@ -16,7 +17,6 @@ $end_info$
#include <array>
#include <stddef.h>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {
#define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node)

View File

@ -5,7 +5,7 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/IR/IR.h>

View File

@ -5,14 +5,13 @@ $end_info$
*/
#include "Interface/Core/JIT/x86_64/JITClass.h"
#include "Interface/Core/Dispatcher/X86Dispatcher.h"
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/LogManager.h>
#include <array>
#include <stddef.h>
#include <stdint.h>
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {

View File

@ -15,11 +15,13 @@ $end_info$
namespace FEXCore {
LookupCache::LookupCache(FEXCore::Context::ContextImpl *CTX)
: ctx {CTX} {
: BlockLinks_mbr { fextl::pmr::get_default_resource() }
, ctx {CTX} {
TotalCacheSize = ctx->Config.VirtualMemSize / 4096 * 8 + CODE_SIZE + L1_SIZE;
BlockLinks_pma = fextl::make_unique<std::pmr::polymorphic_allocator<std::byte>>(&BlockLinks_mbr);
// Setup our PMR map.
BlockLinks = BlockLinks_pma.new_object<BlockLinksMapType>();
BlockLinks = BlockLinks_pma->new_object<BlockLinksMapType>();
// Block cache ends up looking like this
// PageMemoryMap[VirtualMemoryRegion >> 12]
@ -71,10 +73,8 @@ void LookupCache::ClearCache() {
// Clear L1 and L2 by clearing the full cache.
madvise(reinterpret_cast<void*>(PagePointer), TotalCacheSize, MADV_DONTNEED);
// Clear the BlockLinks allocator which frees the BlockLinks map implicitly.
BlockLinks_mbr.release();
// Allocate a new pointer from the BlockLinks pma again.
BlockLinks = BlockLinks_pma.new_object<BlockLinksMapType>();
BlockLinks = BlockLinks_pma->new_object<BlockLinksMapType>();
// All code is gone, clear the block list
BlockList.clear();
}

View File

@ -2,21 +2,21 @@
#include "Interface/Context/Context.h"
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/memory_resource.h>
#include <FEXCore/fextl/robin_map.h>
#include <FEXCore/fextl/vector.h>
#include <FEXCore/fextl/memory_resource.h>
#include <cstdint>
#include <functional>
#include <memory_resource>
#include <stddef.h>
#include <utility>
#include <mutex>
#include <tsl/robin_map.h>
namespace FEXCore {
class LookupCache {
public:
struct LookupCacheEntry {
uintptr_t HostCode;
uintptr_t GuestCode;
@ -245,10 +245,10 @@ private:
// This makes `BlockLinks` look like a raw pointer that could memory leak, but since it is backed by the MBR, it won't.
std::pmr::monotonic_buffer_resource BlockLinks_mbr;
using BlockLinksMapType = std::pmr::map<BlockLinkTag, std::function<void()>>;
std::pmr::polymorphic_allocator<std::byte> BlockLinks_pma {&BlockLinks_mbr};
fextl::unique_ptr<std::pmr::polymorphic_allocator<std::byte>> BlockLinks_pma;
BlockLinksMapType *BlockLinks;
tsl::robin_map<uint64_t, uint64_t> BlockList;
fextl::robin_map<uint64_t, uint64_t> BlockList;
size_t TotalCacheSize;

View File

@ -8,12 +8,12 @@
#include <FEXCore/Utils/Threads.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/queue.h>
#include <FEXCore/fextl/robin_map.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include <memory>
#include <shared_mutex>
#include <tsl/robin_map.h>
namespace FEXCore::CodeSerialize {
// XXX: Does this need to be signal safe?
@ -111,7 +111,7 @@ namespace FEXCore::CodeSerialize {
// This per section map takes the most time to load and needs to be quick
// This is the map of all code segments for this entry
tsl::robin_map<uint64_t, CodeObjectFileSection*> SectionLookupMap{};
fextl::robin_map<uint64_t, CodeObjectFileSection*> SectionLookupMap{};
/** @} */
// Default initialization

View File

@ -358,8 +358,8 @@ namespace FEXCore {
}
};
ThunkHandler* ThunkHandler::Create() {
return new ThunkHandler_impl();
fextl::unique_ptr<ThunkHandler> ThunkHandler::Create() {
return fextl::make_unique<ThunkHandler_impl>();
}
/**

View File

@ -7,6 +7,7 @@ $end_info$
#pragma once
#include <FEXCore/IR/IR.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/vector.h>
namespace FEXCore::Context {
@ -26,12 +27,12 @@ namespace FEXCore {
class ThunkHandler {
public:
virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) = 0;
virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0;
virtual ~ThunkHandler() { }
virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) = 0;
virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0;
virtual ~ThunkHandler() { }
static ThunkHandler* Create();
static fextl::unique_ptr<ThunkHandler> Create();
virtual void AppendThunkDefinitions(fextl::vector<FEXCore::IR::ThunkDefinition> const& Definitions) = 0;
virtual void AppendThunkDefinitions(fextl::vector<FEXCore::IR::ThunkDefinition> const& Definitions) = 0;
};
};

View File

@ -1,3 +1,4 @@
#include "FEXHeaderUtils/Filesystem.h"
#include "Interface/Context/Context.h"
#include "Interface/IR/AOTIR.h"
@ -5,6 +6,7 @@
#include <FEXCore/IR/RegisterAllocationData.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/HLE/SyscallHandler.h>
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/string.h>
#include <Interface/Core/LookupCache.h>
@ -371,19 +373,18 @@ namespace FEXCore::IR {
}
AOTIRCacheEntry *AOTIRCaptureCache::LoadAOTIRCacheEntry(const fextl::string &filename) {
fextl::string base_filename = fextl::string_from_path(std::filesystem::path(filename).filename());
fextl::string base_filename = FHU::Filesystem::GetFilename(filename);
if (!base_filename.empty()) {
auto filename_hash = XXH3_64bits(filename.c_str(), filename.size());
auto fileid = base_filename + "-";
fileid += std::to_string(filename_hash) + "-";
// append optimization flags to the fileid
fileid += (CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? "S" : "s";
fileid += CTX->Config.TSOEnabled ? "T" : "t";
fileid += CTX->Config.ABILocalFlags ? "L" : "l";
fileid += CTX->Config.ABINoPF ? "p" : "P";
auto fileid = fextl::fmt::format("{}-{}-{}{}{}{}",
base_filename,
filename_hash,
(CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? 'S' : 's',
CTX->Config.TSOEnabled ? 'T' : 't',
CTX->Config.ABILocalFlags ? 'L' : 'l',
CTX->Config.ABINoPF ? 'p' : 'P');
std::unique_lock lk(AOTIRCacheLock);

View File

@ -8,12 +8,12 @@ $end_info$
#include <FEXCore/Config/Config.h>
#include <FEXCore/Utils/ThreadPoolAllocator.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/unordered_map.h>
#include <FEXCore/fextl/vector.h>
#include <functional>
#include <memory>
#include <utility>
namespace FEXCore::Context {
@ -48,7 +48,7 @@ class PassManager final {
public:
void AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants, bool StaticRegisterAllocation);
void AddDefaultValidationPasses();
Pass* InsertPass(std::unique_ptr<Pass> Pass, fextl::string Name = "") {
Pass* InsertPass(fextl::unique_ptr<Pass> Pass, fextl::string Name = "") {
Pass->RegisterPassManager(this);
auto PassPtr = Passes.emplace_back(std::move(Pass)).get();
@ -88,12 +88,12 @@ protected:
FEXCore::HLE::SyscallHandler *SyscallHandler;
private:
fextl::vector<std::unique_ptr<Pass>> Passes;
fextl::vector<fextl::unique_ptr<Pass>> Passes;
fextl::unordered_map<fextl::string, Pass*> NameToPassMaping;
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
fextl::vector<std::unique_ptr<Pass>> ValidationPasses;
void InsertValidationPass(std::unique_ptr<Pass> Pass, fextl::string Name = "") {
fextl::vector<fextl::unique_ptr<Pass>> ValidationPasses;
void InsertValidationPass(fextl::unique_ptr<Pass> Pass, fextl::string Name = "") {
Pass->RegisterPassManager(this);
auto PassPtr = ValidationPasses.emplace_back(std::move(Pass)).get();

View File

@ -1,6 +1,6 @@
#pragma once
#include <memory>
#include <FEXCore/fextl/memory.h>
namespace FEXCore::Utils {
class IntrusivePooledAllocator;
@ -11,23 +11,23 @@ class Pass;
class RegisterAllocationPass;
class RegisterAllocationData;
std::unique_ptr<FEXCore::IR::Pass> CreateConstProp(bool InlineConstants, bool SupportsTSOImm9);
std::unique_ptr<FEXCore::IR::Pass> CreateContextLoadStoreElimination(bool SupportsAVX);
std::unique_ptr<FEXCore::IR::Pass> CreateSyscallOptimization();
std::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination();
std::unique_ptr<FEXCore::IR::Pass> CreateDeadStoreElimination(bool SupportsAVX);
std::unique_ptr<FEXCore::IR::Pass> CreatePassDeadCodeElimination();
std::unique_ptr<FEXCore::IR::Pass> CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator);
std::unique_ptr<FEXCore::IR::RegisterAllocationPass> CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass,
fextl::unique_ptr<FEXCore::IR::Pass> CreateConstProp(bool InlineConstants, bool SupportsTSOImm9);
fextl::unique_ptr<FEXCore::IR::Pass> CreateContextLoadStoreElimination(bool SupportsAVX);
fextl::unique_ptr<FEXCore::IR::Pass> CreateSyscallOptimization();
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination();
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadStoreElimination(bool SupportsAVX);
fextl::unique_ptr<FEXCore::IR::Pass> CreatePassDeadCodeElimination();
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator);
fextl::unique_ptr<FEXCore::IR::RegisterAllocationPass> CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass,
bool OptimizeSRA,
bool SupportsAVX);
std::unique_ptr<FEXCore::IR::Pass> CreateLongDivideEliminationPass();
fextl::unique_ptr<FEXCore::IR::Pass> CreateLongDivideEliminationPass();
namespace Validation {
std::unique_ptr<FEXCore::IR::Pass> CreateIRValidation();
std::unique_ptr<FEXCore::IR::Pass> CreateRAValidation();
std::unique_ptr<FEXCore::IR::Pass> CreatePhiValidation();
std::unique_ptr<FEXCore::IR::Pass> CreateValueDominanceValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreateRAValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreatePhiValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreateValueDominanceValidation();
}
}

View File

@ -22,6 +22,7 @@ $end_info$
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Profiler.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/robin_map.h>
#include <FEXCore/fextl/unordered_map.h>
#include <bit>
@ -29,7 +30,6 @@ $end_info$
#include <memory>
#include <string.h>
#include <tuple>
#include <tsl/robin_map.h>
#include <utility>
namespace FEXCore::IR {
@ -201,7 +201,7 @@ private:
fextl::map<OrderedNode*, uint64_t> AddressgenConsts;
// Pool inline constant generation. These are typically very small and pool efficiently.
tsl::robin_map<uint64_t, OrderedNode*> InlineConstantGen;
fextl::robin_map<uint64_t, OrderedNode*> InlineConstantGen;
OrderedNode *CreateInlineConstant(IREmitter *IREmit, uint64_t Constant) {
const auto it = InlineConstantGen.find(Constant);
if (it != InlineConstantGen.end()) {
@ -1073,8 +1073,8 @@ bool ConstProp::Run(IREmitter *IREmit) {
return Changed;
}
std::unique_ptr<FEXCore::IR::Pass> CreateConstProp(bool InlineConstants, bool SupportsTSOImm9) {
return std::make_unique<ConstProp>(InlineConstants, SupportsTSOImm9);
fextl::unique_ptr<FEXCore::IR::Pass> CreateConstProp(bool InlineConstants, bool SupportsTSOImm9) {
return fextl::make_unique<ConstProp>(InlineConstants, SupportsTSOImm9);
}
}

View File

@ -80,8 +80,8 @@ void DeadCodeElimination::markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp
}
std::unique_ptr<FEXCore::IR::Pass> CreatePassDeadCodeElimination() {
return std::make_unique<DeadCodeElimination>();
fextl::unique_ptr<FEXCore::IR::Pass> CreatePassDeadCodeElimination() {
return fextl::make_unique<DeadCodeElimination>();
}
}

View File

@ -410,7 +410,7 @@ public:
}
bool Run(FEXCore::IR::IREmitter *IREmit) override;
private:
std::unique_ptr<FEXCore::IR::Pass> DCE;
fextl::unique_ptr<FEXCore::IR::Pass> DCE;
ContextInfo ClassifiedStruct;
fextl::unordered_map<FEXCore::IR::NodeID, BlockInfo> OffsetToBlockMap;
@ -784,8 +784,8 @@ bool RCLSE::Run(FEXCore::IR::IREmitter *IREmit) {
namespace FEXCore::IR {
std::unique_ptr<FEXCore::IR::Pass> CreateContextLoadStoreElimination(bool SupportsAVX) {
return std::make_unique<RCLSE>(SupportsAVX);
fextl::unique_ptr<FEXCore::IR::Pass> CreateContextLoadStoreElimination(bool SupportsAVX) {
return fextl::make_unique<RCLSE>(SupportsAVX);
}
}

View File

@ -358,8 +358,8 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) {
return Changed;
}
std::unique_ptr<FEXCore::IR::Pass> CreateDeadStoreElimination(bool SupportsAVX) {
return std::make_unique<DeadStoreElimination>(SupportsAVX);
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadStoreElimination(bool SupportsAVX) {
return fextl::make_unique<DeadStoreElimination>(SupportsAVX);
}
}

View File

@ -220,8 +220,8 @@ bool IRCompaction::Run(IREmitter *IREmit) {
return true;
}
std::unique_ptr<FEXCore::IR::Pass> CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) {
return std::make_unique<IRCompaction>(Allocator);
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) {
return fextl::make_unique<IRCompaction>(Allocator);
}
}

View File

@ -271,7 +271,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
return false;
}
std::unique_ptr<FEXCore::IR::Pass> CreateIRValidation() {
return std::make_unique<IRValidation>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRValidation() {
return fextl::make_unique<IRValidation>();
}
}

View File

@ -114,7 +114,7 @@ bool LongDivideEliminationPass::Run(IREmitter *IREmit) {
return Changed;
}
std::unique_ptr<FEXCore::IR::Pass> CreateLongDivideEliminationPass() {
return std::make_unique<LongDivideEliminationPass>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateLongDivideEliminationPass() {
return fextl::make_unique<LongDivideEliminationPass>();
}
}

View File

@ -70,8 +70,8 @@ bool PhiValidation::Run(IREmitter *IREmit) {
return false;
}
std::unique_ptr<FEXCore::IR::Pass> CreatePhiValidation() {
return std::make_unique<PhiValidation>();
fextl::unique_ptr<FEXCore::IR::Pass> CreatePhiValidation() {
return fextl::make_unique<PhiValidation>();
}
}

View File

@ -452,7 +452,7 @@ bool RAValidation::Run(IREmitter *IREmit) {
return false;
}
std::unique_ptr<FEXCore::IR::Pass> CreateRAValidation() {
return std::make_unique<RAValidation>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateRAValidation() {
return fextl::make_unique<RAValidation>();
}
}

View File

@ -68,8 +68,8 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) {
return Changed;
}
std::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination() {
return std::make_unique<DeadFlagCalculationEliminination>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateDeadFlagCalculationEliminination() {
return fextl::make_unique<DeadFlagCalculationEliminination>();
}
}

View File

@ -90,7 +90,7 @@ namespace {
IR::OrderedNode *SpilledNode;
};
struct RegisterGraph {
struct RegisterGraph : public FEXCore::Allocator::FEXAllocOperators {
IR::RegisterAllocationData::UniquePtr AllocData;
RegisterSet Set;
fextl::vector<RegisterNode> Nodes{};
@ -1559,7 +1559,7 @@ namespace {
return Changed;
}
std::unique_ptr<FEXCore::IR::RegisterAllocationPass> CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA, bool SupportsAVX) {
return std::make_unique<ConstrainedRAPass>(CompactionPass, OptimizeSRA, SupportsAVX);
fextl::unique_ptr<FEXCore::IR::RegisterAllocationPass> CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA, bool SupportsAVX) {
return fextl::make_unique<ConstrainedRAPass>(CompactionPass, OptimizeSRA, SupportsAVX);
}
}

View File

@ -82,8 +82,8 @@ bool SyscallOptimization::Run(IREmitter *IREmit) {
return Changed;
}
std::unique_ptr<FEXCore::IR::Pass> CreateSyscallOptimization() {
return std::make_unique<SyscallOptimization>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateSyscallOptimization() {
return fextl::make_unique<SyscallOptimization>();
}
}

View File

@ -206,8 +206,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) {
return false;
}
std::unique_ptr<FEXCore::IR::Pass> CreateValueDominanceValidation() {
return std::make_unique<ValueDominanceValidation>();
fextl::unique_ptr<FEXCore::IR::Pass> CreateValueDominanceValidation() {
return fextl::make_unique<ValueDominanceValidation>();
}
}

View File

@ -2,6 +2,7 @@
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory_resource.h>
#include <FEXHeaderUtils/Syscalls.h>
#include <FEXHeaderUtils/TypeDefines.h>
@ -32,6 +33,13 @@ extern "C" {
#endif
}
namespace fextl::pmr {
static fextl::pmr::default_resource FEXDefaultResource;
std::pmr::memory_resource* get_default_resource() {
return &FEXDefaultResource;
}
}
namespace FEXCore::Allocator {
MMAP_Hook mmap {::mmap};
MUNMAP_Hook munmap {::munmap};
@ -63,7 +71,7 @@ namespace FEXCore::Allocator {
using GLIBC_REALLOC_Hook = void*(*)(void*, size_t, const void *caller);
using GLIBC_FREE_Hook = void(*)(void*, const void *caller);
std::unique_ptr<Alloc::HostAllocator> Alloc64{};
fextl::unique_ptr<Alloc::HostAllocator> Alloc64{};
void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset);

View File

@ -8,6 +8,7 @@
#include <FEXHeaderUtils/ScopedSignalMask.h>
#include <FEXHeaderUtils/Syscalls.h>
#include <FEXHeaderUtils/TypeDefines.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/vector.h>
#include <algorithm>
@ -142,7 +143,9 @@ namespace Alloc::OSAllocator {
[[maybe_unused]] auto Res = mprotect(reinterpret_cast<void*>(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE);
LOGMAN_THROW_AA_FMT(Res == 0, "Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno));
if (Res == -1) {
LOGMAN_MSG_A_FMT("Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno));
}
LiveVMARegion *LiveRange = new (reinterpret_cast<void*>(ReservedRegion->Base)) LiveVMARegion();
@ -572,7 +575,7 @@ OSAllocator_64Bit::~OSAllocator_64Bit() {
}
}
std::unique_ptr<Alloc::HostAllocator> Create64BitAllocator() {
return std::make_unique<OSAllocator_64Bit>();
fextl::unique_ptr<Alloc::HostAllocator> Create64BitAllocator() {
return fextl::make_unique<OSAllocator_64Bit>();
}
}

View File

@ -1,8 +1,9 @@
#pragma once
#include <FEXCore/fextl/allocator.h>
#include <FEXCore/fextl/memory.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <sys/types.h>
namespace Alloc {
@ -35,5 +36,5 @@ namespace Alloc {
}
namespace Alloc::OSAllocator {
std::unique_ptr<Alloc::HostAllocator> Create64BitAllocator();
fextl::unique_ptr<Alloc::HostAllocator> Create64BitAllocator();
}

View File

@ -0,0 +1,157 @@
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/LogManager.h>
#include <fmt/format.h>
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <unistd.h>
extern "C" {
// The majority of FEX internal code should avoid using the glibc allocator. To ensure glibc allocations don't accidentally slip
// in, FEX overrides these glibc functions with faulting variants.
//
// A notable exception is thunks, which should still use glibc allocations and avoid using `fextl::` namespace.
//
// Other minor exceptions throughout FEX use the `YesIKnowImNotSupposedToUseTheGlibcAllocator` helper to temporarily disable faulting.
#define GLIBC_ALIAS_FUNCTION(func) __attribute__((alias(#func), visibility("default")))
extern void *__libc_calloc(size_t, size_t);
void *calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc);
extern void __libc_free(void*);
void free(void*) GLIBC_ALIAS_FUNCTION(fault_free);
extern void *__libc_malloc(size_t);
void *malloc(size_t) GLIBC_ALIAS_FUNCTION(fault_malloc);
extern void *__libc_memalign(size_t, size_t);
void *memalign(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_memalign);
extern void *__libc_realloc(void*, size_t);
void *realloc(void*, size_t) GLIBC_ALIAS_FUNCTION(fault_realloc);
extern void *__libc_valloc(size_t);
void *valloc(size_t) GLIBC_ALIAS_FUNCTION(fault_valloc);
extern int __posix_memalign(void **, size_t, size_t);
int posix_memalign(void **, size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_posix_memalign);
extern size_t __malloc_usable_size(void*);
size_t malloc_usable_size(void*) GLIBC_ALIAS_FUNCTION(fault_malloc_usable_size);
// Reuse __libc_memalign
void *aligned_alloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_aligned_alloc);
}
namespace FEXCore::Allocator {
// Enable or disable allocation faulting globally.
static bool GlobalEvaluate{};
// Enable or disable allocation faulting per-thread.
static thread_local uint64_t SkipEvalForThread{};
// Internal memory allocation hooks to allow non-faulting allocations through.
CALLOC_Hook calloc_ptr = __libc_calloc;
FREE_Hook free_ptr = __libc_free;
MALLOC_Hook malloc_ptr = __libc_malloc;
MEMALIGN_Hook memalign_ptr = __libc_memalign;
REALLOC_Hook realloc_ptr = __libc_realloc;
VALLOC_Hook valloc_ptr = __libc_valloc;
POSIX_MEMALIGN_Hook posix_memalign_ptr = ::posix_memalign;
MALLOC_USABLE_SIZE_Hook malloc_usable_size_ptr = ::malloc_usable_size;
ALIGNED_ALLOC_Hook aligned_alloc_ptr = __libc_memalign;
// Constructor for per-thread allocation faulting check.
YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() {
++SkipEvalForThread;
}
// Destructor for per-thread allocation faulting check.
YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() {
--SkipEvalForThread;
}
// Hard disabling of per-thread allocation fault checking.
// No coming back from this, used on thread destruction.
FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() {
// Just set it to half of its maximum value so it never wraps back around.
SkipEvalForThread = std::numeric_limits<decltype(SkipEvalForThread)>::max() / 2;
}
// Enable global fault checking.
void SetupFaultEvaluate() {
GlobalEvaluate = true;
}
// Disable global fault checking.
void ClearFaultEvaluate() {
GlobalEvaluate = false;
}
// Evaluate if a glibc hooked allocation should fault.
void EvaluateReturnAddress(void* Return) {
if (!GlobalEvaluate) {
// Fault evaluation disabled globally.
return;
}
if (SkipEvalForThread) {
// Fault evaluation currently disabled for this thread.
return;
}
// We don't know where we are when allocating. Make sure to be safe and generate the string on the stack.
// Print an error message to let a developer know that an allocation faulted.
char Tmp[512];
auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast<uint64_t>(Return));
Tmp[Res.size] = 0;
write(STDERR_FILENO, Tmp, Res.size);
// Trap the execution to stop FEX in its tracks.
FEX_TRAP_EXECUTION;
}
}
extern "C" {
// These are the glibc allocator override symbols.
// These will override the glibc allocators and then check if the allocation should fault.
void *fault_calloc(size_t n, size_t size) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::calloc_ptr(n, size);
}
void fault_free(void* ptr) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
FEXCore::Allocator::free_ptr(ptr);
}
void *fault_malloc(size_t size) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::malloc_ptr(size);
}
void *fault_memalign(size_t align, size_t s) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::memalign_ptr(align, s);
}
void *fault_realloc(void* ptr, size_t size) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::realloc_ptr(ptr, size);
}
void *fault_valloc(size_t size) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::valloc_ptr(size);
}
int fault_posix_memalign(void ** r, size_t a, size_t s) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::posix_memalign_ptr(r, a, s);
}
size_t fault_malloc_usable_size(void *ptr) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::malloc_usable_size_ptr(ptr);
}
void *fault_aligned_alloc(size_t a, size_t s) {
FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0)));
return FEXCore::Allocator::aligned_alloc_ptr(a, s);
}
}

View File

@ -6,10 +6,10 @@ $end_info$
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/vector.h>
#include <alloca.h>
#include <fmt/format.h>
#include <cstdarg>
#include <cstdio>
@ -21,7 +21,7 @@ void InstallHandler(ThrowHandler Handler) { Handlers.emplace_back(Handler); }
void UnInstallHandlers() { Handlers.clear(); }
void MFmt(const char *fmt, const fmt::format_args& args) {
auto msg = fmt::vformat(fmt, args);
auto msg = fextl::fmt::vformat(fmt, args);
for (auto& Handler : Handlers) {
Handler(msg.c_str());
@ -69,7 +69,7 @@ void D(const char *fmt, ...) {
}
void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args) {
const auto msg = fmt::vformat(fmt, args);
const auto msg = fextl::fmt::vformat(fmt, args);
for (auto& Handler : Handlers) {
Handler(level, msg.c_str());

View File

@ -1,7 +1,9 @@
#include <FEXCore/Config/Config.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Telemetry.h>
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/string.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <array>
#include <filesystem>
@ -28,9 +30,8 @@ namespace FEXCore::Telemetry {
DataDirectory += "Telemetry/";
// Ensure the folder structure is created for our configuration
std::error_code ec{};
if (!std::filesystem::exists(DataDirectory, ec) &&
!std::filesystem::create_directories(DataDirectory, ec)) {
if (!FHU::Filesystem::Exists(DataDirectory) &&
!FHU::Filesystem::CreateDirectories(DataDirectory)) {
LogMan::Msg::IFmt("Couldn't create telemetry Folder");
}
}
@ -39,23 +40,24 @@ namespace FEXCore::Telemetry {
auto DataDirectory = Config::GetDataDirectory();
DataDirectory += "Telemetry/" + ApplicationName + ".telem";
std::error_code ec{};
if (std::filesystem::exists(DataDirectory, ec)) {
if (FHU::Filesystem::Exists(DataDirectory)) {
// If the file exists, retain a single backup
auto Backup = DataDirectory + ".1";
std::filesystem::copy_file(DataDirectory, Backup, std::filesystem::copy_options::overwrite_existing, ec);
FHU::Filesystem::CopyFile(DataDirectory, Backup, FHU::Filesystem::CopyOptions::OVERWRITE_EXISTING);
}
std::fstream fs(fextl::string_from_string(DataDirectory), std::ios_base::out | std::ios_base::trunc);
if (fs.is_open()) {
constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO;
int fd = open(DataDirectory.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS);
if (fd != -1) {
for (size_t i = 0; i < TelemetryType::TYPE_LAST; ++i) {
auto &Name = TelemetryNames.at(i);
auto &Data = TelemetryValues.at(i);
fs << Name << ": " << *Data << std::endl;
auto Output = fextl::fmt::format("{}: {}\n", Name, *Data);
write(fd, Output.c_str(), Output.size());
}
fs.flush();
fs.close();
fsync(fd);
close(fd);
}
}

View File

@ -1,12 +1,12 @@
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Threads.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/deque.h>
#include <alloca.h>
#include <cstring>
#include <functional>
#include <memory>
#include <mutex>
#include <pthread.h>
#include <stdint.h>
@ -97,9 +97,14 @@ namespace FEXCore::Threads {
, UserArg {Arg} {
pthread_attr_t Attr{};
Stack = AllocateStackObject(STACK_SIZE);
// pthreads allocates its dtv region behind our back and there is nothing we can do about it.
FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc;
AddStackToLivePool(Stack, STACK_SIZE);
pthread_attr_init(&Attr);
pthread_attr_setstack(&Attr, Stack, STACK_SIZE);
// TODO: Thread creation should be using this instead.
// Causes Steam to crash early though.
// pthread_create(&Thread, &Attr, InitializeThread, this);
pthread_create(&Thread, &Attr, Func, Arg);
pthread_attr_destroy(&Attr);
@ -155,13 +160,17 @@ namespace FEXCore::Threads {
// Put the stack back in to the stack pool
Thread->FreeStack();
// TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread.
FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable();
return Result;
}
std::unique_ptr<FEXCore::Threads::Thread> CreateThread_PThread(
fextl::unique_ptr<FEXCore::Threads::Thread> CreateThread_PThread(
ThreadFunc Func,
void* Arg) {
return std::make_unique<PThread>(Func, Arg);
return fextl::make_unique<PThread>(Func, Arg);
}
void CleanupAfterFork_PThread() {
@ -199,7 +208,7 @@ namespace FEXCore::Threads {
.CleanupAfterFork = CleanupAfterFork_PThread,
};
std::unique_ptr<FEXCore::Threads::Thread> FEXCore::Threads::Thread::Create(
fextl::unique_ptr<FEXCore::Threads::Thread> FEXCore::Threads::Thread::Create(
ThreadFunc Func,
void* Arg) {
return Ptrs.CreateThread(Func, Arg);

View File

@ -3,11 +3,11 @@
#include <FEXCore/Core/Context.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/unordered_map.h>
#include <memory>
#include <optional>
#include <stdint.h>
@ -170,7 +170,7 @@ namespace Type {
FEX_DEFAULT_VISIBILITY fextl::string FindContainer();
FEX_DEFAULT_VISIBILITY fextl::string FindContainerPrefix();
FEX_DEFAULT_VISIBILITY void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer);
FEX_DEFAULT_VISIBILITY void AddLayer(fextl::unique_ptr<FEXCore::Config::Layer> _Layer);
FEX_DEFAULT_VISIBILITY bool Exists(ConfigOption Option);
FEX_DEFAULT_VISIBILITY std::optional<LayerValue*> All(ConfigOption Option);
@ -255,7 +255,7 @@ namespace Type {
*
* @return unique_ptr for that layer
*/
FEX_DEFAULT_VISIBILITY std::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer();
FEX_DEFAULT_VISIBILITY fextl::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer();
/**
* @brief Loads the main application config
@ -265,7 +265,7 @@ namespace Type {
*
* @return unique_ptr for that layer
*/
FEX_DEFAULT_VISIBILITY std::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(fextl::string const *File = nullptr);
FEX_DEFAULT_VISIBILITY fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(fextl::string const *File = nullptr);
/**
* @brief Create an application configuration loader
@ -275,7 +275,7 @@ namespace Type {
*
* @return unique_ptr for that layer
*/
FEX_DEFAULT_VISIBILITY std::unique_ptr<FEXCore::Config::Layer> CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type);
FEX_DEFAULT_VISIBILITY fextl::unique_ptr<FEXCore::Config::Layer> CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type);
/**
* @brief iCreate an environment configuration loader
@ -284,6 +284,6 @@ namespace Type {
*
* @return unique_ptr for that layer
*/
FEX_DEFAULT_VISIBILITY std::unique_ptr<FEXCore::Config::Layer> CreateEnvironmentLayer(char *const _envp[]);
FEX_DEFAULT_VISIBILITY fextl::unique_ptr<FEXCore::Config::Layer> CreateEnvironmentLayer(char *const _envp[]);
}

View File

@ -17,9 +17,6 @@ class IREmitter;
*/
class CodeLoader {
public:
using MapperFn = std::function<void *(void *addr, size_t length, int prot, int flags, int fd, off_t offset)>;
using UnmapperFn = std::function<int(void *addr, size_t length)>;
virtual ~CodeLoader() = default;
/**
@ -37,11 +34,6 @@ public:
*/
virtual uint64_t DefaultRIP() const = 0;
/**
* @brief Maps and copies the executable, also sets up stack
*/
virtual bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) { return false; }
virtual fextl::vector<fextl::string> const *GetApplicationArguments() { return nullptr; }
virtual void GetExecveArguments(fextl::vector<char const*> *Args) {}

View File

@ -6,13 +6,13 @@
#include <FEXCore/Core/CPUID.h>
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/set.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include <istream>
#include <ostream>
#include <memory>
#include <mutex>
#include <shared_mutex>
@ -75,7 +75,7 @@ namespace FEXCore::Context {
void *VDSO_kernel_rt_sigreturn;
};
using CustomCPUFactoryType = std::function<std::unique_ptr<FEXCore::CPU::CPUBackend> (FEXCore::Context::Context*, FEXCore::Core::InternalThreadState *Thread)>;
using CustomCPUFactoryType = std::function<fextl::unique_ptr<FEXCore::CPU::CPUBackend> (FEXCore::Context::Context*, FEXCore::Core::InternalThreadState *Thread)>;
using ExitHandler = std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)>;
@ -291,5 +291,4 @@ namespace FEXCore::Context {
* @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup
*/
FEX_DEFAULT_VISIBILITY void InitializeStaticTables(OperatingMode Mode = MODE_64BIT);
FEX_DEFAULT_VISIBILITY void ShutdownStaticTables();
}

View File

@ -7,11 +7,12 @@
#include <FEXCore/Utils/Event.h>
#include <FEXCore/Utils/InterruptableConditionVariable.h>
#include <FEXCore/Utils/Threads.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/robin_map.h>
#include <FEXCore/fextl/vector.h>
#include <tsl/robin_map.h>
#include <shared_mutex>
#include <type_traits>
namespace FEXCore {
class LookupCache;
@ -57,7 +58,7 @@ namespace FEXCore::Core {
*
* Needs to remain around for as long as the code could be executed at least
*/
struct DebugData {
struct DebugData : public FEXCore::Allocator::FEXAllocOperators {
uint64_t HostCodeSize; ///< The size of the code generated in the host JIT
fextl::vector<DebugDataSubblock> Subblocks;
fextl::vector<DebugDataGuestOpcode> GuestOpcodes;
@ -75,12 +76,12 @@ namespace FEXCore::Core {
struct LocalIREntry {
uint64_t StartAddr;
uint64_t Length;
std::unique_ptr<FEXCore::IR::IRListView, FEXCore::IR::IRListViewDeleter> IR;
fextl::unique_ptr<FEXCore::IR::IRListView, FEXCore::IR::IRListViewDeleter> IR;
FEXCore::IR::RegisterAllocationData::UniquePtr RAData;
std::unique_ptr<FEXCore::Core::DebugData> DebugData;
fextl::unique_ptr<FEXCore::Core::DebugData> DebugData;
};
struct InternalThreadState {
struct InternalThreadState : public FEXCore::Allocator::FEXAllocOperators {
FEXCore::Core::CpuStateFrame* const CurrentFrame = &BaseFrameState;
struct {
@ -93,20 +94,20 @@ namespace FEXCore::Core {
FEXCore::Context::Context *CTX;
std::atomic<SignalEvent> SignalReason{SignalEvent::Nothing};
std::unique_ptr<FEXCore::Threads::Thread> ExecutionThread;
fextl::unique_ptr<FEXCore::Threads::Thread> ExecutionThread;
bool StartPaused {false};
InterruptableConditionVariable StartRunning;
Event ThreadWaiting;
std::unique_ptr<FEXCore::IR::OpDispatchBuilder> OpDispatcher;
fextl::unique_ptr<FEXCore::IR::OpDispatchBuilder> OpDispatcher;
std::unique_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
std::unique_ptr<FEXCore::LookupCache> LookupCache;
fextl::unique_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
fextl::unique_ptr<FEXCore::LookupCache> LookupCache;
tsl::robin_map<uint64_t, LocalIREntry> DebugStore;
fextl::robin_map<uint64_t, LocalIREntry> DebugStore;
std::unique_ptr<FEXCore::Frontend::Decoder> FrontendDecoder;
std::unique_ptr<FEXCore::IR::PassManager> PassManager;
fextl::unique_ptr<FEXCore::Frontend::Decoder> FrontendDecoder;
fextl::unique_ptr<FEXCore::IR::PassManager> PassManager;
FEXCore::HLE::ThreadManagement ThreadManager;
RuntimeStats Stats{};

View File

@ -1,5 +1,6 @@
#pragma once
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
@ -91,6 +92,6 @@ private:
class SourcecodeResolver {
public:
virtual std::unique_ptr<SourcecodeMap> GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) = 0;
virtual fextl::unique_ptr<SourcecodeMap> GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) = 0;
};
}

View File

@ -120,7 +120,7 @@ class DualIntrusiveAllocatorThreadPool final : public DualIntrusiveAllocator {
Utils::FixedSizePooledAllocation<uintptr_t, 5000, 500> PoolObject;
};
class IRListView final {
class IRListView final : public FEXCore::Allocator::FEXAllocOperators {
enum Flags {
FLAG_IsCopy = 1,
FLAG_Shared = 2,
@ -183,7 +183,7 @@ public:
//uint64_t Flags;
uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag
stream.write((const char*)&WrittenFlags, sizeof(WrittenFlags));
// inline data
stream.write((const char*)GetData(), DataSize);
stream.write((const char*)GetListData(), ListSize);
@ -202,7 +202,7 @@ public:
//uint64_t Flags;
uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag
memcpy(ptr, &WrittenFlags, sizeof(WrittenFlags)); ptr += sizeof(WrittenFlags);
// inline data
memcpy(ptr, (const void*)GetData(), DataSize); ptr += DataSize;
memcpy(ptr, (const void*)GetListData(), ListSize); ptr += ListSize;

View File

@ -13,6 +13,52 @@ namespace FEXCore::Allocator {
FEX_DEFAULT_VISIBILITY size_t DetermineVASize();
#ifdef GLIBC_ALLOCATOR_FAULT
// Glibc hooks should only fault once we are in main.
// Required since glibc allocator hooking will catch things before FEX has control.
FEX_DEFAULT_VISIBILITY void SetupFaultEvaluate();
// Glibc hook faulting needs to be disabled when leaving main.
// Required since glibc does some state teardown after main.
FEX_DEFAULT_VISIBILITY void ClearFaultEvaluate();
class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final {
public:
FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator();
FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator();
FEX_DEFAULT_VISIBILITY static void HardDisable();
};
class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final {
public:
GLIBCScopedFault() {
FEXCore::Allocator::SetupFaultEvaluate();
}
~GLIBCScopedFault() {
FEXCore::Allocator::ClearFaultEvaluate();
}
};
#else
FEX_DEFAULT_VISIBILITY inline void SetupFaultEvaluate() {}
FEX_DEFAULT_VISIBILITY inline void ClearFaultEvaluate() {}
class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final {
public:
FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator() {}
FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator() {}
FEX_DEFAULT_VISIBILITY static inline void HardDisable() {}
};
class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final {
public:
GLIBCScopedFault() {
// nop
}
~GLIBCScopedFault() {
// nop
}
};
#endif
struct MemoryRegion {
void *Ptr;
size_t Size;

View File

@ -30,4 +30,16 @@ namespace FEXCore::Allocator {
FEX_DEFAULT_VISIBILITY extern FREE_Hook free;
FEX_DEFAULT_VISIBILITY extern MALLOC_USABLE_SIZE_Hook malloc_usable_size;
FEX_DEFAULT_VISIBILITY extern ALIGNED_ALLOC_Hook aligned_alloc;
struct FEXAllocOperators {
FEXAllocOperators() = default;
void *operator new(size_t size) {
return FEXCore::Allocator::malloc(size);
}
void operator delete(void *ptr) {
return FEXCore::Allocator::free(ptr);
}
};
}

View File

@ -1,8 +1,8 @@
#pragma once
#include <cstddef>
#include <memory>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory.h>
namespace FEXCore {
@ -17,7 +17,7 @@ namespace FEXCore {
static constexpr size_t Size = _Size;
T Items[Size];
std::unique_ptr<BucketList<Size, T>> Next;
fextl::unique_ptr<BucketList<Size, T>> Next;
void Clear() {
Items[0] = T{};
@ -96,7 +96,7 @@ namespace FEXCore {
if (i < (Size-1)) {
that->Items[i+1] = T{};
} else {
that->Next = std::make_unique<BucketList<Size, T>>();
that->Next = fextl::make_unique<BucketList<Size, T>>();
}
}
void Erase(T Val) {

View File

@ -63,7 +63,12 @@ namespace FEXCore::Utils {
using BufferOwnedFlag = std::atomic<ClientFlags>;
struct MemoryBuffer {
struct MemoryBuffer : public FEXCore::Allocator::FEXAllocOperators {
MemoryBuffer(void* Ptr, size_t Size, std::chrono::time_point<ClockType> LastUsed)
: Ptr {Ptr}
, Size {Size}
, LastUsed {LastUsed} {}
void* Ptr;
size_t Size;
std::atomic<std::chrono::time_point<ClockType>> LastUsed;

View File

@ -1,12 +1,13 @@
#pragma once
#include <FEXCore/fextl/memory.h>
#include <functional>
#include <memory>
namespace FEXCore::Threads {
using ThreadFunc = void*(*)(void* user_ptr);
class Thread;
using CreateThreadFunc = std::function<std::unique_ptr<Thread>(ThreadFunc Func, void* Arg)>;
using CreateThreadFunc = std::function<fextl::unique_ptr<Thread>(ThreadFunc Func, void* Arg)>;
using CleanupAfterForkFunc = std::function<void()>;
struct Pointers {
@ -27,7 +28,7 @@ namespace FEXCore::Threads {
* @name Calls provided API functions
* @{ */
static std::unique_ptr<Thread> Create(
static fextl::unique_ptr<Thread> Create(
ThreadFunc Func,
void* Arg);

View File

@ -3,6 +3,7 @@
#include <FEXCore/fextl/string.h>
#include <fmt/format.h>
#include <unistd.h>
namespace fextl::fmt {
template <typename T, size_t SIZE = ::fmt::inline_buffer_size,
@ -36,4 +37,11 @@ namespace fextl::fmt {
-> fextl::string {
return fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...));
}
template <typename... T>
FMT_INLINE auto print(::fmt::format_string<T...> fmt, T&&... args)
-> void {
auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...));
write(STDERR_FILENO, String.c_str(), String.size());
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <FEXCore/fextl/allocator.h>
#include <memory>
#include <new>
#include <fmt/format.h>
namespace fextl {
template<class T>
struct default_delete : public std::default_delete<T> {
void operator()(T* ptr) const {
std::destroy_at(ptr);
FEXCore::Allocator::free(ptr);
}
template<typename U>
requires (std::is_base_of_v<U, T>)
operator fextl::default_delete<U>() {
return fextl::default_delete<U>();
}
};
template<class T, class Deleter = fextl::default_delete<T>>
using unique_ptr = std::unique_ptr<T, Deleter>;
template<class T, class... Args>
fextl::unique_ptr<T> make_unique(Args&&... args) {
auto ptr = FEXCore::Allocator::aligned_alloc(std::alignment_of_v<T>, sizeof(T));
auto Result = ::new (ptr) T (std::forward<Args>(args)...);
return fextl::unique_ptr<T>(Result);
}
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <FEXCore/Utils/MathUtils.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/allocator.h>
#include <memory_resource>
#include <fmt/format.h>
namespace fextl {
namespace pmr {
class default_resource : public std::pmr::memory_resource {
private:
void* do_allocate( std::size_t bytes, std::size_t alignment ) override {
return FEXCore::Allocator::memalign(alignment, bytes);
}
void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override {
return FEXCore::Allocator::free(p);
}
bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override {
return this == &other;
}
};
FEX_DEFAULT_VISIBILITY std::pmr::memory_resource* get_default_resource();
/**
* @brief This is similar to the std::pmr::monotonic_buffer_resource.
*
* The difference is that class doesn't have ownership of the backing memory and
* it also doesn't have any growth factor.
*
* If the amount of memory allocated is overrun then this will overwrite memory unless assertions are enabled.
*
* Ensure that you know how much memory you're going to use before using this class.
*/
class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource {
public:
fixed_size_monotonic_buffer_resource(void* Base, [[maybe_unused]] size_t Size)
: Ptr {reinterpret_cast<uint64_t>(Base)}
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
, PtrEnd {reinterpret_cast<uint64_t>(Base) + Size}
, Size {Size}
#endif
{}
void* do_allocate( std::size_t bytes, std::size_t alignment ) override {
uint64_t NewPtr = FEXCore::AlignUp((uint64_t)Ptr, alignment);
Ptr = NewPtr + bytes;
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
if (Ptr >= PtrEnd) {
LogMan::Msg::AFmt("Fail: Only allocated: {} ({} this time) bytes. Tried allocating at ptr offset: {}.\n",
Size,
bytes,
(uint64_t)(Ptr - (PtrEnd - Size)));
FEX_TRAP_EXECUTION;
}
#endif
return reinterpret_cast<void*>(NewPtr);
}
void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override {
// noop
}
bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override {
return this == &other;
}
private:
uint64_t Ptr;
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
uint64_t PtrEnd;
size_t Size;
#endif
};
}
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <FEXCore/fextl/allocator.h>
#include <tsl/robin_map.h>
namespace fextl {
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<std::pair<const Key, T>>>
using robin_map = tsl::robin_map<Key, T, Hash, KeyEqual, Allocator>;
}

View File

@ -6,4 +6,7 @@
namespace fextl {
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<std::pair<const Key, T>>>
using unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator>;
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<std::pair<const Key, T>>>
using unordered_multimap = std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>;
}

@ -1 +0,0 @@
Subproject commit 2e480985bd5b024d4659988dc30c94ac24b4b14a

2
External/xbyak vendored

@ -1 +1 @@
Subproject commit b0f0c7805ad16d9abbac0f8101cc226669983b57
Subproject commit 5f8c0488bab7a5e1c8cee831c3b6a5a884e10df8

View File

@ -1,6 +1,15 @@
#pragma once
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/memory_resource.h>
#include <FEXCore/fextl/string.h>
#include <algorithm>
#include <fcntl.h>
#include <memory_resource>
#include <string>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <unistd.h>
namespace FHU::Filesystem {
@ -14,4 +23,283 @@ namespace FHU::Filesystem {
inline bool Exists(const char *Path) {
return access(Path, F_OK) == 0;
}
inline bool Exists(const fextl::string &Path) {
return access(Path.c_str(), F_OK) == 0;
}
enum class CreateDirectoryResult {
CREATED,
EXISTS,
ERROR,
};
/**
* @brief Creates a directory at the provided path.
*
* @param Path The path to create a directory at.
*
* @return Result enum depending.
*/
inline CreateDirectoryResult CreateDirectory(const fextl::string &Path) {
auto Result = ::mkdir(Path.c_str(), 0777);
if (Result == 0) {
return CreateDirectoryResult::CREATED;
}
if (Result == -1 && errno == EEXIST) {
// If it exists, we need to check if it is a file or folder.
struct stat buf;
if (stat(Path.c_str(), &buf) == 0) {
// Check to see if the path is a file or folder. Following symlinks.
return S_ISDIR(buf.st_mode) ?
CreateDirectoryResult::EXISTS :
CreateDirectoryResult::ERROR;
}
}
// Couldn't create, or the path that existed wasn't a folder.
return CreateDirectoryResult::ERROR;
}
/**
* @brief Creates a directory tree with the provided path.
*
* @param Path The path to create a tree at.
*
* @return True if the directory tree was created or already exists.
*/
inline bool CreateDirectories(const fextl::string &Path) {
// Try to create the directory initially.
if (CreateDirectory(Path) != CreateDirectoryResult::ERROR) {
return true;
}
// Walk the path in reverse and create paths as we go.
fextl::string TmpPath {Path.substr(0, Path.rfind('/', Path.size() - 1))};
if (!TmpPath.empty() && CreateDirectories(TmpPath)) {
return CreateDirectory(Path) != CreateDirectoryResult::ERROR;
}
return false;
}
/**
* @brief Extracts the filename component from a file path.
*
* @param Path The path to create a directory at.
*
* @return The filename component of the path.
*/
inline fextl::string GetFilename(const fextl::string &Path) {
auto LastSeparator = Path.rfind('/');
if (LastSeparator == fextl::string::npos) {
// No separator. Likely relative `.`, `..`, `<Application Name>`, or empty string.
return Path;
}
return Path.substr(LastSeparator + 1);
}
inline fextl::string ParentPath(const fextl::string &Path) {
auto LastSeparator = Path.rfind('/');
if (LastSeparator == fextl::string::npos) {
// No separator. Likely relative `.`, `..`, `<Application Name>`, or empty string.
if (Path == "." || Path == "..") {
// In this edge-case, return nothing to match std::filesystem::path::parent_path behaviour.
return {};
}
return Path;
}
if (LastSeparator == 0) {
// In the case of root, just return.
return "/";
}
auto SubString = Path.substr(0, LastSeparator);
while (SubString.size() > 1 && SubString.ends_with("/")) {
// If the substring still ended with `/` then we need to string that off as well.
--LastSeparator;
SubString = Path.substr(0, LastSeparator);
}
return SubString;
}
inline bool IsRelative(const fextl::string &Path) {
return !Path.starts_with('/');
}
inline bool IsAbsolute(const fextl::string &Path) {
return Path.starts_with('/');
}
enum class CopyOptions {
NONE,
SKIP_EXISTING,
OVERWRITE_EXISTING,
};
/**
* @brief Copy a file from a location to another
*
* Behaves similarly to std::filesystem::copy_file but with less copy options.
*
* @param From Source file location.
* @param To Destination file location.
* @param Options Copy options.
*
* @return True if the copy succeeded, false otherwise.
*/
inline bool CopyFile(const fextl::string &From, const fextl::string &To, CopyOptions Options = CopyOptions::NONE) {
const bool DestExists = Exists(To);
if (Options == CopyOptions::SKIP_EXISTING && DestExists) {
// If the destination file exists already and the skip existing flag is set then
// return true without error.
return true;
}
if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) {
// If we are overwriting and the file exists then we want to use `sendfile` to overwrite
int SourceFD = open(From.c_str(), O_RDONLY | O_CLOEXEC);
if (SourceFD == -1) {
return false;
}
int DestinationFD = open(To.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0200);
if (DestinationFD == -1) {
close(SourceFD);
return false;
}
struct stat buf;
if (fstat(SourceFD, &buf) != 0) {
close(DestinationFD);
close(SourceFD);
return false;
}
// Set the destination permissions to the original source permissions.
if (fchmod(DestinationFD, buf.st_mode) != 0) {
close(DestinationFD);
close(SourceFD);
return false;
}
bool Result = sendfile(DestinationFD, SourceFD, nullptr, buf.st_size) == buf.st_size;
close(DestinationFD);
close(SourceFD);
return Result;
}
if (!DestExists) {
// If the destination doesn't exist then just use rename.
return rename(From.c_str(), To.c_str()) == 0;
}
return false;
}
inline fextl::string LexicallyNormal(const fextl::string &Path) {
const auto PathSize = Path.size();
// Early exit on empty paths.
if (PathSize == 0) {
return {};
}
const auto IsAbsolutePath = IsAbsolute(Path);
const auto EndsWithSeparator = Path.ends_with('/');
// Count the number of separators up front
const auto SeparatorCount = std::count(Path.begin(), Path.end(), '/');
// Use std::list to store path elements to avoid iterator invalidation on insert/erase.
// The list is allocated on stack to be more optimal. The size is determined by the
// maximum number of list objects (separator count plus 2) multiplied by the list
// element size (32-bytes per element: the string_view itself and the prev/next pointers).
size_t DataSize = (sizeof(std::string_view) + sizeof(void*) * 2) * (SeparatorCount + 2);
void *Data = alloca(DataSize);
fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize);
std::pmr::polymorphic_allocator pa {&mbr};
std::pmr::list<std::string_view> Parts{pa};
size_t CurrentOffset{};
do {
auto FoundSeperator = Path.find('/', CurrentOffset);
if (FoundSeperator == Path.npos) {
FoundSeperator = PathSize;
}
const auto Begin = Path.begin() + CurrentOffset;
const auto End = Path.begin() + FoundSeperator;
const auto Size = End - Begin;
// Only insert parts that contain data.
if (Size != 0) {
Parts.emplace_back(std::string_view(Begin, End));
}
if (Size == 0) {
// If the view is empty, skip over the separator.
FoundSeperator += 1;
}
CurrentOffset = FoundSeperator;
} while (CurrentOffset != PathSize);
size_t CurrentIterDistance{};
for (auto iter = Parts.begin(); iter != Parts.end();) {
auto &Part = *iter;
if (Part == ".") {
// Erase '.' directory parts if not at root.
if (CurrentIterDistance > 0 || IsAbsolutePath) {
// Erasing this iterator, don't increase iter distances
iter = Parts.erase(iter);
continue;
}
}
if (Part == "..") {
if (CurrentIterDistance > 0) {
// If not at root then remove both this iterator and the previous one.
// ONLY if the previous iterator is also not ".."
//
// If the previous iterator is '.' then /only/ erase the previous iterator.
auto PreviousIter = iter;
--PreviousIter;
if (*PreviousIter == ".") {
// Erasing the previous iterator, iterator distance has subtracted by one
--CurrentIterDistance;
Parts.erase(PreviousIter);
}
else if (*PreviousIter != "..") {
// Erasing the previous iterator, iterator distance has subtracted by one
// Also erasing current iterator, which means iterator distance also doesn't increase by one.
--CurrentIterDistance;
Parts.erase(PreviousIter);
iter = Parts.erase(iter);
continue;
}
}
else if (IsAbsolutePath) {
// `..` at the base. Just remove this
iter = Parts.erase(iter);
continue;
}
}
// Interator distance increased by one.
++CurrentIterDistance;
++iter;
}
// Add a final separator unless the last element is ellipses.
const bool NeedsFinalSeparator = EndsWithSeparator && (!Parts.empty() && Parts.back() != "." && Parts.back() != "..");
return fextl::fmt::format("{}{}{}",
IsAbsolutePath ? "/" : "",
fmt::join(Parts, "/"),
NeedsFinalSeparator ? "/" : "");
}
}

View File

@ -1,13 +1,14 @@
#pragma once
#include <FEXCore/fextl/string.h>
#include <fcntl.h>
#include <string>
#include <sys/stat.h>
#include <span>
#include <unistd.h>
namespace FHU::Symlinks {
// Checks to see if a filepath is a symlink.
inline bool IsSymlink(const std::string &Filename) {
inline bool IsSymlink(const fextl::string &Filename) {
struct stat Buffer{};
int Result = lstat(Filename.c_str(), &Buffer);
return Result == 0 && S_ISLNK(Buffer.st_mode);
@ -17,7 +18,7 @@ inline bool IsSymlink(const std::string &Filename) {
// Doesn't handle recursive symlinks.
// Doesn't append null terminator character.
// Returns a string_view of the resolved path, or an empty view on error.
inline std::string_view ResolveSymlink(const std::string &Filename, std::span<char> ResultBuffer) {
inline std::string_view ResolveSymlink(const fextl::string &Filename, std::span<char> ResultBuffer) {
ssize_t Result = readlink(Filename.c_str(), ResultBuffer.data(), ResultBuffer.size());
if (Result == -1) {
return {};

View File

@ -3,7 +3,7 @@
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include "OptionParser.h"
#include "cpp-optparse/OptionParser.h"
#include "git_version.h"
#include <stdint.h>
@ -12,7 +12,7 @@ namespace FEX::ArgLoader {
fextl::vector<fextl::string> RemainingArgs;
fextl::vector<fextl::string> ProgramArguments;
static std::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") ";
static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") ";
void FEX::ArgLoader::ArgLoader::Load() {
optparse::OptionParser Parser{};
Parser.version(Version);
@ -39,12 +39,8 @@ namespace FEX::ArgLoader {
using uint32 = uint32_t;
#define AFTER_PARSE
#include <FEXCore/Config/ConfigOptions.inl>
// TODO: Convert cpp-optparse over to fextl::vector
auto ParserArgs = Parser.args();
auto ParsedArgs = Parser.parsed_args();
RemainingArgs.insert(RemainingArgs.begin(), ParserArgs.begin(), ParserArgs.end());
ProgramArguments.insert(ProgramArguments.begin(), ParsedArgs.begin(), ParsedArgs.end());
RemainingArgs = Parser.args();
ProgramArguments = Parser.parsed_args();
}
void LoadWithoutArguments(int _argc, char **_argv) {

View File

@ -1,3 +1,5 @@
add_subdirectory(cpp-optparse/)
set(NAME Common)
set(SRCS
ArgumentLoader.cpp

View File

@ -5,6 +5,7 @@
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/string.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <FEXHeaderUtils/SymlinkChecks.h>
#include <cstring>
@ -58,7 +59,11 @@ namespace FEX::Config {
// If the program name isn't resolved to an absolute path then glibc breaks inside it's `_dl_get_origin` function.
// This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here.
if (!Program.starts_with('/')) {
Program = std::filesystem::canonical(std::move(Program)).string();
char ExistsTempPath[PATH_MAX];
char *RealPath = realpath(Program.c_str(), ExistsTempPath);
if (RealPath) {
Program = RealPath;
}
}
// If FEX was invoked through an FD path (either binfmt_misc or execveat) then we need to check the
@ -89,9 +94,9 @@ namespace FEX::Config {
// This symlink will be in the style of `/dev/fd/<FD>`.
//
// If the argument /is/ a symlink then resolve its path to get the original application name.
if (FHU::Symlinks::IsSymlink(fextl::string_from_string(Program))) {
if (FHU::Symlinks::IsSymlink(Program)) {
char Filename[PATH_MAX];
auto SymlinkPath = FHU::Symlinks::ResolveSymlink(fextl::string_from_string(Program), Filename);
auto SymlinkPath = FHU::Symlinks::ResolveSymlink(Program, Filename);
if (SymlinkPath.starts_with('/')) {
// This file was executed through an FD.
// Remove the ` (deleted)` text if the file was deleted after the fact.
@ -120,7 +125,7 @@ namespace FEX::Config {
FEX::ArgLoader::LoadWithoutArguments(argc, argv);
}
else {
FEXCore::Config::AddLayer(std::make_unique<FEX::ArgLoader::ArgLoader>(argc, argv));
FEXCore::Config::AddLayer(fextl::make_unique<FEX::ArgLoader::ArgLoader>(argc, argv));
}
FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp));
@ -138,9 +143,9 @@ namespace FEX::Config {
fextl::string& Program = Args[0];
bool Wine = false;
std::filesystem::path ProgramName;
fextl::string ProgramName;
for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) {
auto CurrentProgramName = std::filesystem::path(Args[CurrentProgramNameIndex]).filename();
auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]);
if (CurrentProgramName == "wine-preloader" ||
CurrentProgramName == "wine64-preloader") {
@ -162,10 +167,10 @@ namespace FEX::Config {
else {
if (Wine == true) {
// If this was path separated with '\' then we need to check that.
auto WinSeparator = CurrentProgramName.string().find_last_of('\\');
if (WinSeparator != CurrentProgramName.string().npos) {
auto WinSeparator = CurrentProgramName.find_last_of('\\');
if (WinSeparator != CurrentProgramName.npos) {
// Used windows separators
CurrentProgramName = CurrentProgramName.string().substr(WinSeparator + 1);
CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1);
}
}
@ -176,8 +181,8 @@ namespace FEX::Config {
}
}
FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(fextl::string_from_path(ProgramName), FEXCore::Config::LayerType::LAYER_GLOBAL_APP));
FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(fextl::string_from_path(ProgramName), FEXCore::Config::LayerType::LAYER_LOCAL_APP));
FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_GLOBAL_APP));
FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_LOCAL_APP));
auto SteamID = getenv("SteamAppId");
if (SteamID) {
@ -188,8 +193,7 @@ namespace FEX::Config {
FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP));
}
// TODO: No need for conversion once Config uses fextl.
return ApplicationNames{std::move(Program), fextl::string_from_path(ProgramName)};
return ApplicationNames{std::move(Program), std::move(ProgramName)};
}
return {};
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/string.h>
@ -10,19 +11,6 @@
#include <unistd.h>
namespace FEX {
[[maybe_unused]]
static
std::optional<fextl::string> get_fdpath(int fd) {
char SymlinkPath[PATH_MAX];
std::filesystem::path Path = std::filesystem::path("/proc/self/fd") / std::to_string(fd);
int Result = readlinkat(AT_FDCWD, Path.c_str(), SymlinkPath, sizeof(SymlinkPath));
if (Result != -1) {
return fextl::string(SymlinkPath, Result);
}
// Not fatal if an FD doesn't point to a file
return std::nullopt;
}
inline
int get_fdpath(int fd, char *SymlinkPath) {

View File

@ -7,6 +7,7 @@
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <fcntl.h>
#include <filesystem>
@ -211,10 +212,10 @@ namespace FEXServerClient {
return -1;
}
fextl::string FEXServerPath = fextl::string_from_path(std::filesystem::path(InterpreterPath).parent_path()) + "/FEXServer";
fextl::string FEXServerPath = FHU::Filesystem::ParentPath(InterpreterPath) + "/FEXServer";
// Check if a local FEXServer next to FEXInterpreter exists
// If it does then it takes priority over the installed one
if (!std::filesystem::exists(FEXServerPath)) {
if (!FHU::Filesystem::Exists(FEXServerPath)) {
FEXServerPath = "FEXServer";
}

@ -0,0 +1 @@
Subproject commit 1f3b88a1ba3c4c6302a096d7e9002982e8811cb7

View File

@ -66,8 +66,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
return PAGE_ALIGN(last->p_vaddr + last->p_memsz);
}
template<typename T>
bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr &Header, int prot, int flags, T Mapper) {
bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr &Header, int prot, int flags, FEX::HLE::SyscallHandler *const Handler) {
auto addr = Base + PAGE_START(Header.p_vaddr);
auto size = Header.p_filesz + PAGE_OFFSET(Header.p_vaddr);
@ -80,16 +79,17 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
return true;
}
void *rv = Mapper((void*)addr, size, prot, flags, file.fd, off);
void *rv = Handler->GuestMmap((void*)addr, size, prot, flags, file.fd, off);
if (rv == MAP_FAILED) {
// uhoh, something went wrong
LogMan::Msg::EFmt("MapFile: Some elf mapping failed, {}, fd: {}\n", errno, file.fd);
return false;
} else {
auto Filename = FEX::get_fdpath(file.fd);
if (Filename.has_value()) {
Sections.push_back({Base, (uintptr_t)rv, size, (off_t)off, Filename.value(), (prot & PROT_EXEC) != 0});
char Tmp[PATH_MAX];
auto PathLength = FEX::get_fdpath(file.fd, Tmp);
if (PathLength != -1) {
Sections.push_back({Base, (uintptr_t)rv, size, (off_t)off, fextl::string(Tmp, PathLength), (prot & PROT_EXEC) != 0});
}
return true;
@ -111,8 +111,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
return rv;
}
template <typename TMap, typename TUnmap>
std::optional<uintptr_t> LoadElfFile(ELFParser& Elf, uintptr_t *BrkBase, TMap Mapper, TUnmap Unmapper, uint64_t LoadHint = 0) {
std::optional<uintptr_t> LoadElfFile(ELFParser& Elf, uintptr_t *BrkBase, FEX::HLE::SyscallHandler *const Handler, uint64_t LoadHint = 0) {
uintptr_t LoadBase = 0;
@ -123,7 +122,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
if (Elf.ehdr.e_type == ET_DYN) {
// needs base address
auto TotalSize = CalculateTotalElfSize(Elf.phdrs) + (BrkBase ? BRK_SIZE : 0);
LoadBase = (uintptr_t)Mapper(reinterpret_cast<void*>(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
LoadBase = (uintptr_t)Handler->GuestMmap(reinterpret_cast<void*>(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if ((void*)LoadBase == MAP_FAILED) {
return {};
}
@ -141,7 +140,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
int MapProt = MapFlags(Header);
int MapType = MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED;
if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Mapper)) {
if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Handler)) {
return {};
}
@ -157,7 +156,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
}
if (BSSPageStart != BSSPageEnd) {
auto bss = Mapper((void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0);
auto bss = Handler->GuestMmap((void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0);
if ((void*)bss == MAP_FAILED) {
LogMan::Msg::EFmt("Failed to allocate BSS @ {}, {}\n", fmt::ptr(bss), errno);
return {};
@ -353,7 +352,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
uint64_t val;
};
bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) override {
bool MapMemory(FEX::HLE::SyscallHandler *const Handler) {
for (auto Header: MainElf.phdrs) {
if (Header.p_type == PT_GNU_STACK) {
if (Header.p_flags & PF_X)
@ -407,7 +406,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
uint64_t StackHint = Is64BitMode() ? STACK_HINT_64 : STACK_HINT_32;
// Allocate the base of the full 128MB stack range.
StackPointerBase = Mapper(reinterpret_cast<void*>(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0);
StackPointerBase = Handler->GuestMmap(reinterpret_cast<void*>(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0);
if (StackPointerBase == reinterpret_cast<void*>(~0ULL)) {
LogMan::Msg::EFmt("Allocating stack failed");
@ -415,7 +414,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
}
// Allocate with permissions the 8MB of regular stack size.
StackPointer = reinterpret_cast<uintptr_t>(Mapper(
StackPointer = reinterpret_cast<uintptr_t>(Handler->GuestMmap(
reinterpret_cast<void*>(reinterpret_cast<uint64_t>(StackPointerBase) + FULL_STACK_SIZE - StackSize()),
StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0));
@ -464,7 +463,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
if (!MainElf.InterpreterElf.empty()) {
uint64_t InterpLoadBase = 0;
if (auto elf = LoadElfFile(InterpElf, nullptr, Mapper, Unmapper)) {
if (auto elf = LoadElfFile(InterpElf, nullptr, Handler)) {
InterpLoadBase = *elf;
} else {
LogMan::Msg::EFmt("Failed to load interpreter elf file");
@ -530,7 +529,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
uintptr_t LoadBase = 0;
if (auto elf = LoadElfFile(MainElf, &BrkBase, Mapper, Unmapper, ELFLoadHint)) {
if (auto elf = LoadElfFile(MainElf, &BrkBase, Handler, ELFLoadHint)) {
LoadBase = *elf;
if (MainElf.ehdr.e_type == ET_DYN) {
BaseOffset = LoadBase;
@ -542,7 +541,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
// XXX Randomise brk?
BrkStart = (uint64_t)Mapper((void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
BrkStart = (uint64_t)Handler->GuestMmap((void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if ((void*)BrkStart == MAP_FAILED) {
LogMan::Msg::EFmt("Failed to allocate BRK @ {:x}, {}\n", BrkBase, errno);
@ -585,7 +584,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader {
if (!VSyscallEntry) [[unlikely]] {
// If the VDSO thunk doesn't exist then we might not have a vsyscall entry.
// Newer glibc requires vsyscall to exist now. So let's allocate a buffer and stick a vsyscall in to it.
auto VSyscallPage = Mapper(nullptr, FHU::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
auto VSyscallPage = Handler->GuestMmap(nullptr, FHU::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
constexpr static uint8_t VSyscallCode[] = {
0xcd, 0x80, // int 0x80
0xc3, // ret

View File

@ -28,6 +28,7 @@ $end_info$
#include <FEXCore/fextl/sstream.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <atomic>
#include <cerrno>
@ -123,27 +124,31 @@ namespace FEXServerLogging {
}
void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fextl::vector<fextl::string> *args) {
// Open the file pointer to the filename and see if we need to find an interpreter
std::fstream File(fextl::string_from_string(*Filename), std::fstream::in | std::fstream::binary);
if (!File.is_open()) {
// Open the Filename to determine if it is a shebang file.
int FD = open(Filename->c_str(), O_RDONLY | O_CLOEXEC);
if (FD == -1) {
return;
}
File.seekg(0, std::fstream::end);
const auto FileSize = File.tellg();
File.seekg(0, std::fstream::beg);
std::array<char, 257> Header;
const auto ChunkSize = 257l;
const auto ReadSize = pread(FD, &Header.at(0), ChunkSize, 0);
const auto Data = std::span<char>(Header.data(), ReadSize);
// Is the file large enough for shebang
if (FileSize <= 2) {
if (ReadSize <= 2) {
close(FD);
return;
}
// Handle shebang files
if (File.get() == '#' &&
File.get() == '!') {
fextl::string InterpreterLine;
std::getline(File, InterpreterLine);
if (Data[0] == '#' &&
Data[1] == '!') {
fextl::string InterpreterLine {
Data.begin() + 2, // strip off "#!" prefix
std::find(Data.begin(), Data.end(), '\n')
};
fextl::vector<fextl::string> ShebangArguments{};
// Shebang line can have a single argument
@ -168,17 +173,14 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe
// Insert all the arguments at the start
args->insert(args->begin(), ShebangArguments.begin(), ShebangArguments.end());
// Done here
return;
}
close(FD);
}
void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) {
auto RootFSLink = ELFCodeLoader::ResolveRootfsFile(*Filename, RootFS);
std::error_code ec{};
if (std::filesystem::exists(RootFSLink, ec)) {
if (FHU::Filesystem::Exists(RootFSLink)) {
*Filename = RootFSLink;
}
}
@ -197,6 +199,7 @@ bool IsInterpreterInstalled() {
}
int main(int argc, char **argv, char **const envp) {
FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope;
const bool IsInterpreter = RanAsInterpreter(argv[0]);
ExecutedWithFD = getauxval(AT_EXECFD) != 0;
@ -292,8 +295,7 @@ int main(int argc, char **argv, char **const envp) {
RootFSRedirect(&Program.ProgramPath, LDPath());
InterpreterHandler(&Program.ProgramPath, LDPath(), &Args);
std::error_code ec{};
if (!ExecutedWithFD && !FEXFD && !std::filesystem::exists(Program.ProgramPath, ec)) {
if (!ExecutedWithFD && !FEXFD && !FHU::Filesystem::Exists(Program.ProgramPath)) {
// Early exit if the program passed in doesn't exist
// Will prevent a crash later
fmt::print(stderr, "{}: command not found\n", Program.ProgramPath);
@ -342,12 +344,18 @@ int main(int argc, char **argv, char **const envp) {
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, "<Anonymous>");
}
else {
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, std::filesystem::canonical(Program.ProgramPath).string());
{
char ExistsTempPath[PATH_MAX];
char *RealPath = realpath(Program.ProgramPath.c_str(), ExistsTempPath);
if (RealPath) {
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, fextl::string(RealPath));
}
}
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, Program.ProgramName);
}
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode() ? "1" : "0");
std::unique_ptr<FEX::HLE::MemAllocator> Allocator;
fextl::unique_ptr<FEX::HLE::MemAllocator> Allocator;
fextl::vector<FEXCore::Allocator::MemoryRegion> Base48Bit;
if (Loader.Is64BitMode()) {
@ -402,18 +410,17 @@ int main(int argc, char **argv, char **const envp) {
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX, SignalDelegation.get())
: FEX::HLE::x32::CreateHandler(CTX, SignalDelegation.get(), std::move(Allocator));
auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get());
auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get());
{
// Load VDSO in to memory prior to mapping our ELFs.
void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get());
Loader.SetVDSOBase(VDSOBase);
Loader.CalculateHWCaps(CTX);
// Load VDSO in to memory prior to mapping our ELFs.
void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), Mapper);
Loader.SetVDSOBase(VDSOBase);
Loader.CalculateHWCaps(CTX);
if (!Loader.MapMemory(Mapper, Unmapper)) {
// failed to map
LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32);
return -ENOEXEC;
if (!Loader.MapMemory(SyscallHandler.get())) {
// failed to map
LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32);
return -ENOEXEC;
}
}
SyscallHandler->SetCodeLoader(&Loader);
@ -484,6 +491,7 @@ int main(int argc, char **argv, char **const envp) {
}
if (AOTEnabled) {
std::error_code ec{};
std::filesystem::create_directories(std::filesystem::path(FEXCore::Config::GetDataDirectory()) / "aotir", ec);
if (!ec) {
CTX->WriteFilesWithCode([](const fextl::string& fileid, const fextl::string& filename) {
@ -508,7 +516,6 @@ int main(int argc, char **argv, char **const envp) {
SignalDelegation.reset();
FEXCore::Context::Context::DestroyContext(CTX);
FEXCore::Context::ShutdownStaticTables();
FEXCore::Threads::Shutdown();
Loader.FreeSections();
@ -523,6 +530,7 @@ int main(int argc, char **argv, char **const envp) {
// Allocator is now original system allocator
FEXCore::Telemetry::Shutdown(Program.ProgramName);
FEXCore::Profiler::Shutdown();
if (ShutdownReason == FEXCore::Context::ExitReason::EXIT_SHUTDOWN) {
return ProgramStatus;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "Common/Config.h"
#include "Tests/LinuxSyscalls/Syscalls.h"
#include "Linux/Utils/ELFContainer.h"
#include "Linux/Utils/ELFSymbolDatabase.h"
@ -21,6 +22,7 @@
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/MathUtils.h>
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
@ -37,7 +39,7 @@ namespace FEX::HarnessHelper {
bool SupportsAVX) {
bool Matches = true;
const auto DumpGPRs = [OutputGPRs](const std::string& Name, uint64_t A, uint64_t B) {
const auto DumpGPRs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) {
if (!OutputGPRs) {
return;
}
@ -48,7 +50,7 @@ namespace FEX::HarnessHelper {
fmt::print("{}: 0x{:016x} {} 0x{:016x}\n", Name, A, A==B ? "==" : "!=", B);
};
const auto DumpFLAGs = [OutputGPRs](const std::string& Name, uint64_t A, uint64_t B) {
const auto DumpFLAGs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) {
if (!OutputGPRs) {
return;
}
@ -85,12 +87,12 @@ namespace FEX::HarnessHelper {
}
};
const auto CheckGPRs = [&Matches, DumpGPRs](const std::string& Name, uint64_t A, uint64_t B){
const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B){
DumpGPRs(Name, A, B);
Matches &= A == B;
};
const auto CheckFLAGS = [&Matches, DumpFLAGs](const std::string& Name, uint64_t A, uint64_t B){
const auto CheckFLAGS = [&Matches, DumpFLAGs](const fextl::string& Name, uint64_t A, uint64_t B){
DumpFLAGs(Name, A, B);
Matches &= A == B;
};
@ -106,7 +108,7 @@ namespace FEX::HarnessHelper {
// GPRS
for (unsigned i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i, MatchMask >>= 1) {
if (MatchMask & 1) {
CheckGPRs("GPR" + std::to_string(i), State1.gregs[i], State2.gregs[i]);
CheckGPRs(fextl::fmt::format("GPR{}", std::to_string(i)), State1.gregs[i], State2.gregs[i]);
}
}
@ -114,15 +116,15 @@ namespace FEX::HarnessHelper {
if (SupportsAVX) {
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) {
if (MatchMask & 1) {
CheckGPRs("XMM0_" + std::to_string(i), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]);
CheckGPRs("XMM1_" + std::to_string(i), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]);
CheckGPRs(fextl::fmt::format("XMM0_{}", std::to_string(i)), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]);
CheckGPRs(fextl::fmt::format("XMM1_{}", std::to_string(i)), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]);
}
}
} else {
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) {
if (MatchMask & 1) {
CheckGPRs("XMM0_" + std::to_string(i), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]);
CheckGPRs("XMM1_" + std::to_string(i), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]);
CheckGPRs(fextl::fmt::format("XMM0_{}", std::to_string(i)), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]);
CheckGPRs(fextl::fmt::format("XMM1_{}", std::to_string(i)), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]);
}
}
}
@ -159,16 +161,29 @@ namespace FEX::HarnessHelper {
}
inline void ReadFile(fextl::string const &Filename, fextl::vector<char> *Data) {
std::fstream TestFile(fextl::string_from_string(Filename), std::fstream::in | std::fstream::binary);
LOGMAN_THROW_A_FMT(TestFile.is_open(), "Failed to open file");
int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
LogMan::Msg::AFmt("Failed to open file");
}
TestFile.seekg(0, std::fstream::end);
const size_t FileSize = TestFile.tellg();
TestFile.seekg(0, std::fstream::beg);
struct stat buf;
if (fstat(fd, &buf) != 0) {
close(fd);
LogMan::Msg::AFmt("Failed to open file");
}
auto FileSize = buf.st_size;
if (FileSize <= 0) {
close(fd);
LogMan::Msg::AFmt("Failed to open file");
}
Data->resize(FileSize);
const auto ReadSize = pread(fd, Data->data(), FileSize, 0);
TestFile.read(Data->data(), FileSize);
close(fd);
LOGMAN_THROW_AA_FMT(ReadSize == FileSize, "Failed to open file");
}
class ConfigLoader final {
@ -307,15 +322,15 @@ namespace FEX::HarnessHelper {
uint64_t *State1Data = reinterpret_cast<uint64_t*>(reinterpret_cast<uint64_t>(State1) + Offset);
uint64_t *State2Data = reinterpret_cast<uint64_t*>(reinterpret_cast<uint64_t>(State2) + Offset);
const auto DumpGPRs = [this](const std::string& Name, uint64_t A, uint64_t B) {
const auto DumpGPRs = [this](const fextl::string& Name, uint64_t A, uint64_t B) {
if (!ConfigDumpGPRs()) {
return;
}
fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A==B ? "==" : "!=", B);
fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A==B ? "==" : "!=", B);
};
const auto CheckGPRs = [&Matches, DumpGPRs](const std::string& Name, uint64_t A, uint64_t B) {
const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B) {
DumpGPRs(Name, A, B);
Matches &= A == B;
};
@ -325,9 +340,9 @@ namespace FEX::HarnessHelper {
if (NameIndex == 0) // RIP
Name = "RIP";
else if (NameIndex >= 1 && NameIndex < 17)
Name = fmt::format("GPR{}", NameIndex - 1);
Name = fextl::fmt::format("GPR{}", NameIndex - 1);
else if (NameIndex >= 17 && NameIndex < 33)
Name = fmt::format("XMM[{}][{}]", NameIndex - 17, j);
Name = fextl::fmt::format("XMM[{}][{}]", NameIndex - 17, j);
else if (NameIndex == 33)
Name = "gs";
else if (NameIndex == 34)
@ -335,13 +350,13 @@ namespace FEX::HarnessHelper {
else if (NameIndex == 35)
Name = "rflags";
else if (NameIndex >= 36 && NameIndex < 45)
Name = fmt::format("MM[{}][{}]", NameIndex - 36, j);
Name = fextl::fmt::format("MM[{}][{}]", NameIndex - 36, j);
if (State1) {
CheckGPRs(fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]);
CheckGPRs(fextl::fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]);
}
if (State2) {
CheckGPRs(fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]);
CheckGPRs(fextl::fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]);
}
}
@ -475,39 +490,39 @@ namespace FEX::HarnessHelper {
return RIP;
}
bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) override {
bool MapMemoryInternal(auto Mapper, auto Munmap) {
bool LimitedSize = true;
auto DoMMap = [&Mapper](uint64_t Address, size_t Size) -> void* {
void *Result = Mapper(reinterpret_cast<void*>(Address), Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
auto DoMMap = [](auto This, auto Mapper, uint64_t Address, size_t Size) -> void* {
void *Result = (This->*Mapper)(reinterpret_cast<void*>(Address), Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
LOGMAN_THROW_AA_FMT(Result == reinterpret_cast<void*>(Address), "Map Memory mmap failed");
return Result;
};
if (LimitedSize) {
DoMMap(0xe000'0000, FHU::FEX_PAGE_SIZE * 10);
DoMMap(this, Mapper, 0xe000'0000, FHU::FEX_PAGE_SIZE * 10);
// SIB8
// We test [-128, -126] (Bottom)
// We test [-8, 8] (Middle)
// We test [120, 127] (Top)
// Can fit in two pages
DoMMap(0xe800'0000 - FHU::FEX_PAGE_SIZE, FHU::FEX_PAGE_SIZE * 2);
DoMMap(this, Mapper, 0xe800'0000 - FHU::FEX_PAGE_SIZE, FHU::FEX_PAGE_SIZE * 2);
}
else {
// This is scratch memory location and SIB8 location
DoMMap(0xe000'0000, 0x1000'0000);
DoMMap(this, Mapper, 0xe000'0000, 0x1000'0000);
// This is for large SIB 32bit displacement testing
DoMMap(0x2'0000'0000, 0x1'0000'1000);
DoMMap(this, Mapper, 0x2'0000'0000, 0x1'0000'1000);
}
// Map in the memory region for the test file
size_t Length = FEXCore::AlignUp(TestFileSize, FHU::FEX_PAGE_SIZE);
Mapper(reinterpret_cast<void*>(Code_start_page), Length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, TestFD, 0);
(this->*Mapper)(reinterpret_cast<void*>(Code_start_page), Length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, TestFD, 0);
RIP = Code_start_page;
// Map the memory regions the test file asks for
for (auto& [region, size] : Config.GetMemoryRegions()) {
DoMMap(region, size);
DoMMap(this, Mapper, region, size);
}
LoadMemory();
@ -515,6 +530,15 @@ namespace FEX::HarnessHelper {
return true;
}
bool MapMemory(FEX::HLE::SyscallHandler *const Handler) {
SyscallHandler = Handler;
return MapMemoryInternal(&FEX::HarnessHelper::HarnessCodeLoader::SyscallMMap, &FEX::HarnessHelper::HarnessCodeLoader::SyscallMunmap);
}
bool MapMemory() {
return MapMemoryInternal(&FEX::HarnessHelper::HarnessCodeLoader::MMap, &FEX::HarnessHelper::HarnessCodeLoader::Munmap);
}
void LoadMemory() {
// Memory base here starts at the start location we passed back with GetLayout()
// This will write at [CODE_START_RANGE + 0, RawFile.size() )
@ -540,7 +564,23 @@ namespace FEX::HarnessHelper {
bool RequiresBMI2() const { return Config.RequiresBMI2(); }
bool RequiresCLWB() const { return Config.RequiresCLWB(); }
protected:
void *SyscallMMap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
return SyscallHandler->GuestMmap(addr, length, prot, flags, fd, offset);
}
int SyscallMunmap(void *addr, size_t length) {
return SyscallHandler->GuestMunmap(addr, length);
}
void *MMap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
return mmap(addr, length, prot, flags, fd, offset);
}
int Munmap(void *addr, size_t length) {
return munmap(addr, length);
}
private:
FEX::HLE::SyscallHandler *SyscallHandler{};
constexpr static uint64_t STACK_SIZE = FHU::FEX_PAGE_SIZE;
constexpr static uint64_t STACK_OFFSET = 0xc000'0000;
// Zero is special case to know when we are done

View File

@ -172,7 +172,7 @@ int main(int argc, char **argv, char **const envp)
LogMan::Msg::InstallHandler(MsgHandler);
FEXCore::Config::Initialize();
FEXCore::Config::AddLayer(std::make_unique<FEX::ArgLoader::ArgLoader>(argc, argv));
FEXCore::Config::AddLayer(fextl::make_unique<FEX::ArgLoader::ArgLoader>(argc, argv));
FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp));
FEXCore::Config::Load();
// Ensure the IRLoader runs in 64-bit mode.

View File

@ -17,6 +17,7 @@ $end_info$
#include <FEXCore/fextl/fmt.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/sstream.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <git_version.h>
@ -759,12 +760,12 @@ namespace FEX::EmulatedFile {
char *RealPath = realpath(Path, ExistsTempPath);
if (RealPath) {
RealPathExists = true;
Creator = FDReadCreators.find(realpath(Path, Tmp));
Creator = FDReadCreators.find(RealPath);
}
}
if (!RealPathExists) {
Creator = FDReadCreators.find(fextl::string_from_path(std::filesystem::path(Path).lexically_normal()));
Creator = FDReadCreators.find(FHU::Filesystem::LexicallyNormal(Path));
}
if (Creator == FDReadCreators.end()) {

View File

@ -19,6 +19,7 @@ $end_info$
#include <FEXCore/fextl/list.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
#include <FEXHeaderUtils/Filesystem.h>
#include <FEXHeaderUtils/ScopedSignalMask.h>
#include <FEXHeaderUtils/Syscalls.h>
@ -42,13 +43,13 @@ $end_info$
namespace JSON {
struct JsonAllocator {
jsonPool_t PoolObject;
std::unique_ptr<fextl::list<json_t>> json_objects;
fextl::unique_ptr<fextl::list<json_t>> json_objects;
};
static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero");
json_t* PoolInit(jsonPool_t* Pool) {
JsonAllocator* alloc = reinterpret_cast<JsonAllocator*>(Pool);
alloc->json_objects = std::make_unique<fextl::list<json_t>>();
alloc->json_objects = fextl::make_unique<fextl::list<json_t>>();
return &*alloc->json_objects->emplace(alloc->json_objects->end());
}
@ -62,39 +63,31 @@ namespace FEX::HLE {
struct open_how;
static bool LoadFile(fextl::vector<char> &Data, const fextl::string &Filename) {
std::fstream File(fextl::string_from_string(Filename), std::ios::in);
if (!File.is_open()) {
int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return false;
}
if (!File.seekg(0, std::fstream::end)) {
LogMan::Msg::DFmt("Couldn't load configuration file: Seek end");
struct stat buf;
if (fstat(fd, &buf) != 0) {
LogMan::Msg::DFmt("Couldn't load configuration file: fstat");
close(fd);
return false;
}
auto FileSize = File.tellg();
if (File.fail()) {
LogMan::Msg::DFmt("Couldn't load configuration file: tellg");
return false;
}
if (!File.seekg(0, std::fstream::beg)) {
LogMan::Msg::DFmt("Couldn't load configuration file: Seek beginning");
return false;
}
auto FileSize = buf.st_size;
if (FileSize <= 0) {
LogMan::Msg::DFmt("FileSize less than or equal to zero specified");
close(fd);
return false;
}
Data.resize(FileSize);
if (!File.read(Data.data(), FileSize)) {
// Probably means permissions aren't set. Just early exit
return false;
}
return true;
const auto ReadSize = pread(fd, Data.data(), FileSize, 0);
close(fd);
return ReadSize == FileSize;
}
struct ThunkDBObject {
@ -216,7 +209,6 @@ static void LoadThunkDatabase(fextl::unordered_map<fextl::string, ThunkDBObject>
FileManager::FileManager(FEXCore::Context::Context *ctx)
: EmuFD {ctx} {
auto ThunkConfigFile = ThunkConfig();
// We try to load ThunksDB from:
@ -287,7 +279,7 @@ FileManager::FileManager(FEXCore::Context::Context *ctx)
}
// Now that we loaded the thunks object, walk through and ensure dependencies are enabled as well
auto ThunkGuestPath = std::filesystem::path { Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32() };
auto ThunkGuestPath = Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32() ;
for (auto const &DBObject : ThunkDB) {
if (!DBObject.second.Enabled) {
continue;
@ -298,17 +290,17 @@ FileManager::FileManager(FEXCore::Context::Context *ctx)
struct {
decltype(FileManager::ThunkOverlays)& ThunkOverlays;
decltype(ThunkDB)& ThunkDB;
const std::filesystem::path& ThunkGuestPath;
const fextl::string& ThunkGuestPath;
bool Is64BitMode;
void SetupOverlay(const ThunkDBObject& DBDepend) {
auto ThunkPath = ThunkGuestPath / DBDepend.LibraryName;
if (!std::filesystem::exists(ThunkPath)) {
auto ThunkPath = fextl::fmt::format("{}/{}", ThunkGuestPath, DBDepend.LibraryName);
if (!FHU::Filesystem::Exists(ThunkPath)) {
if (!Is64BitMode) {
// Guest libraries not existing is expected since not all libraries are thunked on 32-bit
return;
}
ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath.string());
ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath);
}
for (const auto& Overlay : DBDepend.Overlays) {
@ -663,7 +655,11 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz
dirfd != AT_FDCWD) {
// Passed in a dirfd that isn't magic FDCWD
// We need to get the path from the fd now
Path = FEX::get_fdpath(dirfd).value_or("");
char Tmp[PATH_MAX] = "";
auto PathLength = FEX::get_fdpath(dirfd, Tmp);
if (PathLength != -1) {
Path = fextl::string(Tmp, PathLength);
}
if (pathname) {
if (!Path.empty()) {

View File

@ -5,6 +5,7 @@
#include <FEXHeaderUtils/Syscalls.h>
#include <FEXHeaderUtils/TypeDefines.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/memory.h>
#include <bitset>
#include <linux/mman.h>
@ -44,6 +45,7 @@ public:
FindPageRangePtr = &MemAllocator32Bit::FindPageRange;
}
}
void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override;
int Munmap(void *addr, size_t length) override;
void *Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) override;
@ -603,12 +605,12 @@ public:
}
};
std::unique_ptr<FEX::HLE::MemAllocator> Create32BitAllocator() {
return std::make_unique<MemAllocator32Bit>();
fextl::unique_ptr<FEX::HLE::MemAllocator> Create32BitAllocator() {
return fextl::make_unique<MemAllocator32Bit>();
}
std::unique_ptr<FEX::HLE::MemAllocator> CreatePassthroughAllocator() {
return std::make_unique<MemAllocatorPassThrough>();
fextl::unique_ptr<FEX::HLE::MemAllocator> CreatePassthroughAllocator() {
return fextl::make_unique<MemAllocatorPassThrough>();
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <FEXCore/fextl/memory.h>
#include <cstdint>
#include <memory>
@ -16,6 +18,6 @@ namespace FEX::HLE {
virtual uint64_t Shmdt(const void* shmaddr) = 0;
};
std::unique_ptr<FEX::HLE::MemAllocator> Create32BitAllocator();
std::unique_ptr<FEX::HLE::MemAllocator> CreatePassthroughAllocator();
fextl::unique_ptr<FEX::HLE::MemAllocator> Create32BitAllocator();
fextl::unique_ptr<FEX::HLE::MemAllocator> CreatePassthroughAllocator();
}

View File

@ -23,7 +23,7 @@ namespace Core {
}
namespace FEX::HLE {
class SignalDelegator final : public FEXCore::SignalDelegator {
class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators {
public:
// Returns true if the host handled the signal
// Arguments are the same as sigaction handler

View File

@ -6,6 +6,7 @@ desc: Glue logic, brk allocations
$end_info$
*/
#include "FEXHeaderUtils/Filesystem.h"
#include "Linux/Utils/ELFContainer.h"
#include "Linux/Utils/ELFParser.h"
@ -237,7 +238,6 @@ static bool IsShebangFilename(fextl::string const &Filename) {
uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args) {
fextl::string Filename{};
std::error_code ec;
fextl::string RootFS = FEX::HLE::_SyscallHandler->RootFSPath();
ELFLoader::ELFContainer::ELFType Type{};
@ -257,7 +257,7 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env
// For absolute paths, check the rootfs first (if available)
if (pathname[0] == '/') {
auto Path = FEX::HLE::_SyscallHandler->FM.GetEmulatedPath(pathname, true);
if (!Path.empty() && std::filesystem::exists(Path, ec)) {
if (!Path.empty() && FHU::Filesystem::Exists(Path)) {
Filename = Path;
}
else {
@ -268,8 +268,8 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env
Filename = pathname;
}
bool exists = std::filesystem::exists(Filename, ec);
if (ec || !exists) {
bool exists = FHU::Filesystem::Exists(Filename);
if (!exists) {
return -ENOENT;
}
@ -867,7 +867,7 @@ static bool isHEX(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
std::unique_ptr<FEXCore::HLE::SourcecodeMap> SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) {
fextl::unique_ptr<FEXCore::HLE::SourcecodeMap> SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) {
ELFParser GuestELF;
@ -929,7 +929,7 @@ std::unique_ptr<FEXCore::HLE::SourcecodeMap> SyscallHandler::GenerateMap(const s
goto DoGenerate;
}
auto rv = std::make_unique<FEXCore::HLE::SourcecodeMap>();
auto rv = fextl::make_unique<FEXCore::HLE::SourcecodeMap>();
{
auto len = rv->SourceFile.size();
@ -1006,7 +1006,7 @@ std::unique_ptr<FEXCore::HLE::SourcecodeMap> SyscallHandler::GenerateMap(const s
uintptr_t CurrentOffset{};
int LastOffsetLine;
auto rv = std::make_unique<FEXCore::HLE::SourcecodeMap>();
auto rv = fextl::make_unique<FEXCore::HLE::SourcecodeMap>();
rv->SourceFile = GuestSourceFile;

View File

@ -16,6 +16,7 @@ $end_info$
#include <FEXCore/IR/IR.h>
#include <FEXCore/Utils/CompilerDefs.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/vector.h>
@ -92,7 +93,7 @@ struct ExecveAtArgs {
uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args);
class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver {
class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver, public FEXCore::Allocator::FEXAllocOperators {
public:
virtual ~SyscallHandler();
@ -252,9 +253,9 @@ private:
void Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret);
#endif
std::unique_ptr<FEX::HLE::MemAllocator> Alloc32Handler{};
fextl::unique_ptr<FEX::HLE::MemAllocator> Alloc32Handler{};
std::unique_ptr<FEXCore::HLE::SourcecodeMap> GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override;
fextl::unique_ptr<FEXCore::HLE::SourcecodeMap> GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override;
///// VMA (Virtual Memory Area) tracking /////

View File

@ -199,14 +199,16 @@ void SyscallHandler::TrackMmap(uintptr_t Base, uintptr_t Size, int Prot, int Fla
fstat64(fd, &buf);
MRID mrid {buf.st_dev, buf.st_ino};
auto filename = FEX::get_fdpath(fd);
char Tmp[PATH_MAX];
auto PathLength = FEX::get_fdpath(fd, Tmp);
if (filename.has_value()) {
if (PathLength != -1) {
Tmp[PathLength] = '\0';
auto [Iter, Inserted] = VMATracking.MappedResources.emplace(mrid, MappedResource {nullptr, nullptr, 0});
Resource = &Iter->second;
if (Inserted) {
Resource->AOTIRCacheEntry = CTX->LoadAOTIRCacheEntry(filename.value());
Resource->AOTIRCacheEntry = CTX->LoadAOTIRCacheEntry(fextl::string(Tmp, PathLength));
Resource->Iterator = Iter;
}
}

View File

@ -11,6 +11,7 @@ $end_info$
#include <FEXCore/HLE/SyscallHandler.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory.h>
#include <bitset>
#include <cerrno>
@ -39,7 +40,7 @@ namespace FEX::HLE::x32 {
void RegisterTime(FEX::HLE::SyscallHandler *Handler);
void RegisterTimer(FEX::HLE::SyscallHandler *Handler);
x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr<MemAllocator> Allocator)
x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator)
: SyscallHandler{ctx, _SignalDelegation}, AllocHandler{std::move(Allocator)} {
OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX32;
RegisterSyscallHandlers();
@ -110,8 +111,8 @@ namespace FEX::HLE::x32 {
#endif
}
std::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr<MemAllocator> Allocator) {
return std::make_unique<x32SyscallHandler>(ctx, _SignalDelegation, std::move(Allocator));
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator) {
return fextl::make_unique<x32SyscallHandler>(ctx, _SignalDelegation, std::move(Allocator));
}
}

View File

@ -6,6 +6,7 @@ $end_info$
#pragma once
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include "Tests/LinuxSyscalls/Syscalls.h"
@ -33,7 +34,7 @@ namespace FEX::HLE::x32 {
class x32SyscallHandler final : public FEX::HLE::SyscallHandler {
public:
x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr<MemAllocator> Allocator);
x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator);
FEX::HLE::MemAllocator *GetAllocator() { return AllocHandler.get(); }
void *GuestMmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override;
@ -69,12 +70,12 @@ public:
private:
void RegisterSyscallHandlers();
std::unique_ptr<MemAllocator> AllocHandler{};
fextl::unique_ptr<MemAllocator> AllocHandler{};
};
std::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx,
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx,
FEX::HLE::SignalDelegator *_SignalDelegation,
std::unique_ptr<MemAllocator> Allocator);
fextl::unique_ptr<MemAllocator> Allocator);
//////
// REGISTER_SYSCALL_IMPL implementation
// Given a syscall name + a lambda, and it will generate an strace string, extract number of arguments

View File

@ -113,7 +113,7 @@ namespace FEX::HLE::x64 {
#endif
}
std::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) {
return std::make_unique<x64SyscallHandler>(ctx, _SignalDelegation);
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) {
return fextl::make_unique<x64SyscallHandler>(ctx, _SignalDelegation);
}
}

View File

@ -11,6 +11,7 @@ $end_info$
#include <FEXCore/HLE/SyscallHandler.h>
#include <FEXCore/IR/IR.h>
#include <FEXCore/fextl/memory.h>
#include <FEXCore/fextl/string.h>
#include <atomic>
@ -70,7 +71,7 @@ class x64SyscallHandler final : public FEX::HLE::SyscallHandler {
void RegisterSyscallHandlers();
};
std::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation);
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation);
//////
// REGISTER_SYSCALL_IMPL implementation

Some files were not shown because too many files have changed in this diff Show More