-/* Copyright (c) 2010. The SimGrid Team.
+/* Copyright (c) 2010-2014. The SimGrid Team.
* All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
#include <lauxlib.h>
#include <lualib.h>
-XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_state_cloner, lua, "Lua state management");
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua_state_cloner, bindings, "Lua state management");
static void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr);
+static void sglua_remove_maestro_table(lua_State* L, int index, void* maestro_table_ptr);
static void* sglua_get_maestro_table_ptr(lua_State* L, int index);
static void sglua_get_table_by_ptr(lua_State* L, void* table_ptr);
static int l_get_from_maestro(lua_State* L);
static void sglua_copy_userdata(lua_State* src, lua_State* dst);
static void sglua_copy_thread(lua_State* src, lua_State* dst);
-/**
- * @brief Returns the father of a state, i.e. the state that created it.
- * @param L a Lua state
- * @return its father, or NULL if the state was not created by sglua_clone_state()
- */
-static lua_State* sglua_get_father(lua_State* L) {
-
- /* ... */
- lua_pushstring(L, "simgrid.father");
- /* ... "simgrid.father" */
- lua_rawget(L, LUA_REGISTRYINDEX);
- /* ... father */
- lua_State* father = lua_touserdata(L, -1);
- lua_pop(L, 1);
- /* ... */
- return father;
-}
-
/**
* @brief Adds a reference to a maestro table to the list of known maestro
* tables of a state.
* @param index index of the copy of the maestro table in the stack of L
* @param maestro_table_ptr pointer to the original table in maestro's world
*/
-void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr) {
+static void sglua_add_maestro_table(lua_State* L, int index, void* maestro_table_ptr) {
/* we will set both [ptr] -> table and [table] -> ptr */
/* ... */
}
+/**
+ * @brief Removes a reference to a maestro table to the list of known maestro
+ * tables of a state.
+ *
+ * @param L a state (can be maestro itself)
+ * @param index index of the copy of the maestro table in the stack of L
+ * @param maestro_table_ptr pointer to the original table in maestro's world
+ */
+static void sglua_remove_maestro_table(lua_State* L, int index, void* maestro_table_ptr) {
+
+ /* we will unset both [ptr] -> table and [table] -> ptr */
+
+ /* ... */
+ lua_pushvalue(L, index);
+ /* ... table */
+ lua_pushstring(L, "simgrid.maestro_tables");
+ /* ... table "simgrid.maestro_tables" */
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ /* ... table maestrotbs */
+ lua_pushvalue(L, -2);
+ /* ... table maestrotbs table */
+ lua_pushnil(L);
+ /* ... table maestrotbs table nil */
+ lua_pushlightuserdata(L, maestro_table_ptr);
+ /* ... table maestrotbs table nil tableptr */
+ lua_pushnil(L);
+ /* ... table maestrotbs table nil tableptr nil*/
+ lua_settable(L, -5);
+ /* ... table maestrotbs table nil */
+ lua_settable(L, -3);
+ /* ... table maestrotbs */
+ lua_pop(L, 2);
+ /* ... */
+}
+
/**
* @brief For a table in the stack of L, returns a pointer that identifies the
* same table in in maestro's world.
/**
* @brief Pops a value from the stack of a source state and pushes it on the
* stack of another state.
+ * If the value is a table, its content is copied recursively.
+ *
+ * This function is similar to lua_xmove() but it 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_move_value(lua_State* src, lua_State* dst) {
+
+ sglua_copy_value(src, dst);
+ lua_pop(src, 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.
*
- * TODO: add support of closures
+ * 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_move_value(lua_State* src, lua_State *dst) {
+void sglua_copy_value(lua_State* src, lua_State* dst) {
luaL_checkany(src, -1); /* check the value to copy */
case LUA_TTHREAD:
sglua_copy_thread(src, dst);
break;
- }
- /* the value has been copied to dst: remove it from src */
- lua_pop(src, 1);
+ case LUA_TNONE:
+ XBT_ERROR("This index is acceptable but non-valid");
+ break;
+ }
- indent -= 2;
XBT_DEBUG("%sData copied", sglua_get_spaces(indent));
- sglua_stack_dump("src after copying a value (should be ...): ", src);
+ sglua_stack_dump("src after copying a value (should be ... value): ", src);
sglua_stack_dump("dst after copying a value (should be ... value): ", dst);
}
* @param dst destination state
*/
static void sglua_copy_number(lua_State* src, lua_State* dst) {
- lua_pushnumber(dst, lua_tonumber(src, -1));
+ lua_Number n = lua_tonumber(src, -1);
+ if ( ((lua_Integer) n) == n) {
+ lua_pushinteger(dst, lua_tointeger(src, -1));
+ }
+ else
+ lua_pushnumber(dst, lua_tonumber(src, -1));
}
/**
}
/**
- * @brief Copies the table value on the top of src to the top of dst.
+ * @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 is already known by the destination state, it is not copied
- * again.
+ * 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
/* get from maestro the pointer that identifies this table */
void* table_ptr = sglua_get_maestro_table_ptr(src, -1);
- if (table_ptr == NULL) {
+ 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);
-
- if (!sglua_is_maestro(src)) {
- XBT_DEBUG("%sMaestro does not know this table",
- sglua_get_spaces(indent));
- }
+ XBT_DEBUG("%sMaestro does not know this table",
+ sglua_get_spaces(indent));
}
if (sglua_is_maestro(src)) {
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);
}
/* mark the table as known right now to avoid infinite recursion */
sglua_add_maestro_table(dst, -1, table_ptr);
- /* FIXME: we may have added a table with a non-maestro pointer, is this a
- problem? */
+ /* 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);
}
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);
+ }
}
/**
* @brief Copies the function on the top of src to the top of dst.
*
* It can be a Lua function or a C function.
- * Copying upvalues is not implemented yet (TODO).
*
* @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: just copy the pointer */
- lua_CFunction f = lua_tocfunction(src, -1);
- lua_pushcfunction(dst, f);
+ /* 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 = 64;
+ 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 */
- int error = lua_dump(src, sglua_memory_writer, &buffer);
+ /* copy the binary chunk from src into a buffer
+ * c.heinrich: Added parameter TRUE for Lua 5.3 - this strips all debug
+ * information from the function.
+ */
+ // Was before merge: XBT_GNUC_UNUSED and was replaced with XBT_ATTRIB_UNUSED
+ XBT_ATTRIB_UNUSED int error = lua_dump(src, sglua_memory_writer, &buffer, TRUE);
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)");
/* copy the data */
/* src: ... udata
dst: ... */
- size_t size = lua_objlen(src, -1);
+ size_t size = lua_rawlen(src, -1);
void* src_block = lua_touserdata(src, -1);
void* dst_block = lua_newuserdata(dst, size);
/* dst: ... udata */
/* L: table key */
XBT_DEBUG("__index of '%s' begins", key);
- /* want a global or a registry value? */
- int pseudo_index;
- if (lua_equal(L, 1, LUA_REGISTRYINDEX)) {
- /* registry */
- pseudo_index = LUA_REGISTRYINDEX;
+ /* get the father */
+ lua_State* maestro = sglua_get_maestro(); /* maestro: */
+
+ /* want a global or a registry value?
+ get the value from maestro */
+ if (lua_compare(L, 1, LUA_REGISTRYINDEX, LUA_OPEQ)) {
+ /* case: registry */
+ lua_getfield(maestro, LUA_REGISTRYINDEX, key); /* maestro: ... value */
XBT_DEBUG("Will get the value from the registry of maestro");
}
- else {
- /* global */
- pseudo_index = LUA_GLOBALSINDEX;
+ else { /* case: global */
+ lua_getglobal(maestro, key); /* maestro: ... value */
XBT_DEBUG("Will get the value from the globals of maestro");
}
- /* get the father */
- lua_State* maestro = sglua_get_maestro();
-
- /* L: table key */
+ /* L: table key */
- /* get the value from maestro */
- lua_getfield(maestro, pseudo_index, key);
- /* maestro: ... value */
/* push the value onto the stack of L */
sglua_move_value(maestro, L);
lua_setmetatable(L, -2); /* thread newenv mt reg */
lua_pop(L, 1); /* thread newenv mt */
lua_setmetatable(L, -2); /* thread newenv */
- lua_setfenv(L, -2); /* thread */
- lua_pop(L, 1); /* -- */
+ lua_pushvalue(L, LUA_REGISTRYINDEX); /* thread newenv reg */
+ lua_insert(L, -2); /* thread reg newenv */
+ lua_seti(L, -2, LUA_RIDX_GLOBALS); /* thread reg */
+ lua_pop(L, 2); /* -- */
/* create the table of known tables from maestro */
lua_pushstring(L, "simgrid.maestro_tables");
/* "simgrid.maestro_tables" */
- lua_newtable(L); /* "simgrid.maestro_tables" maestrotbs*/
+ lua_newtable(L); /* "simgrid.maestro_tables" maestrotbs */
lua_rawset(L, LUA_REGISTRYINDEX);
/* -- */
- /* open the standard libs (theoretically, this is not necessary as they can
- * be inherited like any global values, but without a proper support of
- * closures, iterators like ipairs don't work). */
- XBT_DEBUG("Metatable of globals and registry set, opening standard libraries now");
- luaL_openlibs(L);
+ /* opening the standard libs is not necessary as they are
+ * inherited like any global values */
+ /* luaL_openlibs(L); */
XBT_DEBUG("New state created");