diff --git a/Common/System/System.h b/Common/System/System.h index a713616a1095..f82d39e5c728 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -98,6 +98,8 @@ enum SystemProperty { SYSPROP_SUPPORTS_PERMISSIONS, SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE, + + SYSPROP_CAN_JIT, }; std::string System_GetProperty(SystemProperty prop); diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index b88c9c4230f9..70aa0100d453 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -225,6 +225,8 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return true; default: return false; } diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 464e736d9af8..625e470735fc 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -387,6 +387,8 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return true; default: return false; } diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 8daac5bc898e..dd7632ac56ad 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -472,6 +472,9 @@ void SystemInfoScreen::CreateViews() { int totalThreads = cpu_info.num_cores * cpu_info.logical_cpu_count; std::string cores = StringFromFormat(si->T("%d (%d per core, %d cores)"), totalThreads, cpu_info.logical_cpu_count, cpu_info.num_cores); deviceSpecs->Add(new InfoItem(si->T("Threads"), cores)); +#endif +#if PPSSPP_PLATFORM(IOS) + deviceSpecs->Add(new InfoItem(si->T("JIT available"), System_GetPropertyBool(SYSPROP_CAN_JIT) ? di->T("Yes") : di->T("No"))); #endif deviceSpecs->Add(new ItemHeader(si->T("GPU Information"))); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index bdde5cdcbfd9..93bf0dfbb418 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -694,6 +694,12 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch } } + if (System_GetPropertyBool(SYSPROP_CAN_JIT) == false && g_Config.iCpuCore == (int)CPUCore::JIT) { + // Just gonna force it to the IR interpreter on startup. + // We don't hide the option, but we make sure it's off on bootup. In case someone wants + // to experiment in future iOS versions or something... + g_Config.iCpuCore = (int)CPUCore::IR_JIT; + } auto des = GetI18NCategory("DesktopUI"); // Note to translators: do not translate this/add this to PPSSPP-lang's files. diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 0ba7fac4b69e..18970f130e94 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -439,6 +439,8 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return true; default: return false; } diff --git a/Windows/main.cpp b/Windows/main.cpp index 716a01d12353..c322b755b7c7 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -310,6 +310,8 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return true; default: return false; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 10fdf97e57a8..6b71ea07d604 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -443,6 +443,8 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return true; default: return false; } diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 003bb396df2c..e161f1d598d2 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -89,7 +89,14 @@ std::string System_GetProperty(SystemProperty prop) { return ""; } std::vector System_GetPropertyStringVec(SystemProperty prop) { return std::vector(); } int System_GetPropertyInt(SystemProperty prop) { return -1; } float System_GetPropertyFloat(SystemProperty prop) { return -1.0f; } -bool System_GetPropertyBool(SystemProperty prop) { return false; } +bool System_GetPropertyBool(SystemProperty prop) { + switch (prop) { + case SYSPROP_CAN_JIT: + return true; + default: + return false; + } +} void System_SendMessage(const char *command, const char *parameter) {} void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } diff --git a/ios/main.mm b/ios/main.mm index 4b3e768d5cf7..71352d782fe7 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -14,8 +14,10 @@ #import "PPSSPPUIApplication.h" #import "ViewController.h" +#include "Common/MemoryUtil.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" +#include "Common/StringUtils.h" #include "Common/Profiler/Profiler.h" #define CS_OPS_STATUS 0 /* return status */ @@ -52,11 +54,14 @@ kern_return_t catch_exception_raise(mach_port_t exception_port, static float g_safeInsetTop = 0.0; static float g_safeInsetBottom = 0.0; +static bool g_jitAvailable = false; +static int g_iosVersionMajor; +static int g_iosVersionMinor; std::string System_GetProperty(SystemProperty prop) { switch (prop) { case SYSPROP_NAME: - return "iOS:"; + return StringFromFormat("iOS %d.%d", g_iosVersionMajor, g_iosVersionMinor); case SYSPROP_LANGREGION: return "en_US"; default: @@ -78,6 +83,8 @@ int System_GetPropertyInt(SystemProperty prop) { return 44100; case SYSPROP_DEVICE_TYPE: return DEVICE_TYPE_MOBILE; + case SYSPROP_SYSTEMVERSION: + return g_iosVersionMajor; default: return -1; } @@ -110,6 +117,9 @@ bool System_GetPropertyBool(SystemProperty prop) { #else return false; #endif + case SYSPROP_CAN_JIT: + return g_jitAvailable; + default: return false; } @@ -200,28 +210,58 @@ void Vibrate(int mode) { int main(int argc, char *argv[]) { + // Hacky hacks to try to enable JIT by pretending to be a debugger. csops = reinterpret_cast(dlsym(dlopen(nullptr, RTLD_LAZY), "csops")); exc_server = reinterpret_cast(dlsym(dlopen(NULL, RTLD_LAZY), "exc_server")); ptrace = reinterpret_cast(dlsym(dlopen(NULL, RTLD_LAZY), "ptrace")); // see https://github.com/hrydgard/ppsspp/issues/11905 - if (!cs_debugged()) { - pid_t pid = fork(); - if (pid == 0) { - ptrace(PT_TRACE_ME, 0, nullptr, 0); - exit(0); - } else if (pid < 0) { - perror("Unable to fork"); - - ptrace(PT_TRACE_ME, 0, nullptr, 0); - ptrace(PT_SIGEXC, 0, nullptr, 0); - - mach_port_t port = MACH_PORT_NULL; - mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); - mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); - task_set_exception_ports(mach_task_self(), EXC_MASK_SOFTWARE, port, EXCEPTION_DEFAULT, THREAD_STATE_NONE); - pthread_t thread; - pthread_create(&thread, nullptr, exception_handler, reinterpret_cast(&port)); + + // Tried checking for JIT support here with AllocateExecutableMemory and ProtectMemoryPages, + // but it just succeeds, and then fails when you try to execute from it. + + // So, we'll just resort to a version check. + + std::string version = [[UIDevice currentDevice].systemVersion UTF8String]; + if (2 != sscanf(version.c_str(), "%d.%d", &g_iosVersionMajor, &g_iosVersionMinor)) { + // Just set it to 14.0 if the parsing fails for whatever reason. + g_iosVersionMajor = 14; + g_iosVersionMinor = 0; + } + + if (g_iosVersionMajor > 14 || (g_iosVersionMajor == 14 && g_iosVersionMinor >= 3)) { + g_jitAvailable = false; + } else { + g_jitAvailable = true; + } + + bool debuggerAttached = cs_debugged(); + + if (!debuggerAttached) { + // Try to fool iOS into thinking a debugger is attached. + // This doesn't work in iOS 14.4 anymore so don't even try there. + if (!(g_iosVersionMajor == 14 && g_iosVersionMinor == 4)) { + pid_t pid = fork(); + if (pid == 0) { + printf("Forked a ptrace call"); + ptrace(PT_TRACE_ME, 0, nullptr, 0); + exit(0); + } else if (pid < 0) { + perror("Unable to fork"); + + ptrace(PT_TRACE_ME, 0, nullptr, 0); + ptrace(PT_SIGEXC, 0, nullptr, 0); + + mach_port_t port = MACH_PORT_NULL; + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); + mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); + task_set_exception_ports(mach_task_self(), EXC_MASK_SOFTWARE, port, EXCEPTION_DEFAULT, THREAD_STATE_NONE); + pthread_t thread; + pthread_create(&thread, nullptr, exception_handler, reinterpret_cast(&port)); + } } + } else { + // Debugger is attached - we can actually JIT. Override the version detect. + g_jitAvailable = true; } PROFILE_INIT(); diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 677e831717ed..2733287e55a8 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -69,6 +69,10 @@ float System_GetPropertyFloat(SystemProperty prop) { return -1; } bool System_GetPropertyBool(SystemProperty prop) { + switch (prop) { + case SYSPROP_CAN_JIT: + return true; + } return false; }