re-implement xmove implicit transfers and hope it works proper this time

This commit is contained in:
ThePhD 2017-09-13 10:20:24 -04:00
parent 5816c6c34b
commit dcff5cdaa0
4 changed files with 234 additions and 63 deletions

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2017-09-13 06:45:53.519071 UTC // Generated 2017-09-13 14:18:42.960702 UTC
// This header was generated with sol v2.18.2 (revision 66eb025) // This header was generated with sol v2.18.2 (revision 5816c6c)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -5672,6 +5672,17 @@ namespace sol {
// beginning of sol/stack_reference.hpp // beginning of sol/stack_reference.hpp
namespace sol { namespace sol {
namespace detail {
inline bool xmovable(lua_State* leftL, lua_State* rightL) {
if (rightL == nullptr || leftL == nullptr || leftL == rightL) {
return false;
}
const void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX);
const void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX);
return leftregistry == rightregistry;
}
} // namespace detail
class stack_reference { class stack_reference {
private: private:
lua_State* luastate = nullptr; lua_State* luastate = nullptr;
@ -5707,7 +5718,7 @@ namespace sol {
return; return;
} }
int i = r.stack_index(); int i = r.stack_index();
if (r.lua_state() != luastate) { if (detail::xmovable(lua_state(), r.lua_state())) {
lua_pushvalue(r.lua_state(), r.index); lua_pushvalue(r.lua_state(), r.index);
lua_xmove(r.lua_state(), luastate, 1); lua_xmove(r.lua_state(), luastate, 1);
i = absolute_index(luastate, -1); i = absolute_index(luastate, -1);
@ -5931,40 +5942,54 @@ namespace sol {
} }
reference(lua_State* L, const reference& r) noexcept reference(lua_State* L, const reference& r) noexcept
: luastate(L) { : luastate(L) {
if (r.ref == LUA_NOREF) { if (r.ref == LUA_REFNIL) {
ref = LUA_REFNIL;
return;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
int p = r.push(); if (detail::xmovable(lua_state(), r.lua_state())) {
if (r.lua_state() != luastate) { r.push(lua_state());
lua_xmove(r.lua_state(), L, p); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return;
} }
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = r.copy();
} }
reference(lua_State* L, reference&& r) noexcept reference(lua_State* L, reference&& r) noexcept
: luastate(L) { : luastate(L) {
if (r.ref == LUA_NOREF) { if (r.ref == LUA_REFNIL) {
ref = LUA_REFNIL;
return;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
if (r.lua_state() != luastate) { if (detail::xmovable(lua_state(), r.lua_state())) {
int p = r.push(); r.push(lua_state());
lua_xmove(r.lua_state(), L, p);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return;
} }
else { ref = r.ref;
ref = r.ref; r.ref = LUA_NOREF;
r.luastate = nullptr; r.luastate = nullptr;
r.ref = LUA_NOREF;
}
} }
reference(lua_State* L, const stack_reference& r) noexcept reference(lua_State* L, const stack_reference& r) noexcept
: luastate(L) { : luastate(L) {
if (!r.valid()) { if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
r.push(luastate); if (r.get_type() == type::nil) {
ref = LUA_REFNIL;
return;
}
if (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) {
return;
}
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
} }
reference(lua_State* L, int index = -1) noexcept reference(lua_State* L, int index = -1) noexcept
@ -5995,26 +6020,43 @@ namespace sol {
o.ref = LUA_NOREF; o.ref = LUA_NOREF;
} }
reference& operator=(reference&& o) noexcept { reference& operator=(reference&& r) noexcept {
if (valid()) { if (r.ref == LUA_REFNIL) {
deref(); ref = LUA_REFNIL;
return *this;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF;
return *this;
}
if (detail::xmovable(lua_state(), r.lua_state())) {
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return *this;
} }
luastate = o.luastate;
ref = o.ref;
o.luastate = nullptr;
o.ref = LUA_NOREF;
ref = r.ref;
r.ref = LUA_NOREF;
r.luastate = nullptr;
return *this; return *this;
} }
reference& operator=(const reference& o) noexcept { reference& operator=(const reference& r) noexcept {
if (valid()) { if (r.ref == LUA_REFNIL) {
deref(); ref = LUA_REFNIL;
return *this;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF;
return *this;
}
if (detail::xmovable(lua_state(), r.lua_state())) {
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return *this;
} }
luastate = o.luastate; ref = r.copy();
ref = o.copy();
return *this; return *this;
} }

View File

@ -167,40 +167,54 @@ namespace sol {
} }
reference(lua_State* L, const reference& r) noexcept reference(lua_State* L, const reference& r) noexcept
: luastate(L) { : luastate(L) {
if (r.ref == LUA_NOREF) { if (r.ref == LUA_REFNIL) {
ref = LUA_REFNIL;
return;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
int p = r.push(); if (detail::xmovable(lua_state(), r.lua_state())) {
if (r.lua_state() != luastate) { r.push(lua_state());
lua_xmove(r.lua_state(), L, p); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return;
} }
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = r.copy();
} }
reference(lua_State* L, reference&& r) noexcept reference(lua_State* L, reference&& r) noexcept
: luastate(L) { : luastate(L) {
if (r.ref == LUA_NOREF) { if (r.ref == LUA_REFNIL) {
ref = LUA_REFNIL;
return;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
if (r.lua_state() != luastate) { if (detail::xmovable(lua_state(), r.lua_state())) {
int p = r.push(); r.push(lua_state());
lua_xmove(r.lua_state(), L, p);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return;
} }
else { ref = r.ref;
ref = r.ref; r.ref = LUA_NOREF;
r.luastate = nullptr; r.luastate = nullptr;
r.ref = LUA_NOREF;
}
} }
reference(lua_State* L, const stack_reference& r) noexcept reference(lua_State* L, const stack_reference& r) noexcept
: luastate(L) { : luastate(L) {
if (!r.valid()) { if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) {
ref = LUA_NOREF; ref = LUA_NOREF;
return; return;
} }
r.push(luastate); if (r.get_type() == type::nil) {
ref = LUA_REFNIL;
return;
}
if (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) {
return;
}
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
} }
reference(lua_State* L, int index = -1) noexcept reference(lua_State* L, int index = -1) noexcept
@ -231,26 +245,43 @@ namespace sol {
o.ref = LUA_NOREF; o.ref = LUA_NOREF;
} }
reference& operator=(reference&& o) noexcept { reference& operator=(reference&& r) noexcept {
if (valid()) { if (r.ref == LUA_REFNIL) {
deref(); ref = LUA_REFNIL;
return *this;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF;
return *this;
}
if (detail::xmovable(lua_state(), r.lua_state())) {
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return *this;
} }
luastate = o.luastate;
ref = o.ref;
o.luastate = nullptr;
o.ref = LUA_NOREF;
ref = r.ref;
r.ref = LUA_NOREF;
r.luastate = nullptr;
return *this; return *this;
} }
reference& operator=(const reference& o) noexcept { reference& operator=(const reference& r) noexcept {
if (valid()) { if (r.ref == LUA_REFNIL) {
deref(); ref = LUA_REFNIL;
return *this;
}
if (r.ref == LUA_NOREF || lua_state() == nullptr) {
ref = LUA_NOREF;
return *this;
}
if (detail::xmovable(lua_state(), r.lua_state())) {
r.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return *this;
} }
luastate = o.luastate; ref = r.copy();
ref = o.copy();
return *this; return *this;
} }

View File

@ -25,6 +25,17 @@
#include "types.hpp" #include "types.hpp"
namespace sol { namespace sol {
namespace detail {
inline bool xmovable(lua_State* leftL, lua_State* rightL) {
if (rightL == nullptr || leftL == nullptr || leftL == rightL) {
return false;
}
const void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX);
const void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX);
return leftregistry == rightregistry;
}
} // namespace detail
class stack_reference { class stack_reference {
private: private:
lua_State* luastate = nullptr; lua_State* luastate = nullptr;
@ -60,7 +71,7 @@ namespace sol {
return; return;
} }
int i = r.stack_index(); int i = r.stack_index();
if (r.lua_state() != luastate) { if (detail::xmovable(lua_state(), r.lua_state())) {
lua_pushvalue(r.lua_state(), r.index); lua_pushvalue(r.lua_state(), r.index);
lua_xmove(r.lua_state(), luastate, 1); lua_xmove(r.lua_state(), luastate, 1);
i = absolute_index(luastate, -1); i = absolute_index(luastate, -1);

View File

@ -108,7 +108,7 @@ end
} }
} }
TEST_CASE("coroutines/implicit transfer", "check that copy and move assignment constructors implicitly shift things around") { TEST_CASE("coroutines/explicit transfer", "check that the xmove constructors shift things around appropriately") {
const std::string code = R"( const std::string code = R"(
-- main thread - L1 -- main thread - L1
-- co - L2 -- co - L2
@ -194,3 +194,90 @@ co = nil
std::string s = t[1]; std::string s = t[1];
REQUIRE(s == "SOME_TABLE"); REQUIRE(s == "SOME_TABLE");
} }
TEST_CASE("coroutines/implicit transfer", "check that copy and move assignment constructors implicitly shift things around") {
const std::string code = R"(
-- main thread - L1
-- co - L2
-- co2 - L3
x = co_test.new("x")
local co = coroutine.wrap(
function()
local t = co_test.new("t")
local co2 = coroutine.wrap(
function()
local t2 = { "SOME_TABLE" }
t:copy_store(t2) -- t2 = [L3], t.obj = [L2]
end
)
co2()
co2 = nil
collectgarbage() -- t2 ref in t remains valid!
x:store(t:get()) -- t.obj = [L2], x.obj = [L1]
end
)
co()
collectgarbage()
collectgarbage()
co = nil
)";
struct co_test_implicit {
std::string identifier;
sol::reference obj;
co_test_implicit(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
// must be explicit
obj = std::move(ref);
}
void copy_store(sol::table ref) {
// must be explicit
obj = ref;
}
sol::reference get() {
return obj;
}
~co_test_implicit() {
}
};
sol::state lua;
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<co_test_implicit>("co_test",
sol::constructors<co_test_implicit(sol::this_state, std::string)>(),
"store", &co_test_implicit::store,
"copy_store", &co_test_implicit::copy_store,
"get", &co_test_implicit::get
);
auto r = lua.safe_script(code);
REQUIRE(r.valid());
co_test_implicit& ct = lua["x"];
lua_State* Lmain1 = lua.lua_state();
lua_State* Lmain2 = sol::main_thread(lua);
lua_State* Lmain3 = ct.get().lua_state();
REQUIRE(Lmain1 == Lmain2);
REQUIRE(Lmain1 == Lmain3);
sol::table t = ct.get();
REQUIRE(t.size() == 1);
std::string s = t[1];
REQUIRE(s == "SOME_TABLE");
}