summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-06-27 19:47:00 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-06-27 19:47:00 -0400
commit0cc7436be1f57299384c5acad5d32e13f2f4d1cf (patch)
treeaccf51717e388f6daab391876c2a1d68c6e702bd /indra/llcommon
parent6ee98f4e9b5ea9ade06056a9d1f4c1e0b1c00b44 (diff)
Introduce TypeTag<T> template whose int value differs for each T.
This replaces type_tag<T>(), which searched and possibly extended the type_tags unordered_map at runtime. If we called lua_emplace<T>() from different threads, that would require locking type_tags. In contrast, the compiler must instantiate a distinct TypeTag<T> for every distinct T passed to lua_emplace<T>(), so each gets a distinct value at static initialization time. No locking is required; no lookup; no allocations. Add a test to llluamanager_test.cpp to verify that each distinct T passed to lua_emplace<T>() gets its own TypeTag<T>::value, and that each gets its own destructor -- but that different lua_emplace<T>() calls with the same T share the same TypeTag<T>::value and the same destructor.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/lua_function.cpp2
-rw-r--r--indra/llcommon/lua_function.h44
2 files changed, 28 insertions, 18 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index 255385b8c4..2d08de68c5 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -38,6 +38,8 @@ const S32 INTERRUPTS_SUSPEND_LIMIT = 100;
#define lua_register(L, n, f) (lua_pushcfunction(L, (f), n), lua_setglobal(L, (n)))
#define lua_rawlen lua_objlen
+int DistinctInt::mValues{0};
+
/*****************************************************************************
* luau namespace
*****************************************************************************/
diff --git a/indra/llcommon/lua_function.h b/indra/llcommon/lua_function.h
index 284f911fa8..c32a586d79 100644
--- a/indra/llcommon/lua_function.h
+++ b/indra/llcommon/lua_function.h
@@ -195,26 +195,34 @@ int name##_luasub::call(lua_State* L)
/*****************************************************************************
* lua_emplace<T>(), lua_toclass<T>()
*****************************************************************************/
-namespace {
+// Every instance of DistinctInt has a different int value, barring int
+// wraparound.
+class DistinctInt
+{
+public:
+ DistinctInt(): mValue(++mValues) {}
+ int get() const { return mValue; }
+ operator int() const { return mValue; }
+private:
+ static int mValues;
+ int mValue;
+};
-// If we start engaging lua_emplace<T>() from more than one thread, type_tags
-// will need locking.
-std::unordered_map<std::type_index, int> type_tags;
+namespace {
-// find or create a new Luau userdata "tag" for type T
template <typename T>
-int type_tag()
+struct TypeTag
{
- // The first time we encounter a given type T, assign a new distinct tag
- // value based on the number of previously-created tags. But avoid tag 0,
- // which is evidently the default for userdata objects created without
- // explicit tags. Don't try to destroy a nonexistent T object in a random
- // userdata object!
- auto [entry, created] = type_tags.emplace(std::type_index(typeid(T)), int(type_tags.size()+1));
- // Luau only permits up to LUA_UTAG_LIMIT distinct userdata tags (ca. 128)
- llassert(entry->second < LUA_UTAG_LIMIT);
- return entry->second;
-}
+ // For (std::is_same<T, U>), &TypeTag<T>::value == &TypeTag<U>::value.
+ // For (! std::is_same<T, U>), &TypeTag<T>::value != &TypeTag<U>::value.
+ // And every distinct instance of DistinctInt has a distinct value.
+ // Therefore, TypeTag<T>::value is an int uniquely associated with each
+ // distinct T.
+ static DistinctInt value;
+};
+
+template <typename T>
+DistinctInt TypeTag<T>::value;
} // anonymous namespace
@@ -233,7 +241,7 @@ template <class T, typename... ARGS>
void lua_emplace(lua_State* L, ARGS&&... args)
{
luaL_checkstack(L, 1, nullptr);
- int tag{ type_tag<T>() };
+ int tag{ TypeTag<T>::value };
if (! lua_getuserdatadtor(L, tag))
{
// We haven't yet told THIS lua_State the destructor to use for this tag.
@@ -267,7 +275,7 @@ template <class T>
T* lua_toclass(lua_State* L, int index)
{
// get void* pointer to userdata (if that's what it is)
- void* ptr{ lua_touserdatatagged(L, index, type_tag<T>()) };
+ void* ptr{ lua_touserdatatagged(L, index, TypeTag<T>::value) };
// Derive the T* from ptr. If in future lua_emplace() must manually
// align our T* within the Lua-provided void*, adjust accordingly.
return static_cast<T*>(ptr);