Explorar o código

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.
Alex Szpakowski %!s(int64=3) %!d(string=hai) anos
pai
achega
888051d01e

+ 2 - 0
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -1849,6 +1849,7 @@
 		FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = "<group>"; };
 		FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = "<group>"; };
 		FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
 		FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
 		FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_GraphicsShader.lua; sourceTree = "<group>"; };
 		FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_GraphicsShader.lua; sourceTree = "<group>"; };
+		FA69B918273828DD00CDC2E7 /* jitsetup.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = jitsetup.lua; sourceTree = "<group>"; };
 		FA6A2B641F5F7B6B0074C308 /* wrap_Data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Data.h; sourceTree = "<group>"; };
 		FA6A2B641F5F7B6B0074C308 /* wrap_Data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Data.h; sourceTree = "<group>"; };
 		FA6A2B651F5F7B6B0074C308 /* wrap_Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Data.cpp; sourceTree = "<group>"; };
 		FA6A2B651F5F7B6B0074C308 /* wrap_Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Data.cpp; sourceTree = "<group>"; };
 		FA6A2B681F5F7F560074C308 /* DataView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataView.cpp; sourceTree = "<group>"; };
 		FA6A2B681F5F7F560074C308 /* DataView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataView.cpp; sourceTree = "<group>"; };
@@ -2966,6 +2967,7 @@
 				FA1E95B4271F932B0044CF08 /* arg.lua */,
 				FA1E95B4271F932B0044CF08 /* arg.lua */,
 				FA577A8D16C71D3600860150 /* boot.lua */,
 				FA577A8D16C71D3600860150 /* boot.lua */,
 				FA1E95B5271F932B0044CF08 /* callbacks.lua */,
 				FA1E95B5271F932B0044CF08 /* callbacks.lua */,
+				FA69B918273828DD00CDC2E7 /* jitsetup.lua */,
 				FA0B7BFE1A95902C000E1D17 /* love.cpp */,
 				FA0B7BFE1A95902C000E1D17 /* love.cpp */,
 				FA0B7BFF1A95902C000E1D17 /* love.h */,
 				FA0B7BFF1A95902C000E1D17 /* love.h */,
 			);
 			);

+ 16 - 8
src/love.cpp

@@ -142,14 +142,6 @@ enum DoneAction
 
 
 static DoneAction runlove(int argc, char **argv, int &retval)
 static DoneAction runlove(int argc, char **argv, int &retval)
 {
 {
-#ifdef LOVE_LEGENDARY_APP_ARGV_HACK
-	int hack_argc = 0;
-	char **hack_argv = 0;
-	get_app_arguments(argc, argv, hack_argc, hack_argv);
-	argc = hack_argc;
-	argv = hack_argv;
-#endif // LOVE_LEGENDARY_APP_ARGV_HACK
-
 	// Oh, you just want the version? Okay!
 	// Oh, you just want the version? Okay!
 	if (argc > 1 && strcmp(argv[1], "--version") == 0)
 	if (argc > 1 && strcmp(argv[1], "--version") == 0)
 	{
 	{
@@ -166,6 +158,22 @@ static DoneAction runlove(int argc, char **argv, int &retval)
 	lua_State *L = luaL_newstate();
 	lua_State *L = luaL_newstate();
 	luaL_openlibs(L);
 	luaL_openlibs(L);
 
 
+	// LuaJIT-specific setup needs to be done as early as possible - before
+	// get_app_arguments because that loads external library code. This is also
+	// loaded inside require("love"). Note that it doesn't use the love table.
+	love_preload(L, luaopen_love_jitsetup, "love.jitsetup");
+	lua_getglobal(L, "require");
+	lua_pushstring(L, "love.jitsetup");
+	lua_call(L, 1, 0);
+
+#ifdef LOVE_LEGENDARY_APP_ARGV_HACK
+	int hack_argc = 0;
+	char **hack_argv = nullptr;
+	get_app_arguments(argc, argv, hack_argc, hack_argv);
+	argc = hack_argc;
+	argv = hack_argv;
+#endif // LOVE_LEGENDARY_APP_ARGV_HACK
+
 	// Add love to package.preload for easy requiring.
 	// Add love to package.preload for easy requiring.
 	love_preload(L, luaopen_love, "love");
 	love_preload(L, luaopen_love, "love");
 
 

+ 71 - 0
src/modules/love/jitsetup.lua

@@ -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
src/modules/love/love.cpp

@@ -97,6 +97,10 @@ static const char boot_lua[] =
 #include "boot.lua"
 #include "boot.lua"
 ;
 ;
 
 
+static const char jit_setup_lua[] =
+#include "jitsetup.lua"
+;
+
 // All modules define a c-accessible luaopen
 // All modules define a c-accessible luaopen
 // so let's make use of those, instead
 // so let's make use of those, instead
 // of addressing implementations directly.
 // of addressing implementations directly.
@@ -160,6 +164,7 @@ extern "C"
 	extern int luaopen_love_window(lua_State*);
 	extern int luaopen_love_window(lua_State*);
 #endif
 #endif
 	extern int luaopen_love_nogame(lua_State*);
 	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_arg(lua_State*);
 	extern int luaopen_love_callbacks(lua_State*);
 	extern int luaopen_love_callbacks(lua_State*);
 	extern int luaopen_love_boot(lua_State*);
 	extern int luaopen_love_boot(lua_State*);
@@ -224,6 +229,7 @@ static const luaL_Reg modules[] = {
 	{ "love.window", luaopen_love_window },
 	{ "love.window", luaopen_love_window },
 #endif
 #endif
 	{ "love.nogame", luaopen_love_nogame },
 	{ "love.nogame", luaopen_love_nogame },
+	{ "love.jitsetup", luaopen_love_jitsetup },
 	{ "love.arg", luaopen_love_arg },
 	{ "love.arg", luaopen_love_arg },
 	{ "love.callbacks", luaopen_love_callbacks },
 	{ "love.callbacks", luaopen_love_callbacks },
 	{ "love.boot", luaopen_love_boot },
 	{ "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)
 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_insistpinnedthread(L);
 
 
 	love::luax_insistglobal(L, "love");
 	love::luax_insistglobal(L, "love");
@@ -501,10 +516,6 @@ int luaopen_love(lua_State *L)
 		lua_setfield(L, -2, "hasDeprecationOutput");
 		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.
 	// Necessary for Data-creating methods to work properly in Data subclasses.
 	love::luax_require(L, "love.data");
 	love::luax_require(L, "love.data");
 	lua_pop(L, 1);
 	lua_pop(L, 1);
@@ -657,6 +668,14 @@ int luaopen_love_nogame(lua_State *L)
 	return 1;
 	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)
 int luaopen_love_arg(lua_State *L)
 {
 {
 	if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0)
 	if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0)

+ 3 - 0
src/modules/love/love.h

@@ -36,6 +36,9 @@ LOVE_EXPORT const char *love_version();
 LOVE_EXPORT const char *love_codename();
 LOVE_EXPORT const char *love_codename();
 LOVE_EXPORT int luaopen_love(lua_State *L);
 LOVE_EXPORT int luaopen_love(lua_State *L);
 LOVE_EXPORT int luaopen_love_nogame(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);
 LOVE_EXPORT int luaopen_love_boot(lua_State *L);
 
 
 #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK
 #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK