/** * @brief Copies the function on the top of src to the top of dst. * * It can be a Lua function or a C function. * * @param src source state * @param dst destination state */ static void sglua_copy_function(lua_State* src, lua_State* dst) { if (lua_iscfunction(src, -1)) { /* it's a C function */ XBT_DEBUG("It's a C function"); sglua_stack_dump("src before copying upvalues: ", src); /* get the function pointer */ int function_index = lua_gettop(src); lua_CFunction f = lua_tocfunction(src, function_index); /* copy the upvalues */ int i = 0; const char* upvalue_name = NULL; do { i++; upvalue_name = lua_getupvalue(src, function_index, i); if (upvalue_name != NULL) { XBT_DEBUG("Upvalue %s", upvalue_name); sglua_move_value(src, dst); } } while (upvalue_name != NULL); sglua_stack_dump("src before copying pointer: ", src); /* set the function */ lua_pushcclosure(dst, f, i - 1); XBT_DEBUG("Function pointer copied"); } else { /* it's a Lua function: dump it from src */ s_sglua_buffer_t buffer; buffer.capacity = 128; /* an empty function uses 77 bytes */ buffer.size = 0; buffer.data = xbt_new(char, buffer.capacity); /* copy the binary chunk from src into a buffer */ _XBT_GNUC_UNUSED int error = lua_dump(src, sglua_memory_writer, &buffer); xbt_assert(!error, "Failed to dump the function from the source state: error %d", error); XBT_DEBUG("Fonction dumped: %zu bytes", buffer.size); /* fwrite(buffer.data, buffer.size, buffer.size, stderr); fprintf(stderr, "\n"); */ /* load the chunk into dst */ error = luaL_loadbuffer(dst, buffer.data, buffer.size, "(dumped function)"); xbt_assert(!error, "Failed to load the function into the destination state: %s", lua_tostring(dst, -1)); } }
/** * @brief Pushes onto the stack a copy of the value on top another stack. * If the value is a table, its content is copied recursively. * * This function allows to move a value between two different global states. * * @param src the source state (not necessarily maestro) * @param dst the destination state */ void sglua_copy_value(lua_State* src, lua_State* dst) { luaL_checkany(src, -1); /* check the value to copy */ int indent = (lua_gettop(dst) - 1) * 6; XBT_DEBUG("%sCopying data %s", sglua_get_spaces(indent), sglua_tostring(src, -1)); sglua_stack_dump("src before copying a value (should be ... value): ", src); sglua_stack_dump("dst before copying a value (should be ...): ", dst); switch (lua_type(src, -1)) { case LUA_TNIL: sglua_copy_nil(src, dst); break; case LUA_TNUMBER: sglua_copy_number(src, dst); break; case LUA_TBOOLEAN: sglua_copy_boolean(src, dst); break; case LUA_TSTRING: sglua_copy_string(src, dst); break; case LUA_TFUNCTION: sglua_copy_function(src, dst); break; case LUA_TTABLE: sglua_copy_table(src, dst); break; case LUA_TLIGHTUSERDATA: sglua_copy_lightuserdata(src, dst); break; case LUA_TUSERDATA: sglua_copy_userdata(src, dst); break; case LUA_TTHREAD: sglua_copy_thread(src, dst); break; } XBT_DEBUG("%sData copied", sglua_get_spaces(indent)); sglua_stack_dump("src after copying a value (should be ... value): ", src); sglua_stack_dump("dst after copying a value (should be ... value): ", dst); }
/** * \brief Like luaL_checkudata, with additional debug logs. * * This function is for debugging purposes only. * * \param L a lua state * \param ud index of the userdata to check in the stack * \param tname key of the metatable of this userdata in the registry */ void* sglua_checkudata_debug(lua_State* L, int ud, const char* tname) { XBT_DEBUG("Checking the userdata: ud = %d", ud); sglua_stack_dump(L, "my_checkudata: "); void* p = lua_touserdata(L, ud); lua_getfield(L, LUA_REGISTRYINDEX, tname); const void* correct_mt = lua_topointer(L, -1); int has_mt = lua_getmetatable(L, ud); XBT_DEBUG("Checking the userdata: has metatable ? %d", has_mt); const void* actual_mt = nullptr; if (has_mt) { actual_mt = lua_topointer(L, -1); lua_pop(L, 1); } XBT_DEBUG("Checking the task's metatable: expected %p, found %p", correct_mt, actual_mt); sglua_stack_dump(L, "my_checkudata: "); if (p == nullptr || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) XBT_ERROR("Error: Userdata is nullptr, couldn't find metatable or top of stack does not equal element below it."); lua_pop(L, 2); return p; }
/** * @brief Copies the table value on top of src to the top of dst. * * A deep copy of the table is made. If the table has a metatable, the * metatable is also copied. * If the table comes from maestro and is already known by the destination * state, it is not copied again. * * @param src source state * @param dst destination state */ static void sglua_copy_table(lua_State* src, lua_State* dst) { /* src: ... table dst: ... */ int indent = lua_gettop(dst) * 6 + 2; /* get from maestro the pointer that identifies this table */ void* table_ptr = sglua_get_maestro_table_ptr(src, -1); int known_by_maestro = (table_ptr != NULL); if (!known_by_maestro) { /* the table didn't come from maestro: nevermind, use the pointer of src */ table_ptr = (void*) lua_topointer(src, -1); XBT_DEBUG("%sMaestro does not know this table", sglua_get_spaces(indent)); } if (sglua_is_maestro(src)) { /* register the table in maestro itself */ XBT_DEBUG("%sKeeping track of this table in maestro itself", sglua_get_spaces(indent)); sglua_add_maestro_table(src, -1, table_ptr); known_by_maestro = 1; xbt_assert(sglua_get_maestro_table_ptr(src, -1) == table_ptr); } /* to avoid infinite recursion, see if this table is already known by dst */ sglua_get_table_by_ptr(dst, table_ptr); /* dst: ... table/nil */ if (!lua_isnil(dst, -1)) { XBT_DEBUG("%sNothing to do: table already known (%p)", sglua_get_spaces(indent), table_ptr); /* dst: ... table */ } else { XBT_DEBUG("%sFirst visit of this table (%p)", sglua_get_spaces(indent), table_ptr); /* dst: ... nil */ lua_pop(dst, 1); /* dst: ... */ /* first visit: create the new table in dst */ lua_newtable(dst); /* dst: ... table */ /* mark the table as known right now to avoid infinite recursion */ sglua_add_maestro_table(dst, -1, table_ptr); /* we may have added a table with a non-maestro pointer, but if it was the * case, we will remove it later */ XBT_DEBUG("%sTable marked as known", sglua_get_spaces(indent)); xbt_assert(sglua_get_maestro_table_ptr(dst, -1) == table_ptr); sglua_stack_dump("dst after marking the table as known (should be ... table): ", dst); /* copy the metatable if any */ int has_meta_table = lua_getmetatable(src, -1); /* src: ... table mt? */ if (has_meta_table) { XBT_DEBUG("%sCopying the metatable", sglua_get_spaces(indent)); /* src: ... table mt */ sglua_copy_table(src, dst); /* dst: ... table mt */ lua_pop(src, 1); /* src: ... table */ lua_setmetatable(dst, -2); /* dst: ... table */ } else { /* src: ... table */ XBT_DEBUG("%sNo metatable", sglua_get_spaces(indent)); } sglua_stack_dump("src before traversing the table (should be ... table): ", src); sglua_stack_dump("dst before traversing the table (should be ... table): ", dst); /* traverse the table of src and copy each element */ lua_pushnil(src); /* src: ... table nil */ while (lua_next(src, -2) != 0) { /* src: ... table key value */ XBT_DEBUG("%sCopying table element %s", sglua_get_spaces(indent), sglua_keyvalue_tostring(src, -2, -1)); sglua_stack_dump("src before copying table element (should be ... table key value): ", src); sglua_stack_dump("dst before copying table element (should be ... table): ", dst); /* copy the key */ lua_pushvalue(src, -2); /* src: ... table key value key */ indent += 2; XBT_DEBUG("%sCopying the key part of the table element", sglua_get_spaces(indent)); sglua_move_value(src, dst); /* src: ... table key value dst: ... table key */ XBT_DEBUG("%sCopied the key part of the table element", sglua_get_spaces(indent)); /* copy the value */ XBT_DEBUG("%sCopying the value part of the table element", sglua_get_spaces(indent)); sglua_move_value(src, dst); /* src: ... table key dst: ... table key value */ XBT_DEBUG("%sCopied the value part of the table element", sglua_get_spaces(indent)); indent -= 2; /* set the table element */ lua_settable(dst, -3); /* dst: ... table */ /* the key stays on top of src for next iteration */ sglua_stack_dump("src before next iteration (should be ... table key): ", src); sglua_stack_dump("dst before next iteration (should be ... table): ", dst); XBT_DEBUG("%sTable element copied", sglua_get_spaces(indent)); } XBT_DEBUG("%sFinished traversing the table", sglua_get_spaces(indent)); } if (!known_by_maestro) { /* actually,it was not a maestro table: forget the pointer */ sglua_remove_maestro_table(dst, -1, table_ptr); } }