Potential very hacky workaround for arm64 JIT allocation issues.

Try to reserve blocks of executable memory before external library code claims the address space. LuaJIT on arm64 currently has a very limited range of memory it can use for JIT code.
This commit is contained in:
Alex Szpakowski
2021-11-12 21:58:49 -04:00
parent 1bb22d2e90
commit 888051d01e
5 changed files with 115 additions and 12 deletions
+71
View File
@@ -0,0 +1,71 @@
R"luastring"--(
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
-- There is a matching delimiter at the bottom of the file.
--[[
Copyright (c) 2006-2021 LOVE Development Team
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--]]
if type(jit) ~= "table" or not jit.status() then
return
end
-- Double the defaults.
jit.opt.start("maxtrace=2000", "maxrecord=8000")
-- Somewhat arbitrary value. Needs to be higher than the combined sizes below,
-- and higher than the default (512) because that's already too low.
jit.opt.start("maxmcode=16384")
if jit.arch == "arm64" then
-- https://github.com/LuaJIT/LuaJIT/issues/285
-- LuaJIT 2.1 on arm64 currently (as of commit b4b2dce) can only use memory
-- for JIT compilation within a certain short range. Other libraries such as
-- SDL can take all the usable space in that range and cause attempts at JIT
-- compilation to both fail and take a long time.
-- This is a very hacky attempt at a workaround. LuaJIT allocates executable
-- code in pools. We'll try "reserving" pools before any external code is
-- executed, by causing JIT compilation via a small loop. We can't easily
-- tell if JIT compilation succeeded, so we do several successively smaller
-- pool allocations in case previous ones fail.
-- This is a really hacky hack and by no means foolproof - there are a lot of
-- potential situations (especially when threads are used) where previously
-- executed external code will still take up space that LuaJIT needed for itself.
jit.opt.start("sizemcode=2048")
for i=1, 100 do end
jit.opt.start("sizemcode=1024")
for i=1, 100 do end
jit.opt.start("sizemcode=512")
for i=1, 100 do end
jit.opt.start("sizemcode=256")
for i=1, 100 do end
jit.opt.start("sizemcode=128")
for i=1, 100 do end
else
-- Somewhat arbitrary value (>= the default).
jit.opt.start("sizemcode=128")
end
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
--)luastring"--"
+23 -4
View File
@@ -97,6 +97,10 @@ static const char boot_lua[] =
#include "boot.lua"
;
static const char jit_setup_lua[] =
#include "jitsetup.lua"
;
// All modules define a c-accessible luaopen
// so let's make use of those, instead
// of addressing implementations directly.
@@ -160,6 +164,7 @@ extern "C"
extern int luaopen_love_window(lua_State*);
#endif
extern int luaopen_love_nogame(lua_State*);
extern int luaopen_love_jitsetup(lua_State*);
extern int luaopen_love_arg(lua_State*);
extern int luaopen_love_callbacks(lua_State*);
extern int luaopen_love_boot(lua_State*);
@@ -224,6 +229,7 @@ static const luaL_Reg modules[] = {
{ "love.window", luaopen_love_window },
#endif
{ "love.nogame", luaopen_love_nogame },
{ "love.jitsetup", luaopen_love_jitsetup },
{ "love.arg", luaopen_love_arg },
{ "love.callbacks", luaopen_love_callbacks },
{ "love.boot", luaopen_love_boot },
@@ -404,6 +410,15 @@ static void luax_addcompatibilityalias(lua_State *L, const char *module, const c
int luaopen_love(lua_State *L)
{
// Preload module loaders.
for (int i = 0; modules[i].name != nullptr; i++)
love::luax_preload(L, modules[i].func, modules[i].name);
// jitsetup is also loaded in the love executable runlove function. It's
// needed here too for threads. Note that it doesn't use the love table.
love::luax_require(L, "love.jitsetup");
lua_pop(L, 1);
love::luax_insistpinnedthread(L);
love::luax_insistglobal(L, "love");
@@ -501,10 +516,6 @@ int luaopen_love(lua_State *L)
lua_setfield(L, -2, "hasDeprecationOutput");
}
// Preload module loaders.
for (int i = 0; modules[i].name != nullptr; i++)
love::luax_preload(L, modules[i].func, modules[i].name);
// Necessary for Data-creating methods to work properly in Data subclasses.
love::luax_require(L, "love.data");
lua_pop(L, 1);
@@ -657,6 +668,14 @@ int luaopen_love_nogame(lua_State *L)
return 1;
}
int luaopen_love_jitsetup(lua_State *L)
{
if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "jitsetup.lua") == 0)
lua_call(L, 0, 1);
return 1;
}
int luaopen_love_arg(lua_State *L)
{
if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0)
+3
View File
@@ -36,6 +36,9 @@ LOVE_EXPORT const char *love_version();
LOVE_EXPORT const char *love_codename();
LOVE_EXPORT int luaopen_love(lua_State *L);
LOVE_EXPORT int luaopen_love_nogame(lua_State *L);
LOVE_EXPORT int luaopen_love_jitsetup(lua_State *L);
LOVE_EXPORT int luaopen_love_arg(lua_State *L);
LOVE_EXPORT int luaopen_love_callbacks(lua_State *L);
LOVE_EXPORT int luaopen_love_boot(lua_State *L);
#ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK