AP_Scripting: dynamically load some binding objects

Only create the binding object (singleton metatable/userdata or C
function reference) once the user first references a particular
singleton or userdata creation function. Once created, the object is
stored into the script's environment so it doesn't get recreated on the
next reference and there isn't any further overhead. The userdatas are
no longer shared between scripts which imposes a slight memory penalty
for multiple scripts using the same singleton but this avoids an
additional lookup time cost.

Userdata and ap_objects aren't eligible for this optimization as the C++
code might want a particular metatable at any time.

Saves ~9.3K Lua heap.
This commit is contained in:
Thomas Watson 2024-06-28 15:16:44 -05:00 committed by Andrew Tridgell
parent 059af2117d
commit b64ed6ca56
1 changed files with 39 additions and 19 deletions

View File

@ -2499,6 +2499,43 @@ void emit_loaders(void) {
emit_type_index(parsed_singletons, "singleton");
emit_type_index(parsed_ap_objects, "ap_object");
fprintf(source, "static int binding_index(lua_State *L) {\n");
fprintf(source, " const char * name = luaL_checkstring(L, 2);\n");
fprintf(source, "\n");
fprintf(source, " bool found = false;\n");
fprintf(source, " for (uint32_t i = 0; i < ARRAY_SIZE(singleton_fun); i++) {\n");
fprintf(source, " if (strcmp(name, singleton_fun[i].name) == 0) {\n");
fprintf(source, " lua_newuserdata(L, 0);\n");
fprintf(source, " if (luaL_newmetatable(L, name)) { // need to create metatable\n");
fprintf(source, " lua_pushcfunction(L, singleton_fun[i].func);\n");
fprintf(source, " lua_setfield(L, -2, \"__index\");\n");
fprintf(source, " }\n");
fprintf(source, " lua_setmetatable(L, -2);\n");
fprintf(source, " found = true;\n");
fprintf(source, " break;\n");
fprintf(source, " }\n");
fprintf(source, " }\n");
fprintf(source, " if (!found) {\n");
fprintf(source, " for (uint32_t i = 0; i < ARRAY_SIZE(new_userdata); i++) {\n");
fprintf(source, " if (strcmp(name, new_userdata[i].name) == 0) {\n");
fprintf(source, " lua_pushcfunction(L, new_userdata[i].fun);\n");
fprintf(source, " found = true;\n");
fprintf(source, " break;\n");
fprintf(source, " }\n");
fprintf(source, " }\n");
fprintf(source, " }\n");
fprintf(source, " if (!found) {\n");
fprintf(source, " return 0;\n");
fprintf(source, " }\n");
fprintf(source, "\n");
fprintf(source, " // store found value to avoid a re-index\n");
fprintf(source, " lua_pushvalue(L, -2);\n");
fprintf(source, " lua_pushvalue(L, -2);\n");
fprintf(source, " lua_settable(L, -5);\n");
fprintf(source, "\n");
fprintf(source, " return 1;\n");
fprintf(source, "}\n\n");
fprintf(source, "void load_generated_bindings(lua_State *L) {\n");
fprintf(source, " luaL_checkstack(L, 5, \"Out of stack\");\n"); // this is more stack space then we need, but should never fail
fprintf(source, " // userdata metatables\n");
@ -2525,24 +2562,7 @@ void emit_loaders(void) {
fprintf(source, " }\n");
fprintf(source, "\n");
fprintf(source, " // singleton metatables\n");
fprintf(source, " for (uint32_t i = 0; i < ARRAY_SIZE(singleton_fun); i++) {\n");
fprintf(source, " lua_newuserdata(L, 0);\n");
fprintf(source, " luaL_newmetatable(L, singleton_fun[i].name);\n");
fprintf(source, " lua_pushcfunction(L, singleton_fun[i].func);\n");
fprintf(source, " lua_setfield(L, -2, \"__index\");\n");
fprintf(source, " lua_setmetatable(L, -2);\n");
fprintf(source, " lua_setglobal(L, singleton_fun[i].name);\n");
fprintf(source, " }\n");
fprintf(source, "\n");
fprintf(source, " // userdata creation funcs\n");
fprintf(source, " for (uint32_t i = 0; i < ARRAY_SIZE(new_userdata); i++) {\n");
fprintf(source, " lua_pushcfunction(L, new_userdata[i].fun);\n");
fprintf(source, " lua_setglobal(L, new_userdata[i].name);\n");
fprintf(source, " }\n");
fprintf(source, "\n");
fprintf(source, " // singletons and userdata creation funcs are loaded dynamically\n");
fprintf(source, "}\n\n");
}
@ -2601,7 +2621,7 @@ void emit_userdata_new_funcs(void) {
void emit_sandbox(void) {
fprintf(source, "void load_generated_sandbox(lua_State *L) {\n");
fprintf(source, " lua_createtable(L, 0, 1);\n");
fprintf(source, " lua_pushglobaltable(L);\n");
fprintf(source, " lua_pushcfunction(L, binding_index);\n");
fprintf(source, " lua_setfield(L, -2, \"__index\");\n");
fprintf(source, " lua_setmetatable(L, -2);\n");
fprintf(source, "}\n");