diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-16 18:06:02 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-16 18:06:02 +0200 |
| commit | bbb4f99918d00308b52af3289c29624bfeb0066b (patch) | |
| tree | aebfba19ae4bb2bddc2beaa18f80a64d254b4ae6 | |
| parent | d6f5a7795360e3c2a6fc2d424904b6daa1f2accd (diff) | |
| download | lanes-bbb4f99918d00308b52af3289c29624bfeb0066b.tar.gz lanes-bbb4f99918d00308b52af3289c29624bfeb0066b.tar.bz2 lanes-bbb4f99918d00308b52af3289c29624bfeb0066b.zip | |
some dead code elimination and other trifles
| -rw-r--r-- | deep_test/deep_test.cpp | 50 | ||||
| -rw-r--r-- | src/cancel.cpp | 38 | ||||
| -rw-r--r-- | src/cancel.h | 12 | ||||
| -rw-r--r-- | src/compat.cpp | 39 | ||||
| -rw-r--r-- | src/deep.cpp | 56 | ||||
| -rw-r--r-- | src/deep.h | 2 | ||||
| -rw-r--r-- | src/keeper.cpp | 60 | ||||
| -rw-r--r-- | src/lanes.cpp | 329 | ||||
| -rw-r--r-- | src/lanes_private.h | 2 | ||||
| -rw-r--r-- | src/macros_and_utils.h | 4 | ||||
| -rw-r--r-- | src/state.cpp | 36 | ||||
| -rw-r--r-- | src/state.h | 4 | ||||
| -rw-r--r-- | src/threading.cpp | 20 | ||||
| -rw-r--r-- | src/threading.h | 18 | ||||
| -rw-r--r-- | src/tools.cpp | 669 | ||||
| -rw-r--r-- | src/tools.h | 48 | ||||
| -rw-r--r-- | src/uniquekey.h | 2 | ||||
| -rw-r--r-- | src/universe.cpp | 10 | ||||
| -rw-r--r-- | src/universe.h | 13 | ||||
| -rw-r--r-- | tests/basic.lua | 42 | ||||
| -rw-r--r-- | tests/cancel.lua | 22 | ||||
| -rw-r--r-- | tests/linda_perf.lua | 14 |
22 files changed, 703 insertions, 787 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp index b11445b..3a58d81 100644 --- a/deep_test/deep_test.cpp +++ b/deep_test/deep_test.cpp | |||
| @@ -20,7 +20,7 @@ class MyDeepFactory : public DeepFactory | |||
| 20 | 20 | ||
| 21 | static MyDeepFactory g_MyDeepFactory; | 21 | static MyDeepFactory g_MyDeepFactory; |
| 22 | 22 | ||
| 23 | // ################################################################################################ | 23 | // ################################################################################################# |
| 24 | 24 | ||
| 25 | // a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. | 25 | // a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. |
| 26 | struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude | 26 | struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude |
| @@ -28,7 +28,7 @@ struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a De | |||
| 28 | lua_Integer val{ 0 }; | 28 | lua_Integer val{ 0 }; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | // ################################################################################################ | 31 | // ################################################################################################# |
| 32 | 32 | ||
| 33 | DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const | 33 | DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const |
| 34 | { | 34 | { |
| @@ -36,7 +36,7 @@ DeepPrelude* MyDeepFactory::newDeepObjectInternal(lua_State* L) const | |||
| 36 | return deep_test; | 36 | return deep_test; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | // ################################################################################################ | 39 | // ################################################################################################# |
| 40 | 40 | ||
| 41 | void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const | 41 | void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const |
| 42 | { | 42 | { |
| @@ -44,7 +44,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 44 | delete deep_test; | 44 | delete deep_test; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | // ################################################################################################ | 47 | // ################################################################################################# |
| 48 | 48 | ||
| 49 | [[nodiscard]] static int deep_set(lua_State* L) | 49 | [[nodiscard]] static int deep_set(lua_State* L) |
| 50 | { | 50 | { |
| @@ -54,7 +54,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 54 | return 0; | 54 | return 0; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | // ################################################################################################ | 57 | // ################################################################################################# |
| 58 | 58 | ||
| 59 | [[nodiscard]] static int deep_setuv(lua_State* L) | 59 | [[nodiscard]] static int deep_setuv(lua_State* L) |
| 60 | { | 60 | { |
| @@ -65,7 +65,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 65 | return 1; | 65 | return 1; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | // ################################################################################################ | 68 | // ################################################################################################# |
| 69 | 69 | ||
| 70 | // won't actually do anything as deep userdata don't have uservalue slots | 70 | // won't actually do anything as deep userdata don't have uservalue slots |
| 71 | [[nodiscard]] static int deep_getuv(lua_State* L) | 71 | [[nodiscard]] static int deep_getuv(lua_State* L) |
| @@ -76,7 +76,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 76 | return 1; | 76 | return 1; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | // ################################################################################################ | 79 | // ################################################################################################# |
| 80 | 80 | ||
| 81 | [[nodiscard]] static int deep_tostring(lua_State* L) | 81 | [[nodiscard]] static int deep_tostring(lua_State* L) |
| 82 | { | 82 | { |
| @@ -85,7 +85,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 85 | return 1; | 85 | return 1; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | // ################################################################################################ | 88 | // ################################################################################################# |
| 89 | 89 | ||
| 90 | [[nodiscard]] static int deep_gc(lua_State* L) | 90 | [[nodiscard]] static int deep_gc(lua_State* L) |
| 91 | { | 91 | { |
| @@ -93,7 +93,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) cons | |||
| 93 | return 0; | 93 | return 0; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | // ################################################################################################ | 96 | // ################################################################################################# |
| 97 | 97 | ||
| 98 | static luaL_Reg const deep_mt[] = | 98 | static luaL_Reg const deep_mt[] = |
| 99 | { | 99 | { |
| @@ -105,7 +105,7 @@ static luaL_Reg const deep_mt[] = | |||
| 105 | { nullptr, nullptr } | 105 | { nullptr, nullptr } |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | // ################################################################################################ | 108 | // ################################################################################################# |
| 109 | 109 | ||
| 110 | int luaD_new_deep( lua_State* L) | 110 | int luaD_new_deep( lua_State* L) |
| 111 | { | 111 | { |
| @@ -114,15 +114,15 @@ int luaD_new_deep( lua_State* L) | |||
| 114 | return g_MyDeepFactory.pushDeepUserdata(Dest{ L }, nuv); | 114 | return g_MyDeepFactory.pushDeepUserdata(Dest{ L }, nuv); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | // ################################################################################################ | 117 | // ################################################################################################# |
| 118 | // ################################################################################################ | 118 | // ################################################################################################# |
| 119 | 119 | ||
| 120 | struct MyClonableUserdata | 120 | struct MyClonableUserdata |
| 121 | { | 121 | { |
| 122 | lua_Integer val; | 122 | lua_Integer val; |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
| 125 | // ################################################################################################ | 125 | // ################################################################################################# |
| 126 | 126 | ||
| 127 | [[nodiscard]] static int clonable_set(lua_State* L) | 127 | [[nodiscard]] static int clonable_set(lua_State* L) |
| 128 | { | 128 | { |
| @@ -132,7 +132,7 @@ struct MyClonableUserdata | |||
| 132 | return 0; | 132 | return 0; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | // ################################################################################################ | 135 | // ################################################################################################# |
| 136 | 136 | ||
| 137 | [[nodiscard]] static int clonable_setuv(lua_State* L) | 137 | [[nodiscard]] static int clonable_setuv(lua_State* L) |
| 138 | { | 138 | { |
| @@ -143,7 +143,7 @@ struct MyClonableUserdata | |||
| 143 | return 1; | 143 | return 1; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | // ################################################################################################ | 146 | // ################################################################################################# |
| 147 | 147 | ||
| 148 | [[nodiscard]] static int clonable_getuv(lua_State* L) | 148 | [[nodiscard]] static int clonable_getuv(lua_State* L) |
| 149 | { | 149 | { |
| @@ -153,7 +153,7 @@ struct MyClonableUserdata | |||
| 153 | return 1; | 153 | return 1; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | // ################################################################################################ | 156 | // ################################################################################################# |
| 157 | 157 | ||
| 158 | [[nodiscard]] static int clonable_tostring(lua_State* L) | 158 | [[nodiscard]] static int clonable_tostring(lua_State* L) |
| 159 | { | 159 | { |
| @@ -162,7 +162,7 @@ struct MyClonableUserdata | |||
| 162 | return 1; | 162 | return 1; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | // ################################################################################################ | 165 | // ################################################################################################# |
| 166 | 166 | ||
| 167 | [[nodiscard]] static int clonable_gc(lua_State* L) | 167 | [[nodiscard]] static int clonable_gc(lua_State* L) |
| 168 | { | 168 | { |
| @@ -170,7 +170,7 @@ struct MyClonableUserdata | |||
| 170 | return 0; | 170 | return 0; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | // ################################################################################################ | 173 | // ################################################################################################# |
| 174 | 174 | ||
| 175 | // this is all we need to make a userdata lanes-clonable. no dependency on Lanes code. | 175 | // this is all we need to make a userdata lanes-clonable. no dependency on Lanes code. |
| 176 | [[nodiscard]] static int clonable_lanesclone(lua_State* L) | 176 | [[nodiscard]] static int clonable_lanesclone(lua_State* L) |
| @@ -193,7 +193,7 @@ struct MyClonableUserdata | |||
| 193 | return 0; | 193 | return 0; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | // ################################################################################################ | 196 | // ################################################################################################# |
| 197 | 197 | ||
| 198 | static luaL_Reg const clonable_mt[] = | 198 | static luaL_Reg const clonable_mt[] = |
| 199 | { | 199 | { |
| @@ -206,7 +206,7 @@ static luaL_Reg const clonable_mt[] = | |||
| 206 | { nullptr, nullptr } | 206 | { nullptr, nullptr } |
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | // ################################################################################################ | 209 | // ################################################################################################# |
| 210 | 210 | ||
| 211 | int luaD_new_clonable( lua_State* L) | 211 | int luaD_new_clonable( lua_State* L) |
| 212 | { | 212 | { |
| @@ -216,8 +216,8 @@ int luaD_new_clonable( lua_State* L) | |||
| 216 | return 1; | 216 | return 1; |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | // ################################################################################################ | 219 | // ################################################################################################# |
| 220 | // ################################################################################################ | 220 | // ################################################################################################# |
| 221 | 221 | ||
| 222 | static luaL_Reg const deep_module[] = | 222 | static luaL_Reg const deep_module[] = |
| 223 | { | 223 | { |
| @@ -226,14 +226,14 @@ static luaL_Reg const deep_module[] = | |||
| 226 | { nullptr, nullptr } | 226 | { nullptr, nullptr } |
| 227 | }; | 227 | }; |
| 228 | 228 | ||
| 229 | // ################################################################################################ | 229 | // ################################################################################################# |
| 230 | 230 | ||
| 231 | LANES_API int luaopen_deep_test(lua_State* L) | 231 | LANES_API int luaopen_deep_test(lua_State* L) |
| 232 | { | 232 | { |
| 233 | luaL_newlib( L, deep_module); // M | 233 | luaL_newlib( L, deep_module); // M |
| 234 | 234 | ||
| 235 | // preregister the metatables for the types we can instantiate so that Lanes can know about them | 235 | // preregister the metatables for the types we can instantiate so that Lanes can know about them |
| 236 | if( luaL_newmetatable( L, "clonable")) // M mt | 236 | if (luaL_newmetatable( L, "clonable")) // M mt |
| 237 | { | 237 | { |
| 238 | luaL_setfuncs( L, clonable_mt, 0); | 238 | luaL_setfuncs( L, clonable_mt, 0); |
| 239 | lua_pushvalue(L, -1); // M mt mt | 239 | lua_pushvalue(L, -1); // M mt mt |
| @@ -241,7 +241,7 @@ LANES_API int luaopen_deep_test(lua_State* L) | |||
| 241 | } | 241 | } |
| 242 | lua_setfield(L, -2, "__clonableMT"); // M | 242 | lua_setfield(L, -2, "__clonableMT"); // M |
| 243 | 243 | ||
| 244 | if( luaL_newmetatable( L, "deep")) // mt | 244 | if (luaL_newmetatable( L, "deep")) // mt |
| 245 | { | 245 | { |
| 246 | luaL_setfuncs( L, deep_mt, 0); | 246 | luaL_setfuncs( L, deep_mt, 0); |
| 247 | lua_pushvalue(L, -1); // mt mt | 247 | lua_pushvalue(L, -1); // mt mt |
diff --git a/src/cancel.cpp b/src/cancel.cpp index b3e52b6..fe1f3e6 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
| @@ -39,8 +39,8 @@ THE SOFTWARE. | |||
| 39 | #include "threading.h" | 39 | #include "threading.h" |
| 40 | #include "tools.h" | 40 | #include "tools.h" |
| 41 | 41 | ||
| 42 | // ################################################################################################ | 42 | // ################################################################################################# |
| 43 | // ################################################################################################ | 43 | // ################################################################################################# |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Check if the thread in question ('L') has been signalled for cancel. | 46 | * Check if the thread in question ('L') has been signalled for cancel. |
| @@ -58,7 +58,7 @@ THE SOFTWARE. | |||
| 58 | return lane ? lane->cancel_request : CancelRequest::None; | 58 | return lane ? lane->cancel_request : CancelRequest::None; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | // ################################################################################################ | 61 | // ################################################################################################# |
| 62 | 62 | ||
| 63 | //--- | 63 | //--- |
| 64 | // bool = cancel_test() | 64 | // bool = cancel_test() |
| @@ -66,15 +66,15 @@ THE SOFTWARE. | |||
| 66 | // Available inside the global namespace of lanes | 66 | // Available inside the global namespace of lanes |
| 67 | // returns a boolean saying if a cancel request is pending | 67 | // returns a boolean saying if a cancel request is pending |
| 68 | // | 68 | // |
| 69 | LUAG_FUNC( cancel_test) | 69 | LUAG_FUNC(cancel_test) |
| 70 | { | 70 | { |
| 71 | CancelRequest test{ cancel_test(L) }; | 71 | CancelRequest test{ cancel_test(L) }; |
| 72 | lua_pushboolean(L, test != CancelRequest::None); | 72 | lua_pushboolean(L, test != CancelRequest::None); |
| 73 | return 1; | 73 | return 1; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | // ################################################################################################ | 76 | // ################################################################################################# |
| 77 | // ################################################################################################ | 77 | // ################################################################################################# |
| 78 | 78 | ||
| 79 | [[nodiscard]] static void cancel_hook(lua_State* L, [[maybe_unused]] lua_Debug* ar) | 79 | [[nodiscard]] static void cancel_hook(lua_State* L, [[maybe_unused]] lua_Debug* ar) |
| 80 | { | 80 | { |
| @@ -86,8 +86,8 @@ LUAG_FUNC( cancel_test) | |||
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | // ################################################################################################ | 89 | // ################################################################################################# |
| 90 | // ################################################################################################ | 90 | // ################################################################################################# |
| 91 | 91 | ||
| 92 | //--- | 92 | //--- |
| 93 | // = thread_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] ) | 93 | // = thread_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] ) |
| @@ -106,7 +106,7 @@ LUAG_FUNC( cancel_test) | |||
| 106 | // false if the cancellation timed out, or a kill was needed. | 106 | // false if the cancellation timed out, or a kill was needed. |
| 107 | // | 107 | // |
| 108 | 108 | ||
| 109 | // ################################################################################################ | 109 | // ################################################################################################# |
| 110 | 110 | ||
| 111 | [[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, lua_Duration duration_, bool wake_lane_) | 111 | [[nodiscard]] static CancelResult thread_cancel_soft(Lane* lane_, lua_Duration duration_, bool wake_lane_) |
| 112 | { | 112 | { |
| @@ -124,7 +124,7 @@ LUAG_FUNC( cancel_test) | |||
| 124 | return lane_->waitForCompletion(duration_) ? CancelResult::Cancelled : CancelResult::Timeout; | 124 | return lane_->waitForCompletion(duration_) ? CancelResult::Cancelled : CancelResult::Timeout; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | // ################################################################################################ | 127 | // ################################################################################################# |
| 128 | 128 | ||
| 129 | [[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, lua_Duration duration_, bool wake_lane_) | 129 | [[nodiscard]] static CancelResult thread_cancel_hard(Lane* lane_, lua_Duration duration_, bool wake_lane_) |
| 130 | { | 130 | { |
| @@ -143,7 +143,7 @@ LUAG_FUNC( cancel_test) | |||
| 143 | return result; | 143 | return result; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | // ################################################################################################ | 146 | // ################################################################################################# |
| 147 | 147 | ||
| 148 | CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Duration duration_, bool wake_lane_) | 148 | CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Duration duration_, bool wake_lane_) |
| 149 | { | 149 | { |
| @@ -169,8 +169,8 @@ CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Durat | |||
| 169 | return thread_cancel_hard(lane_, duration_, wake_lane_); | 169 | return thread_cancel_hard(lane_, duration_, wake_lane_); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | // ################################################################################################ | 172 | // ################################################################################################# |
| 173 | // ################################################################################################ | 173 | // ################################################################################################# |
| 174 | 174 | ||
| 175 | CancelOp which_cancel_op(char const* op_string_) | 175 | CancelOp which_cancel_op(char const* op_string_) |
| 176 | { | 176 | { |
| @@ -202,7 +202,7 @@ CancelOp which_cancel_op(char const* op_string_) | |||
| 202 | return op; | 202 | return op; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | // ################################################################################################ | 205 | // ################################################################################################# |
| 206 | 206 | ||
| 207 | [[nodiscard]] static CancelOp which_cancel_op(lua_State* L, int idx_) | 207 | [[nodiscard]] static CancelOp which_cancel_op(lua_State* L, int idx_) |
| 208 | { | 208 | { |
| @@ -220,12 +220,12 @@ CancelOp which_cancel_op(char const* op_string_) | |||
| 220 | return CancelOp::Hard; | 220 | return CancelOp::Hard; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | // ################################################################################################ | 223 | // ################################################################################################# |
| 224 | 224 | ||
| 225 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lindas]) | 225 | // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lindas]) |
| 226 | LUAG_FUNC(thread_cancel) | 226 | LUAG_FUNC(thread_cancel) |
| 227 | { | 227 | { |
| 228 | Lane* const lane{ lua_toLane(L, 1) }; | 228 | Lane* const lane{ ToLane(L, 1) }; |
| 229 | CancelOp const op{ which_cancel_op(L, 2) }; // this removes the op string from the stack | 229 | CancelOp const op{ which_cancel_op(L, 2) }; // this removes the op string from the stack |
| 230 | 230 | ||
| 231 | int hook_count{ 0 }; | 231 | int hook_count{ 0 }; |
| @@ -235,7 +235,7 @@ LUAG_FUNC(thread_cancel) | |||
| 235 | lua_remove(L, 2); // argument is processed, remove it | 235 | lua_remove(L, 2); // argument is processed, remove it |
| 236 | if (hook_count < 1) | 236 | if (hook_count < 1) |
| 237 | { | 237 | { |
| 238 | return luaL_error(L, "hook count cannot be < 1"); | 238 | return luaL_error(L, "hook count cannot be < 1"); // doesn't return |
| 239 | } | 239 | } |
| 240 | } | 240 | } |
| 241 | 241 | ||
| @@ -246,7 +246,7 @@ LUAG_FUNC(thread_cancel) | |||
| 246 | lua_remove(L, 2); // argument is processed, remove it | 246 | lua_remove(L, 2); // argument is processed, remove it |
| 247 | if (wait_timeout.count() < 0.0) | 247 | if (wait_timeout.count() < 0.0) |
| 248 | { | 248 | { |
| 249 | return luaL_error(L, "cancel timeout cannot be < 0"); | 249 | return luaL_error(L, "cancel timeout cannot be < 0"); // doesn't return |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired | 252 | // we wake by default in "hard" mode (remember that hook is hard too), but this can be turned off if desired |
| @@ -255,7 +255,7 @@ LUAG_FUNC(thread_cancel) | |||
| 255 | { | 255 | { |
| 256 | if (!lua_isboolean(L, 2)) | 256 | if (!lua_isboolean(L, 2)) |
| 257 | { | 257 | { |
| 258 | return luaL_error(L, "wake_lindas parameter is not a boolean"); | 258 | return luaL_error(L, "wake_lindas parameter is not a boolean"); // doesn't return |
| 259 | } | 259 | } |
| 260 | wake_lane = lua_toboolean(L, 2); | 260 | wake_lane = lua_toboolean(L, 2); |
| 261 | lua_remove(L, 2); // argument is processed, remove it | 261 | lua_remove(L, 2); // argument is processed, remove it |
diff --git a/src/cancel.h b/src/cancel.h index 10a9804..8cff1c9 100644 --- a/src/cancel.h +++ b/src/cancel.h | |||
| @@ -10,12 +10,10 @@ extern "C" { | |||
| 10 | } | 10 | } |
| 11 | #endif // __cplusplus | 11 | #endif // __cplusplus |
| 12 | 12 | ||
| 13 | #include "uniquekey.h" | ||
| 14 | #include "macros_and_utils.h" | 13 | #include "macros_and_utils.h" |
| 14 | #include "uniquekey.h" | ||
| 15 | 15 | ||
| 16 | #include <chrono> | 16 | // ################################################################################################# |
| 17 | |||
| 18 | // ################################################################################################ | ||
| 19 | 17 | ||
| 20 | class Lane; // forward | 18 | class Lane; // forward |
| 21 | 19 | ||
| @@ -59,10 +57,10 @@ static constexpr UniqueKey CANCEL_ERROR{ 0xe97d41626cc97577ull, "lanes.cancel_er | |||
| 59 | raise_lua_error(L); // doesn't return | 57 | raise_lua_error(L); // doesn't return |
| 60 | } | 58 | } |
| 61 | 59 | ||
| 62 | // ################################################################################################ | 60 | // ################################################################################################# |
| 63 | // ################################################################################################ | 61 | // ################################################################################################# |
| 64 | 62 | ||
| 65 | LUAG_FUNC(cancel_test); | 63 | LUAG_FUNC(cancel_test); |
| 66 | LUAG_FUNC(thread_cancel); | 64 | LUAG_FUNC(thread_cancel); |
| 67 | 65 | ||
| 68 | // ################################################################################################ | 66 | // ################################################################################################# |
diff --git a/src/compat.cpp b/src/compat.cpp index 73d0f6b..9f652a7 100644 --- a/src/compat.cpp +++ b/src/compat.cpp | |||
| @@ -1,20 +1,17 @@ | |||
| 1 | /* | 1 | // ################################################################################################# |
| 2 | * ############################################################################################### | 2 | // ###################################### Lua 5.1 / 5.2 / 5.3 ###################################### |
| 3 | * ####################################### Lua 5.1/5.2/5.3 ####################################### | 3 | // ################################################################################################# |
| 4 | * ############################################################################################### | 4 | |
| 5 | */ | ||
| 6 | #include "compat.h" | 5 | #include "compat.h" |
| 7 | #include "macros_and_utils.h" | 6 | #include "macros_and_utils.h" |
| 8 | 7 | ||
| 9 | /* | 8 | // ################################################################################################# |
| 10 | ** Copied from Lua 5.2 loadlib.c | 9 | // ################################################################################################# |
| 11 | */ | ||
| 12 | // ################################################################################################ | ||
| 13 | // ################################################################################################ | ||
| 14 | #if LUA_VERSION_NUM == 501 | 10 | #if LUA_VERSION_NUM == 501 |
| 15 | // ################################################################################################ | 11 | // ################################################################################################# |
| 16 | // ################################################################################################ | 12 | // ################################################################################################# |
| 17 | 13 | ||
| 14 | // Copied from Lua 5.2 loadlib.c | ||
| 18 | static int luaL_getsubtable(lua_State* L, int idx, const char* fname) | 15 | static int luaL_getsubtable(lua_State* L, int idx, const char* fname) |
| 19 | { | 16 | { |
| 20 | lua_getfield(L, idx, fname); | 17 | lua_getfield(L, idx, fname); |
| @@ -31,7 +28,7 @@ static int luaL_getsubtable(lua_State* L, int idx, const char* fname) | |||
| 31 | } | 28 | } |
| 32 | } | 29 | } |
| 33 | 30 | ||
| 34 | // ################################################################################################ | 31 | // ################################################################################################# |
| 35 | 32 | ||
| 36 | void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) | 33 | void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) |
| 37 | { | 34 | { |
| @@ -50,11 +47,11 @@ void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int g | |||
| 50 | } | 47 | } |
| 51 | #endif // LUA_VERSION_NUM | 48 | #endif // LUA_VERSION_NUM |
| 52 | 49 | ||
| 53 | // ################################################################################################ | 50 | // ################################################################################################# |
| 54 | // ################################################################################################ | 51 | // ################################################################################################# |
| 55 | #if LUA_VERSION_NUM < 504 | 52 | #if LUA_VERSION_NUM < 504 |
| 56 | // ################################################################################################ | 53 | // ################################################################################################# |
| 57 | // ################################################################################################ | 54 | // ################################################################################################# |
| 58 | 55 | ||
| 59 | void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) | 56 | void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) |
| 60 | { | 57 | { |
| @@ -62,13 +59,13 @@ void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue) | |||
| 62 | return lua_newuserdata(L, sz); | 59 | return lua_newuserdata(L, sz); |
| 63 | } | 60 | } |
| 64 | 61 | ||
| 65 | // ################################################################################################ | 62 | // ################################################################################################# |
| 66 | 63 | ||
| 67 | // push on stack uservalue #n of full userdata at idx | 64 | // push on stack uservalue #n of full userdata at idx |
| 68 | int lua_getiuservalue(lua_State* L, int idx, int n) | 65 | int lua_getiuservalue(lua_State* L, int idx, int n) |
| 69 | { | 66 | { |
| 70 | // full userdata can have only 1 uservalue before 5.4 | 67 | // full userdata can have only 1 uservalue before 5.4 |
| 71 | if( n > 1) | 68 | if (n > 1) |
| 72 | { | 69 | { |
| 73 | lua_pushnil(L); | 70 | lua_pushnil(L); |
| 74 | return LUA_TNONE; | 71 | return LUA_TNONE; |
| @@ -91,13 +88,13 @@ int lua_getiuservalue(lua_State* L, int idx, int n) | |||
| 91 | return lua_type(L, -1); | 88 | return lua_type(L, -1); |
| 92 | } | 89 | } |
| 93 | 90 | ||
| 94 | // ################################################################################################ | 91 | // ################################################################################################# |
| 95 | 92 | ||
| 96 | // Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. | 93 | // Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. |
| 97 | // Returns 0 if the userdata does not have that value. | 94 | // Returns 0 if the userdata does not have that value. |
| 98 | int lua_setiuservalue(lua_State* L, int idx, int n) | 95 | int lua_setiuservalue(lua_State* L, int idx, int n) |
| 99 | { | 96 | { |
| 100 | if( n > 1 | 97 | if (n > 1 |
| 101 | #if LUA_VERSION_NUM == 501 | 98 | #if LUA_VERSION_NUM == 501 |
| 102 | || lua_type(L, -1) != LUA_TTABLE | 99 | || lua_type(L, -1) != LUA_TTABLE |
| 103 | #endif | 100 | #endif |
diff --git a/src/deep.cpp b/src/deep.cpp index 3eb38dc..3326f98 100644 --- a/src/deep.cpp +++ b/src/deep.cpp | |||
| @@ -81,7 +81,7 @@ static void set_deep_lookup(lua_State* L) | |||
| 81 | STACK_CHECK( L, 0); | 81 | STACK_CHECK( L, 0); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | // ################################################################################################ | 84 | // ################################################################################################# |
| 85 | 85 | ||
| 86 | /* | 86 | /* |
| 87 | * Pops the key (metatable or factory) off the stack, and replaces with the | 87 | * Pops the key (metatable or factory) off the stack, and replaces with the |
| @@ -92,7 +92,7 @@ static void get_deep_lookup(lua_State* L) | |||
| 92 | STACK_GROW( L, 1); | 92 | STACK_GROW( L, 1); |
| 93 | STACK_CHECK_START_REL(L, 1); // a | 93 | STACK_CHECK_START_REL(L, 1); // a |
| 94 | DEEP_LOOKUP_KEY.pushValue(L); // a {} | 94 | DEEP_LOOKUP_KEY.pushValue(L); // a {} |
| 95 | if( !lua_isnil( L, -1)) | 95 | if (!lua_isnil( L, -1)) |
| 96 | { | 96 | { |
| 97 | lua_insert( L, -2); // {} a | 97 | lua_insert( L, -2); // {} a |
| 98 | lua_rawget( L, -2); // {} b | 98 | lua_rawget( L, -2); // {} b |
| @@ -101,7 +101,7 @@ static void get_deep_lookup(lua_State* L) | |||
| 101 | STACK_CHECK( L, 1); | 101 | STACK_CHECK( L, 1); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | // ################################################################################################ | 104 | // ################################################################################################# |
| 105 | 105 | ||
| 106 | /* | 106 | /* |
| 107 | * Return the registered factory for 'index' (deep userdata proxy), | 107 | * Return the registered factory for 'index' (deep userdata proxy), |
| @@ -124,7 +124,7 @@ static void get_deep_lookup(lua_State* L) | |||
| 124 | STACK_GROW( L, 1); | 124 | STACK_GROW( L, 1); |
| 125 | STACK_CHECK_START_REL(L, 0); | 125 | STACK_CHECK_START_REL(L, 0); |
| 126 | 126 | ||
| 127 | if( !lua_getmetatable( L, index)) // deep ... metatable? | 127 | if (!lua_getmetatable( L, index)) // deep ... metatable? |
| 128 | { | 128 | { |
| 129 | return nullptr; // no metatable: can't be a deep userdata object! | 129 | return nullptr; // no metatable: can't be a deep userdata object! |
| 130 | } | 130 | } |
| @@ -139,7 +139,7 @@ static void get_deep_lookup(lua_State* L) | |||
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | // ################################################################################################ | 142 | // ################################################################################################# |
| 143 | 143 | ||
| 144 | void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) | 144 | void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) |
| 145 | { | 145 | { |
| @@ -148,7 +148,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) | |||
| 148 | STACK_CHECK(L, 0); | 148 | STACK_CHECK(L, 0); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | // ################################################################################################ | 151 | // ################################################################################################# |
| 152 | 152 | ||
| 153 | /* | 153 | /* |
| 154 | * void= mt.__gc( proxy_ud ) | 154 | * void= mt.__gc( proxy_ud ) |
| @@ -169,7 +169,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) | |||
| 169 | { | 169 | { |
| 170 | // retrieve wrapped __gc | 170 | // retrieve wrapped __gc |
| 171 | lua_pushvalue( L, lua_upvalueindex( 1)); // self __gc? | 171 | lua_pushvalue( L, lua_upvalueindex( 1)); // self __gc? |
| 172 | if( !lua_isnil( L, -1)) | 172 | if (!lua_isnil( L, -1)) |
| 173 | { | 173 | { |
| 174 | lua_insert( L, -2); // __gc self | 174 | lua_insert( L, -2); // __gc self |
| 175 | lua_call( L, 1, 0); // | 175 | lua_call( L, 1, 0); // |
| @@ -180,7 +180,7 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) | |||
| 180 | return 0; | 180 | return 0; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | // ################################################################################################ | 183 | // ################################################################################################# |
| 184 | 184 | ||
| 185 | /* | 185 | /* |
| 186 | * Push a proxy userdata on the stack. | 186 | * Push a proxy userdata on the stack. |
| @@ -194,25 +194,25 @@ void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_) | |||
| 194 | char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_) | 194 | char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_) |
| 195 | { | 195 | { |
| 196 | // Check if a proxy already exists | 196 | // Check if a proxy already exists |
| 197 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 197 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
| 198 | lua_pushlightuserdata( L, prelude); // DPC deep | 198 | lua_pushlightuserdata(L, prelude); // DPC deep |
| 199 | lua_rawget( L, -2); // DPC proxy | 199 | lua_rawget(L, -2); // DPC proxy |
| 200 | if ( !lua_isnil( L, -1)) | 200 | if (!lua_isnil(L, -1)) |
| 201 | { | 201 | { |
| 202 | lua_remove( L, -2); // proxy | 202 | lua_remove(L, -2); // proxy |
| 203 | return nullptr; | 203 | return nullptr; |
| 204 | } | 204 | } |
| 205 | else | 205 | else |
| 206 | { | 206 | { |
| 207 | lua_pop( L, 1); // DPC | 207 | lua_pop(L, 1); // DPC |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | STACK_GROW( L, 7); | 210 | STACK_GROW(L, 7); |
| 211 | STACK_CHECK_START_REL(L, 0); | 211 | STACK_CHECK_START_REL(L, 0); |
| 212 | 212 | ||
| 213 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) | 213 | // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) |
| 214 | DeepPrelude** proxy = (DeepPrelude**) lua_newuserdatauv(L, sizeof(DeepPrelude*), nuv_); // DPC proxy | 214 | DeepPrelude** const proxy{ lua_newuserdatauv<DeepPrelude*>(L, nuv_) }; // DPC proxy |
| 215 | ASSERT_L( proxy); | 215 | ASSERT_L(proxy); |
| 216 | *proxy = prelude; | 216 | *proxy = prelude; |
| 217 | prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data | 217 | prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data |
| 218 | 218 | ||
| @@ -221,7 +221,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L | |||
| 221 | lua_pushlightuserdata( L, std::bit_cast<void*>(&factory)); // DPC proxy factory | 221 | lua_pushlightuserdata( L, std::bit_cast<void*>(&factory)); // DPC proxy factory |
| 222 | get_deep_lookup( L); // DPC proxy metatable? | 222 | get_deep_lookup( L); // DPC proxy metatable? |
| 223 | 223 | ||
| 224 | if( lua_isnil( L, -1)) // // No metatable yet. | 224 | if (lua_isnil( L, -1)) // // No metatable yet. |
| 225 | { | 225 | { |
| 226 | lua_pop(L, 1); // DPC proxy | 226 | lua_pop(L, 1); // DPC proxy |
| 227 | int const oldtop{ lua_gettop(L) }; | 227 | int const oldtop{ lua_gettop(L) }; |
| @@ -245,7 +245,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L | |||
| 245 | lua_newtable( L); // DPC proxy metatable | 245 | lua_newtable( L); // DPC proxy metatable |
| 246 | lua_pushnil( L); // DPC proxy metatable nil | 246 | lua_pushnil( L); // DPC proxy metatable nil |
| 247 | } | 247 | } |
| 248 | if( lua_isnil( L, -1)) | 248 | if (lua_isnil( L, -1)) |
| 249 | { | 249 | { |
| 250 | // Add our own '__gc' method | 250 | // Add our own '__gc' method |
| 251 | lua_pop( L, 1); // DPC proxy metatable | 251 | lua_pop( L, 1); // DPC proxy metatable |
| @@ -269,22 +269,22 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L | |||
| 269 | // L.registry._LOADED exists without having registered the 'package' library. | 269 | // L.registry._LOADED exists without having registered the 'package' library. |
| 270 | lua_getglobal( L, "require"); // DPC proxy metatable require() | 270 | lua_getglobal( L, "require"); // DPC proxy metatable require() |
| 271 | // check that the module is already loaded (or being loaded, we are happy either way) | 271 | // check that the module is already loaded (or being loaded, we are happy either way) |
| 272 | if( lua_isfunction( L, -1)) | 272 | if (lua_isfunction( L, -1)) |
| 273 | { | 273 | { |
| 274 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" | 274 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" |
| 275 | lua_getfield( L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // DPC proxy metatable require() "module" _R._LOADED | 275 | lua_getfield( L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); // DPC proxy metatable require() "module" _R._LOADED |
| 276 | if( lua_istable( L, -1)) | 276 | if (lua_istable( L, -1)) |
| 277 | { | 277 | { |
| 278 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | 278 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" |
| 279 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module | 279 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module |
| 280 | int const alreadyloaded = lua_toboolean( L, -1); | 280 | int const alreadyloaded = lua_toboolean( L, -1); |
| 281 | if( !alreadyloaded) // not loaded | 281 | if (!alreadyloaded) // not loaded |
| 282 | { | 282 | { |
| 283 | int require_result; | 283 | int require_result; |
| 284 | lua_pop( L, 2); // DPC proxy metatable require() "module" | 284 | lua_pop( L, 2); // DPC proxy metatable require() "module" |
| 285 | // require "modname" | 285 | // require "modname" |
| 286 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? | 286 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? |
| 287 | if( require_result != LUA_OK) | 287 | if (require_result != LUA_OK) |
| 288 | { | 288 | { |
| 289 | // failed, return the error message | 289 | // failed, return the error message |
| 290 | lua_pushfstring( L, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname); | 290 | lua_pushfstring( L, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname); |
| @@ -326,7 +326,7 @@ char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, L | |||
| 326 | return nullptr; | 326 | return nullptr; |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | // ################################################################################################ | 329 | // ################################################################################################# |
| 330 | 330 | ||
| 331 | /* | 331 | /* |
| 332 | * Create a deep userdata | 332 | * Create a deep userdata |
| @@ -354,7 +354,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const | |||
| 354 | return luaL_error( L, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); | 354 | return luaL_error( L, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | if( prelude->m_magic != DEEP_VERSION) | 357 | if (prelude->m_magic != DEEP_VERSION) |
| 358 | { | 358 | { |
| 359 | // just in case, don't leak the newly allocated deep userdata object | 359 | // just in case, don't leak the newly allocated deep userdata object |
| 360 | deleteDeepObjectInternal(L, prelude); | 360 | deleteDeepObjectInternal(L, prelude); |
| @@ -364,7 +364,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const | |||
| 364 | ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1 | 364 | ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1 |
| 365 | ASSERT_L(&prelude->m_factory == this); | 365 | ASSERT_L(&prelude->m_factory == this); |
| 366 | 366 | ||
| 367 | if( lua_gettop( L) - oldtop != 0) | 367 | if (lua_gettop( L) - oldtop != 0) |
| 368 | { | 368 | { |
| 369 | // just in case, don't leak the newly allocated deep userdata object | 369 | // just in case, don't leak the newly allocated deep userdata object |
| 370 | deleteDeepObjectInternal(L, prelude); | 370 | deleteDeepObjectInternal(L, prelude); |
| @@ -380,7 +380,7 @@ int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const | |||
| 380 | return 1; | 380 | return 1; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | // ################################################################################################ | 383 | // ################################################################################################# |
| 384 | 384 | ||
| 385 | /* | 385 | /* |
| 386 | * Access deep userdata through a proxy. | 386 | * Access deep userdata through a proxy. |
| @@ -402,7 +402,7 @@ DeepPrelude* DeepFactory::toDeep(lua_State* L, int index) const | |||
| 402 | return *proxy; | 402 | return *proxy; |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | // ################################################################################################ | 405 | // ################################################################################################# |
| 406 | 406 | ||
| 407 | /* | 407 | /* |
| 408 | * Copy deep userdata between two separate Lua states (from L to L2) | 408 | * Copy deep userdata between two separate Lua states (from L to L2) |
| @@ -28,7 +28,7 @@ enum class LookupMode | |||
| 28 | FromKeeper // send a function from a keeper state to a lane | 28 | FromKeeper // send a function from a keeper state to a lane |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | // ################################################################################################ | 31 | // ################################################################################################# |
| 32 | 32 | ||
| 33 | // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator | 33 | // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator |
| 34 | static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull, "DEEP_VERSION_3" }; | 34 | static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull, "DEEP_VERSION_3" }; |
diff --git a/src/keeper.cpp b/src/keeper.cpp index 3e26d5e..5d94944 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
| @@ -48,9 +48,9 @@ | |||
| 48 | #include <algorithm> | 48 | #include <algorithm> |
| 49 | #include <cassert> | 49 | #include <cassert> |
| 50 | 50 | ||
| 51 | // ################################################################################### | 51 | // ################################################################################################# |
| 52 | // Keeper implementation | 52 | // Keeper implementation |
| 53 | // ################################################################################### | 53 | // ################################################################################################# |
| 54 | 54 | ||
| 55 | class keeper_fifo | 55 | class keeper_fifo |
| 56 | { | 56 | { |
| @@ -74,7 +74,7 @@ class keeper_fifo | |||
| 74 | 74 | ||
| 75 | static constexpr int CONTENTS_TABLE{ 1 }; | 75 | static constexpr int CONTENTS_TABLE{ 1 }; |
| 76 | 76 | ||
| 77 | // ################################################################################################## | 77 | // ################################################################################################# |
| 78 | 78 | ||
| 79 | // replaces the fifo ud by its uservalue on the stack | 79 | // replaces the fifo ud by its uservalue on the stack |
| 80 | [[nodiscard]] static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) | 80 | [[nodiscard]] static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) |
| @@ -91,7 +91,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; | |||
| 91 | return fifo; | 91 | return fifo; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | // ################################################################################################## | 94 | // ################################################################################################# |
| 95 | 95 | ||
| 96 | // in: nothing | 96 | // in: nothing |
| 97 | // out: { first = 1, count = 0, limit = -1} | 97 | // out: { first = 1, count = 0, limit = -1} |
| @@ -107,7 +107,7 @@ static constexpr int CONTENTS_TABLE{ 1 }; | |||
| 107 | return fifo; | 107 | return fifo; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | // ################################################################################################## | 110 | // ################################################################################################# |
| 111 | 111 | ||
| 112 | // in: expect fifo ... on top of the stack | 112 | // in: expect fifo ... on top of the stack |
| 113 | // out: nothing, removes all pushed values from the stack | 113 | // out: nothing, removes all pushed values from the stack |
| @@ -124,7 +124,7 @@ static void fifo_push(lua_State* L, keeper_fifo* fifo_, int count_) | |||
| 124 | fifo_->count += count_; | 124 | fifo_->count += count_; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | // ################################################################################################## | 127 | // ################################################################################################# |
| 128 | 128 | ||
| 129 | // in: fifo | 129 | // in: fifo |
| 130 | // out: ...|nothing | 130 | // out: ...|nothing |
| @@ -140,7 +140,7 @@ static void fifo_peek(lua_State* L, keeper_fifo* fifo_, int count_) | |||
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | // ################################################################################################## | 143 | // ################################################################################################# |
| 144 | 144 | ||
| 145 | // in: fifo | 145 | // in: fifo |
| 146 | // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) | 146 | // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) |
| @@ -177,7 +177,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, int count_) | |||
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | // ################################################################################################## | 180 | // ################################################################################################# |
| 181 | 181 | ||
| 182 | // in: linda_ud expected at stack slot idx | 182 | // in: linda_ud expected at stack slot idx |
| 183 | // out: fifos[ud] | 183 | // out: fifos[ud] |
| @@ -205,7 +205,7 @@ static void push_table(lua_State* L, int idx_) | |||
| 205 | STACK_CHECK(L, 1); | 205 | STACK_CHECK(L, 1); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | // ################################################################################################## | 208 | // ################################################################################################# |
| 209 | 209 | ||
| 210 | int keeper_push_linda_storage(Universe* U, Dest L, void* ptr_, uintptr_t magic_) | 210 | int keeper_push_linda_storage(Universe* U, Dest L, void* ptr_, uintptr_t magic_) |
| 211 | { | 211 | { |
| @@ -258,7 +258,7 @@ int keeper_push_linda_storage(Universe* U, Dest L, void* ptr_, uintptr_t magic_) | |||
| 258 | return 1; | 258 | return 1; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | // ################################################################################################## | 261 | // ################################################################################################# |
| 262 | 262 | ||
| 263 | // in: linda_ud | 263 | // in: linda_ud |
| 264 | int keepercall_clear(lua_State* L) | 264 | int keepercall_clear(lua_State* L) |
| @@ -274,7 +274,7 @@ int keepercall_clear(lua_State* L) | |||
| 274 | return 0; | 274 | return 0; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | // ################################################################################################## | 277 | // ################################################################################################# |
| 278 | 278 | ||
| 279 | // in: linda_ud, key, ... | 279 | // in: linda_ud, key, ... |
| 280 | // out: true|false | 280 | // out: true|false |
| @@ -285,7 +285,7 @@ int keepercall_send(lua_State* L) | |||
| 285 | // get the fifo associated to this key in this linda, create it if it doesn't exist | 285 | // get the fifo associated to this key in this linda, create it if it doesn't exist |
| 286 | lua_pushvalue(L, 2); // ud key ... fifos key | 286 | lua_pushvalue(L, 2); // ud key ... fifos key |
| 287 | lua_rawget(L, -2); // ud key ... fifos fifo | 287 | lua_rawget(L, -2); // ud key ... fifos fifo |
| 288 | if( lua_isnil(L, -1)) | 288 | if (lua_isnil(L, -1)) |
| 289 | { | 289 | { |
| 290 | lua_pop(L, 1); // ud key ... fifos | 290 | lua_pop(L, 1); // ud key ... fifos |
| 291 | std::ignore = fifo_new(L); // ud key ... fifos fifo | 291 | std::ignore = fifo_new(L); // ud key ... fifos fifo |
| @@ -311,7 +311,7 @@ int keepercall_send(lua_State* L) | |||
| 311 | return 1; | 311 | return 1; |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | // ################################################################################################## | 314 | // ################################################################################################# |
| 315 | 315 | ||
| 316 | // in: linda_ud, key [, key]? | 316 | // in: linda_ud, key [, key]? |
| 317 | // out: (key, val) or nothing | 317 | // out: (key, val) or nothing |
| @@ -347,13 +347,13 @@ int keepercall_receive(lua_State* L) | |||
| 347 | return 0; | 347 | return 0; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | // ################################################################################################## | 350 | // ################################################################################################# |
| 351 | 351 | ||
| 352 | // in: linda_ud key mincount [maxcount] | 352 | // in: linda_ud key mincount [maxcount] |
| 353 | int keepercall_receive_batched(lua_State* L) | 353 | int keepercall_receive_batched(lua_State* L) |
| 354 | { | 354 | { |
| 355 | int const min_count{ static_cast<int>(lua_tointeger(L, 3)) }; | 355 | int const min_count{ static_cast<int>(lua_tointeger(L, 3)) }; |
| 356 | if( min_count > 0) | 356 | if (min_count > 0) |
| 357 | { | 357 | { |
| 358 | int const max_count{ static_cast<int>(luaL_optinteger(L, 4, min_count)) }; | 358 | int const max_count{ static_cast<int>(luaL_optinteger(L, 4, min_count)) }; |
| 359 | lua_settop(L, 2); // ud key | 359 | lua_settop(L, 2); // ud key |
| @@ -364,7 +364,7 @@ int keepercall_receive_batched(lua_State* L) | |||
| 364 | lua_rawget(L, 2); // key fifos fifo | 364 | lua_rawget(L, 2); // key fifos fifo |
| 365 | lua_remove(L, 2); // key fifo | 365 | lua_remove(L, 2); // key fifo |
| 366 | keeper_fifo* const fifo{ prepare_fifo_access(L, 2) }; // key fifotbl | 366 | keeper_fifo* const fifo{ prepare_fifo_access(L, 2) }; // key fifotbl |
| 367 | if( fifo != nullptr && fifo->count >= min_count) | 367 | if (fifo != nullptr && fifo->count >= min_count) |
| 368 | { | 368 | { |
| 369 | fifo_pop(L, fifo, std::min( max_count, fifo->count)); // key ... | 369 | fifo_pop(L, fifo, std::min( max_count, fifo->count)); // key ... |
| 370 | } | 370 | } |
| @@ -380,7 +380,7 @@ int keepercall_receive_batched(lua_State* L) | |||
| 380 | } | 380 | } |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | // ################################################################################################## | 383 | // ################################################################################################# |
| 384 | 384 | ||
| 385 | // in: linda_ud key n | 385 | // in: linda_ud key n |
| 386 | // out: true or nil | 386 | // out: true or nil |
| @@ -403,7 +403,7 @@ int keepercall_limit(lua_State* L) | |||
| 403 | lua_settop(L, 0); | 403 | lua_settop(L, 0); |
| 404 | // return true if we decide that blocked threads waiting to write on that key should be awakened | 404 | // return true if we decide that blocked threads waiting to write on that key should be awakened |
| 405 | // this is the case if we detect the key was full but it is no longer the case | 405 | // this is the case if we detect the key was full but it is no longer the case |
| 406 | if( | 406 | if ( |
| 407 | ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit | 407 | ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit |
| 408 | && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit | 408 | && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit |
| 409 | ) | 409 | ) |
| @@ -416,7 +416,7 @@ int keepercall_limit(lua_State* L) | |||
| 416 | return lua_gettop(L); | 416 | return lua_gettop(L); |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | // ################################################################################################## | 419 | // ################################################################################################# |
| 420 | 420 | ||
| 421 | // in: linda_ud key [[val] ...] | 421 | // in: linda_ud key [[val] ...] |
| 422 | //out: true if the linda was full but it's no longer the case, else nothing | 422 | //out: true if the linda was full but it's no longer the case, else nothing |
| @@ -462,7 +462,7 @@ int keepercall_set(lua_State* L) | |||
| 462 | lua_pushvalue(L, 2); // fifos key [val [, ...]] key | 462 | lua_pushvalue(L, 2); // fifos key [val [, ...]] key |
| 463 | lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil | 463 | lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil |
| 464 | keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; | 464 | keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) }; |
| 465 | if( fifo == nullptr) // can be nullptr if we store a value at a new key | 465 | if (fifo == nullptr) // can be nullptr if we store a value at a new key |
| 466 | { // fifos key [val [, ...]] nil | 466 | { // fifos key [val [, ...]] nil |
| 467 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | 467 | // no need to wake writers in that case, because a writer can't wait on an inexistent key |
| 468 | lua_pop(L, 1); // fifos key [val [, ...]] | 468 | lua_pop(L, 1); // fifos key [val [, ...]] |
| @@ -489,7 +489,7 @@ int keepercall_set(lua_State* L) | |||
| 489 | return should_wake_writers ? (lua_pushboolean(L, 1), 1) : 0; | 489 | return should_wake_writers ? (lua_pushboolean(L, 1), 1) : 0; |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | // ################################################################################################## | 492 | // ################################################################################################# |
| 493 | 493 | ||
| 494 | // in: linda_ud key [count] | 494 | // in: linda_ud key [count] |
| 495 | // out: at most <count> values | 495 | // out: at most <count> values |
| @@ -517,7 +517,7 @@ int keepercall_get(lua_State* L) | |||
| 517 | return 0; | 517 | return 0; |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | // ################################################################################################## | 520 | // ################################################################################################# |
| 521 | 521 | ||
| 522 | // in: linda_ud [, key [, ...]] | 522 | // in: linda_ud [, key [, ...]] |
| 523 | int keepercall_count(lua_State* L) | 523 | int keepercall_count(lua_State* L) |
| @@ -586,9 +586,9 @@ int keepercall_count(lua_State* L) | |||
| 586 | return 1; | 586 | return 1; |
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | //################################################################################### | 589 | // ################################################################################################# |
| 590 | // Keeper API, accessed from linda methods | 590 | // Keeper API, accessed from linda methods |
| 591 | //################################################################################### | 591 | // ################################################################################################# |
| 592 | 592 | ||
| 593 | /*---=== Keeper states ===--- | 593 | /*---=== Keeper states ===--- |
| 594 | */ | 594 | */ |
| @@ -636,7 +636,7 @@ void close_keepers(Universe* U) | |||
| 636 | } | 636 | } |
| 637 | } | 637 | } |
| 638 | 638 | ||
| 639 | // ################################################################################################## | 639 | // ################################################################################################# |
| 640 | 640 | ||
| 641 | /* | 641 | /* |
| 642 | * Initialize keeper states | 642 | * Initialize keeper states |
| @@ -746,7 +746,7 @@ void init_keepers(Universe* U, lua_State* L) | |||
| 746 | STACK_CHECK(L, 0); | 746 | STACK_CHECK(L, 0); |
| 747 | } | 747 | } |
| 748 | 748 | ||
| 749 | // ################################################################################################## | 749 | // ################################################################################################# |
| 750 | 750 | ||
| 751 | // should be called only when inside a keeper_acquire/keeper_release pair (see Linda::ProtectedCall) | 751 | // should be called only when inside a keeper_acquire/keeper_release pair (see Linda::ProtectedCall) |
| 752 | Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) | 752 | Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) |
| @@ -760,7 +760,7 @@ Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) | |||
| 760 | return nullptr; | 760 | return nullptr; |
| 761 | } | 761 | } |
| 762 | 762 | ||
| 763 | // ################################################################################################## | 763 | // ################################################################################################# |
| 764 | 764 | ||
| 765 | Keeper* keeper_acquire(Keepers* keepers_, uintptr_t magic_) | 765 | Keeper* keeper_acquire(Keepers* keepers_, uintptr_t magic_) |
| 766 | { | 766 | { |
| @@ -784,7 +784,7 @@ Keeper* keeper_acquire(Keepers* keepers_, uintptr_t magic_) | |||
| 784 | return nullptr; | 784 | return nullptr; |
| 785 | } | 785 | } |
| 786 | 786 | ||
| 787 | // ################################################################################################## | 787 | // ################################################################################################# |
| 788 | 788 | ||
| 789 | void keeper_release(Keeper* K) | 789 | void keeper_release(Keeper* K) |
| 790 | { | 790 | { |
| @@ -795,7 +795,7 @@ void keeper_release(Keeper* K) | |||
| 795 | } | 795 | } |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | // ################################################################################################## | 798 | // ################################################################################################# |
| 799 | 799 | ||
| 800 | void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode_) | 800 | void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode_) |
| 801 | { | 801 | { |
| @@ -821,7 +821,7 @@ void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode | |||
| 821 | } | 821 | } |
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | // ################################################################################################## | 824 | // ################################################################################################# |
| 825 | 825 | ||
| 826 | /* | 826 | /* |
| 827 | * Call a function ('func_name') in the keeper state, and pass on the returned | 827 | * Call a function ('func_name') in the keeper state, and pass on the returned |
diff --git a/src/lanes.cpp b/src/lanes.cpp index 17d4f67..3aa3365 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
| @@ -101,8 +101,63 @@ THE SOFTWARE. | |||
| 101 | 101 | ||
| 102 | #include <atomic> | 102 | #include <atomic> |
| 103 | 103 | ||
| 104 | // forwarding (will do things better later) | 104 | // ################################################################################################# |
| 105 | static void tracking_add(Lane* lane_); | 105 | |
| 106 | #if HAVE_LANE_TRACKING() | ||
| 107 | |||
| 108 | // The chain is ended by '(Lane*)(-1)', not nullptr: | ||
| 109 | // 'tracking_first -> ... -> ... -> (-1)' | ||
| 110 | #define TRACKING_END ((Lane *)(-1)) | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Add the lane to tracking chain; the ones still running at the end of the | ||
| 114 | * whole process will be cancelled. | ||
| 115 | */ | ||
| 116 | static void tracking_add(Lane* lane_) | ||
| 117 | { | ||
| 118 | std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; | ||
| 119 | assert(lane_->tracking_next == nullptr); | ||
| 120 | |||
| 121 | lane_->tracking_next = lane_->U->tracking_first; | ||
| 122 | lane_->U->tracking_first = lane_; | ||
| 123 | } | ||
| 124 | |||
| 125 | // ################################################################################################# | ||
| 126 | |||
| 127 | /* | ||
| 128 | * A free-running lane has ended; remove it from tracking chain | ||
| 129 | */ | ||
| 130 | [[nodiscard]] static bool tracking_remove(Lane* lane_) | ||
| 131 | { | ||
| 132 | bool found{ false }; | ||
| 133 | std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; | ||
| 134 | // Make sure (within the MUTEX) that we actually are in the chain | ||
| 135 | // still (at process exit they will remove us from chain and then | ||
| 136 | // cancel/kill). | ||
| 137 | // | ||
| 138 | if (lane_->tracking_next != nullptr) | ||
| 139 | { | ||
| 140 | Lane** ref = (Lane**) &lane_->U->tracking_first; | ||
| 141 | |||
| 142 | while( *ref != TRACKING_END) | ||
| 143 | { | ||
| 144 | if (*ref == lane_) | ||
| 145 | { | ||
| 146 | *ref = lane_->tracking_next; | ||
| 147 | lane_->tracking_next = nullptr; | ||
| 148 | found = true; | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | ref = (Lane**) &((*ref)->tracking_next); | ||
| 152 | } | ||
| 153 | assert( found); | ||
| 154 | } | ||
| 155 | return found; | ||
| 156 | } | ||
| 157 | |||
| 158 | #endif // HAVE_LANE_TRACKING() | ||
| 159 | |||
| 160 | // ################################################################################################# | ||
| 106 | 161 | ||
| 107 | Lane::Lane(Universe* U_, lua_State* L_) | 162 | Lane::Lane(Universe* U_, lua_State* L_) |
| 108 | : U{ U_ } | 163 | : U{ U_ } |
| @@ -180,114 +235,44 @@ static constexpr UniqueKey FINALIZER_REGKEY{ 0x188fccb8bf348e09ull }; | |||
| 180 | 235 | ||
| 181 | // ################################################################################################# | 236 | // ################################################################################################# |
| 182 | 237 | ||
| 183 | /* | 238 | Lane::~Lane() |
| 184 | * Push a table stored in registry onto Lua stack. | ||
| 185 | * | ||
| 186 | * If there is no existing table, create one if 'create' is true. | ||
| 187 | * | ||
| 188 | * Returns: true if a table was pushed | ||
| 189 | * false if no table found, not created, and nothing pushed | ||
| 190 | */ | ||
| 191 | [[nodiscard]] static bool push_registry_table(lua_State* L, UniqueKey key, bool create) | ||
| 192 | { | 239 | { |
| 193 | STACK_GROW(L, 3); | 240 | // Clean up after a (finished) thread |
| 194 | STACK_CHECK_START_REL(L, 0); | 241 | // |
| 195 | 242 | #if HAVE_LANE_TRACKING() | |
| 196 | key.pushValue(L); // ? | 243 | if (U->tracking_first != nullptr) |
| 197 | if (lua_isnil(L, -1)) // nil? | ||
| 198 | { | 244 | { |
| 199 | lua_pop(L, 1); // | 245 | // Lane was cleaned up, no need to handle at process termination |
| 200 | STACK_CHECK(L, 0); | 246 | std::ignore = tracking_remove(this); |
| 201 | |||
| 202 | if (!create) | ||
| 203 | { | ||
| 204 | return false; | ||
| 205 | } | ||
| 206 | |||
| 207 | lua_newtable(L); // t | ||
| 208 | key.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); | ||
| 209 | } | 247 | } |
| 210 | STACK_CHECK(L, 1); | 248 | #endif // HAVE_LANE_TRACKING() |
| 211 | return true; // table pushed | ||
| 212 | } | 249 | } |
| 213 | 250 | ||
| 214 | // ################################################################################################# | 251 | // ################################################################################################# |
| 252 | // ########################################## Finalizer ############################################ | ||
| 253 | // ################################################################################################# | ||
| 215 | 254 | ||
| 216 | #if HAVE_LANE_TRACKING() | ||
| 217 | 255 | ||
| 218 | // The chain is ended by '(Lane*)(-1)', not nullptr: | 256 | // Push the finalizers table on the stack. |
| 219 | // 'tracking_first -> ... -> ... -> (-1)' | 257 | // If there is no existing table, create ti. |
| 220 | #define TRACKING_END ((Lane *)(-1)) | 258 | static void push_finalizers_table(lua_State* L) |
| 221 | |||
| 222 | /* | ||
| 223 | * Add the lane to tracking chain; the ones still running at the end of the | ||
| 224 | * whole process will be cancelled. | ||
| 225 | */ | ||
| 226 | static void tracking_add(Lane* lane_) | ||
| 227 | { | 259 | { |
| 228 | std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; | 260 | STACK_GROW(L, 3); |
| 229 | assert(lane_->tracking_next == nullptr); | 261 | STACK_CHECK_START_REL(L, 0); |
| 230 | |||
| 231 | lane_->tracking_next = lane_->U->tracking_first; | ||
| 232 | lane_->U->tracking_first = lane_; | ||
| 233 | } | ||
| 234 | |||
| 235 | // ################################################################################################# | ||
| 236 | 262 | ||
| 237 | /* | 263 | FINALIZER_REGKEY.pushValue(L); // ? |
| 238 | * A free-running lane has ended; remove it from tracking chain | 264 | if (lua_isnil(L, -1)) // nil? |
| 239 | */ | ||
| 240 | [[nodiscard]] static bool tracking_remove(Lane* lane_) | ||
| 241 | { | ||
| 242 | bool found{ false }; | ||
| 243 | std::lock_guard<std::mutex> guard{ lane_->U->tracking_cs }; | ||
| 244 | // Make sure (within the MUTEX) that we actually are in the chain | ||
| 245 | // still (at process exit they will remove us from chain and then | ||
| 246 | // cancel/kill). | ||
| 247 | // | ||
| 248 | if (lane_->tracking_next != nullptr) | ||
| 249 | { | 265 | { |
| 250 | Lane** ref = (Lane**) &lane_->U->tracking_first; | 266 | lua_pop(L, 1); // |
| 251 | 267 | // store a newly created table in the registry, but leave it on the stack too | |
| 252 | while( *ref != TRACKING_END) | 268 | lua_newtable(L); // t |
| 253 | { | 269 | FINALIZER_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // t |
| 254 | if (*ref == lane_) | ||
| 255 | { | ||
| 256 | *ref = lane_->tracking_next; | ||
| 257 | lane_->tracking_next = nullptr; | ||
| 258 | found = true; | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | ref = (Lane**) &((*ref)->tracking_next); | ||
| 262 | } | ||
| 263 | assert( found); | ||
| 264 | } | 270 | } |
| 265 | return found; | 271 | STACK_CHECK(L, 1); |
| 266 | } | 272 | } |
| 267 | 273 | ||
| 268 | #endif // HAVE_LANE_TRACKING() | ||
| 269 | |||
| 270 | // ################################################################################################# | 274 | // ################################################################################################# |
| 271 | 275 | ||
| 272 | Lane::~Lane() | ||
| 273 | { | ||
| 274 | // Clean up after a (finished) thread | ||
| 275 | // | ||
| 276 | #if HAVE_LANE_TRACKING() | ||
| 277 | if (U->tracking_first != nullptr) | ||
| 278 | { | ||
| 279 | // Lane was cleaned up, no need to handle at process termination | ||
| 280 | std::ignore = tracking_remove(this); | ||
| 281 | } | ||
| 282 | #endif // HAVE_LANE_TRACKING() | ||
| 283 | } | ||
| 284 | |||
| 285 | /* | ||
| 286 | * ############################################################################################### | ||
| 287 | * ########################################## Finalizer ########################################## | ||
| 288 | * ############################################################################################### | ||
| 289 | */ | ||
| 290 | |||
| 291 | //--- | 276 | //--- |
| 292 | // void= finalizer( finalizer_func ) | 277 | // void= finalizer( finalizer_func ) |
| 293 | // | 278 | // |
| @@ -296,12 +281,12 @@ Lane::~Lane() | |||
| 296 | // Add a function that will be called when exiting the lane, either via | 281 | // Add a function that will be called when exiting the lane, either via |
| 297 | // normal return or an error. | 282 | // normal return or an error. |
| 298 | // | 283 | // |
| 299 | LUAG_FUNC( set_finalizer) | 284 | LUAG_FUNC(set_finalizer) |
| 300 | { | 285 | { |
| 301 | luaL_argcheck(L, lua_isfunction(L, 1), 1, "finalizer should be a function"); | 286 | luaL_argcheck(L, lua_isfunction(L, 1), 1, "finalizer should be a function"); |
| 302 | luaL_argcheck(L, lua_gettop( L) == 1, 1, "too many arguments"); | 287 | luaL_argcheck(L, lua_gettop( L) == 1, 1, "too many arguments"); |
| 303 | // Get the current finalizer table (if any), create one if it doesn't exist | 288 | // Get the current finalizer table (if any), create one if it doesn't exist |
| 304 | std::ignore = push_registry_table(L, FINALIZER_REGKEY, true); // finalizer {finalisers} | 289 | push_finalizers_table(L); // finalizer {finalisers} |
| 305 | STACK_GROW(L, 2); | 290 | STACK_GROW(L, 2); |
| 306 | lua_pushinteger(L, lua_rawlen(L, -1) + 1); // finalizer {finalisers} idx | 291 | lua_pushinteger(L, lua_rawlen(L, -1) + 1); // finalizer {finalisers} idx |
| 307 | lua_pushvalue(L, 1); // finalizer {finalisers} idx finalizer | 292 | lua_pushvalue(L, 1); // finalizer {finalisers} idx finalizer |
| @@ -310,7 +295,44 @@ LUAG_FUNC( set_finalizer) | |||
| 310 | return 0; | 295 | return 0; |
| 311 | } | 296 | } |
| 312 | 297 | ||
| 298 | // ################################################################################################# | ||
| 299 | |||
| 300 | static void push_stack_trace(lua_State* L, int rc_, int stk_base_) | ||
| 301 | { | ||
| 302 | // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry | ||
| 303 | switch(rc_) | ||
| 304 | { | ||
| 305 | case LUA_OK: // no error, body return values are on the stack | ||
| 306 | break; | ||
| 313 | 307 | ||
| 308 | case LUA_ERRRUN: // cancellation or a runtime error | ||
| 309 | #if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler | ||
| 310 | { | ||
| 311 | STACK_CHECK_START_REL(L, 0); | ||
| 312 | // fetch the call stack table from the registry where the handler stored it | ||
| 313 | STACK_GROW(L, 1); | ||
| 314 | // yields nil if no stack was generated (in case of cancellation for example) | ||
| 315 | STACKTRACE_REGKEY.pushValue(L); // err trace|nil | ||
| 316 | STACK_CHECK(L, 1); | ||
| 317 | |||
| 318 | // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed | ||
| 319 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table | ||
| 320 | ASSERT_L(lua_type(L, 1 + stk_base_) == (CANCEL_ERROR.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); | ||
| 321 | // Just leaving the stack trace table on the stack is enough to get it through to the master. | ||
| 322 | break; | ||
| 323 | } | ||
| 324 | #endif // fall through if not ERROR_FULL_STACK | ||
| 325 | |||
| 326 | case LUA_ERRMEM: // memory allocation error (handler not called) | ||
| 327 | case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) | ||
| 328 | default: | ||
| 329 | // we should have a single value which is either a string (the error message) or CANCEL_ERROR | ||
| 330 | ASSERT_L((lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || CANCEL_ERROR.equals(L, stk_base_))); | ||
| 331 | break; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | // ################################################################################################# | ||
| 314 | //--- | 336 | //--- |
| 315 | // Run finalizers - if any - with the given parameters | 337 | // Run finalizers - if any - with the given parameters |
| 316 | // | 338 | // |
| @@ -324,43 +346,37 @@ LUAG_FUNC( set_finalizer) | |||
| 324 | // | 346 | // |
| 325 | // TBD: should we add stack trace on failing finalizer, wouldn't be hard.. | 347 | // TBD: should we add stack trace on failing finalizer, wouldn't be hard.. |
| 326 | // | 348 | // |
| 327 | static void push_stack_trace( lua_State* L, int rc_, int stk_base_); | ||
| 328 | 349 | ||
| 329 | [[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc) | 350 | [[nodiscard]] static int run_finalizers(lua_State* L, int lua_rc_) |
| 330 | { | 351 | { |
| 331 | int finalizers_index; | 352 | FINALIZER_REGKEY.pushValue(L); // ... finalizers? |
| 332 | int n; | 353 | if (lua_isnil(L, -1)) |
| 333 | int err_handler_index = 0; | ||
| 334 | int rc = LUA_OK; // ... | ||
| 335 | if (!push_registry_table(L, FINALIZER_REGKEY, false)) // ... finalizers? | ||
| 336 | { | 354 | { |
| 355 | lua_pop(L, 1); | ||
| 337 | return 0; // no finalizers | 356 | return 0; // no finalizers |
| 338 | } | 357 | } |
| 339 | 358 | ||
| 340 | STACK_GROW(L, 5); | 359 | STACK_GROW(L, 5); |
| 341 | 360 | ||
| 342 | finalizers_index = lua_gettop( L); | 361 | int const finalizers_index{ lua_gettop(L) }; |
| 343 | 362 | int const err_handler_index{ ERROR_FULL_STACK ? (lua_pushcfunction(L, lane_error), lua_gettop(L)) : 0 }; | |
| 344 | #if ERROR_FULL_STACK | ||
| 345 | lua_pushcfunction(L, lane_error); // ... finalizers lane_error | ||
| 346 | err_handler_index = lua_gettop( L); | ||
| 347 | #endif // ERROR_FULL_STACK | ||
| 348 | 363 | ||
| 349 | for( n = (int) lua_rawlen(L, finalizers_index); n > 0; -- n) | 364 | int rc{ LUA_OK }; |
| 365 | for (int n = static_cast<int>(lua_rawlen(L, finalizers_index)); n > 0; --n) | ||
| 350 | { | 366 | { |
| 351 | int args = 0; | 367 | int args = 0; |
| 352 | lua_pushinteger(L, n); // ... finalizers lane_error n | 368 | lua_pushinteger(L, n); // ... finalizers lane_error n |
| 353 | lua_rawget(L, finalizers_index); // ... finalizers lane_error finalizer | 369 | lua_rawget(L, finalizers_index); // ... finalizers lane_error finalizer |
| 354 | ASSERT_L( lua_isfunction(L, -1)); | 370 | ASSERT_L(lua_isfunction(L, -1)); |
| 355 | if (lua_rc != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack | 371 | if (lua_rc_ != LUA_OK) // we have an error message and an optional stack trace at the bottom of the stack |
| 356 | { | 372 | { |
| 357 | ASSERT_L( finalizers_index == 2 || finalizers_index == 3); | 373 | ASSERT_L( finalizers_index == 2 || finalizers_index == 3); |
| 358 | //char const* err_msg = lua_tostring(L, 1); | 374 | //char const* err_msg = lua_tostring(L, 1); |
| 359 | lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg | 375 | lua_pushvalue(L, 1); // ... finalizers lane_error finalizer err_msg |
| 360 | // note we don't always have a stack trace for example when CANCEL_ERROR, or when we got an error that doesn't call our handler, such as LUA_ERRMEM | 376 | // note we don't always have a stack trace for example when CANCEL_ERROR, or when we got an error that doesn't call our handler, such as LUA_ERRMEM |
| 361 | if (finalizers_index == 3) | 377 | if (finalizers_index == 3) |
| 362 | { | 378 | { |
| 363 | lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace | 379 | lua_pushvalue(L, 2); // ... finalizers lane_error finalizer err_msg stack_trace |
| 364 | } | 380 | } |
| 365 | args = finalizers_index - 1; | 381 | args = finalizers_index - 1; |
| 366 | } | 382 | } |
| @@ -369,21 +385,21 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_); | |||
| 369 | rc = lua_pcall(L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2? | 385 | rc = lua_pcall(L, args, 0, err_handler_index); // ... finalizers lane_error err_msg2? |
| 370 | if (rc != LUA_OK) | 386 | if (rc != LUA_OK) |
| 371 | { | 387 | { |
| 372 | push_stack_trace(L, rc, lua_gettop( L)); | 388 | push_stack_trace(L, rc, lua_gettop(L)); |
| 373 | // If one finalizer fails, don't run the others. Return this | 389 | // If one finalizer fails, don't run the others. Return this |
| 374 | // as the 'real' error, replacing what we could have had (or not) | 390 | // as the 'real' error, replacing what we could have had (or not) |
| 375 | // from the actual code. | 391 | // from the actual code. |
| 376 | break; | 392 | break; |
| 377 | } | 393 | } |
| 378 | // no error, proceed to next finalizer // ... finalizers lane_error | 394 | // no error, proceed to next finalizer // ... finalizers lane_error |
| 379 | } | 395 | } |
| 380 | 396 | ||
| 381 | if (rc != LUA_OK) | 397 | if (rc != LUA_OK) |
| 382 | { | 398 | { |
| 383 | // ERROR_FULL_STACK accounts for the presence of lane_error on the stack | 399 | // ERROR_FULL_STACK accounts for the presence of lane_error on the stack |
| 384 | int nb_err_slots = lua_gettop( L) - finalizers_index - ERROR_FULL_STACK; | 400 | int const nb_err_slots{ lua_gettop(L) - finalizers_index - ERROR_FULL_STACK }; |
| 385 | // a finalizer generated an error, this is what we leave of the stack | 401 | // a finalizer generated an error, this is what we leave of the stack |
| 386 | for( n = nb_err_slots; n > 0; -- n) | 402 | for (int n = nb_err_slots; n > 0; --n) |
| 387 | { | 403 | { |
| 388 | lua_replace(L, n); | 404 | lua_replace(L, n); |
| 389 | } | 405 | } |
| @@ -399,9 +415,9 @@ static void push_stack_trace( lua_State* L, int rc_, int stk_base_); | |||
| 399 | } | 415 | } |
| 400 | 416 | ||
| 401 | /* | 417 | /* |
| 402 | * ############################################################################################### | 418 | * ################################################################################################ |
| 403 | * ########################################### Threads ########################################### | 419 | * ########################################### Threads ############################################ |
| 404 | * ############################################################################################### | 420 | * ################################################################################################ |
| 405 | */ | 421 | */ |
| 406 | 422 | ||
| 407 | // | 423 | // |
| @@ -425,7 +441,7 @@ static void selfdestruct_add(Lane* lane_) | |||
| 425 | lane_->U->selfdestruct_first = lane_; | 441 | lane_->U->selfdestruct_first = lane_; |
| 426 | } | 442 | } |
| 427 | 443 | ||
| 428 | // ############################################################################################### | 444 | // ################################################################################################# |
| 429 | 445 | ||
| 430 | /* | 446 | /* |
| 431 | * A free-running lane has ended; remove it from selfdestruct chain | 447 | * A free-running lane has ended; remove it from selfdestruct chain |
| @@ -460,7 +476,7 @@ static void selfdestruct_add(Lane* lane_) | |||
| 460 | return found; | 476 | return found; |
| 461 | } | 477 | } |
| 462 | 478 | ||
| 463 | // ############################################################################################### | 479 | // ################################################################################################# |
| 464 | 480 | ||
| 465 | /* | 481 | /* |
| 466 | * Process end; cancel any still free-running threads | 482 | * Process end; cancel any still free-running threads |
| @@ -567,7 +583,7 @@ static void selfdestruct_add(Lane* lane_) | |||
| 567 | return 0; | 583 | return 0; |
| 568 | } | 584 | } |
| 569 | 585 | ||
| 570 | // ############################################################################################### | 586 | // ################################################################################################# |
| 571 | 587 | ||
| 572 | //--- | 588 | //--- |
| 573 | // = _single( [cores_uint=1] ) | 589 | // = _single( [cores_uint=1] ) |
| @@ -597,7 +613,7 @@ LUAG_FUNC( set_singlethreaded) | |||
| 597 | #endif | 613 | #endif |
| 598 | } | 614 | } |
| 599 | 615 | ||
| 600 | // ############################################################################################### | 616 | // ################################################################################################# |
| 601 | 617 | ||
| 602 | /* | 618 | /* |
| 603 | * str= lane_error( error_val|str ) | 619 | * str= lane_error( error_val|str ) |
| @@ -710,41 +726,6 @@ LUAG_FUNC( set_error_reporting) | |||
| 710 | } | 726 | } |
| 711 | #endif // ERROR_FULL_STACK | 727 | #endif // ERROR_FULL_STACK |
| 712 | 728 | ||
| 713 | static void push_stack_trace( lua_State* L, int rc_, int stk_base_) | ||
| 714 | { | ||
| 715 | // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry | ||
| 716 | switch( rc_) | ||
| 717 | { | ||
| 718 | case LUA_OK: // no error, body return values are on the stack | ||
| 719 | break; | ||
| 720 | |||
| 721 | case LUA_ERRRUN: // cancellation or a runtime error | ||
| 722 | #if ERROR_FULL_STACK // when ERROR_FULL_STACK, we installed a handler | ||
| 723 | { | ||
| 724 | STACK_CHECK_START_REL(L, 0); | ||
| 725 | // fetch the call stack table from the registry where the handler stored it | ||
| 726 | STACK_GROW(L, 1); | ||
| 727 | // yields nil if no stack was generated (in case of cancellation for example) | ||
| 728 | STACKTRACE_REGKEY.pushValue(L); // err trace|nil | ||
| 729 | STACK_CHECK(L, 1); | ||
| 730 | |||
| 731 | // For cancellation the error message is CANCEL_ERROR, and a stack trace isn't placed | ||
| 732 | // For other errors, the message can be whatever was thrown, and we should have a stack trace table | ||
| 733 | ASSERT_L(lua_type(L, 1 + stk_base_) == (CANCEL_ERROR.equals(L, stk_base_) ? LUA_TNIL : LUA_TTABLE)); | ||
| 734 | // Just leaving the stack trace table on the stack is enough to get it through to the master. | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | #endif // fall through if not ERROR_FULL_STACK | ||
| 738 | |||
| 739 | case LUA_ERRMEM: // memory allocation error (handler not called) | ||
| 740 | case LUA_ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) | ||
| 741 | default: | ||
| 742 | // we should have a single value which is either a string (the error message) or CANCEL_ERROR | ||
| 743 | ASSERT_L((lua_gettop(L) == stk_base_) && ((lua_type(L, stk_base_) == LUA_TSTRING) || CANCEL_ERROR.equals(L, stk_base_))); | ||
| 744 | break; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | // ################################################################################################# | 729 | // ################################################################################################# |
| 749 | 730 | ||
| 750 | LUAG_FUNC(set_debug_threadname) | 731 | LUAG_FUNC(set_debug_threadname) |
| @@ -772,7 +753,7 @@ LUAG_FUNC(set_debug_threadname) | |||
| 772 | 753 | ||
| 773 | LUAG_FUNC(get_debug_threadname) | 754 | LUAG_FUNC(get_debug_threadname) |
| 774 | { | 755 | { |
| 775 | Lane* const lane{ lua_toLane(L, 1) }; | 756 | Lane* const lane{ ToLane(L, 1) }; |
| 776 | luaL_argcheck(L, lua_gettop(L) == 1, 2, "too many arguments"); | 757 | luaL_argcheck(L, lua_gettop(L) == 1, 2, "too many arguments"); |
| 777 | lua_pushstring(L, lane->debug_name); | 758 | lua_pushstring(L, lane->debug_name); |
| 778 | return 1; | 759 | return 1; |
| @@ -828,8 +809,7 @@ static struct errcode_name s_errcodes[] = | |||
| 828 | }; | 809 | }; |
| 829 | static char const* get_errcode_name( int _code) | 810 | static char const* get_errcode_name( int _code) |
| 830 | { | 811 | { |
| 831 | int i; | 812 | for (int i{ 0 }; i < 7; ++i) |
| 832 | for( i = 0; i < 7; ++ i) | ||
| 833 | { | 813 | { |
| 834 | if (s_errcodes[i].code == _code) | 814 | if (s_errcodes[i].code == _code) |
| 835 | { | 815 | { |
| @@ -891,7 +871,6 @@ static void lane_main(Lane* lane) | |||
| 891 | push_stack_trace(L, rc, 1); // retvals|error [trace] | 871 | push_stack_trace(L, rc, 1); // retvals|error [trace] |
| 892 | 872 | ||
| 893 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name(rc), CANCEL_ERROR.equals(L, 1) ? "cancelled" : lua_typename(L, lua_type(L, 1)))); | 873 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name(rc), CANCEL_ERROR.equals(L, 1) ? "cancelled" : lua_typename(L, lua_type(L, 1)))); |
| 894 | // STACK_DUMP(L); | ||
| 895 | // Call finalizers, if the script has set them up. | 874 | // Call finalizers, if the script has set them up. |
| 896 | // | 875 | // |
| 897 | int rc2{ run_finalizers(L, rc) }; | 876 | int rc2{ run_finalizers(L, rc) }; |
| @@ -1295,7 +1274,7 @@ LUAG_FUNC(lane_new) | |||
| 1295 | [[nodiscard]] static int lane_gc(lua_State* L) | 1274 | [[nodiscard]] static int lane_gc(lua_State* L) |
| 1296 | { | 1275 | { |
| 1297 | bool have_gc_cb{ false }; | 1276 | bool have_gc_cb{ false }; |
| 1298 | Lane* const lane{ lua_toLane(L, 1) }; // ud | 1277 | Lane* const lane{ ToLane(L, 1) }; // ud |
| 1299 | 1278 | ||
| 1300 | // if there a gc callback? | 1279 | // if there a gc callback? |
| 1301 | lua_getiuservalue(L, 1, 1); // ud uservalue | 1280 | lua_getiuservalue(L, 1, 1); // ud uservalue |
| @@ -1393,7 +1372,7 @@ void push_thread_status(lua_State* L, Lane* lane_) | |||
| 1393 | // | 1372 | // |
| 1394 | LUAG_FUNC(thread_join) | 1373 | LUAG_FUNC(thread_join) |
| 1395 | { | 1374 | { |
| 1396 | Lane* const lane{ lua_toLane(L, 1) }; | 1375 | Lane* const lane{ ToLane(L, 1) }; |
| 1397 | lua_Duration const duration{ luaL_optnumber(L, 2, -1.0) }; | 1376 | lua_Duration const duration{ luaL_optnumber(L, 2, -1.0) }; |
| 1398 | lua_State* const L2{ lane->L }; | 1377 | lua_State* const L2{ lane->L }; |
| 1399 | 1378 | ||
| @@ -1474,7 +1453,7 @@ LUAG_FUNC(thread_index) | |||
| 1474 | static constexpr int UD{ 1 }; | 1453 | static constexpr int UD{ 1 }; |
| 1475 | static constexpr int KEY{ 2 }; | 1454 | static constexpr int KEY{ 2 }; |
| 1476 | static constexpr int USR{ 3 }; | 1455 | static constexpr int USR{ 3 }; |
| 1477 | Lane* const lane{ lua_toLane(L, UD) }; | 1456 | Lane* const lane{ ToLane(L, UD) }; |
| 1478 | ASSERT_L(lua_gettop(L) == 2); | 1457 | ASSERT_L(lua_gettop(L) == 2); |
| 1479 | 1458 | ||
| 1480 | STACK_GROW(L, 8); // up to 8 positions are needed in case of error propagation | 1459 | STACK_GROW(L, 8); // up to 8 positions are needed in case of error propagation |
| @@ -1647,11 +1626,9 @@ LUAG_FUNC(threads) | |||
| 1647 | } | 1626 | } |
| 1648 | #endif // HAVE_LANE_TRACKING() | 1627 | #endif // HAVE_LANE_TRACKING() |
| 1649 | 1628 | ||
| 1650 | /* | 1629 | // ################################################################################################# |
| 1651 | * ############################################################################################### | 1630 | // ######################################## Timer support ########################################## |
| 1652 | * ######################################## Timer support ######################################## | 1631 | // ################################################################################################# |
| 1653 | * ############################################################################################### | ||
| 1654 | */ | ||
| 1655 | 1632 | ||
| 1656 | /* | 1633 | /* |
| 1657 | * secs = now_secs() | 1634 | * secs = now_secs() |
| @@ -1722,11 +1699,9 @@ LUAG_FUNC(wakeup_conv) | |||
| 1722 | return 1; | 1699 | return 1; |
| 1723 | } | 1700 | } |
| 1724 | 1701 | ||
| 1725 | /* | 1702 | // ################################################################################################# |
| 1726 | * ############################################################################################### | 1703 | // ######################################## Module linkage ######################################### |
| 1727 | * ######################################## Module linkage ####################################### | 1704 | // ################################################################################################# |
| 1728 | * ############################################################################################### | ||
| 1729 | */ | ||
| 1730 | 1705 | ||
| 1731 | extern int LG_linda(lua_State* L); | 1706 | extern int LG_linda(lua_State* L); |
| 1732 | static struct luaL_Reg const lanes_functions[] = | 1707 | static struct luaL_Reg const lanes_functions[] = |
diff --git a/src/lanes_private.h b/src/lanes_private.h index 18e55fd..5e6160d 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
| @@ -98,7 +98,7 @@ static constexpr UniqueKey LANE_POINTER_REGKEY{ 0xB3022205633743BCull }; // used | |||
| 98 | // 'Lane' are malloc/free'd and the handle only carries a pointer. | 98 | // 'Lane' are malloc/free'd and the handle only carries a pointer. |
| 99 | // This is not deep userdata since the handle's not portable among lanes. | 99 | // This is not deep userdata since the handle's not portable among lanes. |
| 100 | // | 100 | // |
| 101 | [[nodiscard]] inline Lane* lua_toLane(lua_State* L, int i_) | 101 | [[nodiscard]] inline Lane* ToLane(lua_State* L, int i_) |
| 102 | { | 102 | { |
| 103 | return *(static_cast<Lane**>(luaL_checkudata(L, i_, "Lane"))); | 103 | return *(static_cast<Lane**>(luaL_checkudata(L, i_, "Lane"))); |
| 104 | } | 104 | } |
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 073e940..c01363a 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h | |||
| @@ -35,7 +35,6 @@ using namespace std::chrono_literals; | |||
| 35 | #ifdef NDEBUG | 35 | #ifdef NDEBUG |
| 36 | 36 | ||
| 37 | #define _ASSERT_L(lua,c) //nothing | 37 | #define _ASSERT_L(lua,c) //nothing |
| 38 | #define STACK_DUMP(L) //nothing | ||
| 39 | 38 | ||
| 40 | #define STACK_CHECK_START_REL(L, offset_) | 39 | #define STACK_CHECK_START_REL(L, offset_) |
| 41 | #define STACK_CHECK_START_ABS(L, offset_) | 40 | #define STACK_CHECK_START_ABS(L, offset_) |
| @@ -45,8 +44,7 @@ using namespace std::chrono_literals; | |||
| 45 | 44 | ||
| 46 | #else // NDEBUG | 45 | #else // NDEBUG |
| 47 | 46 | ||
| 48 | #define _ASSERT_L(L, cond_) if( (cond_) == 0) { (void) luaL_error(L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} | 47 | #define _ASSERT_L(L, cond_) if ((cond_) == 0) { (void) luaL_error(L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} |
| 49 | #define STACK_DUMP(L) luaG_dump(L) | ||
| 50 | 48 | ||
| 51 | class StackChecker | 49 | class StackChecker |
| 52 | { | 50 | { |
diff --git a/src/state.cpp b/src/state.cpp index 1ba5a77..9ad237d 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
| @@ -37,7 +37,7 @@ THE SOFTWARE. | |||
| 37 | #include "tools.h" | 37 | #include "tools.h" |
| 38 | #include "universe.h" | 38 | #include "universe.h" |
| 39 | 39 | ||
| 40 | // ################################################################################################ | 40 | // ################################################################################################# |
| 41 | 41 | ||
| 42 | /*---=== Serialize require ===--- | 42 | /*---=== Serialize require ===--- |
| 43 | */ | 43 | */ |
| @@ -71,7 +71,7 @@ THE SOFTWARE. | |||
| 71 | 71 | ||
| 72 | // the required module (or an error message) is left on the stack as returned value by original require function | 72 | // the required module (or an error message) is left on the stack as returned value by original require function |
| 73 | 73 | ||
| 74 | if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? | 74 | if (rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? |
| 75 | { | 75 | { |
| 76 | raise_lua_error(L); | 76 | raise_lua_error(L); |
| 77 | } | 77 | } |
| @@ -108,7 +108,7 @@ void serialize_require(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L) | |||
| 108 | STACK_CHECK(L, 0); | 108 | STACK_CHECK(L, 0); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | // ################################################################################################ | 111 | // ################################################################################################# |
| 112 | 112 | ||
| 113 | /*---=== luaG_newstate ===---*/ | 113 | /*---=== luaG_newstate ===---*/ |
| 114 | 114 | ||
| @@ -161,10 +161,9 @@ static luaL_Reg const libs[] = | |||
| 161 | 161 | ||
| 162 | static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, char const* name_, size_t len_) | 162 | static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, char const* name_, size_t len_) |
| 163 | { | 163 | { |
| 164 | int i; | 164 | for (int i{ 0 }; libs[i].name; ++i) |
| 165 | for( i = 0; libs[i].name; ++ i) | ||
| 166 | { | 165 | { |
| 167 | if( strncmp( name_, libs[i].name, len_) == 0) | 166 | if (strncmp( name_, libs[i].name, len_) == 0) |
| 168 | { | 167 | { |
| 169 | lua_CFunction libfunc = libs[i].func; | 168 | lua_CFunction libfunc = libs[i].func; |
| 170 | name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ | 169 | name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ |
| @@ -176,7 +175,7 @@ static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, char const | |||
| 176 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | 175 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) |
| 177 | luaL_requiref( L, name_, libfunc, !isLanesCore); | 176 | luaL_requiref( L, name_, libfunc, !isLanesCore); |
| 178 | // lanes.core doesn't declare a global, so scan it here and now | 177 | // lanes.core doesn't declare a global, so scan it here and now |
| 179 | if( isLanesCore == true) | 178 | if (isLanesCore == true) |
| 180 | { | 179 | { |
| 181 | populate_func_lookup_table( L, -1, name_); | 180 | populate_func_lookup_table( L, -1, name_); |
| 182 | } | 181 | } |
| @@ -220,7 +219,7 @@ void initialize_on_state_create( Universe* U, lua_State* L) | |||
| 220 | { | 219 | { |
| 221 | STACK_CHECK_START_REL(L, 1); // settings | 220 | STACK_CHECK_START_REL(L, 1); // settings |
| 222 | lua_getfield(L, -1, "on_state_create"); // settings on_state_create|nil | 221 | lua_getfield(L, -1, "on_state_create"); // settings on_state_create|nil |
| 223 | if( !lua_isnil(L, -1)) | 222 | if (!lua_isnil(L, -1)) |
| 224 | { | 223 | { |
| 225 | // store C function pointer in an internal variable | 224 | // store C function pointer in an internal variable |
| 226 | U->on_state_create_func = lua_tocfunction(L, -1); // settings on_state_create | 225 | U->on_state_create_func = lua_tocfunction(L, -1); // settings on_state_create |
| @@ -371,7 +370,7 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) | |||
| 371 | { | 370 | { |
| 372 | // special "*" case (mainly to help with LuaJIT compatibility) | 371 | // special "*" case (mainly to help with LuaJIT compatibility) |
| 373 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 372 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
| 374 | if( libs_[0] == '*' && libs_[1] == 0) | 373 | if (libs_[0] == '*' && libs_[1] == 0) |
| 375 | { | 374 | { |
| 376 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 375 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
| 377 | luaL_openlibs( L); | 376 | luaL_openlibs( L); |
| @@ -396,26 +395,25 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) | |||
| 396 | STACK_CHECK(L, 0); | 395 | STACK_CHECK(L, 0); |
| 397 | 396 | ||
| 398 | // scan all libraries, open them one by one | 397 | // scan all libraries, open them one by one |
| 399 | if( libs_) | 398 | if (libs_) |
| 400 | { | 399 | { |
| 401 | char const* p; | 400 | unsigned int len{ 0 }; |
| 402 | unsigned int len = 0; | 401 | for (char const* p{ libs_ }; *p; p += len) |
| 403 | for( p = libs_; *p; p += len) | ||
| 404 | { | 402 | { |
| 405 | // skip delimiters ('.' can be part of name for "lanes.core") | 403 | // skip delimiters ('.' can be part of name for "lanes.core") |
| 406 | while( *p && !isalnum( *p) && *p != '.') | 404 | while( *p && !isalnum(*p) && *p != '.') |
| 407 | ++ p; | 405 | ++ p; |
| 408 | // skip name | 406 | // skip name |
| 409 | len = 0; | 407 | len = 0; |
| 410 | while( isalnum( p[len]) || p[len] == '.') | 408 | while( isalnum(p[len]) || p[len] == '.') |
| 411 | ++ len; | 409 | ++ len; |
| 412 | // open library | 410 | // open library |
| 413 | open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len); | 411 | open1lib(DEBUGSPEW_PARAM_COMMA( U) L, p, len); |
| 414 | } | 412 | } |
| 415 | } | 413 | } |
| 416 | lua_gc( L, LUA_GCRESTART, 0); | 414 | lua_gc(L, LUA_GCRESTART, 0); |
| 417 | 415 | ||
| 418 | serialize_require( DEBUGSPEW_PARAM_COMMA( U) L); | 416 | serialize_require(DEBUGSPEW_PARAM_COMMA( U) L); |
| 419 | 417 | ||
| 420 | // call this after the base libraries are loaded and GC is restarted | 418 | // call this after the base libraries are loaded and GC is restarted |
| 421 | // will raise an error in from_ in case of problem | 419 | // will raise an error in from_ in case of problem |
| @@ -423,7 +421,7 @@ lua_State* luaG_newstate(Universe* U, Source from_, char const* libs_) | |||
| 423 | 421 | ||
| 424 | STACK_CHECK(L, 0); | 422 | STACK_CHECK(L, 0); |
| 425 | // after all this, register everything we find in our name<->function database | 423 | // after all this, register everything we find in our name<->function database |
| 426 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | 424 | lua_pushglobaltable(L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack |
| 427 | STACK_CHECK(L, 1); | 425 | STACK_CHECK(L, 1); |
| 428 | populate_func_lookup_table(L, -1, nullptr); | 426 | populate_func_lookup_table(L, -1, nullptr); |
| 429 | 427 | ||
diff --git a/src/state.h b/src/state.h index e1c311a..059e163 100644 --- a/src/state.h +++ b/src/state.h | |||
| @@ -8,12 +8,12 @@ class Universe; | |||
| 8 | 8 | ||
| 9 | void serialize_require(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L); | 9 | void serialize_require(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L); |
| 10 | 10 | ||
| 11 | // ################################################################################################ | 11 | // ################################################################################################# |
| 12 | 12 | ||
| 13 | [[nodiscard]] lua_State* create_state(Universe* U, lua_State* from_); | 13 | [[nodiscard]] lua_State* create_state(Universe* U, lua_State* from_); |
| 14 | [[nodiscard]] lua_State* luaG_newstate(Universe* U, Source _from, char const* libs); | 14 | [[nodiscard]] lua_State* luaG_newstate(Universe* U, Source _from, char const* libs); |
| 15 | 15 | ||
| 16 | // ################################################################################################ | 16 | // ################################################################################################# |
| 17 | 17 | ||
| 18 | void initialize_on_state_create(Universe* U, lua_State* L); | 18 | void initialize_on_state_create(Universe* U, lua_State* L); |
| 19 | void call_on_state_create(Universe* U, lua_State* L, lua_State* from_, LookupMode mode_); | 19 | void call_on_state_create(Universe* U, lua_State* L, lua_State* from_, LookupMode mode_); |
diff --git a/src/threading.cpp b/src/threading.cpp index 259693a..c7928c1 100644 --- a/src/threading.cpp +++ b/src/threading.cpp | |||
| @@ -105,8 +105,8 @@ THE SOFTWARE. | |||
| 105 | 105 | ||
| 106 | /*---=== Threading ===---*/ | 106 | /*---=== Threading ===---*/ |
| 107 | 107 | ||
| 108 | // ################################################################################################## | 108 | // ################################################################################################# |
| 109 | // ################################################################################################## | 109 | // ################################################################################################# |
| 110 | #if THREADAPI == THREADAPI_WINDOWS | 110 | #if THREADAPI == THREADAPI_WINDOWS |
| 111 | 111 | ||
| 112 | static int const gs_prio_remap[] = | 112 | static int const gs_prio_remap[] = |
| @@ -120,7 +120,7 @@ static int const gs_prio_remap[] = | |||
| 120 | THREAD_PRIORITY_TIME_CRITICAL | 120 | THREAD_PRIORITY_TIME_CRITICAL |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | // ############################################################################################### | 123 | // ################################################################################################# |
| 124 | 124 | ||
| 125 | void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) | 125 | void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) |
| 126 | { | 126 | { |
| @@ -131,7 +131,7 @@ void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) | |||
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | // ############################################################################################### | 134 | // ################################################################################################# |
| 135 | 135 | ||
| 136 | void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, [[maybe_unused]] bool sudo_) | 136 | void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, [[maybe_unused]] bool sudo_) |
| 137 | { | 137 | { |
| @@ -142,7 +142,7 @@ void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, [[maybe_unused]] boo | |||
| 142 | } | 142 | } |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | // ############################################################################################### | 145 | // ################################################################################################# |
| 146 | 146 | ||
| 147 | void THREAD_SET_AFFINITY(unsigned int aff) | 147 | void THREAD_SET_AFFINITY(unsigned int aff) |
| 148 | { | 148 | { |
| @@ -152,7 +152,7 @@ void THREAD_SET_AFFINITY(unsigned int aff) | |||
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | // ############################################################################################### | 155 | // ################################################################################################# |
| 156 | 156 | ||
| 157 | #if !defined __GNUC__ | 157 | #if !defined __GNUC__ |
| 158 | //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx | 158 | //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx |
| @@ -187,11 +187,11 @@ void THREAD_SETNAME(char const* _name) | |||
| 187 | #endif // !__GNUC__ | 187 | #endif // !__GNUC__ |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | // ################################################################################################## | 190 | // ################################################################################################# |
| 191 | // ################################################################################################## | 191 | // ################################################################################################# |
| 192 | #else // THREADAPI == THREADAPI_PTHREAD | 192 | #else // THREADAPI == THREADAPI_PTHREAD |
| 193 | // ################################################################################################## | 193 | // ################################################################################################# |
| 194 | // ################################################################################################## | 194 | // ################################################################################################# |
| 195 | 195 | ||
| 196 | // PThread (Linux, OS X, ...) | 196 | // PThread (Linux, OS X, ...) |
| 197 | // | 197 | // |
diff --git a/src/threading.h b/src/threading.h index fc35730..e13932b 100644 --- a/src/threading.h +++ b/src/threading.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #define THREADAPI_WINDOWS 1 | 7 | #define THREADAPI_WINDOWS 1 |
| 8 | #define THREADAPI_PTHREAD 2 | 8 | #define THREADAPI_PTHREAD 2 |
| 9 | 9 | ||
| 10 | #if( defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) | 10 | #if (defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) |
| 11 | //#pragma message ( "THREADAPI_WINDOWS" ) | 11 | //#pragma message ( "THREADAPI_WINDOWS" ) |
| 12 | #define THREADAPI THREADAPI_WINDOWS | 12 | #define THREADAPI THREADAPI_WINDOWS |
| 13 | #else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 13 | #else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| @@ -17,8 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | static constexpr int THREAD_PRIO_DEFAULT{ -999 }; | 18 | static constexpr int THREAD_PRIO_DEFAULT{ -999 }; |
| 19 | 19 | ||
| 20 | // ################################################################################################## | 20 | // ################################################################################################# |
| 21 | // ################################################################################################## | 21 | // ################################################################################################# |
| 22 | #if THREADAPI == THREADAPI_WINDOWS | 22 | #if THREADAPI == THREADAPI_WINDOWS |
| 23 | 23 | ||
| 24 | #if defined(PLATFORM_XBOX) | 24 | #if defined(PLATFORM_XBOX) |
| @@ -43,11 +43,11 @@ static constexpr int THREAD_PRIO_DEFAULT{ -999 }; | |||
| 43 | static constexpr int THREAD_PRIO_MIN{ -3 }; | 43 | static constexpr int THREAD_PRIO_MIN{ -3 }; |
| 44 | static constexpr int THREAD_PRIO_MAX{ +3 }; | 44 | static constexpr int THREAD_PRIO_MAX{ +3 }; |
| 45 | 45 | ||
| 46 | // ################################################################################################## | 46 | // ################################################################################################# |
| 47 | // ################################################################################################## | 47 | // ################################################################################################# |
| 48 | #else // THREADAPI == THREADAPI_PTHREAD | 48 | #else // THREADAPI == THREADAPI_PTHREAD |
| 49 | // ################################################################################################## | 49 | // ################################################################################################# |
| 50 | // ################################################################################################## | 50 | // ################################################################################################# |
| 51 | 51 | ||
| 52 | // PThread (Linux, OS X, ...) | 52 | // PThread (Linux, OS X, ...) |
| 53 | 53 | ||
| @@ -65,8 +65,8 @@ static constexpr int THREAD_PRIO_MIN{ -3 }; | |||
| 65 | static constexpr int THREAD_PRIO_MAX{ +3 }; | 65 | static constexpr int THREAD_PRIO_MAX{ +3 }; |
| 66 | 66 | ||
| 67 | #endif // THREADAPI == THREADAPI_PTHREAD | 67 | #endif // THREADAPI == THREADAPI_PTHREAD |
| 68 | // ################################################################################################## | 68 | // ################################################################################################# |
| 69 | // ################################################################################################## | 69 | // ################################################################################################# |
| 70 | 70 | ||
| 71 | void THREAD_SETNAME(char const* _name); | 71 | void THREAD_SETNAME(char const* _name); |
| 72 | void THREAD_SET_PRIORITY(int prio_, bool sudo_); | 72 | void THREAD_SET_PRIORITY(int prio_, bool sudo_); |
diff --git a/src/tools.cpp b/src/tools.cpp index ad706be..cd25eda 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
| @@ -35,13 +35,12 @@ THE SOFTWARE. | |||
| 35 | 35 | ||
| 36 | #include "universe.h" | 36 | #include "universe.h" |
| 37 | 37 | ||
| 38 | // functions implemented in deep.c | ||
| 39 | extern void push_registry_subtable( lua_State* L, UniqueKey key_); | ||
| 40 | |||
| 41 | DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); | 38 | DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); |
| 42 | 39 | ||
| 40 | // crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | ||
| 41 | static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | ||
| 43 | 42 | ||
| 44 | // ################################################################################################ | 43 | // ################################################################################################# |
| 45 | 44 | ||
| 46 | /* | 45 | /* |
| 47 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it | 46 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it |
| @@ -76,7 +75,7 @@ void push_registry_subtable_mode( lua_State* L, UniqueKey key_, const char* mode | |||
| 76 | ASSERT_L(lua_istable(L, -1)); | 75 | ASSERT_L(lua_istable(L, -1)); |
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | // ################################################################################################ | 78 | // ################################################################################################# |
| 80 | 79 | ||
| 81 | /* | 80 | /* |
| 82 | * Push a registry subtable (keyed by unique 'key_') onto the stack. | 81 | * Push a registry subtable (keyed by unique 'key_') onto the stack. |
| @@ -87,60 +86,7 @@ void push_registry_subtable( lua_State* L, UniqueKey key_) | |||
| 87 | push_registry_subtable_mode(L, key_, nullptr); | 86 | push_registry_subtable_mode(L, key_, nullptr); |
| 88 | } | 87 | } |
| 89 | 88 | ||
| 90 | // ################################################################################################ | 89 | // ################################################################################################# |
| 91 | |||
| 92 | /*---=== luaG_dump ===---*/ | ||
| 93 | #ifdef _DEBUG | ||
| 94 | void luaG_dump( lua_State* L) | ||
| 95 | { | ||
| 96 | int top = lua_gettop( L); | ||
| 97 | int i; | ||
| 98 | |||
| 99 | fprintf( stderr, "\n\tDEBUG STACK:\n"); | ||
| 100 | |||
| 101 | if( top == 0) | ||
| 102 | fprintf( stderr, "\t(none)\n"); | ||
| 103 | |||
| 104 | for( i = 1; i <= top; ++ i) | ||
| 105 | { | ||
| 106 | LuaType type{ lua_type_as_enum(L, i) }; | ||
| 107 | |||
| 108 | fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type)); | ||
| 109 | |||
| 110 | // Print item contents here... | ||
| 111 | // | ||
| 112 | // Note: this requires 'tostring()' to be defined. If it is NOT, | ||
| 113 | // enable it for more debugging. | ||
| 114 | // | ||
| 115 | STACK_CHECK_START_REL(L, 0); | ||
| 116 | STACK_GROW( L, 2); | ||
| 117 | |||
| 118 | lua_getglobal( L, "tostring"); | ||
| 119 | // | ||
| 120 | // [-1]: tostring function, or nil | ||
| 121 | |||
| 122 | if( !lua_isfunction( L, -1)) | ||
| 123 | { | ||
| 124 | fprintf( stderr, "('tostring' not available)"); | ||
| 125 | } | ||
| 126 | else | ||
| 127 | { | ||
| 128 | lua_pushvalue( L, i); | ||
| 129 | lua_call( L, 1 /*args*/, 1 /*retvals*/); | ||
| 130 | |||
| 131 | // Don't trust the string contents | ||
| 132 | // | ||
| 133 | fprintf( stderr, "%s", lua_tostring( L, -1)); | ||
| 134 | } | ||
| 135 | lua_pop( L, 1); | ||
| 136 | STACK_CHECK( L, 0); | ||
| 137 | fprintf( stderr, "\n"); | ||
| 138 | } | ||
| 139 | fprintf( stderr, "\n"); | ||
| 140 | } | ||
| 141 | #endif // _DEBUG | ||
| 142 | |||
| 143 | // ################################################################################################ | ||
| 144 | 90 | ||
| 145 | // same as PUC-Lua l_alloc | 91 | // same as PUC-Lua l_alloc |
| 146 | extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) | 92 | extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) |
| @@ -231,7 +177,7 @@ void initialize_allocator_function(Universe* U, lua_State* L) | |||
| 231 | STACK_CHECK(L, 1); | 177 | STACK_CHECK(L, 1); |
| 232 | } | 178 | } |
| 233 | 179 | ||
| 234 | // ################################################################################################ | 180 | // ################################################################################################# |
| 235 | 181 | ||
| 236 | [[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) | 182 | [[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) |
| 237 | { | 183 | { |
| @@ -239,7 +185,6 @@ void initialize_allocator_function(Universe* U, lua_State* L) | |||
| 239 | return 666; | 185 | return 666; |
| 240 | } | 186 | } |
| 241 | 187 | ||
| 242 | |||
| 243 | /* | 188 | /* |
| 244 | * differentiation between C, bytecode and JIT-fast functions | 189 | * differentiation between C, bytecode and JIT-fast functions |
| 245 | * | 190 | * |
| @@ -262,25 +207,25 @@ enum FuncSubType | |||
| 262 | FST_FastJIT | 207 | FST_FastJIT |
| 263 | } ; | 208 | } ; |
| 264 | 209 | ||
| 265 | FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) | 210 | FuncSubType luaG_getfuncsubtype(lua_State* L, int _i) |
| 266 | { | 211 | { |
| 267 | if( lua_tocfunction( L, _i)) | 212 | if (lua_tocfunction(L, _i)) // nullptr for LuaJIT-fast && bytecode functions |
| 268 | { | 213 | { |
| 269 | return FST_Native; | 214 | return FST_Native; |
| 270 | } | 215 | } |
| 271 | { | 216 | { |
| 272 | int mustpush = 0, dumpres; | 217 | int mustpush{ 0 }; |
| 273 | if( lua_absindex( L, _i) != lua_gettop( L)) | 218 | if (lua_absindex(L, _i) != lua_gettop(L)) |
| 274 | { | 219 | { |
| 275 | lua_pushvalue( L, _i); | 220 | lua_pushvalue(L, _i); |
| 276 | mustpush = 1; | 221 | mustpush = 1; |
| 277 | } | 222 | } |
| 278 | // the provided writer fails with code 666 | 223 | // the provided writer fails with code 666 |
| 279 | // therefore, anytime we get 666, this means that lua_dump() attempted a dump | 224 | // therefore, anytime we get 666, this means that lua_dump() attempted a dump |
| 280 | // all other cases mean this is either a C or LuaJIT-fast function | 225 | // all other cases mean this is either a C or LuaJIT-fast function |
| 281 | dumpres = lua504_dump(L, dummy_writer, nullptr, 0); | 226 | int const dumpres{ lua504_dump(L, dummy_writer, nullptr, 0) }; |
| 282 | lua_pop( L, mustpush); | 227 | lua_pop(L, mustpush); |
| 283 | if( dumpres == 666) | 228 | if (dumpres == 666) |
| 284 | { | 229 | { |
| 285 | return FST_Bytecode; | 230 | return FST_Bytecode; |
| 286 | } | 231 | } |
| @@ -290,40 +235,28 @@ FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) | |||
| 290 | 235 | ||
| 291 | // ################################################################################################# | 236 | // ################################################################################################# |
| 292 | 237 | ||
| 293 | [[nodiscard]] static lua_CFunction luaG_tocfunction(lua_State* L, int _i, FuncSubType* _out) | ||
| 294 | { | ||
| 295 | lua_CFunction p = lua_tocfunction( L, _i); | ||
| 296 | *_out = luaG_getfuncsubtype( L, _i); | ||
| 297 | return p; | ||
| 298 | } | ||
| 299 | |||
| 300 | // crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | ||
| 301 | static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | ||
| 302 | |||
| 303 | // ################################################################################################# | ||
| 304 | |||
| 305 | // inspired from tconcat() in ltablib.c | 238 | // inspired from tconcat() in ltablib.c |
| 306 | [[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) | 239 | [[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) |
| 307 | { | 240 | { |
| 308 | int i = 1; | ||
| 309 | luaL_Buffer b; | 241 | luaL_Buffer b; |
| 310 | STACK_CHECK_START_REL(L, 0); | 242 | STACK_CHECK_START_REL(L, 0); |
| 311 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... | 243 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... |
| 312 | luaL_buffinit( L, &b); // ... {} ... &b? | 244 | luaL_buffinit(L, &b); // ... {} ... &b? |
| 313 | for( ; i < last; ++ i) | 245 | int i = 1; |
| 246 | for (; i < last; ++i) | ||
| 314 | { | 247 | { |
| 315 | lua_rawgeti( L, t, i); | 248 | lua_rawgeti( L, t, i); |
| 316 | luaL_addvalue( &b); | 249 | luaL_addvalue( &b); |
| 317 | luaL_addlstring(&b, "/", 1); | 250 | luaL_addlstring(&b, "/", 1); |
| 318 | } | 251 | } |
| 319 | if( i == last) // add last value (if interval was not empty) | 252 | if (i == last) // add last value (if interval was not empty) |
| 320 | { | 253 | { |
| 321 | lua_rawgeti( L, t, i); | 254 | lua_rawgeti(L, t, i); |
| 322 | luaL_addvalue( &b); | 255 | luaL_addvalue(&b); |
| 323 | } | 256 | } |
| 324 | // &b is popped at that point (-> replaced by the result) | 257 | // &b is popped at that point (-> replaced by the result) |
| 325 | luaL_pushresult( &b); // ... {} ... "<result>" | 258 | luaL_pushresult(&b); // ... {} ... "<result>" |
| 326 | STACK_CHECK( L, 1); | 259 | STACK_CHECK(L, 1); |
| 327 | return lua_tolstring( L, -1, length); | 260 | return lua_tolstring( L, -1, length); |
| 328 | } | 261 | } |
| 329 | 262 | ||
| @@ -337,12 +270,12 @@ static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull }; | |||
| 337 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter | 270 | * if we already had an entry of type [o] = ..., replace the name if the new one is shorter |
| 338 | * pops the processed object from the stack | 271 | * pops the processed object from the stack |
| 339 | */ | 272 | */ |
| 340 | static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, int _ctx_base, int _depth) | 273 | static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _depth) |
| 341 | { | 274 | { |
| 342 | // slot 1 in the stack contains the table that receives everything we found | 275 | // slot 1 in the stack contains the table that receives everything we found |
| 343 | int const dest = _ctx_base; | 276 | int const dest{ _ctx_base }; |
| 344 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 277 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
| 345 | int const fqn = _ctx_base + 1; | 278 | int const fqn{ _ctx_base + 1 }; |
| 346 | 279 | ||
| 347 | size_t prevNameLength, newNameLength; | 280 | size_t prevNameLength, newNameLength; |
| 348 | char const* prevName; | 281 | char const* prevName; |
| @@ -352,16 +285,16 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
| 352 | 285 | ||
| 353 | STACK_CHECK_START_REL(L, 0); | 286 | STACK_CHECK_START_REL(L, 0); |
| 354 | // first, raise an error if the function is already known | 287 | // first, raise an error if the function is already known |
| 355 | lua_pushvalue( L, -1); // ... {bfc} k o o | 288 | lua_pushvalue(L, -1); // ... {bfc} k o o |
| 356 | lua_rawget( L, dest); // ... {bfc} k o name? | 289 | lua_rawget(L, dest); // ... {bfc} k o name? |
| 357 | prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) | 290 | prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) |
| 358 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) | 291 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) |
| 359 | lua_pushvalue( L, -3); // ... {bfc} k o name? k | 292 | lua_pushvalue(L, -3); // ... {bfc} k o name? k |
| 360 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING); | 293 | ASSERT_L(lua_type(L, -1) == LUA_TNUMBER || lua_type(L, -1) == LUA_TSTRING); |
| 361 | ++ _depth; | 294 | ++_depth; |
| 362 | lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? | 295 | lua_rawseti(L, fqn, _depth); // ... {bfc} k o name? |
| 363 | // generate name | 296 | // generate name |
| 364 | DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength);// ... {bfc} k o name? "f.q.n" | 297 | DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n" |
| 365 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | 298 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order |
| 366 | // on different VMs even when the tables are populated the exact same way. | 299 | // on different VMs even when the tables are populated the exact same way. |
| 367 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | 300 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), |
| @@ -375,36 +308,36 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
| 375 | { | 308 | { |
| 376 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); | 309 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); |
| 377 | // the previous name is 'smaller' than the one we just generated: keep it! | 310 | // the previous name is 'smaller' than the one we just generated: keep it! |
| 378 | lua_pop( L, 3); // ... {bfc} k | 311 | lua_pop(L, 3); // ... {bfc} k |
| 379 | } | 312 | } |
| 380 | else | 313 | else |
| 381 | { | 314 | { |
| 382 | // the name we generated is either the first one, or a better fit for our purposes | 315 | // the name we generated is either the first one, or a better fit for our purposes |
| 383 | if( prevName) | 316 | if (prevName) |
| 384 | { | 317 | { |
| 385 | // clear the previous name for the database to avoid clutter | 318 | // clear the previous name for the database to avoid clutter |
| 386 | lua_insert( L, -2); // ... {bfc} k o "f.q.n" prevName | 319 | lua_insert(L, -2); // ... {bfc} k o "f.q.n" prevName |
| 387 | // t[prevName] = nil | 320 | // t[prevName] = nil |
| 388 | lua_pushnil( L); // ... {bfc} k o "f.q.n" prevName nil | 321 | lua_pushnil(L); // ... {bfc} k o "f.q.n" prevName nil |
| 389 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | 322 | lua_rawset(L, dest); // ... {bfc} k o "f.q.n" |
| 390 | } | 323 | } |
| 391 | else | 324 | else |
| 392 | { | 325 | { |
| 393 | lua_remove( L, -2); // ... {bfc} k o "f.q.n" | 326 | lua_remove(L, -2); // ... {bfc} k o "f.q.n" |
| 394 | } | 327 | } |
| 395 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); | 328 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename(L, lua_type( L, -2)), newName)); |
| 396 | // prepare the stack for database feed | 329 | // prepare the stack for database feed |
| 397 | lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" | 330 | lua_pushvalue(L, -1); // ... {bfc} k o "f.q.n" "f.q.n" |
| 398 | lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o | 331 | lua_pushvalue(L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o |
| 399 | ASSERT_L( lua_rawequal( L, -1, -4)); | 332 | ASSERT_L(lua_rawequal(L, -1, -4)); |
| 400 | ASSERT_L( lua_rawequal( L, -2, -3)); | 333 | ASSERT_L(lua_rawequal(L, -2, -3)); |
| 401 | // t["f.q.n"] = o | 334 | // t["f.q.n"] = o |
| 402 | lua_rawset( L, dest); // ... {bfc} k o "f.q.n" | 335 | lua_rawset(L, dest); // ... {bfc} k o "f.q.n" |
| 403 | // t[o] = "f.q.n" | 336 | // t[o] = "f.q.n" |
| 404 | lua_rawset( L, dest); // ... {bfc} k | 337 | lua_rawset(L, dest); // ... {bfc} k |
| 405 | // remove table name from fqn stack | 338 | // remove table name from fqn stack |
| 406 | lua_pushnil( L); // ... {bfc} k nil | 339 | lua_pushnil(L); // ... {bfc} k nil |
| 407 | lua_rawseti( L, fqn, _depth); // ... {bfc} k | 340 | lua_rawseti(L, fqn, _depth); // ... {bfc} k |
| 408 | } | 341 | } |
| 409 | -- _depth; | 342 | -- _depth; |
| 410 | STACK_CHECK(L, -1); | 343 | STACK_CHECK(L, -1); |
| @@ -414,122 +347,121 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L | |||
| 414 | 347 | ||
| 415 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) | 348 | static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) |
| 416 | { | 349 | { |
| 417 | lua_Integer visit_count; | ||
| 418 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 350 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
| 419 | int const fqn = _ctx_base + 1; | 351 | int const fqn = _ctx_base + 1; |
| 420 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops | 352 | // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops |
| 421 | int const cache = _ctx_base + 2; | 353 | int const cache = _ctx_base + 2; |
| 422 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) | 354 | // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) |
| 423 | int const breadth_first_cache = lua_gettop( L) + 1; | 355 | int const breadth_first_cache = lua_gettop(L) + 1; |
| 424 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); | 356 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); |
| 425 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 357 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 426 | 358 | ||
| 427 | STACK_GROW( L, 6); | 359 | STACK_GROW(L, 6); |
| 428 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) | 360 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) |
| 429 | STACK_CHECK_START_REL(L, 0); // ... {_i} | 361 | STACK_CHECK_START_REL(L, 0); // ... {_i} |
| 430 | 362 | ||
| 431 | // if object is a userdata, replace it by its metatable | 363 | // if object is a userdata, replace it by its metatable |
| 432 | if( lua_type( L, _i) == LUA_TUSERDATA) | 364 | if (lua_type(L, _i) == LUA_TUSERDATA) |
| 433 | { | 365 | { |
| 434 | lua_getmetatable( L, _i); // ... {_i} mt | 366 | lua_getmetatable(L, _i); // ... {_i} mt |
| 435 | lua_replace( L, _i); // ... {_i} | 367 | lua_replace(L, _i); // ... {_i} |
| 436 | } | 368 | } |
| 437 | 369 | ||
| 438 | // if table is already visited, we are done | 370 | // if table is already visited, we are done |
| 439 | lua_pushvalue( L, _i); // ... {_i} {} | 371 | lua_pushvalue(L, _i); // ... {_i} {} |
| 440 | lua_rawget( L, cache); // ... {_i} nil|n | 372 | lua_rawget(L, cache); // ... {_i} nil|n |
| 441 | visit_count = lua_tointeger( L, -1); // 0 if nil, else n | 373 | lua_Integer visit_count{ lua_tointeger(L, -1) }; // 0 if nil, else n |
| 442 | lua_pop( L, 1); // ... {_i} | 374 | lua_pop(L, 1); // ... {_i} |
| 443 | STACK_CHECK( L, 0); | 375 | STACK_CHECK(L, 0); |
| 444 | if( visit_count > 0) | 376 | if (visit_count > 0) |
| 445 | { | 377 | { |
| 446 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); | 378 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); |
| 447 | return; | 379 | return; |
| 448 | } | 380 | } |
| 449 | 381 | ||
| 450 | // remember we visited this table (1-visit count) | 382 | // remember we visited this table (1-visit count) |
| 451 | lua_pushvalue( L, _i); // ... {_i} {} | 383 | lua_pushvalue(L, _i); // ... {_i} {} |
| 452 | lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 | 384 | lua_pushinteger(L, visit_count + 1); // ... {_i} {} 1 |
| 453 | lua_rawset( L, cache); // ... {_i} | 385 | lua_rawset(L, cache); // ... {_i} |
| 454 | STACK_CHECK( L, 0); | 386 | STACK_CHECK(L, 0); |
| 455 | 387 | ||
| 456 | // this table is at breadth_first_cache index | 388 | // this table is at breadth_first_cache index |
| 457 | lua_newtable( L); // ... {_i} {bfc} | 389 | lua_newtable(L); // ... {_i} {bfc} |
| 458 | ASSERT_L( lua_gettop( L) == breadth_first_cache); | 390 | ASSERT_L( lua_gettop(L) == breadth_first_cache); |
| 459 | // iterate over all entries in the processed table | 391 | // iterate over all entries in the processed table |
| 460 | lua_pushnil( L); // ... {_i} {bfc} nil | 392 | lua_pushnil(L); // ... {_i} {bfc} nil |
| 461 | while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v | 393 | while( lua_next(L, _i) != 0) // ... {_i} {bfc} k v |
| 462 | { | 394 | { |
| 463 | // just for debug, not actually needed | 395 | // just for debug, not actually needed |
| 464 | //char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; | 396 | //char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string"; |
| 465 | // subtable: process it recursively | 397 | // subtable: process it recursively |
| 466 | if( lua_istable( L, -1)) // ... {_i} {bfc} k {} | 398 | if (lua_istable(L, -1)) // ... {_i} {bfc} k {} |
| 467 | { | 399 | { |
| 468 | // increment visit count to make sure we will actually scan it at this recursive level | 400 | // increment visit count to make sure we will actually scan it at this recursive level |
| 469 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 401 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
| 470 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {} | 402 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} {} |
| 471 | lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n? | 403 | lua_rawget(L, cache); // ... {_i} {bfc} k {} {} n? |
| 472 | visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1 | 404 | visit_count = lua_tointeger(L, -1) + 1; // 1 if we got nil, else n+1 |
| 473 | lua_pop( L, 1); // ... {_i} {bfc} k {} {} | 405 | lua_pop(L, 1); // ... {_i} {bfc} k {} {} |
| 474 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | 406 | lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n |
| 475 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | 407 | lua_rawset(L, cache); // ... {_i} {bfc} k {} |
| 476 | // store the table in the breadth-first cache | 408 | // store the table in the breadth-first cache |
| 477 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 409 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k |
| 478 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k {} | 410 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k {} |
| 479 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k {} | 411 | lua_rawset(L, breadth_first_cache); // ... {_i} {bfc} k {} |
| 480 | // generate a name, and if we already had one name, keep whichever is the shorter | 412 | // generate a name, and if we already had one name, keep whichever is the shorter |
| 481 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k | 413 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k |
| 482 | } | 414 | } |
| 483 | else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func | 415 | else if (lua_isfunction(L, -1) && (luaG_getfuncsubtype(L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func |
| 484 | { | 416 | { |
| 485 | // generate a name, and if we already had one name, keep whichever is the shorter | 417 | // generate a name, and if we already had one name, keep whichever is the shorter |
| 486 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k | 418 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k |
| 487 | } | 419 | } |
| 488 | else | 420 | else |
| 489 | { | 421 | { |
| 490 | lua_pop( L, 1); // ... {_i} {bfc} k | 422 | lua_pop(L, 1); // ... {_i} {bfc} k |
| 491 | } | 423 | } |
| 492 | STACK_CHECK( L, 2); | 424 | STACK_CHECK(L, 2); |
| 493 | } | 425 | } |
| 494 | // now process the tables we encountered at that depth | 426 | // now process the tables we encountered at that depth |
| 495 | ++ _depth; | 427 | ++ _depth; |
| 496 | lua_pushnil( L); // ... {_i} {bfc} nil | 428 | lua_pushnil(L); // ... {_i} {bfc} nil |
| 497 | while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} | 429 | while (lua_next(L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} |
| 498 | { | 430 | { |
| 499 | DEBUGSPEW_CODE( char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"); | 431 | DEBUGSPEW_CODE(char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string"); |
| 500 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); | 432 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); |
| 501 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 433 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 502 | // un-visit this table in case we do need to process it | 434 | // un-visit this table in case we do need to process it |
| 503 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 435 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
| 504 | lua_rawget( L, cache); // ... {_i} {bfc} k {} n | 436 | lua_rawget(L, cache); // ... {_i} {bfc} k {} n |
| 505 | ASSERT_L( lua_type( L, -1) == LUA_TNUMBER); | 437 | ASSERT_L(lua_type(L, -1) == LUA_TNUMBER); |
| 506 | visit_count = lua_tointeger( L, -1) - 1; | 438 | visit_count = lua_tointeger(L, -1) - 1; |
| 507 | lua_pop( L, 1); // ... {_i} {bfc} k {} | 439 | lua_pop(L, 1); // ... {_i} {bfc} k {} |
| 508 | lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} | 440 | lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} |
| 509 | if( visit_count > 0) | 441 | if (visit_count > 0) |
| 510 | { | 442 | { |
| 511 | lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n | 443 | lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n |
| 512 | } | 444 | } |
| 513 | else | 445 | else |
| 514 | { | 446 | { |
| 515 | lua_pushnil( L); // ... {_i} {bfc} k {} {} nil | 447 | lua_pushnil(L); // ... {_i} {bfc} k {} {} nil |
| 516 | } | 448 | } |
| 517 | lua_rawset( L, cache); // ... {_i} {bfc} k {} | 449 | lua_rawset(L, cache); // ... {_i} {bfc} k {} |
| 518 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) | 450 | // push table name in fqn stack (note that concatenation will crash if name is a not string!) |
| 519 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 451 | lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k |
| 520 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} | 452 | lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} k {} |
| 521 | populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, lua_gettop( L), _depth); | 453 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, lua_gettop(L), _depth); |
| 522 | lua_pop( L, 1); // ... {_i} {bfc} k | 454 | lua_pop(L, 1); // ... {_i} {bfc} k |
| 523 | STACK_CHECK( L, 2); | 455 | STACK_CHECK(L, 2); |
| 524 | } | 456 | } |
| 525 | // remove table name from fqn stack | 457 | // remove table name from fqn stack |
| 526 | lua_pushnil( L); // ... {_i} {bfc} nil | 458 | lua_pushnil(L); // ... {_i} {bfc} nil |
| 527 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} | 459 | lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} |
| 528 | -- _depth; | 460 | -- _depth; |
| 529 | // we are done with our cache | 461 | // we are done with our cache |
| 530 | lua_pop( L, 1); // ... {_i} | 462 | lua_pop(L, 1); // ... {_i} |
| 531 | STACK_CHECK( L, 0); | 463 | STACK_CHECK(L, 0); |
| 532 | // we are done // ... {_i} {bfc} | 464 | // we are done // ... {_i} {bfc} |
| 533 | } | 465 | } |
| 534 | 466 | ||
| 535 | // ################################################################################################# | 467 | // ################################################################################################# |
| @@ -542,59 +474,59 @@ void populate_func_lookup_table(lua_State* L, int i_, char const* name_) | |||
| 542 | int const ctx_base = lua_gettop(L) + 1; | 474 | int const ctx_base = lua_gettop(L) + 1; |
| 543 | int const in_base = lua_absindex(L, i_); | 475 | int const in_base = lua_absindex(L, i_); |
| 544 | int start_depth = 0; | 476 | int start_depth = 0; |
| 545 | DEBUGSPEW_CODE( Universe* U = universe_get( L)); | 477 | DEBUGSPEW_CODE(Universe* U = universe_get(L)); |
| 546 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); | 478 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); |
| 547 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 479 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 548 | STACK_GROW(L, 3); | 480 | STACK_GROW(L, 3); |
| 549 | STACK_CHECK_START_REL(L, 0); | 481 | STACK_CHECK_START_REL(L, 0); |
| 550 | LOOKUP_REGKEY.pushValue(L); // {} | 482 | LOOKUP_REGKEY.pushValue(L); // {} |
| 551 | STACK_CHECK( L, 1); | 483 | STACK_CHECK(L, 1); |
| 552 | ASSERT_L( lua_istable( L, -1)); | 484 | ASSERT_L(lua_istable(L, -1)); |
| 553 | if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function | 485 | if (lua_type(L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function |
| 554 | { | 486 | { |
| 555 | name_ = name_ ? name_ : "nullptr"; | 487 | name_ = name_ ? name_ : "nullptr"; |
| 556 | lua_pushvalue( L, in_base); // {} f | 488 | lua_pushvalue(L, in_base); // {} f |
| 557 | lua_pushstring( L, name_); // {} f _name | 489 | lua_pushstring(L, name_); // {} f _name |
| 558 | lua_rawset( L, -3); // {} | 490 | lua_rawset(L, -3); // {} |
| 559 | lua_pushstring( L, name_); // {} _name | 491 | lua_pushstring(L, name_); // {} _name |
| 560 | lua_pushvalue( L, in_base); // {} _name f | 492 | lua_pushvalue(L, in_base); // {} _name f |
| 561 | lua_rawset( L, -3); // {} | 493 | lua_rawset(L, -3); // {} |
| 562 | lua_pop( L, 1); // | 494 | lua_pop(L, 1); // |
| 563 | } | 495 | } |
| 564 | else if( lua_type( L, in_base) == LUA_TTABLE) | 496 | else if (lua_type(L, in_base) == LUA_TTABLE) |
| 565 | { | 497 | { |
| 566 | lua_newtable(L); // {} {fqn} | 498 | lua_newtable(L); // {} {fqn} |
| 567 | if( name_) | 499 | if (name_) |
| 568 | { | 500 | { |
| 569 | STACK_CHECK( L, 2); | 501 | STACK_CHECK(L, 2); |
| 570 | lua_pushstring( L, name_); // {} {fqn} "name" | 502 | lua_pushstring(L, name_); // {} {fqn} "name" |
| 571 | // generate a name, and if we already had one name, keep whichever is the shorter | 503 | // generate a name, and if we already had one name, keep whichever is the shorter |
| 572 | lua_pushvalue( L, in_base); // {} {fqn} "name" t | 504 | lua_pushvalue(L, in_base); // {} {fqn} "name" t |
| 573 | update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, start_depth); // {} {fqn} "name" | 505 | update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, start_depth); // {} {fqn} "name" |
| 574 | // don't forget to store the name at the bottom of the fqn stack | 506 | // don't forget to store the name at the bottom of the fqn stack |
| 575 | ++ start_depth; | 507 | ++ start_depth; |
| 576 | lua_rawseti( L, -2, start_depth); // {} {fqn} | 508 | lua_rawseti(L, -2, start_depth); // {} {fqn} |
| 577 | STACK_CHECK( L, 2); | 509 | STACK_CHECK(L, 2); |
| 578 | } | 510 | } |
| 579 | // retrieve the cache, create it if we haven't done it yet | 511 | // retrieve the cache, create it if we haven't done it yet |
| 580 | LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? | 512 | LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? |
| 581 | if( lua_isnil( L, -1)) | 513 | if (lua_isnil(L, -1)) |
| 582 | { | 514 | { |
| 583 | lua_pop( L, 1); // {} {fqn} | 515 | lua_pop(L, 1); // {} {fqn} |
| 584 | lua_newtable( L); // {} {fqn} {cache} | 516 | lua_newtable(L); // {} {fqn} {cache} |
| 585 | LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); | 517 | LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); |
| 586 | STACK_CHECK( L, 3); | 518 | STACK_CHECK(L, 3); |
| 587 | } | 519 | } |
| 588 | // process everything we find in that table, filling in lookup data for all functions and tables we see there | 520 | // process everything we find in that table, filling in lookup data for all functions and tables we see there |
| 589 | populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, in_base, start_depth); | 521 | populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, in_base, start_depth); |
| 590 | lua_pop( L, 3); | 522 | lua_pop(L, 3); |
| 591 | } | 523 | } |
| 592 | else | 524 | else |
| 593 | { | 525 | { |
| 594 | lua_pop( L, 1); // | 526 | lua_pop(L, 1); // |
| 595 | (void) luaL_error( L, "unsupported module type %s", lua_typename( L, lua_type( L, in_base))); | 527 | luaL_error(L, "unsupported module type %s", lua_typename(L, lua_type(L, in_base))); // doesn't return |
| 596 | } | 528 | } |
| 597 | STACK_CHECK( L, 0); | 529 | STACK_CHECK(L, 0); |
| 598 | } | 530 | } |
| 599 | 531 | ||
| 600 | // ################################################################################################# | 532 | // ################################################################################################# |
| @@ -609,38 +541,34 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 609 | */ | 541 | */ |
| 610 | [[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) | 542 | [[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) |
| 611 | { | 543 | { |
| 612 | lua_Integer id; | 544 | i = lua_absindex(L, i); |
| 613 | 545 | ||
| 614 | i = lua_absindex( L, i); | 546 | STACK_GROW(L, 3); |
| 615 | |||
| 616 | STACK_GROW( L, 3); | ||
| 617 | 547 | ||
| 618 | STACK_CHECK_START_REL(L, 0); | 548 | STACK_CHECK_START_REL(L, 0); |
| 619 | push_registry_subtable( L, REG_MTID); // ... _R[REG_MTID] | 549 | push_registry_subtable(L, REG_MTID); // ... _R[REG_MTID] |
| 620 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} | 550 | lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} |
| 621 | lua_rawget( L, -2); // ... _R[REG_MTID] mtk? | 551 | lua_rawget(L, -2); // ... _R[REG_MTID] mtk? |
| 622 | 552 | ||
| 623 | id = lua_tointeger( L, -1); // 0 for nil | 553 | lua_Integer id{ lua_tointeger(L, -1) }; // 0 for nil |
| 624 | lua_pop( L, 1); // ... _R[REG_MTID] | 554 | lua_pop(L, 1); // ... _R[REG_MTID] |
| 625 | STACK_CHECK( L, 1); | 555 | STACK_CHECK(L, 1); |
| 626 | 556 | ||
| 627 | if( id == 0) | 557 | if (id == 0) |
| 628 | { | 558 | { |
| 629 | id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed); | 559 | id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed); |
| 630 | 560 | ||
| 631 | /* Create two-way references: id_uint <-> table | 561 | // Create two-way references: id_uint <-> table |
| 632 | */ | 562 | lua_pushvalue(L, i); // ... _R[REG_MTID] {mt} |
| 633 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} | 563 | lua_pushinteger(L, id); // ... _R[REG_MTID] {mt} id |
| 634 | lua_pushinteger( L, id); // ... _R[REG_MTID] {mt} id | 564 | lua_rawset(L, -3); // ... _R[REG_MTID] |
| 635 | lua_rawset( L, -3); // ... _R[REG_MTID] | ||
| 636 | 565 | ||
| 637 | lua_pushinteger( L, id); // ... _R[REG_MTID] id | 566 | lua_pushinteger(L, id); // ... _R[REG_MTID] id |
| 638 | lua_pushvalue( L, i); // ... _R[REG_MTID] id {mt} | 567 | lua_pushvalue(L, i); // ... _R[REG_MTID] id {mt} |
| 639 | lua_rawset( L, -3); // ... _R[REG_MTID] | 568 | lua_rawset(L, -3); // ... _R[REG_MTID] |
| 640 | } | 569 | } |
| 641 | lua_pop( L, 1); // ... | 570 | lua_pop(L, 1); // ... |
| 642 | 571 | STACK_CHECK(L, 0); | |
| 643 | STACK_CHECK( L, 0); | ||
| 644 | 572 | ||
| 645 | return id; | 573 | return id; |
| 646 | } | 574 | } |
| @@ -684,7 +612,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 684 | if (mode_ == LookupMode::FromKeeper) | 612 | if (mode_ == LookupMode::FromKeeper) |
| 685 | { | 613 | { |
| 686 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! | 614 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! |
| 687 | if( f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) | 615 | if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) |
| 688 | { | 616 | { |
| 689 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" | 617 | lua_getupvalue( L, i, 1); // ... v ... "f.q.n" |
| 690 | } | 618 | } |
| @@ -722,7 +650,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 722 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); | 650 | typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); |
| 723 | // second return value can be nil if the table was not found | 651 | // second return value can be nil if the table was not found |
| 724 | // probable reason: the function was removed from the source Lua state before Lanes was required. | 652 | // probable reason: the function was removed from the source Lua state before Lanes was required. |
| 725 | if( lua_isnil( L, -1)) | 653 | if (lua_isnil( L, -1)) |
| 726 | { | 654 | { |
| 727 | gotchaA = " referenced by"; | 655 | gotchaA = " referenced by"; |
| 728 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | 656 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; |
| @@ -744,22 +672,20 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 744 | 672 | ||
| 745 | // ################################################################################################# | 673 | // ################################################################################################# |
| 746 | 674 | ||
| 747 | /* | 675 | // Push a looked-up table, or nothing if we found nothing |
| 748 | * Push a looked-up table, or nothing if we found nothing | 676 | [[nodiscard]] bool InterCopyContext::lookup_table() const |
| 749 | */ | ||
| 750 | [[nodiscard]] static bool lookup_table(Dest L2, Source L1, SourceIndex i_, LookupMode mode_, char const* upName_) | ||
| 751 | { | 677 | { |
| 752 | // get the name of the table we want to send | 678 | // get the name of the table we want to send |
| 753 | size_t len; | 679 | size_t len; |
| 754 | char const* fqn = find_lookup_name(L1, i_, mode_, upName_, &len); | 680 | char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); |
| 755 | if (nullptr == fqn) // name not found, it is some user-created table | 681 | if (nullptr == fqn) // name not found, it is some user-created table |
| 756 | { | 682 | { |
| 757 | return false; | 683 | return false; |
| 758 | } | 684 | } |
| 759 | // push the equivalent table in the destination's stack, retrieved from the lookup table | 685 | // push the equivalent table in the destination's stack, retrieved from the lookup table |
| 760 | STACK_CHECK_START_REL(L2, 0); // L // L2 | 686 | STACK_CHECK_START_REL(L2, 0); // L // L2 |
| 761 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | 687 | STACK_GROW(L2, 3); // up to 3 slots are necessary on error |
| 762 | switch( mode_) | 688 | switch (mode) |
| 763 | { | 689 | { |
| 764 | default: // shouldn't happen, in theory... | 690 | default: // shouldn't happen, in theory... |
| 765 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return | 691 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return |
| @@ -780,7 +706,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 780 | lua_rawget(L2, -2); // {} t | 706 | lua_rawget(L2, -2); // {} t |
| 781 | // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) | 707 | // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) |
| 782 | // but not when we extract something out of a keeper, as there is nothing to clone! | 708 | // but not when we extract something out of a keeper, as there is nothing to clone! |
| 783 | if (lua_isnil(L2, -1) && mode_ == LookupMode::LaneBody) | 709 | if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody) |
| 784 | { | 710 | { |
| 785 | lua_pop(L2, 2); // | 711 | lua_pop(L2, 2); // |
| 786 | STACK_CHECK(L2, 0); | 712 | STACK_CHECK(L2, 0); |
| @@ -797,7 +723,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 797 | lua_pop(L2, 1); // {} t | 723 | lua_pop(L2, 1); // {} t |
| 798 | // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error | 724 | // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error |
| 799 | luaL_error( | 725 | luaL_error( |
| 800 | (mode_ == LookupMode::FromKeeper) ? L2 : L1 | 726 | (mode == LookupMode::FromKeeper) ? L2 : L1 |
| 801 | , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." | 727 | , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." |
| 802 | , from ? from : "main" | 728 | , from ? from : "main" |
| 803 | , fqn | 729 | , fqn |
| @@ -808,7 +734,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 808 | lua_remove(L2, -2); // t | 734 | lua_remove(L2, -2); // t |
| 809 | break; | 735 | break; |
| 810 | } | 736 | } |
| 811 | STACK_CHECK( L2, 1); | 737 | STACK_CHECK(L2, 1); |
| 812 | return true; | 738 | return true; |
| 813 | } | 739 | } |
| 814 | 740 | ||
| @@ -877,7 +803,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 877 | lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} | 803 | lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} |
| 878 | lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 | 804 | lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 |
| 879 | // if table is already visited, we are done | 805 | // if table is already visited, we are done |
| 880 | if( !lua_isnil(L, -1)) | 806 | if (!lua_isnil(L, -1)) |
| 881 | { | 807 | { |
| 882 | lua_pop(L, 1); // o "r" {c} {fqn} ... {?} | 808 | lua_pop(L, 1); // o "r" {c} {fqn} ... {?} |
| 883 | return shortest_; | 809 | return shortest_; |
| @@ -902,7 +828,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 902 | { | 828 | { |
| 903 | STACK_CHECK(L, 2); | 829 | STACK_CHECK(L, 2); |
| 904 | // update shortest name | 830 | // update shortest name |
| 905 | if( depth_ < shortest_) | 831 | if (depth_ < shortest_) |
| 906 | { | 832 | { |
| 907 | shortest_ = depth_; | 833 | shortest_ = depth_; |
| 908 | std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" | 834 | std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" |
| @@ -924,7 +850,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 924 | // search in the table's metatable too | 850 | // search in the table's metatable too |
| 925 | if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} | 851 | if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} |
| 926 | { | 852 | { |
| 927 | if( lua_istable(L, -1)) | 853 | if (lua_istable(L, -1)) |
| 928 | { | 854 | { |
| 929 | ++ depth_; | 855 | ++ depth_; |
| 930 | lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" | 856 | lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" |
| @@ -966,7 +892,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 966 | int uvi = 1; | 892 | int uvi = 1; |
| 967 | while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} | 893 | while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} |
| 968 | { | 894 | { |
| 969 | if( lua_istable(L, -1)) // if it is a table, look inside | 895 | if (lua_istable(L, -1)) // if it is a table, look inside |
| 970 | { | 896 | { |
| 971 | ++ depth_; | 897 | ++ depth_; |
| 972 | lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" | 898 | lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" |
| @@ -1010,13 +936,13 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull }; | |||
| 1010 | int luaG_nameof( lua_State* L) | 936 | int luaG_nameof( lua_State* L) |
| 1011 | { | 937 | { |
| 1012 | int what = lua_gettop( L); | 938 | int what = lua_gettop( L); |
| 1013 | if( what > 1) | 939 | if (what > 1) |
| 1014 | { | 940 | { |
| 1015 | luaL_argerror( L, what, "too many arguments."); | 941 | luaL_argerror( L, what, "too many arguments."); |
| 1016 | } | 942 | } |
| 1017 | 943 | ||
| 1018 | // nil, boolean, light userdata, number and string aren't identifiable | 944 | // nil, boolean, light userdata, number and string aren't identifiable |
| 1019 | if( lua_type( L, 1) < LUA_TTABLE) | 945 | if (lua_type( L, 1) < LUA_TTABLE) |
| 1020 | { | 946 | { |
| 1021 | lua_pushstring( L, luaL_typename( L, 1)); // o "type" | 947 | lua_pushstring( L, luaL_typename( L, 1)); // o "type" |
| 1022 | lua_insert( L, -2); // "type" o | 948 | lua_insert( L, -2); // "type" o |
| @@ -1036,7 +962,7 @@ int luaG_nameof( lua_State* L) | |||
| 1036 | // this is where we start the search | 962 | // this is where we start the search |
| 1037 | lua_pushglobaltable( L); // o nil {c} {fqn} _G | 963 | lua_pushglobaltable( L); // o nil {c} {fqn} _G |
| 1038 | (void) discover_object_name_recur( L, 6666, 1); | 964 | (void) discover_object_name_recur( L, 6666, 1); |
| 1039 | if( lua_isnil( L, 2)) // try again with registry, just in case... | 965 | if (lua_isnil( L, 2)) // try again with registry, just in case... |
| 1040 | { | 966 | { |
| 1041 | lua_pop( L, 1); // o nil {c} {fqn} | 967 | lua_pop( L, 1); // o nil {c} {fqn} |
| 1042 | lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" | 968 | lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" |
| @@ -1056,56 +982,56 @@ int luaG_nameof( lua_State* L) | |||
| 1056 | /* | 982 | /* |
| 1057 | * Push a looked-up native/LuaJIT function. | 983 | * Push a looked-up native/LuaJIT function. |
| 1058 | */ | 984 | */ |
| 1059 | static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mode_, char const* upName_) | 985 | void InterCopyContext::lookup_native_func() const |
| 1060 | { | 986 | { |
| 1061 | // get the name of the function we want to send | 987 | // get the name of the function we want to send |
| 1062 | size_t len; | 988 | size_t len; |
| 1063 | char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); | 989 | char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len); |
| 1064 | // push the equivalent function in the destination's stack, retrieved from the lookup table | 990 | // push the equivalent function in the destination's stack, retrieved from the lookup table |
| 1065 | STACK_CHECK_START_REL(L2, 0); // L // L2 | 991 | STACK_CHECK_START_REL(L2, 0); // L1 // L2 |
| 1066 | STACK_GROW( L2, 3); // up to 3 slots are necessary on error | 992 | STACK_GROW(L2, 3); // up to 3 slots are necessary on error |
| 1067 | switch( mode_) | 993 | switch (mode) |
| 1068 | { | 994 | { |
| 1069 | default: // shouldn't happen, in theory... | 995 | default: // shouldn't happen, in theory... |
| 1070 | (void) luaL_error( L, "internal error: unknown lookup mode"); | 996 | luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return |
| 1071 | return; | 997 | break; |
| 1072 | 998 | ||
| 1073 | case LookupMode::ToKeeper: | 999 | case LookupMode::ToKeeper: |
| 1074 | // push a sentinel closure that holds the lookup name as upvalue | 1000 | // push a sentinel closure that holds the lookup name as upvalue |
| 1075 | lua_pushlstring( L2, fqn, len); // "f.q.n" | 1001 | lua_pushlstring(L2, fqn, len); // "f.q.n" |
| 1076 | lua_pushcclosure( L2, func_lookup_sentinel, 1); // f | 1002 | lua_pushcclosure(L2, func_lookup_sentinel, 1); // f |
| 1077 | break; | 1003 | break; |
| 1078 | 1004 | ||
| 1079 | case LookupMode::LaneBody: | 1005 | case LookupMode::LaneBody: |
| 1080 | case LookupMode::FromKeeper: | 1006 | case LookupMode::FromKeeper: |
| 1081 | LOOKUP_REGKEY.pushValue(L2); // {} | 1007 | LOOKUP_REGKEY.pushValue(L2); // {} |
| 1082 | STACK_CHECK( L2, 1); | 1008 | STACK_CHECK(L2, 1); |
| 1083 | ASSERT_L( lua_istable( L2, -1)); | 1009 | _ASSERT_L(L1, lua_istable(L2, -1)); |
| 1084 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | 1010 | lua_pushlstring(L2, fqn, len); // {} "f.q.n" |
| 1085 | lua_rawget( L2, -2); // {} f | 1011 | lua_rawget(L2, -2); // {} f |
| 1086 | // nil means we don't know how to transfer stuff: user should do something | 1012 | // nil means we don't know how to transfer stuff: user should do something |
| 1087 | // anything other than function or table should not happen! | 1013 | // anything other than function or table should not happen! |
| 1088 | if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1)) | 1014 | if (!lua_isfunction( L2, -1) && !lua_istable( L2, -1)) |
| 1089 | { | 1015 | { |
| 1090 | char const* from, * to; | 1016 | char const* from, * to; |
| 1091 | lua_getglobal( L, "decoda_name"); // ... f ... decoda_name | 1017 | lua_getglobal(L1, "decoda_name"); // ... f ... decoda_name |
| 1092 | from = lua_tostring( L, -1); | 1018 | from = lua_tostring(L1, -1); |
| 1093 | lua_pop( L, 1); // ... f ... | 1019 | lua_pop(L1, 1); // ... f ... |
| 1094 | lua_getglobal( L2, "decoda_name"); // {} f decoda_name | 1020 | lua_getglobal(L2, "decoda_name"); // {} f decoda_name |
| 1095 | to = lua_tostring( L2, -1); | 1021 | to = lua_tostring(L2, -1); |
| 1096 | lua_pop( L2, 1); // {} f | 1022 | lua_pop(L2, 1); // {} f |
| 1097 | // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error | 1023 | // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error |
| 1098 | (void) luaL_error( | 1024 | (void) luaL_error( |
| 1099 | (mode_ == LookupMode::FromKeeper) ? L2 : L | 1025 | (mode == LookupMode::FromKeeper) ? L2 : L1 |
| 1100 | , "%s%s: function '%s' not found in %s destination transfer database." | 1026 | , "%s%s: function '%s' not found in %s destination transfer database." |
| 1101 | , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN " | 1027 | , lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN " |
| 1102 | , from ? from : "main" | 1028 | , from ? from : "main" |
| 1103 | , fqn | 1029 | , fqn |
| 1104 | , to ? to : "main" | 1030 | , to ? to : "main" |
| 1105 | ); | 1031 | ); |
| 1106 | return; | 1032 | return; |
| 1107 | } | 1033 | } |
| 1108 | lua_remove( L2, -2); // f | 1034 | lua_remove(L2, -2); // f |
| 1109 | break; | 1035 | break; |
| 1110 | 1036 | ||
| 1111 | /* keep it in case I need it someday, who knows... | 1037 | /* keep it in case I need it someday, who knows... |
| @@ -1115,7 +1041,7 @@ static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mo | |||
| 1115 | char const* upname; | 1041 | char const* upname; |
| 1116 | lua_CFunction f = lua_tocfunction( L, i); | 1042 | lua_CFunction f = lua_tocfunction( L, i); |
| 1117 | // copy upvalues | 1043 | // copy upvalues |
| 1118 | for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) | 1044 | for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) |
| 1119 | { | 1045 | { |
| 1120 | luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] | 1046 | luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] |
| 1121 | } | 1047 | } |
| @@ -1166,7 +1092,7 @@ static char const* vt_names[] = | |||
| 1166 | [[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) | 1092 | [[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) |
| 1167 | { | 1093 | { |
| 1168 | luaL_Buffer* B = (luaL_Buffer*) ud; | 1094 | luaL_Buffer* B = (luaL_Buffer*) ud; |
| 1169 | if( !B->L) | 1095 | if (!B->L) |
| 1170 | { | 1096 | { |
| 1171 | luaL_buffinit( L, B); | 1097 | luaL_buffinit( L, B); |
| 1172 | } | 1098 | } |
| @@ -1278,7 +1204,7 @@ void InterCopyContext::copy_func() const | |||
| 1278 | { // ... _G up[n] | 1204 | { // ... _G up[n] |
| 1279 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); | 1205 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); |
| 1280 | #if LUA_VERSION_NUM >= 502 | 1206 | #if LUA_VERSION_NUM >= 502 |
| 1281 | if( lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? | 1207 | if (lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? |
| 1282 | { | 1208 | { |
| 1283 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); | 1209 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); |
| 1284 | lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> | 1210 | lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> |
| @@ -1331,8 +1257,7 @@ void InterCopyContext::copy_func() const | |||
| 1331 | */ | 1257 | */ |
| 1332 | void InterCopyContext::copy_cached_func() const | 1258 | void InterCopyContext::copy_cached_func() const |
| 1333 | { | 1259 | { |
| 1334 | FuncSubType funcSubType; | 1260 | FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) }; |
| 1335 | std::ignore = luaG_tocfunction(L1, L1_i, &funcSubType); // nullptr for LuaJIT-fast && bytecode functions | ||
| 1336 | if (funcSubType == FST_Bytecode) | 1261 | if (funcSubType == FST_Bytecode) |
| 1337 | { | 1262 | { |
| 1338 | void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); | 1263 | void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); |
| @@ -1376,7 +1301,7 @@ void InterCopyContext::copy_cached_func() const | |||
| 1376 | } | 1301 | } |
| 1377 | else // function is native/LuaJIT: no need to cache | 1302 | else // function is native/LuaJIT: no need to cache |
| 1378 | { | 1303 | { |
| 1379 | lookup_native_func(L2, L1, L1_i, mode, name); // ... {cache} ... function | 1304 | lookup_native_func(); // ... {cache} ... function |
| 1380 | // if the function was in fact a lookup sentinel, we can either get a function or a table here | 1305 | // if the function was in fact a lookup sentinel, we can either get a function or a table here |
| 1381 | _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); | 1306 | _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); |
| 1382 | } | 1307 | } |
| @@ -1440,7 +1365,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
| 1440 | SourceIndex const val_i{ lua_gettop(L1) }; | 1365 | SourceIndex const val_i{ lua_gettop(L1) }; |
| 1441 | SourceIndex const key_i{ val_i - 1 }; | 1366 | SourceIndex const key_i{ val_i - 1 }; |
| 1442 | 1367 | ||
| 1443 | // Only basic key types are copied over; others ignored | 1368 | // For the key, only basic key types are copied over. others ignored |
| 1444 | InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; | 1369 | InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; |
| 1445 | if (!c.inter_copy_one()) | 1370 | if (!c.inter_copy_one()) |
| 1446 | { | 1371 | { |
| @@ -1451,7 +1376,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
| 1451 | } | 1376 | } |
| 1452 | 1377 | ||
| 1453 | char* valPath{ nullptr }; | 1378 | char* valPath{ nullptr }; |
| 1454 | if( U->verboseErrors) | 1379 | if (U->verboseErrors) |
| 1455 | { | 1380 | { |
| 1456 | // for debug purposes, let's try to build a useful name | 1381 | // for debug purposes, let's try to build a useful name |
| 1457 | if (lua_type(L1, key_i) == LUA_TSTRING) | 1382 | if (lua_type(L1, key_i) == LUA_TSTRING) |
| @@ -1483,20 +1408,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
| 1483 | valPath = (char*) alloca(strlen(name) + 16 + 5); | 1408 | valPath = (char*) alloca(strlen(name) + 16 + 5); |
| 1484 | sprintf(valPath, "%s[U:%p]", name, key); | 1409 | sprintf(valPath, "%s[U:%p]", name, key); |
| 1485 | } | 1410 | } |
| 1486 | else if( lua_type( L1, key_i) == LUA_TBOOLEAN) | 1411 | else if (lua_type( L1, key_i) == LUA_TBOOLEAN) |
| 1487 | { | 1412 | { |
| 1488 | int const key{ lua_toboolean(L1, key_i) }; | 1413 | int const key{ lua_toboolean(L1, key_i) }; |
| 1489 | valPath = (char*) alloca(strlen(name) + 8); | 1414 | valPath = (char*) alloca(strlen(name) + 8); |
| 1490 | sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); | 1415 | sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); |
| 1491 | } | 1416 | } |
| 1492 | } | 1417 | } |
| 1493 | /* | ||
| 1494 | * Contents of metatables are copied with cache checking; | ||
| 1495 | * important to detect loops. | ||
| 1496 | */ | ||
| 1497 | c.L1_i = SourceIndex{ val_i }; | 1418 | c.L1_i = SourceIndex{ val_i }; |
| 1498 | c.name = valPath ? valPath : name; | 1419 | // Contents of metatables are copied with cache checking. important to detect loops. |
| 1499 | c.vt = VT::NORMAL; | 1420 | c.vt = VT::NORMAL; |
| 1421 | c.name = valPath ? valPath : name; | ||
| 1500 | if (c.inter_copy_one()) | 1422 | if (c.inter_copy_one()) |
| 1501 | { | 1423 | { |
| 1502 | _ASSERT_L(L1, lua_istable( L2, -3)); | 1424 | _ASSERT_L(L1, lua_istable( L2, -3)); |
| @@ -1539,7 +1461,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1539 | STACK_CHECK(L2, 0); | 1461 | STACK_CHECK(L2, 0); |
| 1540 | 1462 | ||
| 1541 | // no metatable? -> not clonable | 1463 | // no metatable? -> not clonable |
| 1542 | if( !lua_getmetatable(L1, L1_i)) // ... mt? | 1464 | if (!lua_getmetatable(L1, L1_i)) // ... mt? |
| 1543 | { | 1465 | { |
| 1544 | STACK_CHECK(L1, 0); | 1466 | STACK_CHECK(L1, 0); |
| 1545 | return false; | 1467 | return false; |
| @@ -1547,7 +1469,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1547 | 1469 | ||
| 1548 | // no __lanesclone? -> not clonable | 1470 | // no __lanesclone? -> not clonable |
| 1549 | lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? | 1471 | lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? |
| 1550 | if( lua_isnil(L1, -1)) | 1472 | if (lua_isnil(L1, -1)) |
| 1551 | { | 1473 | { |
| 1552 | lua_pop(L1, 2); // ... | 1474 | lua_pop(L1, 2); // ... |
| 1553 | STACK_CHECK(L1, 0); | 1475 | STACK_CHECK(L1, 0); |
| @@ -1565,12 +1487,12 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1565 | lua_pop(L1, 1); // ... mt __lanesclone [uv]+ | 1487 | lua_pop(L1, 1); // ... mt __lanesclone [uv]+ |
| 1566 | -- uvi; | 1488 | -- uvi; |
| 1567 | // create the clone userdata with the required number of uservalue slots | 1489 | // create the clone userdata with the required number of uservalue slots |
| 1568 | void* clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... u | 1490 | void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // ... u |
| 1569 | // copy the metatable in the target state, and give it to the clone we put there | 1491 | // copy the metatable in the target state, and give it to the clone we put there |
| 1570 | InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; | 1492 | InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; |
| 1571 | if (c.inter_copy_one()) // ... u mt|sentinel | 1493 | if (c.inter_copy_one()) // ... u mt|sentinel |
| 1572 | { | 1494 | { |
| 1573 | if( LookupMode::ToKeeper == mode) // ... u sentinel | 1495 | if (LookupMode::ToKeeper == mode) // ... u sentinel |
| 1574 | { | 1496 | { |
| 1575 | _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); | 1497 | _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); |
| 1576 | // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn | 1498 | // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn |
| @@ -1645,7 +1567,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1645 | } | 1567 | } |
| 1646 | 1568 | ||
| 1647 | // try clonable userdata first | 1569 | // try clonable userdata first |
| 1648 | if( copyclone()) | 1570 | if (copyclone()) |
| 1649 | { | 1571 | { |
| 1650 | STACK_CHECK(L1, 0); | 1572 | STACK_CHECK(L1, 0); |
| 1651 | STACK_CHECK(L2, 1); | 1573 | STACK_CHECK(L2, 1); |
| @@ -1714,8 +1636,8 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1714 | } | 1636 | } |
| 1715 | lua_pop(L2, 1); // ... | 1637 | lua_pop(L2, 1); // ... |
| 1716 | 1638 | ||
| 1717 | // this function has 2 upvalues: the fqn of its metatable, and the userdata itself | 1639 | // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself |
| 1718 | bool const found{ lookup_table(L2, L1, L1_i, mode, name) }; // ... mt? | 1640 | bool const found{ lookup_table() }; // ... mt? |
| 1719 | if (!found) | 1641 | if (!found) |
| 1720 | { | 1642 | { |
| 1721 | STACK_CHECK(L2, 0); | 1643 | STACK_CHECK(L2, 0); |
| @@ -1802,7 +1724,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1802 | * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) | 1724 | * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) |
| 1803 | * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism | 1725 | * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism |
| 1804 | */ | 1726 | */ |
| 1805 | if (lookup_table(L2, L1, L1_i, mode, name)) | 1727 | if (lookup_table()) |
| 1806 | { | 1728 | { |
| 1807 | _ASSERT_L(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know | 1729 | _ASSERT_L(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know |
| 1808 | return true; | 1730 | return true; |
| @@ -1849,6 +1771,71 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1849 | 1771 | ||
| 1850 | // ################################################################################################# | 1772 | // ################################################################################################# |
| 1851 | 1773 | ||
| 1774 | [[nodiscard]] bool InterCopyContext::inter_copy_boolean() const | ||
| 1775 | { | ||
| 1776 | int const v{ lua_toboolean(L1, L1_i) }; | ||
| 1777 | DEBUGSPEW_CODE(fprintf(stderr, "%s\n", v ? "true" : "false")); | ||
| 1778 | lua_pushboolean(L2, v); | ||
| 1779 | return true; | ||
| 1780 | } | ||
| 1781 | |||
| 1782 | // ################################################################################################# | ||
| 1783 | |||
| 1784 | [[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const | ||
| 1785 | { | ||
| 1786 | void* const p{ lua_touserdata(L1, L1_i) }; | ||
| 1787 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); | ||
| 1788 | lua_pushlightuserdata(L2, p); | ||
| 1789 | return true; | ||
| 1790 | } | ||
| 1791 | |||
| 1792 | // ################################################################################################# | ||
| 1793 | |||
| 1794 | [[nodiscard]] bool InterCopyContext::inter_copy_nil() const | ||
| 1795 | { | ||
| 1796 | if (vt == VT::KEY) | ||
| 1797 | { | ||
| 1798 | return false; | ||
| 1799 | } | ||
| 1800 | lua_pushnil(L2); | ||
| 1801 | return true; | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | // ################################################################################################# | ||
| 1805 | |||
| 1806 | [[nodiscard]] bool InterCopyContext::inter_copy_number() const | ||
| 1807 | { | ||
| 1808 | /* LNUM patch support (keeping integer accuracy) */ | ||
| 1809 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
| 1810 | if (lua_isinteger(L1, L1_i)) | ||
| 1811 | { | ||
| 1812 | lua_Integer const v{ lua_tointeger(L1, L1_i) }; | ||
| 1813 | DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); | ||
| 1814 | lua_pushinteger(L2, v); | ||
| 1815 | } | ||
| 1816 | else | ||
| 1817 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
| 1818 | { | ||
| 1819 | lua_Number const v{ lua_tonumber(L1, L1_i) }; | ||
| 1820 | DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); | ||
| 1821 | lua_pushnumber(L2, v); | ||
| 1822 | } | ||
| 1823 | return true; | ||
| 1824 | } | ||
| 1825 | |||
| 1826 | // ################################################################################################# | ||
| 1827 | |||
| 1828 | [[nodiscard]] bool InterCopyContext::inter_copy_string() const | ||
| 1829 | { | ||
| 1830 | size_t len; | ||
| 1831 | char const* const s{ lua_tolstring(L1, L1_i, &len) }; | ||
| 1832 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); | ||
| 1833 | lua_pushlstring(L2, s, len); | ||
| 1834 | return true; | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | // ################################################################################################# | ||
| 1838 | |||
| 1852 | /* | 1839 | /* |
| 1853 | * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove | 1840 | * Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove |
| 1854 | * the original value. | 1841 | * the original value. |
| @@ -1878,7 +1865,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1878 | if (lua_getmetatable(L1, L1_i)) // ... mt | 1865 | if (lua_getmetatable(L1, L1_i)) // ... mt |
| 1879 | { | 1866 | { |
| 1880 | lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? | 1867 | lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? |
| 1881 | if( lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) | 1868 | if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) |
| 1882 | { | 1869 | { |
| 1883 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); | 1870 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); |
| 1884 | val_type = LuaType::NIL; | 1871 | val_type = LuaType::NIL; |
| @@ -1892,81 +1879,21 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull }; | |||
| 1892 | bool ret{ true }; | 1879 | bool ret{ true }; |
| 1893 | switch (val_type) | 1880 | switch (val_type) |
| 1894 | { | 1881 | { |
| 1895 | /* Basic types allowed both as values, and as table keys */ | 1882 | // Basic types allowed both as values, and as table keys |
| 1896 | 1883 | case LuaType::BOOLEAN: ret = inter_copy_boolean(); break; | |
| 1897 | case LuaType::BOOLEAN: | 1884 | case LuaType::NUMBER: ret = inter_copy_number(); break; |
| 1898 | { | 1885 | case LuaType::STRING: ret = inter_copy_string(); break; |
| 1899 | int const v{ lua_toboolean(L1, L1_i) }; | 1886 | case LuaType::LIGHTUSERDATA: ret = inter_copy_lightuserdata();break; |
| 1900 | DEBUGSPEW_CODE( fprintf(stderr, "%s\n", v ? "true" : "false")); | 1887 | |
| 1901 | lua_pushboolean(L2, v); | 1888 | // The following types are not allowed as table keys |
| 1902 | } | 1889 | case LuaType::USERDATA: ret = inter_copy_userdata(); break; |
| 1903 | break; | 1890 | case LuaType::NIL: ret = inter_copy_nil(); break; |
| 1904 | 1891 | case LuaType::FUNCTION: ret = inter_copy_function(); break; | |
| 1905 | case LuaType::NUMBER: | 1892 | case LuaType::TABLE: ret = inter_copy_table(); break; |
| 1906 | /* LNUM patch support (keeping integer accuracy) */ | 1893 | |
| 1907 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 1894 | // The following types cannot be copied |
| 1908 | if( lua_isinteger(L1, L1_i)) | 1895 | case LuaType::CDATA: [[fallthrough]]; |
| 1909 | { | 1896 | case LuaType::THREAD: ret = false; break; |
| 1910 | lua_Integer const v{ lua_tointeger(L1, L1_i) }; | ||
| 1911 | DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v)); | ||
| 1912 | lua_pushinteger(L2, v); | ||
| 1913 | break; | ||
| 1914 | } | ||
| 1915 | else | ||
| 1916 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | ||
| 1917 | { | ||
| 1918 | lua_Number const v{ lua_tonumber(L1, L1_i) }; | ||
| 1919 | DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v)); | ||
| 1920 | lua_pushnumber(L2, v); | ||
| 1921 | } | ||
| 1922 | break; | ||
| 1923 | |||
| 1924 | case LuaType::STRING: | ||
| 1925 | { | ||
| 1926 | size_t len; | ||
| 1927 | char const* const s{ lua_tolstring(L1, L1_i, &len) }; | ||
| 1928 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s)); | ||
| 1929 | lua_pushlstring(L2, s, len); | ||
| 1930 | } | ||
| 1931 | break; | ||
| 1932 | |||
| 1933 | case LuaType::LIGHTUSERDATA: | ||
| 1934 | { | ||
| 1935 | void* const p{ lua_touserdata(L1, L1_i) }; | ||
| 1936 | DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p)); | ||
| 1937 | lua_pushlightuserdata(L2, p); | ||
| 1938 | } | ||
| 1939 | break; | ||
| 1940 | |||
| 1941 | /* The following types are not allowed as table keys */ | ||
| 1942 | |||
| 1943 | case LuaType::USERDATA: | ||
| 1944 | ret = inter_copy_userdata(); | ||
| 1945 | break; | ||
| 1946 | |||
| 1947 | case LuaType::NIL: | ||
| 1948 | if (vt == VT::KEY) | ||
| 1949 | { | ||
| 1950 | ret = false; | ||
| 1951 | break; | ||
| 1952 | } | ||
| 1953 | lua_pushnil( L2); | ||
| 1954 | break; | ||
| 1955 | |||
| 1956 | case LuaType::FUNCTION: | ||
| 1957 | ret = inter_copy_function(); | ||
| 1958 | break; | ||
| 1959 | |||
| 1960 | case LuaType::TABLE: | ||
| 1961 | ret = inter_copy_table(); | ||
| 1962 | break; | ||
| 1963 | |||
| 1964 | /* The following types cannot be copied */ | ||
| 1965 | |||
| 1966 | case LuaType::CDATA: | ||
| 1967 | case LuaType::THREAD: | ||
| 1968 | ret = false; | ||
| 1969 | break; | ||
| 1970 | } | 1897 | } |
| 1971 | 1898 | ||
| 1972 | STACK_CHECK(L2, ret ? 1 : 0); | 1899 | STACK_CHECK(L2, ret ? 1 : 0); |
diff --git a/src/tools.h b/src/tools.h index 06646d3..ddf5c67 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -6,13 +6,7 @@ | |||
| 6 | // forwards | 6 | // forwards |
| 7 | class Universe; | 7 | class Universe; |
| 8 | 8 | ||
| 9 | // ################################################################################################ | 9 | // ################################################################################################# |
| 10 | |||
| 11 | #ifdef _DEBUG | ||
| 12 | void luaG_dump(lua_State* L); | ||
| 13 | #endif // _DEBUG | ||
| 14 | |||
| 15 | // ################################################################################################ | ||
| 16 | 10 | ||
| 17 | void push_registry_subtable_mode(lua_State* L, UniqueKey key_, const char* mode_); | 11 | void push_registry_subtable_mode(lua_State* L, UniqueKey key_, const char* mode_); |
| 18 | void push_registry_subtable(lua_State* L, UniqueKey key_); | 12 | void push_registry_subtable(lua_State* L, UniqueKey key_); |
| @@ -31,12 +25,13 @@ enum class InterCopyResult | |||
| 31 | Error | 25 | Error |
| 32 | }; | 26 | }; |
| 33 | 27 | ||
| 34 | // ################################################################################################ | 28 | // ################################################################################################# |
| 35 | 29 | ||
| 36 | using CacheIndex = Unique<int>; | 30 | using CacheIndex = Unique<int>; |
| 37 | using SourceIndex = Unique<int>; | 31 | using SourceIndex = Unique<int>; |
| 38 | struct InterCopyContext | 32 | class InterCopyContext |
| 39 | { | 33 | { |
| 34 | public: | ||
| 40 | 35 | ||
| 41 | Universe* const U; | 36 | Universe* const U; |
| 42 | Dest const L2; | 37 | Dest const L2; |
| @@ -47,35 +42,50 @@ struct InterCopyContext | |||
| 47 | LookupMode const mode; | 42 | LookupMode const mode; |
| 48 | char const* name; // that one can change when we reuse the context | 43 | char const* name; // that one can change when we reuse the context |
| 49 | 44 | ||
| 50 | [[nodiscard]] bool inter_copy_one() const; | ||
| 51 | |||
| 52 | private: | 45 | private: |
| 53 | 46 | ||
| 54 | [[nodiscard]] bool inter_copy_userdata() const; | 47 | // for use in copy_cached_func |
| 55 | [[nodiscard]] bool inter_copy_function() const; | ||
| 56 | [[nodiscard]] bool inter_copy_table() const; | ||
| 57 | [[nodiscard]] bool copyclone() const; | ||
| 58 | [[nodiscard]] bool copydeep() const; | ||
| 59 | [[nodiscard]] bool push_cached_metatable() const; | ||
| 60 | void copy_func() const; | 48 | void copy_func() const; |
| 49 | void lookup_native_func() const; | ||
| 50 | |||
| 51 | // for use in inter_copy_function | ||
| 61 | void copy_cached_func() const; | 52 | void copy_cached_func() const; |
| 53 | [[nodiscard]] bool lookup_table() const; | ||
| 54 | |||
| 55 | // for use in inter_copy_table | ||
| 62 | void inter_copy_keyvaluepair() const; | 56 | void inter_copy_keyvaluepair() const; |
| 57 | [[nodiscard]] bool push_cached_metatable() const; | ||
| 58 | |||
| 59 | // for use in inter_copy_userdata | ||
| 60 | [[nodiscard]] bool copyclone() const; | ||
| 61 | [[nodiscard]] bool copydeep() const; | ||
| 62 | |||
| 63 | // copying a single Lua stack item | ||
| 64 | [[nodiscard]] bool inter_copy_boolean() const; | ||
| 65 | [[nodiscard]] bool inter_copy_function() const; | ||
| 66 | [[nodiscard]] bool inter_copy_lightuserdata() const; | ||
| 67 | [[nodiscard]] bool inter_copy_nil() const; | ||
| 68 | [[nodiscard]] bool inter_copy_number() const; | ||
| 69 | [[nodiscard]] bool inter_copy_string() const; | ||
| 70 | [[nodiscard]] bool inter_copy_table() const; | ||
| 71 | [[nodiscard]] bool inter_copy_userdata() const; | ||
| 63 | 72 | ||
| 64 | public: | 73 | public: |
| 65 | 74 | ||
| 75 | [[nodiscard]] bool inter_copy_one() const; | ||
| 66 | [[nodiscard]] InterCopyResult inter_copy_package() const; | 76 | [[nodiscard]] InterCopyResult inter_copy_package() const; |
| 67 | [[nodiscard]] InterCopyResult inter_copy(int n_) const; | 77 | [[nodiscard]] InterCopyResult inter_copy(int n_) const; |
| 68 | [[nodiscard]] InterCopyResult inter_move(int n_) const; | 78 | [[nodiscard]] InterCopyResult inter_move(int n_) const; |
| 69 | }; | 79 | }; |
| 70 | 80 | ||
| 71 | // ################################################################################################ | 81 | // ################################################################################################# |
| 72 | 82 | ||
| 73 | [[nodiscard]] int luaG_nameof(lua_State* L); | 83 | [[nodiscard]] int luaG_nameof(lua_State* L); |
| 74 | 84 | ||
| 75 | void populate_func_lookup_table(lua_State* L, int _i, char const* _name); | 85 | void populate_func_lookup_table(lua_State* L, int _i, char const* _name); |
| 76 | void initialize_allocator_function(Universe* U, lua_State* L); | 86 | void initialize_allocator_function(Universe* U, lua_State* L); |
| 77 | 87 | ||
| 78 | // ################################################################################################ | 88 | // ################################################################################################# |
| 79 | 89 | ||
| 80 | // crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 90 | // crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/ |
| 81 | static constexpr UniqueKey CONFIG_REGKEY{ 0x31cd24894eae8624ull }; // registry key to access the configuration | 91 | static constexpr UniqueKey CONFIG_REGKEY{ 0x31cd24894eae8624ull }; // registry key to access the configuration |
diff --git a/src/uniquekey.h b/src/uniquekey.h index 78c0765..84553a5 100644 --- a/src/uniquekey.h +++ b/src/uniquekey.h | |||
| @@ -44,8 +44,10 @@ class UniqueKey | |||
| 44 | } | 44 | } |
| 45 | void pushValue(lua_State* const L) const | 45 | void pushValue(lua_State* const L) const |
| 46 | { | 46 | { |
| 47 | STACK_CHECK_START_REL(L, 0); | ||
| 47 | pushKey(L); | 48 | pushKey(L); |
| 48 | lua_rawget(L, LUA_REGISTRYINDEX); | 49 | lua_rawget(L, LUA_REGISTRYINDEX); |
| 50 | STACK_CHECK(L, 1); | ||
| 49 | } | 51 | } |
| 50 | template <typename OP> | 52 | template <typename OP> |
| 51 | void setValue(lua_State* L, OP operation_) const | 53 | void setValue(lua_State* L, OP operation_) const |
diff --git a/src/universe.cpp b/src/universe.cpp index 4c53987..a02a5e6 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
| @@ -41,7 +41,7 @@ static constexpr UniqueKey UNIVERSE_FULL_REGKEY{ 0x99CA130C09EDC074ull }; | |||
| 41 | // xxh64 of string "UNIVERSE_LIGHT_REGKEY" generated at http://www.nitrxgen.net/hashgen/ | 41 | // xxh64 of string "UNIVERSE_LIGHT_REGKEY" generated at http://www.nitrxgen.net/hashgen/ |
| 42 | static constexpr UniqueKey UNIVERSE_LIGHT_REGKEY{ 0x3663C07C742CEB81ull }; | 42 | static constexpr UniqueKey UNIVERSE_LIGHT_REGKEY{ 0x3663C07C742CEB81ull }; |
| 43 | 43 | ||
| 44 | // ################################################################################################ | 44 | // ################################################################################################# |
| 45 | 45 | ||
| 46 | Universe::Universe() | 46 | Universe::Universe() |
| 47 | { | 47 | { |
| @@ -70,13 +70,13 @@ Universe::Universe() | |||
| 70 | #endif // PLATFORM_LINUX | 70 | #endif // PLATFORM_LINUX |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | // ################################################################################################ | 73 | // ################################################################################################# |
| 74 | 74 | ||
| 75 | // only called from the master state | 75 | // only called from the master state |
| 76 | Universe* universe_create(lua_State* L) | 76 | Universe* universe_create(lua_State* L) |
| 77 | { | 77 | { |
| 78 | ASSERT_L(universe_get(L) == nullptr); | 78 | ASSERT_L(universe_get(L) == nullptr); |
| 79 | Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe | 79 | Universe* const U{ lua_newuserdatauv<Universe>(L, 0) }; // universe |
| 80 | U->Universe::Universe(); | 80 | U->Universe::Universe(); |
| 81 | STACK_CHECK_START_REL(L, 1); | 81 | STACK_CHECK_START_REL(L, 1); |
| 82 | UNIVERSE_FULL_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); | 82 | UNIVERSE_FULL_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); |
| @@ -85,7 +85,7 @@ Universe* universe_create(lua_State* L) | |||
| 85 | return U; | 85 | return U; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | // ################################################################################################ | 88 | // ################################################################################################# |
| 89 | 89 | ||
| 90 | void universe_store(lua_State* L, Universe* U) | 90 | void universe_store(lua_State* L, Universe* U) |
| 91 | { | 91 | { |
| @@ -95,7 +95,7 @@ void universe_store(lua_State* L, Universe* U) | |||
| 95 | STACK_CHECK(L, 0); | 95 | STACK_CHECK(L, 0); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | // ################################################################################################ | 98 | // ################################################################################################# |
| 99 | 99 | ||
| 100 | Universe* universe_get(lua_State* L) | 100 | Universe* universe_get(lua_State* L) |
| 101 | { | 101 | { |
diff --git a/src/universe.h b/src/universe.h index eb85133..320c400 100644 --- a/src/universe.h +++ b/src/universe.h | |||
| @@ -13,7 +13,7 @@ extern "C" { | |||
| 13 | 13 | ||
| 14 | #include <mutex> | 14 | #include <mutex> |
| 15 | 15 | ||
| 16 | // ################################################################################################ | 16 | // ################################################################################################# |
| 17 | 17 | ||
| 18 | // forwards | 18 | // forwards |
| 19 | struct DeepPrelude; | 19 | struct DeepPrelude; |
| @@ -25,7 +25,7 @@ class Lane; | |||
| 25 | */ | 25 | */ |
| 26 | #define HAVE_LANE_TRACKING() 1 | 26 | #define HAVE_LANE_TRACKING() 1 |
| 27 | 27 | ||
| 28 | // ################################################################################################ | 28 | // ################################################################################################# |
| 29 | 29 | ||
| 30 | // everything we need to provide to lua_newstate() | 30 | // everything we need to provide to lua_newstate() |
| 31 | class AllocatorDefinition | 31 | class AllocatorDefinition |
| @@ -35,6 +35,7 @@ class AllocatorDefinition | |||
| 35 | lua_Alloc m_allocF{ nullptr }; | 35 | lua_Alloc m_allocF{ nullptr }; |
| 36 | void* m_allocUD{ nullptr }; | 36 | void* m_allocUD{ nullptr }; |
| 37 | 37 | ||
| 38 | [[nodiscard]] static void* operator new(size_t size_) noexcept = delete; // can't create one outside of a Lua state | ||
| 38 | [[nodiscard]] static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 0); } | 39 | [[nodiscard]] static void* operator new(size_t size_, lua_State* L) noexcept { return lua_newuserdatauv(L, size_, 0); } |
| 39 | // always embedded somewhere else or "in-place constructed" as a full userdata | 40 | // always embedded somewhere else or "in-place constructed" as a full userdata |
| 40 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | 41 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception |
| @@ -72,7 +73,7 @@ class AllocatorDefinition | |||
| 72 | } | 73 | } |
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | // ################################################################################################ | 76 | // ################################################################################################# |
| 76 | 77 | ||
| 77 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator | 78 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator |
| 78 | class ProtectedAllocator : public AllocatorDefinition | 79 | class ProtectedAllocator : public AllocatorDefinition |
| @@ -115,7 +116,7 @@ class ProtectedAllocator : public AllocatorDefinition | |||
| 115 | } | 116 | } |
| 116 | }; | 117 | }; |
| 117 | 118 | ||
| 118 | // ################################################################################################ | 119 | // ################################################################################################# |
| 119 | 120 | ||
| 120 | // everything regarding the Lanes universe is stored in that global structure | 121 | // everything regarding the Lanes universe is stored in that global structure |
| 121 | // held as a full userdata in the master Lua state that required it for the first time | 122 | // held as a full userdata in the master Lua state that required it for the first time |
| @@ -183,13 +184,13 @@ class Universe | |||
| 183 | Universe& operator=(Universe&&) = delete; | 184 | Universe& operator=(Universe&&) = delete; |
| 184 | }; | 185 | }; |
| 185 | 186 | ||
| 186 | // ################################################################################################ | 187 | // ################################################################################################# |
| 187 | 188 | ||
| 188 | [[nodiscard]] Universe* universe_get(lua_State* L); | 189 | [[nodiscard]] Universe* universe_get(lua_State* L); |
| 189 | [[nodiscard]] Universe* universe_create(lua_State* L); | 190 | [[nodiscard]] Universe* universe_create(lua_State* L); |
| 190 | void universe_store(lua_State* L, Universe* U); | 191 | void universe_store(lua_State* L, Universe* U); |
| 191 | 192 | ||
| 192 | // ################################################################################################ | 193 | // ################################################################################################# |
| 193 | 194 | ||
| 194 | #if USE_DEBUG_SPEW() | 195 | #if USE_DEBUG_SPEW() |
| 195 | class DebugSpewIndentScope | 196 | class DebugSpewIndentScope |
diff --git a/tests/basic.lua b/tests/basic.lua index 4b4fae6..1cf37e6 100644 --- a/tests/basic.lua +++ b/tests/basic.lua | |||
| @@ -63,9 +63,9 @@ tables_match= function( a, b ) | |||
| 63 | return subtable( a, b ) and subtable( b, a ) | 63 | return subtable( a, b ) and subtable( b, a ) |
| 64 | end | 64 | end |
| 65 | 65 | ||
| 66 | --############################################################## | 66 | -- ################################################################################################## |
| 67 | --############################################################## | 67 | -- ################################################################################################## |
| 68 | --############################################################## | 68 | -- ################################################################################################## |
| 69 | 69 | ||
| 70 | PRINT( "\n\n", "---=== Tasking (basic) ===---", "\n\n") | 70 | PRINT( "\n\n", "---=== Tasking (basic) ===---", "\n\n") |
| 71 | 71 | ||
| @@ -112,9 +112,9 @@ assert( lane1.status == "done" ) | |||
| 112 | lane1, lane2 = nil | 112 | lane1, lane2 = nil |
| 113 | collectgarbage() | 113 | collectgarbage() |
| 114 | 114 | ||
| 115 | --############################################################## | 115 | -- ################################################################################################## |
| 116 | --############################################################## | 116 | -- ################################################################################################## |
| 117 | --############################################################## | 117 | -- ################################################################################################## |
| 118 | 118 | ||
| 119 | PRINT( "\n\n", "---=== Tasking (cancelling) ===---", "\n\n") | 119 | PRINT( "\n\n", "---=== Tasking (cancelling) ===---", "\n\n") |
| 120 | 120 | ||
| @@ -201,9 +201,9 @@ repeat until wait_receive_batched_lane.status == "cancelled" | |||
| 201 | print "wait_receive_batched_lane is cancelled" | 201 | print "wait_receive_batched_lane is cancelled" |
| 202 | --################################################]] | 202 | --################################################]] |
| 203 | 203 | ||
| 204 | --############################################################## | 204 | -- ################################################################################################## |
| 205 | --############################################################## | 205 | -- ################################################################################################## |
| 206 | --############################################################## | 206 | -- ################################################################################################## |
| 207 | 207 | ||
| 208 | PRINT( "\n\n", "---=== Communications ===---", "\n\n") | 208 | PRINT( "\n\n", "---=== Communications ===---", "\n\n") |
| 209 | 209 | ||
| @@ -285,9 +285,9 @@ collectgarbage() | |||
| 285 | WR("waiting 1s") | 285 | WR("waiting 1s") |
| 286 | linda:receive( 1, "wait") | 286 | linda:receive( 1, "wait") |
| 287 | 287 | ||
| 288 | --############################################################## | 288 | -- ################################################################################################## |
| 289 | --############################################################## | 289 | -- ################################################################################################## |
| 290 | --############################################################## | 290 | -- ################################################################################################## |
| 291 | 291 | ||
| 292 | PRINT( "\n\n", "---=== Stdlib naming ===---", "\n\n") | 292 | PRINT( "\n\n", "---=== Stdlib naming ===---", "\n\n") |
| 293 | 293 | ||
| @@ -341,9 +341,9 @@ end | |||
| 341 | WR("collectgarbage") | 341 | WR("collectgarbage") |
| 342 | collectgarbage() | 342 | collectgarbage() |
| 343 | 343 | ||
| 344 | --############################################################## | 344 | -- ################################################################################################## |
| 345 | --############################################################## | 345 | -- ################################################################################################## |
| 346 | --############################################################## | 346 | -- ################################################################################################## |
| 347 | 347 | ||
| 348 | PRINT( "\n\n", "---=== Comms criss cross ===---", "\n\n") | 348 | PRINT( "\n\n", "---=== Comms criss cross ===---", "\n\n") |
| 349 | 349 | ||
| @@ -374,9 +374,9 @@ WR("collectgarbage") | |||
| 374 | a, b = nil | 374 | a, b = nil |
| 375 | collectgarbage() | 375 | collectgarbage() |
| 376 | 376 | ||
| 377 | --############################################################## | 377 | -- ################################################################################################## |
| 378 | --############################################################## | 378 | -- ################################################################################################## |
| 379 | --############################################################## | 379 | -- ################################################################################################## |
| 380 | 380 | ||
| 381 | PRINT( "\n\n", "---=== Receive & send of code ===---", "\n\n") | 381 | PRINT( "\n\n", "---=== Receive & send of code ===---", "\n\n") |
| 382 | 382 | ||
| @@ -436,9 +436,9 @@ assert( s2==":)" ) | |||
| 436 | local k,ok2= linda:receive( "up" ) | 436 | local k,ok2= linda:receive( "up" ) |
| 437 | assert( ok2 == "ok2" ) | 437 | assert( ok2 == "ok2" ) |
| 438 | 438 | ||
| 439 | --############################################################## | 439 | -- ################################################################################################## |
| 440 | --############################################################## | 440 | -- ################################################################################################## |
| 441 | --############################################################## | 441 | -- ################################################################################################## |
| 442 | 442 | ||
| 443 | PRINT( "\n\n", "---=== :join test ===---", "\n\n") | 443 | PRINT( "\n\n", "---=== :join test ===---", "\n\n") |
| 444 | 444 | ||
diff --git a/tests/cancel.lua b/tests/cancel.lua index c22103f..5bd569f 100644 --- a/tests/cancel.lua +++ b/tests/cancel.lua | |||
| @@ -5,7 +5,7 @@ for k,v in ipairs{...} do | |||
| 5 | remaining_tests[v] = true | 5 | remaining_tests[v] = true |
| 6 | end | 6 | end |
| 7 | 7 | ||
| 8 | --#################################################################### | 8 | -- ################################################################################################## |
| 9 | 9 | ||
| 10 | local lanes = require "lanes" .configure{ with_timers = false} | 10 | local lanes = require "lanes" .configure{ with_timers = false} |
| 11 | 11 | ||
| @@ -13,7 +13,8 @@ local linda = lanes.linda() | |||
| 13 | -- a numeric value to read | 13 | -- a numeric value to read |
| 14 | linda:set( "val", 33.0) | 14 | linda:set( "val", 33.0) |
| 15 | 15 | ||
| 16 | --#################################################################### | 16 | -- ################################################################################################## |
| 17 | |||
| 17 | if not next(which_tests) or which_tests.genlock then | 18 | if not next(which_tests) or which_tests.genlock then |
| 18 | remaining_tests.genlock = nil | 19 | remaining_tests.genlock = nil |
| 19 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" | 20 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" |
| @@ -42,7 +43,8 @@ if not next(which_tests) or which_tests.genlock then | |||
| 42 | 43 | ||
| 43 | print "test OK" | 44 | print "test OK" |
| 44 | end | 45 | end |
| 45 | --#################################################################### | 46 | |
| 47 | -- ################################################################################################## | ||
| 46 | 48 | ||
| 47 | local waitCancellation = function( h, expected_status) | 49 | local waitCancellation = function( h, expected_status) |
| 48 | local l = lanes.linda() | 50 | local l = lanes.linda() |
| @@ -127,8 +129,8 @@ local protectedBody = function( ...) | |||
| 127 | end | 129 | end |
| 128 | end | 130 | end |
| 129 | 131 | ||
| 130 | --#################################################################### | 132 | -- ################################################################################################## |
| 131 | --#################################################################### | 133 | -- ################################################################################################## |
| 132 | 134 | ||
| 133 | if not next(which_tests) or which_tests.linda then | 135 | if not next(which_tests) or which_tests.linda then |
| 134 | remaining_tests.linda = nil | 136 | remaining_tests.linda = nil |
| @@ -149,6 +151,8 @@ if not next(which_tests) or which_tests.linda then | |||
| 149 | linda:cancel( "none") | 151 | linda:cancel( "none") |
| 150 | end | 152 | end |
| 151 | 153 | ||
| 154 | -- ################################################################################################## | ||
| 155 | |||
| 152 | if not next(which_tests) or which_tests.soft then | 156 | if not next(which_tests) or which_tests.soft then |
| 153 | remaining_tests.soft = nil | 157 | remaining_tests.soft = nil |
| 154 | print "\n\n####################################################################\nbegin soft cancel test\n" | 158 | print "\n\n####################################################################\nbegin soft cancel test\n" |
| @@ -171,6 +175,8 @@ if not next(which_tests) or which_tests.soft then | |||
| 171 | waitCancellation( h, "done") | 175 | waitCancellation( h, "done") |
| 172 | end | 176 | end |
| 173 | 177 | ||
| 178 | -- ################################################################################################## | ||
| 179 | |||
| 174 | if not next(which_tests) or which_tests.hook then | 180 | if not next(which_tests) or which_tests.hook then |
| 175 | remaining_tests.hook = nil | 181 | remaining_tests.hook = nil |
| 176 | print "\n\n####################################################################\nbegin hook cancel test\n" | 182 | print "\n\n####################################################################\nbegin hook cancel test\n" |
| @@ -186,6 +192,8 @@ if not next(which_tests) or which_tests.hook then | |||
| 186 | waitCancellation( h, "cancelled") | 192 | waitCancellation( h, "cancelled") |
| 187 | end | 193 | end |
| 188 | 194 | ||
| 195 | -- ################################################################################################## | ||
| 196 | |||
| 189 | if not next(which_tests) or which_tests.hard then | 197 | if not next(which_tests) or which_tests.hard then |
| 190 | remaining_tests.hard = nil | 198 | remaining_tests.hard = nil |
| 191 | print "\n\n####################################################################\nbegin hard cancel test\n" | 199 | print "\n\n####################################################################\nbegin hard cancel test\n" |
| @@ -203,6 +211,8 @@ if not next(which_tests) or which_tests.hard then | |||
| 203 | waitCancellation( h, "cancelled") | 211 | waitCancellation( h, "cancelled") |
| 204 | end | 212 | end |
| 205 | 213 | ||
| 214 | -- ################################################################################################## | ||
| 215 | |||
| 206 | if not next(which_tests) or which_tests.hard_unprotected then | 216 | if not next(which_tests) or which_tests.hard_unprotected then |
| 207 | remaining_tests.hard_unprotected = nil | 217 | remaining_tests.hard_unprotected = nil |
| 208 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" | 218 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" |
| @@ -220,7 +230,7 @@ if not next(which_tests) or which_tests.hard_unprotected then | |||
| 220 | waitCancellation( h, "cancelled") | 230 | waitCancellation( h, "cancelled") |
| 221 | end | 231 | end |
| 222 | 232 | ||
| 223 | --#################################################################### | 233 | -- ################################################################################################## |
| 224 | 234 | ||
| 225 | local unknown_test, val = next(remaining_tests) | 235 | local unknown_test, val = next(remaining_tests) |
| 226 | assert(not unknown_test, tostring(unknown_test) .. " test is unknown") | 236 | assert(not unknown_test, tostring(unknown_test) .. " test is unknown") |
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index 61b8f05..6b79c1f 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua | |||
| @@ -17,7 +17,7 @@ local finalizer = function(err, stk) | |||
| 17 | end | 17 | end |
| 18 | end | 18 | end |
| 19 | 19 | ||
| 20 | --################################################################################################## | 20 | -- ################################################################################################# |
| 21 | 21 | ||
| 22 | -- this lane eats items in the linda one by one | 22 | -- this lane eats items in the linda one by one |
| 23 | local eater = function( l, loop) | 23 | local eater = function( l, loop) |
| @@ -34,7 +34,7 @@ local eater = function( l, loop) | |||
| 34 | print("eater: done ("..val..")") | 34 | print("eater: done ("..val..")") |
| 35 | end | 35 | end |
| 36 | 36 | ||
| 37 | --################################################################################################## | 37 | -- ################################################################################################# |
| 38 | 38 | ||
| 39 | -- this lane eats items in the linda in batches | 39 | -- this lane eats items in the linda in batches |
| 40 | local gobbler = function( l, loop, batch) | 40 | local gobbler = function( l, loop, batch) |
| @@ -51,12 +51,12 @@ local gobbler = function( l, loop, batch) | |||
| 51 | print("gobbler: done ("..val..")") | 51 | print("gobbler: done ("..val..")") |
| 52 | end | 52 | end |
| 53 | 53 | ||
| 54 | --################################################################################################## | 54 | -- ################################################################################################# |
| 55 | 55 | ||
| 56 | local lane_eater_gen = lanes.gen( "*", {priority = 3}, eater) | 56 | local lane_eater_gen = lanes.gen( "*", {priority = 3}, eater) |
| 57 | local lane_gobbler_gen = lanes.gen( "*", {priority = 3}, gobbler) | 57 | local lane_gobbler_gen = lanes.gen( "*", {priority = 3}, gobbler) |
| 58 | 58 | ||
| 59 | --################################################################################################## | 59 | -- ################################################################################################# |
| 60 | 60 | ||
| 61 | -- main thread writes data while a lane reads it | 61 | -- main thread writes data while a lane reads it |
| 62 | local function ziva( preloop, loop, batch) | 62 | local function ziva( preloop, loop, batch) |
| @@ -102,7 +102,7 @@ local function ziva( preloop, loop, batch) | |||
| 102 | return lanes.now_secs() - t1 | 102 | return lanes.now_secs() - t1 |
| 103 | end | 103 | end |
| 104 | 104 | ||
| 105 | --################################################################################################## | 105 | -- ################################################################################################# |
| 106 | 106 | ||
| 107 | TEST1 = TEST1 or 1000 | 107 | TEST1 = TEST1 or 1000 |
| 108 | PREFILL1 = PREFILL1 or 10000 | 108 | PREFILL1 = PREFILL1 or 10000 |
| @@ -130,7 +130,7 @@ for i, v in ipairs( tests1) do | |||
| 130 | print("DURATION = " .. ziva( pre, loop, batch) .. "\n") | 130 | print("DURATION = " .. ziva( pre, loop, batch) .. "\n") |
| 131 | end | 131 | end |
| 132 | 132 | ||
| 133 | --################################################################################################## | 133 | -- ################################################################################################# |
| 134 | 134 | ||
| 135 | -- sequential write/read (no parallelization involved) | 135 | -- sequential write/read (no parallelization involved) |
| 136 | local function ziva2( preloop, loop, batch) | 136 | local function ziva2( preloop, loop, batch) |
| @@ -178,7 +178,7 @@ local function ziva2( preloop, loop, batch) | |||
| 178 | return lanes.now_secs() - t1 | 178 | return lanes.now_secs() - t1 |
| 179 | end | 179 | end |
| 180 | 180 | ||
| 181 | --################################################################################################## | 181 | -- ################################################################################################# |
| 182 | 182 | ||
| 183 | TEST2 = TEST2 or 1000 | 183 | TEST2 = TEST2 or 1000 |
| 184 | PREFILL2 = PREFILL2 or 0 | 184 | PREFILL2 = PREFILL2 or 0 |
