2010-05-06 00:08:41 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "stdpch.h"
# include "lua_helper.h"
# include "nel/misc/file.h"
# include "interface_manager.h"
# include "../client_cfg.h"
# ifdef LUA_NEVRAX_VERSION
# include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger
# endif
extern " C "
{
# include "lualib.h"
}
2010-05-12 09:12:19 +00:00
// to get rid of you_must_not_use_assert___use_nl_assert___read_debug_h_file messages
# include <cassert>
# undef assert
# define assert nlassert
2010-05-06 00:08:41 +00:00
# include <luabind/luabind.hpp>
using namespace std ;
using namespace NLMISC ;
// ***************************************************************************
const char * CLuaState : : _NELSmallScriptTableName = " NELSmallScriptTable " ;
uint CLuaStackChecker : : _ExceptionContextCounter = 0 ;
// ***************************************************************************
void CLuaStackChecker : : incrementExceptionContextCounter ( )
{
//H_AUTO(Lua_CLuaStackChecker_incrementExceptionContextCounter)
+ + _ExceptionContextCounter ;
}
// ***************************************************************************
void CLuaStackChecker : : decrementExceptionContextCounter ( )
{
//H_AUTO(Lua_CLuaStackChecker_decrementExceptionContextCounter)
nlassert ( _ExceptionContextCounter > 0 ) ;
- - _ExceptionContextCounter ;
}
# ifdef LUA_NEVRAX_VERSION
ILuaIDEInterface * LuaDebuggerIDE = NULL ;
static bool LuaDebuggerVisible = false ;
# endif
# ifdef NL_OS_WINDOWS
HMODULE LuaDebuggerModule = 0 ;
# endif
void luaDebuggerMainLoop ( )
{
# ifdef LUA_NEVRAX_VERSION
if ( ! LuaDebuggerIDE ) return ;
if ( ! LuaDebuggerVisible )
{
LuaDebuggerIDE - > showDebugger ( true ) ;
LuaDebuggerIDE - > expandProjectTree ( ) ;
LuaDebuggerIDE - > sortFiles ( ) ;
LuaDebuggerVisible = true ;
}
LuaDebuggerIDE - > doMainLoop ( ) ;
# endif
}
static std : : allocator < uint8 > l_stlAlloc ;
static void l_free_func ( void * block , int oldSize )
{
l_stlAlloc . deallocate ( ( uint8 * ) block , oldSize ) ;
}
static void * l_realloc_func ( void * b , int os , int s )
{
if ( os = = s ) return b ;
void * newB = l_stlAlloc . allocate ( s ) ;
memcpy ( newB , b , std : : min ( os , s ) ) ;
l_free_func ( b , os ) ;
return newB ;
}
const int MinGCThreshold = 128 ; // min value at which garbage collector will be triggered (in kilobytes)
// ***************************************************************************
CLuaState : : CLuaState ( )
{
_State = NULL ;
# ifdef LUA_NEVRAX_VERSION
_GCThreshold = MinGCThreshold ;
# endif
# ifdef NL_OS_WINDOWS
if ( ClientCfg . LoadLuaDebugger )
{
# ifndef LUA_NEVRAX_VERSION
static bool warningShown = false ;
if ( ! warningShown )
{
MessageBox ( NULL , " Lua debugger was asked, but the static lua library against which the client was linked is too old. Please update to lua-5.0.2_nevrax. Debugging won't be available! " , " Lua support " , MB_OK ) ;
warningShown = true ;
}
# else
nlassert ( LuaDebuggerIDE = = NULL ) ; // for now, only one debugger supported...
# ifdef NL_DEBUG
LuaDebuggerModule = : : LoadLibrary ( " lua_ide2_dll_d.dll " ) ;
# else
LuaDebuggerModule = : : LoadLibrary ( " lua_ide2_dll_r.dll " ) ;
# endif
if ( LuaDebuggerModule )
{
TGetLuaIDEInterfaceVersion getVersion = ( TGetLuaIDEInterfaceVersion ) GetProcAddress ( LuaDebuggerModule , " GetLuaIDEInterfaceVersion " ) ;
nlassert ( getVersion ) ;
int dllInterfaceVersion = getVersion ( ) ;
if ( dllInterfaceVersion > LUA_IDE_INTERFACE_VERSION )
{
MessageBox ( NULL , " Lua debugger interface is newer than the application. Debugging will be disabled. Please update your client " , " Lua support " , MB_OK ) ;
}
else if ( dllInterfaceVersion < LUA_IDE_INTERFACE_VERSION )
{
MessageBox ( NULL , " Lua debugger interface is too old. Lua debugging will be disabled. Please ask for a more recent dll. " , " Lua support " , MB_OK ) ;
}
else
{
TGetLuaIDEInterface getter = ( TGetLuaIDEInterface ) GetProcAddress ( LuaDebuggerModule , " GetLuaIDEInterface " ) ;
nlassert ( getter ) ;
LuaDebuggerIDE = getter ( ) ;
LuaDebuggerIDE - > prepareDebug ( " save \\ ___external_debug.lpr " , l_realloc_func , l_free_func , ( HWND ) Driver - > getDisplay ( ) ) ;
_State = LuaDebuggerIDE - > getLuaState ( ) ;
}
}
# endif
}
# endif
if ( ! _State )
{
# ifdef LUA_NEVRAX_VERSION
_State = lua_open ( l_realloc_func , l_free_func ) ;
# else
_State = lua_open ( ) ;
# endif
nlassert ( _State ) ;
}
// *** Load base libs
{
CLuaStackChecker lsc ( this ) ;
# if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
luaL_openlibs ( _State ) ;
# else
luaopen_base ( _State ) ;
luaopen_table ( _State ) ;
luaopen_io ( _State ) ;
luaopen_string ( _State ) ;
luaopen_math ( _State ) ;
luaopen_debug ( _State ) ;
# endif
// open are buggy????
clear ( ) ;
}
// *** Register basics
CLuaStackChecker lsc ( this ) ;
// do: LUA_REGISTRYINDEX.(lightuserdata*)this.classes= {}
pushLightUserData ( ( void * ) this ) ;
newTable ( ) ;
push ( " classes " ) ;
newTable ( ) ; // registry class
setTable ( - 3 ) ;
setTable ( LUA_REGISTRYINDEX ) ;
// add pointer from lua state to this CLuaState object
// do: LUA_REGISTRYINDEX.(lightuserdata*)_State= this
pushLightUserData ( ( void * ) _State ) ; // NB : as creator of the state, we make the assumption that
// no one will be using this pointer in the registry (cf. ref manual about registry)
pushLightUserData ( ( void * ) this ) ;
setTable ( LUA_REGISTRYINDEX ) ;
// Create the Table that contains Function cache for small script execution
push ( _NELSmallScriptTableName ) ; // 1:TableName
newTable ( ) ; // 1:TableName 2:table
setTable ( LUA_REGISTRYINDEX ) ; // ...
_SmallScriptPool = 0 ;
// *** luabind init
luabind : : open ( _State ) ;
}
// ***************************************************************************
CLuaStackRestorer : : CLuaStackRestorer ( CLuaState * state , int finalSize ) : _State ( state ) , _FinalSize ( finalSize )
{
}
// ***************************************************************************
CLuaStackRestorer : : ~ CLuaStackRestorer ( )
{
nlassert ( _State ) ;
_State - > setTop ( _FinalSize ) ;
}
# ifdef NL_OS_WINDOWS
static int NoOpReportHook ( int /* reportType */ , char * /* message */ , int * /* returnValue */ )
{
return TRUE ;
}
# endif
// ***************************************************************************
CLuaState : : ~ CLuaState ( )
{
nlassert ( _State ) ;
# ifdef LUA_NEVRAX_VERSION
if ( ! LuaDebuggerIDE )
# else
if ( 1 )
# endif
{
lua_close ( _State ) ;
}
else
{
# ifdef LUA_NEVRAX_VERSION
LuaDebuggerIDE - > stopDebug ( ) ; // this will also close the lua state
LuaDebuggerIDE = NULL ;
LuaDebuggerVisible = false ;
# ifdef NL_OS_WINDOWS
nlassert ( LuaDebuggerModule )
_CrtSetReportHook ( NoOpReportHook ) ; // prevent dump of memory leaks at this point
//::FreeLibrary(LuaDebuggerModule); // don't free the library now (seems that it destroy, the main window, causing
// a crash when the app window is destroyed for real...
// -> FreeLibrary will be called when the application is closed
LuaDebuggerModule = 0 ;
# endif
# endif
}
// Clear Small Script Cache
_SmallScriptPool = 0 ;
_SmallScriptCache . clear ( ) ;
}
// ***************************************************************************
CLuaState * CLuaState : : fromStatePointer ( lua_State * state )
{
//H_AUTO(Lua_CLuaState_fromStatePointer)
nlassert ( state ) ;
int initialStackSize = lua_gettop ( state ) ;
lua_checkstack ( state , initialStackSize + 2 ) ;
lua_pushlightuserdata ( state , ( void * ) state ) ;
lua_gettable ( state , LUA_REGISTRYINDEX ) ;
if ( ! lua_islightuserdata ( state , - 1 ) )
{
lua_pop ( state , 1 ) ;
return NULL ;
}
CLuaState * ls = ( CLuaState * ) lua_touserdata ( state , - 1 ) ;
lua_pop ( state , 1 ) ;
nlassert ( initialStackSize = = lua_gettop ( state ) ) ;
return ls ;
}
// ***************************************************************************
struct CLuaReader
{
const std : : string * Str ;
bool Done ;
} ;
void CLuaState : : loadScript ( const std : : string & code , const std : : string & dbgSrc )
{
//H_AUTO(Lua_CLuaState_loadScript)
if ( code . empty ( ) ) return ;
struct CHelper
{
static const char * luaChunkReaderFromString ( lua_State * /* L */ , void * ud , size_t * sz )
{
CLuaReader * rd = ( CLuaReader * ) ud ;
if ( ! rd - > Done )
{
rd - > Done = true ;
* sz = rd - > Str - > size ( ) ;
return rd - > Str - > c_str ( ) ;
}
else
{
* sz = 0 ;
return NULL ;
}
}
} ;
CLuaReader rd ;
rd . Str = & code ;
rd . Done = false ;
int result = lua_load ( _State , CHelper : : luaChunkReaderFromString , ( void * ) & rd , dbgSrc . c_str ( ) ) ;
if ( result ! = 0 )
{
// pop the error code
string err = toString ( ) ;
pop ( ) ;
// throw error
throw ELuaParseError ( err ) ;
}
}
// ***************************************************************************
void CLuaState : : executeScriptInternal ( const std : : string & code , const std : : string & dbgSrc , int numRet )
{
//H_AUTO(Lua_CLuaState_executeScriptInternal)
CLuaStackChecker lsc ( this , numRet ) ;
// load the script
loadScript ( code , dbgSrc ) ;
// execute
if ( pcall ( 0 , numRet ) ! = 0 )
{
// pop the error code
string err = toString ( ) ;
pop ( ) ;
// throw error
throw ELuaExecuteError ( err ) ;
}
}
// ***************************************************************************
void CLuaState : : executeScript ( const std : : string & code , int numRet )
{
//H_AUTO(Lua_CLuaState_executeScript)
// run the script, with dbgSrc==script
executeScriptInternal ( code , code , numRet ) ;
}
// ***************************************************************************
bool CLuaState : : executeScriptNoThrow ( const std : : string & code , int numRet )
{
//H_AUTO(Lua_CLuaState_executeScriptNoThrow)
try
{
executeScript ( code , numRet ) ;
}
catch ( ELuaError & e )
{
nlwarning ( e . what ( ) ) ;
return false ;
}
return true ;
}
// ***************************************************************************
bool CLuaState : : executeFile ( const std : : string & pathName )
{
//H_AUTO(Lua_CLuaState_executeFile)
CIFile inputFile ;
if ( ! inputFile . open ( pathName ) )
return false ;
# ifdef LUA_NEVRAX_VERSION
if ( LuaDebuggerIDE )
{
std : : string path = NLMISC : : CPath : : getCurrentPath ( ) + " / " + pathName . c_str ( ) ;
path = CPath : : standardizeDosPath ( path ) ;
LuaDebuggerIDE - > addFile ( path . c_str ( ) ) ;
}
# endif
// load the script text
string script ;
/*
while ( ! inputFile . eof ( ) )
{
char tmpBuff [ 5000 ] ;
inputFile . getline ( tmpBuff , 5000 ) ;
script + = tmpBuff ;
script + = " \n " ;
}
*/
script . resize ( CFile : : getFileSize ( pathName ) ) ;
inputFile . serialBuffer ( ( uint8 * ) & script [ 0 ] , script . size ( ) ) ;
// execute the script text, with dbgSrc==filename (use @ for lua internal purpose)
executeScriptInternal ( script , string ( " @ " ) + CFile : : getFilename ( pathName ) ) ;
return true ;
}
// ***************************************************************************
void CLuaState : : executeSmallScript ( const std : : string & script )
{
//H_AUTO(Lua_CLuaState_executeSmallScript)
if ( script . empty ( ) ) return ;
// *** if the small script has not already been called before, parse it now
TSmallScriptCache : : iterator it = _SmallScriptCache . find ( script ) ;
if ( it = = _SmallScriptCache . end ( ) )
{
CLuaStackChecker lsc ( this ) ;
// add it to a function
loadScript ( script , script ) ;
// Assign the method to the NEL table: NELSmallScriptTable[_SmallScriptPool]= function
push ( _NELSmallScriptTableName ) ; // 1:function 2:NelTableName
getTable ( LUA_REGISTRYINDEX ) ; // 1:function 2:NelTable
insert ( - 2 ) ; // 1:NelTable 2:function
rawSetI ( - 2 , _SmallScriptPool ) ; // 1:NelTable
pop ( ) ;
// bkup in cache map
it = _SmallScriptCache . insert ( make_pair ( script , _SmallScriptPool ) ) . first ;
// next allocated
_SmallScriptPool + + ;
}
// *** Execute the function associated to the script
CLuaStackChecker lsc ( this ) ;
push ( _NELSmallScriptTableName ) ; // 1:NelTableName
getTable ( LUA_REGISTRYINDEX ) ; // 1:NelTable
// get the function at the given index in the "NELSmallScriptTable" table
rawGetI ( - 1 , it - > second ) ; // 1:NelTable 2:function
// execute
if ( pcall ( 0 , 0 ) ! = 0 )
{
// Stack: 1: NelTable 2:errorcode
// pop the error code, and clear stack
string err = toString ( ) ;
pop ( ) ; // 1:NelTable
pop ( ) ; // ....
// throw error
throw ELuaExecuteError ( err ) ;
}
else
{
// Stack: 1:NelTable
pop ( ) ; // ....
}
}
// ***************************************************************************
void CLuaState : : registerFunc ( const char * name , lua_CFunction function )
{
//H_AUTO(Lua_CLuaState_registerFunc)
lua_register ( _State , name , function ) ;
}
// ***************************************************************************
void CLuaState : : pushCClosure ( lua_CFunction function , int n )
{
//H_AUTO(Lua_CLuaState_pushCClosure)
nlassert ( function ) ;
nlassert ( getTop ( ) > = n ) ;
lua_pushcclosure ( _State , function , n ) ;
}
// ***************************************************************************
void CLuaState : : push ( TLuaWrappedFunction function )
{
//H_AUTO(Lua_CLuaState_push)
struct CForwarder
{
static int callFunc ( lua_State * ls )
{
nlassert ( ls ) ;
TLuaWrappedFunction func = ( TLuaWrappedFunction ) lua_touserdata ( ls , lua_upvalueindex ( 1 ) ) ;
CLuaState * state = ( CLuaState * ) lua_touserdata ( ls , lua_upvalueindex ( 2 ) ) ;
nlassert ( func ) ;
nlassert ( state ) ;
// get real function pointer from the values in the closure
int numResults ;
int initialStackSize = state - > getTop ( ) ;
try
{
// call the actual function
numResults = func ( * state ) ;
}
catch ( const std : : exception & e )
{
// restore stack to its initial size
state - > setTop ( initialStackSize ) ;
lua_pushstring ( ls , e . what ( ) ) ;
// TODO : see if this is safe to call lua error there" ... (it does a long jump)
lua_error ( ls ) ;
}
return numResults ;
}
} ;
pushLightUserData ( ( void * ) function ) ;
pushLightUserData ( ( void * ) this ) ;
pushCClosure ( CForwarder : : callFunc , 2 ) ;
}
// ***************************************************************************
// Wrapped function
void CLuaState : : registerFunc ( const char * name , TLuaWrappedFunction function )
{
//H_AUTO(Lua_CLuaState_registerFunc)
nlassert ( function ) ;
CLuaStackChecker lsc ( this ) ;
push ( name ) ;
push ( function ) ;
setTable ( LUA_GLOBALSINDEX ) ;
}
// ***************************************************************************
bool CLuaState : : getTableBooleanValue ( const char * name , bool defaultValue )
{
//H_AUTO(Lua_CLuaState_getTableBooleanValue)
nlassert ( name ) ;
push ( name ) ;
getTable ( - 2 ) ;
if ( isNil ( ) )
{
pop ( ) ;
return defaultValue ;
}
bool result = toBoolean ( - 1 ) ;
pop ( ) ;
return result ;
}
// ***************************************************************************
double CLuaState : : getTableNumberValue ( const char * name , double defaultValue )
{
//H_AUTO(Lua_CLuaState_getTableNumberValue)
nlassert ( name ) ;
push ( name ) ;
getTable ( - 2 ) ;
if ( isNil ( ) )
{
pop ( ) ;
return defaultValue ;
}
double result = toNumber ( - 1 ) ;
pop ( ) ;
return result ;
}
// ***************************************************************************
const char * CLuaState : : getTableStringValue ( const char * name , const char * defaultValue )
{
//H_AUTO(Lua_CLuaState_getTableStringValue)
nlassert ( name ) ;
push ( name ) ;
getTable ( - 2 ) ;
if ( isNil ( ) )
{
pop ( ) ;
return defaultValue ;
}
const char * result = toString ( - 1 ) ;
pop ( ) ;
return result ;
}
// ***************************************************************************
void CLuaState : : getStackContext ( string & ret , uint stackLevel )
{
//H_AUTO(Lua_CLuaState_getStackContext)
nlassert ( _State ) ;
ret . clear ( ) ;
lua_Debug dbg ;
if ( lua_getstack ( _State , stackLevel , & dbg ) )
{
if ( lua_getinfo ( _State , " lS " , & dbg ) )
{
ret = NLMISC : : toString ( " %s:%d: " , dbg . short_src , dbg . currentline ) ;
}
}
}
// ***************************************************************************
int CLuaState : : pcallByName ( const char * functionName , int nargs , int nresults , int funcTableIndex /*=LUA_GLOBALSINDEX*/ , int errfunc /*= 0*/ )
{
//H_AUTO(Lua_CLuaState_pcallByName)
int initialStackSize = getTop ( ) ;
nlassert ( functionName ) ;
nlassert ( isTable ( funcTableIndex ) ) ;
pushValue ( funcTableIndex ) ;
push ( functionName ) ;
getTable ( - 2 ) ;
remove ( - 2 ) ; // get rid of the table
nlassert ( getTop ( ) > = nargs ) ; // not enough arguments on the stack
// insert function before its arguments
insert ( - 1 - nargs ) ;
int result = pcall ( nargs , nresults , errfunc ) ;
int currSize = getTop ( ) ;
if ( result = = 0 )
{
nlassert ( currSize = = initialStackSize - nargs + nresults ) ;
}
else
{
// errors, the stack contains a single string
if ( errfunc = = 0 )
{
nlassert ( currSize = = initialStackSize - nargs + 1 ) ;
}
// else if there's an error handler, can't know the size of stack
}
return result ;
}
// ***************************************************************************
void CLuaState : : dumpStack ( )
{
//H_AUTO(Lua_CLuaState_dumpStack)
nlinfo ( " LUA STACK CONTENT (size = %d) " , getTop ( ) ) ;
nlinfo ( " ================= " ) ;
CLuaStackChecker lsc ( this ) ;
for ( int k = 1 ; k < = getTop ( ) ; + + k )
{
pushValue ( k ) ;
std : : string value = toString ( - 1 ) ? toString ( - 1 ) : " ? " ;
nlinfo ( " Stack entry %d : type = %s, value = %s " , k , getTypename ( type ( - 1 ) ) , value . c_str ( ) ) ;
pop ( ) ;
}
}
// ***************************************************************************
void CLuaState : : getStackAsString ( std : : string & dest )
{
//H_AUTO(Lua_CLuaState_getStackAsString)
dest = NLMISC : : toString ( " Stack size = %d \n " , getTop ( ) ) ;
CLuaStackChecker lsc ( this ) ;
for ( int k = 1 ; k < = getTop ( ) ; + + k )
{
pushValue ( k ) ;
std : : string value = toString ( - 1 ) ? toString ( - 1 ) : " ? " ;
dest + = NLMISC : : toString ( " Stack entry %d : type = %s, value = %s \n " , k , getTypename ( type ( - 1 ) ) , value . c_str ( ) ) ;
pop ( ) ;
}
}
//================================================================================
CLuaStackChecker : : ~ CLuaStackChecker ( )
{
nlassert ( _State ) ;
if ( ! _ExceptionContextCounter )
{
int currSize = _State - > getTop ( ) ;
if ( currSize ! = _FinalWantedSize )
{
static volatile bool assertWanted = true ;
if ( assertWanted )
{
nlwarning ( " Lua stack size error : expected size is %d, current size is %d " , _FinalWantedSize , currSize ) ;
_State - > dumpStack ( ) ;
nlassert ( 0 ) ;
}
}
}
else
{
// this object dtor was called because an exception was thrown, so let the exception
// propagate (the stack must be broken, but because of the exception, not because of code error)
_State - > setTop ( _FinalWantedSize ) ;
}
}
// ***************************************************************************
void ELuaWrappedFunctionException : : init ( CLuaState * ls , const std : : string & reason )
{
//H_AUTO(Lua_ELuaWrappedFunctionException_init)
// Print first Lua Stack Context
CInterfaceManager * pIM = CInterfaceManager : : getInstance ( ) ;
if ( ls )
{
ls - > getStackContext ( _Reason , 1 ) ; // 1 because 0 is the current C function => return 1 for script called
// enclose with cool colors
pIM - > formatLuaStackContext ( _Reason ) ;
}
// Append the reason
_Reason + = reason ;
}
// ***************************************************************************
ELuaWrappedFunctionException : : ELuaWrappedFunctionException ( CLuaState * luaState )
{
//H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
init ( luaState , " " ) ;
}
// ***************************************************************************
ELuaWrappedFunctionException : : ELuaWrappedFunctionException ( CLuaState * luaState , const std : : string & reason )
{
//H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
init ( luaState , reason ) ;
}
// ***************************************************************************
ELuaWrappedFunctionException : : ELuaWrappedFunctionException ( CLuaState * luaState , const char * format , . . . )
{
//H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
std : : string reason ;
NLMISC_CONVERT_VARGS ( reason , format , NLMISC : : MaxCStringSize ) ;
init ( luaState , reason ) ;
}
//================================================================================
void CLuaState : : newTable ( )
{
//H_AUTO(Lua_CLuaState_newTable)
nlverify ( lua_checkstack ( _State , 1 ) ) ;
lua_newtable ( _State ) ;
}
//================================================================================
int CLuaState : : getGCCount ( )
{
//H_AUTO(Lua_CLuaState_getGCCount)
return lua_getgccount ( _State ) ;
}
//================================================================================
int CLuaState : : getGCThreshold ( )
{
//H_AUTO(Lua_CLuaState_getGCThreshold)
# ifdef LUA_NEVRAX_VERSION
return _GCThreshold ;
# else
# if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
return lua_gc ( _State , LUA_GCCOUNT , 0 ) ;
# else
return lua_getgcthreshold ( _State ) ;
# endif
# endif
}
//================================================================================
void CLuaState : : setGCThreshold ( int kb )
{
//H_AUTO(Lua_CLuaState_setGCThreshold)
# ifdef LUA_NEVRAX_VERSION
_GCThreshold = kb ;
handleGC ( ) ;
# else
# if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
lua_gc ( _State , LUA_GCCOLLECT , kb ) ;
# else
lua_setgcthreshold ( _State , kb ) ;
# endif
# endif
}
//================================================================================
void CLuaState : : handleGC ( )
{
//H_AUTO(Lua_CLuaState_handleGC)
# ifdef LUA_NEVRAX_VERSION
// must handle gc manually with the refcounted version
int gcCount = getGCCount ( ) ;
if ( gcCount > = _GCThreshold )
{
nlwarning ( " Triggering GC : memory in use = %d kb, current threshold = %d kb " , gcCount , _GCThreshold ) ;
lua_setgcthreshold ( _State , 0 ) ;
gcCount = getGCCount ( ) ;
_GCThreshold = std : : max ( MinGCThreshold , gcCount * 2 ) ;
nlwarning ( " After GC : memory in use = %d kb, threshold = %d kb " , gcCount , _GCThreshold ) ;
}
# endif
}