| 203 | } |
| 204 | |
| 205 | LuaEnginePtr LuaEngine::create(bool safe) { |
| 206 | LuaEnginePtr self(new LuaEngine); |
| 207 | |
| 208 | self->m_state = lua_newstate(allocate, nullptr); |
| 209 | |
| 210 | self->m_scriptDefaultEnvRegistryId = LUA_NOREF; |
| 211 | self->m_wrappedFunctionMetatableRegistryId = LUA_NOREF; |
| 212 | self->m_requireFunctionMetatableRegistryId = LUA_NOREF; |
| 213 | |
| 214 | self->m_instructionLimit = 0; |
| 215 | self->m_profilingEnabled = false; |
| 216 | self->m_instructionMeasureInterval = 1000; |
| 217 | self->m_instructionCount = 0; |
| 218 | self->m_recursionLevel = 0; |
| 219 | self->m_recursionLimit = 0; |
| 220 | self->m_nullTerminated = 0; |
| 221 | |
| 222 | if (!self->m_state) |
| 223 | throw LuaException("Failed to initialize Lua"); |
| 224 | |
| 225 | lua_checkstack(self->m_state, 5); |
| 226 | |
| 227 | // Create handle stack thread and place it in the registry to prevent it from being garbage |
| 228 | // collected. |
| 229 | |
| 230 | self->m_handleThread = lua_newthread(self->m_state); |
| 231 | luaL_ref(self->m_state, LUA_REGISTRYINDEX); |
| 232 | |
| 233 | // We need 1 extra stack space to move values in and out of the handle stack. |
| 234 | self->m_handleStackSize = LUA_MINSTACK - 1; |
| 235 | self->m_handleStackMax = 0; |
| 236 | |
| 237 | // Set the extra space in the lua main state to the pointer to the main |
| 238 | // LuaEngine |
| 239 | *reinterpret_cast<LuaEngine**>(lua_getextraspace(self->m_state)) = self.get(); |
| 240 | |
| 241 | // Create the common message handler function for pcall to print a better |
| 242 | // message with a traceback |
| 243 | lua_pushcfunction(self->m_state, [](lua_State* state) { |
| 244 | // Don't modify the error if it is one of the special limit errrors |
| 245 | if (lua_islightuserdata(state, 1)) { |
| 246 | void* error = lua_touserdata(state, -1); |
| 247 | if (error == &s_luaInstructionLimitExceptionKey || error == &s_luaRecursionLimitExceptionKey) |
| 248 | return 1; |
| 249 | } |
| 250 | |
| 251 | luaL_traceback(state, state, lua_tostring(state, 1), 0); |
| 252 | lua_remove(state, 1); |
| 253 | return 1; |
| 254 | }); |
| 255 | self->m_pcallTracebackMessageHandlerRegistryId = luaL_ref(self->m_state, LUA_REGISTRYINDEX); |
| 256 | |
| 257 | // Create the common metatable for wrapped functions |
| 258 | lua_newtable(self->m_state); |
| 259 | lua_pushcfunction(self->m_state, [](lua_State* state) { |
| 260 | auto func = (LuaDetail::LuaWrappedFunction*)lua_touserdata(state, 1); |
| 261 | func->~function(); |
| 262 | return 0; |