diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-18 09:03:43 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-18 09:03:43 +0200 |
commit | e3818609b54c81a83aa73beb322ea9c282b7add8 (patch) | |
tree | b165d7925206ceb10a851fc8c1eed8b8566e7727 /src | |
parent | 54b47307ce4b2e21bc12c1602c77fecf55380452 (diff) | |
download | lanes-e3818609b54c81a83aa73beb322ea9c282b7add8.tar.gz lanes-e3818609b54c81a83aa73beb322ea9c282b7add8.tar.bz2 lanes-e3818609b54c81a83aa73beb322ea9c282b7add8.zip |
When it is a function, config.allocator is called with a string hint
Diffstat (limited to 'src')
-rw-r--r-- | src/allocator.h | 47 | ||||
-rw-r--r-- | src/keeper.cpp | 2 | ||||
-rw-r--r-- | src/state.cpp | 15 | ||||
-rw-r--r-- | src/state.h | 2 | ||||
-rw-r--r-- | src/universe.h | 47 |
5 files changed, 59 insertions, 54 deletions
diff --git a/src/allocator.h b/src/allocator.h new file mode 100644 index 0000000..9a9c245 --- /dev/null +++ b/src/allocator.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #pragma once | ||
2 | |||
3 | // ################################################################################################# | ||
4 | |||
5 | // everything we need to provide to lua_newstate() | ||
6 | class AllocatorDefinition | ||
7 | { | ||
8 | public: | ||
9 | // xxh64 of string "kAllocatorVersion_1" generated at https://www.pelock.com/products/hash-calculator | ||
10 | static constexpr uintptr_t kAllocatorVersion{ static_cast<uintptr_t>(0xCF9D321B0DFB5715ull) }; | ||
11 | uintptr_t version{ kAllocatorVersion }; | ||
12 | lua_Alloc allocF{ nullptr }; | ||
13 | void* allocUD{ nullptr }; | ||
14 | |||
15 | [[nodiscard]] static void* operator new(size_t size_) noexcept = delete; // can't create one outside of a Lua state | ||
16 | [[nodiscard]] static void* operator new(size_t size_, lua_State* L_) noexcept { return lua_newuserdatauv(L_, size_, 0); } | ||
17 | // always embedded somewhere else or "in-place constructed" as a full userdata | ||
18 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | ||
19 | static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) {} | ||
20 | |||
21 | AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept | ||
22 | : version{ version_ } | ||
23 | , allocF{ allocF_ } | ||
24 | , allocUD{ allocUD_ } | ||
25 | { | ||
26 | } | ||
27 | AllocatorDefinition() = default; | ||
28 | AllocatorDefinition(AllocatorDefinition const& rhs_) = default; | ||
29 | AllocatorDefinition(AllocatorDefinition&& rhs_) = default; | ||
30 | AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default; | ||
31 | AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default; | ||
32 | |||
33 | void initFrom(lua_State* L_) | ||
34 | { | ||
35 | allocF = lua_getallocf(L_, &allocUD); | ||
36 | } | ||
37 | |||
38 | void* alloc(size_t nsize_) | ||
39 | { | ||
40 | return allocF(allocUD, nullptr, 0, nsize_); | ||
41 | } | ||
42 | |||
43 | void free(void* ptr_, size_t osize_) | ||
44 | { | ||
45 | std::ignore = allocF(allocUD, ptr_, osize_, 0); | ||
46 | } | ||
47 | }; | ||
diff --git a/src/keeper.cpp b/src/keeper.cpp index e058114..11f1797 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -830,7 +830,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, int const nbKeepers_, int | |||
830 | auto _initOneKeeper = [U = &U_, L = L_, gc_threshold = gc_threshold](Keeper& keeper_, int const i_) { | 830 | auto _initOneKeeper = [U = &U_, L = L_, gc_threshold = gc_threshold](Keeper& keeper_, int const i_) { |
831 | STACK_CHECK_START_REL(L, 0); | 831 | STACK_CHECK_START_REL(L, 0); |
832 | // note that we will leak K if we raise an error later | 832 | // note that we will leak K if we raise an error later |
833 | KeeperState const _K{ state::CreateState(U, L) }; // L_: settings _K: | 833 | KeeperState const _K{ state::CreateState(U, L, "keeper") }; // L_: settings _K: |
834 | if (_K == nullptr) { | 834 | if (_K == nullptr) { |
835 | raise_luaL_error(L, "out of memory while creating keeper states"); | 835 | raise_luaL_error(L, "out of memory while creating keeper states"); |
836 | } | 836 | } |
diff --git a/src/state.cpp b/src/state.cpp index ee0b199..bae2ba5 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
@@ -195,24 +195,27 @@ namespace state { | |||
195 | 195 | ||
196 | // ############################################################################################# | 196 | // ############################################################################################# |
197 | 197 | ||
198 | lua_State* CreateState([[maybe_unused]] Universe* const U_, lua_State* const from_) | 198 | lua_State* CreateState([[maybe_unused]] Universe* const U_, lua_State* const from_, std::string_view const& hint_) |
199 | { | 199 | { |
200 | lua_State* const _L { | 200 | lua_State* const _L { |
201 | std::invoke( | 201 | std::invoke( |
202 | [U = U_, from = from_]() { | 202 | [U = U_, from = from_, &hint = hint_]() { |
203 | if constexpr (LUAJIT_FLAVOR() == 64) { | 203 | if constexpr (LUAJIT_FLAVOR() == 64) { |
204 | // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... | 204 | // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... |
205 | return luaL_newstate(); | 205 | return luaL_newstate(); |
206 | } else { | 206 | } else { |
207 | if (U->provideAllocator != nullptr) { // we have a function we can call to obtain an allocator | 207 | if (U->provideAllocator != nullptr) { // we have a function we can call to obtain an allocator |
208 | lua_pushcclosure(from, U->provideAllocator, 0); | 208 | STACK_CHECK_START_REL(from, 0); |
209 | lua_call(from, 0, 1); | 209 | lua_pushcclosure(from, U->provideAllocator, 0); // L: provideAllocator() |
210 | luaG_pushstring(from, hint); // L: provideAllocator() "<hint>" | ||
211 | lua_call(from, 1, 1); // L: result | ||
210 | AllocatorDefinition* const _def{ luaG_tofulluserdata<AllocatorDefinition>(from, -1) }; | 212 | AllocatorDefinition* const _def{ luaG_tofulluserdata<AllocatorDefinition>(from, -1) }; |
211 | if (!_def || _def->version != AllocatorDefinition::kAllocatorVersion) { | 213 | if (!_def || _def->version != AllocatorDefinition::kAllocatorVersion) { |
212 | raise_luaL_error(from, "Bad config.allocator function, must provide a valid AllocatorDefinition"); | 214 | raise_luaL_error(from, "Bad config.allocator function, must provide a valid AllocatorDefinition"); |
213 | } | 215 | } |
214 | lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) }; | 216 | lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) }; |
215 | lua_pop(from, 1); | 217 | lua_pop(from, 1); // L: |
218 | STACK_CHECK(from, 0); | ||
216 | return _L; | 219 | return _L; |
217 | } else { | 220 | } else { |
218 | // reuse the allocator provided when the master state was created | 221 | // reuse the allocator provided when the master state was created |
@@ -271,7 +274,7 @@ namespace state { | |||
271 | */ | 274 | */ |
272 | lua_State* NewLaneState(Universe* const U_, SourceState const from_, std::optional<std::string_view> const& libs_) | 275 | lua_State* NewLaneState(Universe* const U_, SourceState const from_, std::optional<std::string_view> const& libs_) |
273 | { | 276 | { |
274 | DestState const _L{ CreateState(U_, from_) }; | 277 | DestState const _L{ CreateState(U_, from_, "lane") }; |
275 | 278 | ||
276 | STACK_GROW(_L, 2); | 279 | STACK_GROW(_L, 2); |
277 | STACK_CHECK_START_ABS(_L, 0); | 280 | STACK_CHECK_START_ABS(_L, 0); |
diff --git a/src/state.h b/src/state.h index 9b42786..98bb47b 100644 --- a/src/state.h +++ b/src/state.h | |||
@@ -10,7 +10,7 @@ class Universe; | |||
10 | namespace state { | 10 | namespace state { |
11 | 11 | ||
12 | void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_); | 12 | void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_); |
13 | [[nodiscard]] lua_State* CreateState(Universe* U_, lua_State* from_); | 13 | [[nodiscard]] lua_State* CreateState(Universe* U_, lua_State* from_, std::string_view const& hint_); |
14 | void InitializeOnStateCreate(Universe* U_, lua_State* L_); | 14 | void InitializeOnStateCreate(Universe* U_, lua_State* L_); |
15 | [[nodiscard]] lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional<std::string_view> const& libs_); | 15 | [[nodiscard]] lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional<std::string_view> const& libs_); |
16 | 16 | ||
diff --git a/src/universe.h b/src/universe.h index 3742ddd..2edd825 100644 --- a/src/universe.h +++ b/src/universe.h | |||
@@ -1,5 +1,6 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include "allocator.h" | ||
3 | #include "keeper.h" | 4 | #include "keeper.h" |
4 | #include "lanesconf.h" | 5 | #include "lanesconf.h" |
5 | #include "tracker.h" | 6 | #include "tracker.h" |
@@ -14,52 +15,6 @@ class Lane; | |||
14 | 15 | ||
15 | // ################################################################################################# | 16 | // ################################################################################################# |
16 | 17 | ||
17 | // everything we need to provide to lua_newstate() | ||
18 | class AllocatorDefinition | ||
19 | { | ||
20 | public: | ||
21 | // xxh64 of string "kAllocatorVersion_1" generated at https://www.pelock.com/products/hash-calculator | ||
22 | static constexpr uintptr_t kAllocatorVersion{ static_cast<uintptr_t>(0xCF9D321B0DFB5715ull) }; | ||
23 | uintptr_t version{ kAllocatorVersion }; | ||
24 | lua_Alloc allocF{ nullptr }; | ||
25 | void* allocUD{ nullptr }; | ||
26 | |||
27 | [[nodiscard]] static void* operator new(size_t size_) noexcept = delete; // can't create one outside of a Lua state | ||
28 | [[nodiscard]] static void* operator new(size_t size_, lua_State* L_) noexcept { return lua_newuserdatauv(L_, size_, 0); } | ||
29 | // always embedded somewhere else or "in-place constructed" as a full userdata | ||
30 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | ||
31 | static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) { LUA_ASSERT(L_, !"should never be called"); } | ||
32 | |||
33 | AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept | ||
34 | : version{ version_ } | ||
35 | , allocF{ allocF_ } | ||
36 | , allocUD{ allocUD_ } | ||
37 | { | ||
38 | } | ||
39 | AllocatorDefinition() = default; | ||
40 | AllocatorDefinition(AllocatorDefinition const& rhs_) = default; | ||
41 | AllocatorDefinition(AllocatorDefinition&& rhs_) = default; | ||
42 | AllocatorDefinition& operator=(AllocatorDefinition const& rhs_) = default; | ||
43 | AllocatorDefinition& operator=(AllocatorDefinition&& rhs_) = default; | ||
44 | |||
45 | void initFrom(lua_State* L_) | ||
46 | { | ||
47 | allocF = lua_getallocf(L_, &allocUD); | ||
48 | } | ||
49 | |||
50 | void* alloc(size_t nsize_) | ||
51 | { | ||
52 | return allocF(allocUD, nullptr, 0, nsize_); | ||
53 | } | ||
54 | |||
55 | void free(void* ptr_, size_t osize_) | ||
56 | { | ||
57 | std::ignore = allocF(allocUD, ptr_, osize_, 0); | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | // ################################################################################################# | ||
62 | |||
63 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator | 18 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator |
64 | class ProtectedAllocator | 19 | class ProtectedAllocator |
65 | : public AllocatorDefinition | 20 | : public AllocatorDefinition |