Fix Collider/Shape/Joint UserData leak;

refs are cumbersome because they require storing an int and they require
manual cleanup when the object is destroyed.

Instead, we'll go with a pure Lua solution using a table in the
registry.  The table has weak keys containing the LÖVR object, and the
values are the userdata.  This doesn't require any manual cleanup,
reduces the size of objects by 8 bytes, and is about 25% faster.
This commit is contained in:
bjorn 2024-04-01 16:03:42 -07:00
parent 243b6ae21a
commit fdba60214c
6 changed files with 81 additions and 108 deletions

View File

@ -62,27 +62,38 @@ static int l_lovrColliderGetJoints(lua_State* L) {
return 1;
}
static void luax_pushcolliderstash(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrcolliderstash");
if (lua_isnil(L, -1)) {
lua_newtable(L);
lua_replace(L, -2);
// metatable
lua_newtable(L);
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrcolliderstash");
}
}
static int l_lovrColliderGetUserData(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
union { int i; void* p; } ref = { .p = lovrColliderGetUserData(collider) };
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
luax_checktype(L, 1, Collider);
luax_pushcolliderstash(L);
lua_pushvalue(L, 1);
lua_rawget(L, -2);
return 1;
}
static int l_lovrColliderSetUserData(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
union { int i; void* p; } ref = { .p = lovrColliderGetUserData(collider) };
if (ref.i) {
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
}
if (lua_gettop(L) < 2) {
lua_pushnil(L);
}
lua_settop(L, 2);
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
lovrColliderSetUserData(collider, ref.p);
luax_checktype(L, 1, Collider);
luax_pushcolliderstash(L);
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_rawset(L, -3);
return 0;
}

View File

@ -57,27 +57,38 @@ static int l_lovrJointGetColliders(lua_State* L) {
return 2;
}
static void luax_pushjointstash(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrjointstash");
if (lua_isnil(L, -1)) {
lua_newtable(L);
lua_replace(L, -2);
// metatable
lua_newtable(L);
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrjointstash");
}
}
static int l_lovrJointGetUserData(lua_State* L) {
Joint* joint = luax_checkjoint(L, 1);
union { int i; void* p; } ref = { .p = lovrJointGetUserData(joint) };
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
luax_checktype(L, 1, Joint);
luax_pushjointstash(L);
lua_pushvalue(L, 1);
lua_rawget(L, -2);
return 1;
}
static int l_lovrJointSetUserData(lua_State* L) {
Joint* joint = luax_checkjoint(L, 1);
union { int i; void* p; } ref = { .p = lovrJointGetUserData(joint) };
if (ref.i) {
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
}
if (lua_gettop(L) < 2) {
lua_pushnil(L);
}
lua_settop(L, 2);
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
lovrJointSetUserData(joint, ref.p);
luax_checktype(L, 1, Joint);
luax_pushjointstash(L);
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_rawset(L, -3);
return 0;
}

View File

@ -179,27 +179,38 @@ static int l_lovrShapeSetSensor(lua_State* L) {
return 0;
}
static void luax_pushshapestash(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrshapestash");
if (lua_isnil(L, -1)) {
lua_newtable(L);
lua_replace(L, -2);
// metatable
lua_newtable(L);
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "_lovrshapestash");
}
}
static int l_lovrShapeGetUserData(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
union { int i; void* p; } ref = { .p = lovrShapeGetUserData(shape) };
lua_rawgeti(L, LUA_REGISTRYINDEX, ref.i);
luax_checktype(L, 1, Shape);
luax_pushshapestash(L);
lua_pushvalue(L, 1);
lua_rawget(L, -2);
return 1;
}
static int l_lovrShapeSetUserData(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
union { int i; void* p; } ref = { .p = lovrShapeGetUserData(shape) };
if (ref.i) {
luaL_unref(L, LUA_REGISTRYINDEX, ref.i);
}
if (lua_gettop(L) < 2) {
lua_pushnil(L);
}
lua_settop(L, 2);
ref.i = luaL_ref(L, LUA_REGISTRYINDEX);
lovrShapeSetUserData(shape, ref.p);
luax_checktype(L, 1, Shape);
luax_pushshapestash(L);
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_rawset(L, -3);
return 0;
}

View File

@ -84,8 +84,6 @@ void lovrColliderAddShape(Collider* collider, Shape* shape);
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
void* lovrColliderGetUserData(Collider* collider);
void lovrColliderSetUserData(Collider* collider, void* data);
const char* lovrColliderGetTag(Collider* collider);
bool lovrColliderSetTag(Collider* collider, const char* tag);
float lovrColliderGetFriction(Collider* collider);
@ -147,8 +145,6 @@ bool lovrShapeIsEnabled(Shape* shape);
void lovrShapeSetEnabled(Shape* shape, bool enabled);
bool lovrShapeIsSensor(Shape* shape);
void lovrShapeSetSensor(Shape* shape, bool sensor);
void* lovrShapeGetUserData(Shape* shape);
void lovrShapeSetUserData(Shape* shape, void* data);
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z);
void lovrShapeSetPosition(Shape* shape, float x, float y, float z);
void lovrShapeGetOrientation(Shape* shape, float* orientation);
@ -205,8 +201,6 @@ void lovrJointSetCFM(Joint* joint, float cfm);
float lovrJointGetERP(Joint* joint);
void lovrJointSetERP(Joint* joint, float erp);
void lovrJointGetColliders(Joint* joint, Collider** a, Collider** b);
void* lovrJointGetUserData(Joint* joint);
void lovrJointSetUserData(Joint* joint, void* data);
bool lovrJointIsEnabled(Joint* joint);
void lovrJointSetEnabled(Joint* joint, bool enable);

View File

@ -37,7 +37,6 @@ struct Collider {
Collider* next;
arr_t(Shape*) shapes;
arr_t(Joint*) joints;
void* userdata;
uint32_t tag;
};
@ -46,14 +45,12 @@ struct Shape {
ShapeType type;
Collider* collider;
JPH_Shape* shape;
void* userdata;
};
struct Joint {
uint32_t ref;
JointType type;
JPH_Constraint * constraint;
void* userdata;
};
// Broad phase and object phase layers
@ -495,14 +492,6 @@ Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
return collider->joints.data;
}
void* lovrColliderGetUserData(Collider* collider) {
return collider->userdata;
}
void lovrColliderSetUserData(Collider* collider, void* data) {
collider->userdata = data;
}
const char* lovrColliderGetTag(Collider* collider) {
return lovrWorldGetTagName(collider->world, collider->tag);
}
@ -842,14 +831,6 @@ void lovrShapeSetSensor(Shape* shape, bool sensor) {
JPH_Body_SetIsSensor(shape->collider->body, sensor);
}
void* lovrShapeGetUserData(Shape* shape) {
return shape->userdata;
}
void lovrShapeSetUserData(Shape* shape, void* data) {
shape->userdata = data;
}
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
// todo: compound shapes
*x = 0.f;
@ -1119,14 +1100,6 @@ void lovrJointGetColliders(Joint* joint, Collider** a, Collider** b) {
}
}
void* lovrJointGetUserData(Joint* joint) {
return joint->userdata;
}
void lovrJointSetUserData(Joint* joint, void* data) {
joint->userdata = data;
}
bool lovrJointIsEnabled(Joint* joint) {
return JPH_Constraint_GetEnabled(joint->constraint);
}

View File

@ -21,7 +21,6 @@ struct Collider {
World* world;
Collider* prev;
Collider* next;
void* userdata;
uint32_t tag;
arr_t(Shape*) shapes;
arr_t(Joint*) joints;
@ -36,7 +35,6 @@ struct Shape {
Collider* collider;
void* vertices;
void* indices;
void* userdata;
bool sensor;
};
@ -44,7 +42,6 @@ struct Joint {
uint32_t ref;
JointType type;
dJointID id;
void* userdata;
};
static void defaultNearCallback(void* data, dGeomID a, dGeomID b) {
@ -571,14 +568,6 @@ Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
return collider->joints.data;
}
void* lovrColliderGetUserData(Collider* collider) {
return collider->userdata;
}
void lovrColliderSetUserData(Collider* collider, void* data) {
collider->userdata = data;
}
const char* lovrColliderGetTag(Collider* collider) {
return lovrWorldGetTagName(collider->world, collider->tag);
}
@ -899,14 +888,6 @@ void lovrShapeSetSensor(Shape* shape, bool sensor) {
shape->sensor = sensor;
}
void* lovrShapeGetUserData(Shape* shape) {
return shape->userdata;
}
void lovrShapeSetUserData(Shape* shape, void* data) {
shape->userdata = data;
}
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
const dReal* position = dGeomGetOffsetPosition(shape->id);
*x = position[0];
@ -1161,14 +1142,6 @@ void lovrJointGetColliders(Joint* joint, Collider** a, Collider** b) {
}
}
void* lovrJointGetUserData(Joint* joint) {
return joint->userdata;
}
void lovrJointSetUserData(Joint* joint, void* data) {
joint->userdata = data;
}
bool lovrJointIsEnabled(Joint* joint) {
return dJointIsEnabled(joint->id);
}