Skip to content

Commit 7247bcb

Browse files
committed
Luau uses tagged userdata and userdata destructors;
1 parent e810877 commit 7247bcb

File tree

4 files changed

+55
-37
lines changed

4 files changed

+55
-37
lines changed

src/api/api.c

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
#include "graphics/graphics.h"
1515
#endif
1616

17-
typedef void voidFn(void);
18-
1917
#ifdef _WIN32
2018
#define LOVR_EXPORT __declspec(dllexport)
2119
#else
@@ -47,6 +45,16 @@ static int luax_type(lua_State* L) {
4745
return 1;
4846
}
4947

48+
#ifdef LOVR_USE_LUAU
49+
static void luax_destructor(lua_State* L, void* userdata) {
50+
Object* object = userdata;
51+
if (object->pointer) {
52+
lovrRelease(object->pointer, lovrTypeInfo[object->type].destructor);
53+
object->pointer = NULL;
54+
}
55+
}
56+
#endif
57+
5058
static int luax_release(lua_State* L) {
5159
Object* object = lua_touserdata(L, 1);
5260

@@ -68,17 +76,6 @@ static int luax_release(lua_State* L) {
6876
return 0;
6977
}
7078

71-
static int luax_runfinalizers(lua_State* L) {
72-
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrfinalizers");
73-
for (int i = luax_len(L, 2); i >= 1; i--) {
74-
lua_rawgeti(L, 2, i);
75-
voidFn* finalizer = (voidFn*) lua_tocfunction(L, -1);
76-
finalizer();
77-
lua_pop(L, 1);
78-
}
79-
return 0;
80-
}
81-
8279
void luax_preload(lua_State* L) {
8380
static const luaL_Reg lovrModules[] = {
8481
{ "lovr", luaopen_lovr },
@@ -138,13 +135,19 @@ void _luax_registertype(lua_State* L, int type, const char* name, void (*destruc
138135
lua_pushvalue(L, -1);
139136
lua_setfield(L, -1, "__index");
140137

138+
#ifdef LOVR_USE_LUAU
139+
lua_setuserdatadtor(L, type, luax_destructor);
140+
lua_pushvalue(L, -1);
141+
lua_setuserdatametatable(L, type);
142+
#else
141143
// m.__gc = luax_release
142144
lua_pushcfunction(L, luax_release);
143145
lua_setfield(L, -2, "__gc");
144146

145147
// m.__close = gc
146148
lua_pushcfunction(L, luax_release);
147149
lua_setfield(L, -2, "__close");
150+
#endif
148151

149152
// m.__tostring
150153
lua_pushcfunction(L, luax_tostring);
@@ -168,13 +171,18 @@ void _luax_registertype(lua_State* L, int type, const char* name, void (*destruc
168171
}
169172

170173
void* _luax_totype(lua_State* L, int index, int type) {
174+
#ifdef LOVR_USE_LUAU
175+
Object* object = lua_touserdatatagged(L, index, type);
176+
return object ? object->pointer : NULL;
177+
#else
171178
Object* object = lua_touserdata(L, index);
172179

173180
if (object && lua_type(L, index) != LUA_TLIGHTUSERDATA && object->type == type) {
174181
return object->pointer;
175182
}
176183

177184
return NULL;
185+
#endif
178186
}
179187

180188
void* _luax_checktype(lua_State* L, int index, int type) {
@@ -240,9 +248,13 @@ void _luax_pushtype(lua_State* L, int type, void* pointer) {
240248
}
241249

242250
// Allocate userdata
251+
#ifdef LOVR_USE_LUAU
252+
Object* object = (Object*) lua_newuserdatataggedwithmetatable(L, sizeof(Object), type);
253+
#else
243254
Object* object = (Object*) lua_newuserdata(L, sizeof(Object));
244255
luaL_newmetatable(L, lovrTypeInfo[type].name);
245256
lua_setmetatable(L, -2);
257+
#endif
246258
lovrRetain(pointer);
247259
object->pointer = pointer;
248260
object->type = type;
@@ -428,30 +440,35 @@ void luax_setmainthread(lua_State *L) {
428440
#endif
429441
}
430442

431-
void luax_atexit(lua_State* L, voidFn* finalizer) {
443+
typedef struct Finalizer {
444+
struct Finalizer* next;
445+
void (*fn)(void);
446+
} Finalizer;
447+
448+
void luax_atexit(lua_State* L, void (*fn)(void)) {
449+
Finalizer* finalizer = lovrMalloc(sizeof(Finalizer));
450+
finalizer->fn = fn;
451+
432452
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrfinalizers");
453+
finalizer->next = lua_touserdata(L, -1);
454+
lua_pop(L, 1);
433455

434-
if (lua_isnil(L, -1)) {
435-
lua_newtable(L);
436-
lua_replace(L, -2);
456+
lua_pushlightuserdata(L, finalizer);
457+
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrfinalizers");
458+
}
437459

438-
// Userdata sentinel since tables don't have __gc (yet)
439-
lua_newuserdata(L, sizeof(void*));
440-
lua_createtable(L, 0, 1);
441-
lua_pushcfunction(L, luax_runfinalizers);
442-
lua_setfield(L, -2, "__gc");
443-
lua_setmetatable(L, -2);
444-
lua_setfield(L, -2, "");
460+
void luax_close(lua_State* L) {
461+
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrfinalizers");
462+
Finalizer* finalizer = lua_touserdata(L, -1);
445463

446-
// Write to the registry
447-
lua_pushvalue(L, -1);
448-
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrfinalizers");
449-
}
464+
lua_close(L);
450465

451-
int length = luax_len(L, -1);
452-
lua_pushcfunction(L, (lua_CFunction) finalizer);
453-
lua_rawseti(L, -2, length + 1);
454-
lua_pop(L, 1);
466+
while (finalizer) {
467+
finalizer->fn();
468+
Finalizer* next = finalizer->next;
469+
lovrFree(finalizer);
470+
finalizer = next;
471+
}
455472
}
456473

457474
uint32_t _luax_checku32(lua_State* L, int index) {

src/api/api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ int luax_setconf(lua_State* L);
135135
void luax_pushstash(lua_State* L, const char* name);
136136
void luax_setmainthread(lua_State* L);
137137
void luax_atexit(lua_State* L, void (*finalizer)(void));
138+
void luax_close(lua_State* L);
138139
uint32_t _luax_checku32(lua_State* L, int index);
139140
uint32_t _luax_optu32(lua_State* L, int index, uint32_t fallback);
140141
void luax_checkvariant(lua_State* L, int index, union Variant* variant);

src/api/l_thread.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static char* threadRunner(Thread* thread, Blob* body, Variant* arguments, uint32
2121
}
2222

2323
if (!lua_pcall(L, argumentCount, 0, errhandler)) {
24-
lua_close(L);
24+
luax_close(L);
2525
return NULL;
2626
}
2727
}
@@ -30,11 +30,11 @@ static char* threadRunner(Thread* thread, Blob* body, Variant* arguments, uint32
3030
if (lua_type(L, -1) == LUA_TSTRING) {
3131
const char* message = lua_tostring(L, -1);
3232
char* error = lovrStrdup(message);
33-
lua_close(L);
33+
luax_close(L);
3434
return error;
3535
}
3636

37-
lua_close(L);
37+
luax_close(L);
3838
return NULL;
3939
}
4040

src/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ int main(int argc, char** argv) {
4545
if (lua_type(T, 1) == LUA_TSTRING && !strcmp(lua_tostring(T, 1), "restart")) {
4646
luax_checkvariant(T, 2, &cookie);
4747
if (cookie.type == TYPE_OBJECT) memset(&cookie, 0, sizeof(cookie));
48-
lua_close(L);
48+
luax_close(L);
4949
continue;
5050
} else {
5151
int status = lua_tointeger(T, 1);
52-
lua_close(L);
52+
luax_close(L);
5353
os_destroy();
5454
return status;
5555
}

0 commit comments

Comments
 (0)