ConfigDB.cpp: fix vfs_load return value check
baseentity, entity: remove multiple property adds (source of scriptablecomplex memory leak) scriptablecomplex: add code to check for leak regression and prevent them; add suballocator for properties, since 60k are allocated in a short while (!) - saves time and memory This was SVN commit r3429.
This commit is contained in:
parent
e07622b56a
commit
0fa0bfcb28
@ -246,20 +246,20 @@ bool CConfigDB::Reload(EConfigNamespace ns)
|
||||
FileIOBuf buffer;
|
||||
uint buflen;
|
||||
File f;
|
||||
Handle fh;
|
||||
LibError ret;
|
||||
if (m_UseVFS[ns])
|
||||
{
|
||||
// Open file with VFS
|
||||
fh=vfs_load(m_ConfigFile[ns], buffer, buflen);
|
||||
if (fh <= 0)
|
||||
ret = vfs_load(m_ConfigFile[ns], buffer, buflen);
|
||||
if(ret != ERR_OK)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "vfs_load for \"%s\" failed: return was %lld", m_ConfigFile[ns].c_str(), fh);
|
||||
LOG(ERROR, LOG_CATEGORY, "vfs_load for \"%s\" failed: return was %lld", m_ConfigFile[ns].c_str(), ret);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file_open(m_ConfigFile[ns], 0, &f)!=0)
|
||||
if (file_open(m_ConfigFile[ns], 0, &f)!=ERR_OK)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "file_open for \"%s\" failed", m_ConfigFile[ns].c_str());
|
||||
return false;
|
||||
|
38
source/scripting/ScriptableComplex.cpp
Normal file
38
source/scripting/ScriptableComplex.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "precompiled.h"
|
||||
#include "ScriptableComplex.h"
|
||||
|
||||
// suballocator for CJSComplex.m_Properties elements
|
||||
static Bucket bucket;
|
||||
// HACK: it needs to be created/destroyed; since there is no
|
||||
// global init/shutdown call here, we keep a refcnt. this assumes that
|
||||
// going to 0 <==> shutdown! if that proves wrong, bucket_alloc will warn.
|
||||
static uint suballoc_refs; // initialized in suballoc_attach
|
||||
|
||||
void jscomplexproperty_suballoc_attach()
|
||||
{
|
||||
ONCE(\
|
||||
size_t el_size = MAX(sizeof(CJSValComplexProperty), sizeof(CJSComplexProperty<int, true>));\
|
||||
(void)bucket_create(&bucket, el_size);\
|
||||
suballoc_refs = 0;\
|
||||
);
|
||||
suballoc_refs++;
|
||||
}
|
||||
|
||||
void jscomplexproperty_suballoc_detach()
|
||||
{
|
||||
suballoc_refs--;
|
||||
if(suballoc_refs == 0)
|
||||
bucket_destroy(&bucket);
|
||||
}
|
||||
|
||||
void* jscomplexproperty_suballoc()
|
||||
{
|
||||
return bucket_alloc(&bucket, 0);
|
||||
}
|
||||
|
||||
void jscomplexproperty_suballoc_free(IJSComplexProperty* p)
|
||||
{
|
||||
// explicit dtor since caller uses placement new
|
||||
p->~IJSComplexProperty();
|
||||
bucket_free(&bucket, p);
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "JSConversions.h"
|
||||
|
||||
#include "lib/allocators.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#ifndef SCRIPTABLE_COMPLEX_INCLUDED
|
||||
@ -470,6 +472,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern void jscomplexproperty_suballoc_attach();
|
||||
extern void jscomplexproperty_suballoc_detach();
|
||||
extern void* jscomplexproperty_suballoc();
|
||||
extern void jscomplexproperty_suballoc_free(IJSComplexProperty* p);
|
||||
|
||||
template<typename T, bool ReadOnly> class CJSComplex : public IJSComplex
|
||||
{
|
||||
typedef STL_HASH_MAP<CStrW, CJSReflector*, CStrW_hash_compare> ReflectorTable;
|
||||
@ -480,6 +489,7 @@ template<typename T, bool ReadOnly> class CJSComplex : public IJSComplex
|
||||
|
||||
ReflectorTable m_Reflectors;
|
||||
|
||||
|
||||
public:
|
||||
static JSClass JSI_class;
|
||||
|
||||
@ -760,6 +770,8 @@ private:
|
||||
public:
|
||||
CJSComplex()
|
||||
{
|
||||
jscomplexproperty_suballoc_attach();
|
||||
|
||||
m_Parent = NULL;
|
||||
m_JS = NULL;
|
||||
m_EngineOwned = true;
|
||||
@ -767,6 +779,8 @@ public:
|
||||
virtual ~CJSComplex()
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
jscomplexproperty_suballoc_detach();
|
||||
}
|
||||
void Shutdown()
|
||||
{
|
||||
@ -785,7 +799,8 @@ public:
|
||||
JS_RemoveRoot( g_ScriptingHost.GetContext(), &( extProp->m_JSAccessor ) );
|
||||
}
|
||||
}
|
||||
delete( it->second );
|
||||
|
||||
jscomplexproperty_suballoc_free(it->second);
|
||||
}
|
||||
|
||||
|
||||
@ -899,8 +914,11 @@ public:
|
||||
}
|
||||
void AddProperty( CStrW PropertyName, jsval Value )
|
||||
{
|
||||
debug_assert( !HasProperty( PropertyName ) );
|
||||
CJSDynamicComplexProperty* newProp = new CJSValComplexProperty( Value, false );
|
||||
DeletePreviouslyAssignedProperty( PropertyName );
|
||||
void* mem = jscomplexproperty_suballoc();
|
||||
#include "nommgr.h"
|
||||
CJSDynamicComplexProperty* newProp = new(mem) CJSValComplexProperty( Value, false );
|
||||
#include "mmgr.h"
|
||||
m_Properties[PropertyName] = newProp;
|
||||
|
||||
ReflectorTable::iterator it;
|
||||
@ -938,13 +956,43 @@ public:
|
||||
{
|
||||
T::m_IntrinsicProperties[PropertyName] = new CJSSharedProperty<PropType, true>( (PropType IJSComplex::*)Native, PropAllowInheritance, Update, Refresh );
|
||||
}
|
||||
|
||||
// helper routine for Add*Property. Their interface requires the
|
||||
// property not already exist; we check for this (in non-final builds)
|
||||
// and if so, warn and free the previously new-ed memory in
|
||||
// m_Properties[PropertyName] (avoids mem leak).
|
||||
void DeletePreviouslyAssignedProperty( CStrW PropertyName )
|
||||
{
|
||||
#ifndef FINAL
|
||||
PropertyTable::iterator it;
|
||||
it = m_Properties.find( PropertyName );
|
||||
if( it != m_Properties.end() )
|
||||
{
|
||||
debug_warn("BUG: CJSComplexProperty added but already existed!");
|
||||
jscomplexproperty_suballoc_free(it->second);
|
||||
}
|
||||
#else
|
||||
UNUSED2(PropertyName);
|
||||
#endif
|
||||
}
|
||||
|
||||
// PropertyName must not already exist! (verified in non-final release)
|
||||
template<typename PropType> void AddProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
||||
{
|
||||
m_Properties[PropertyName] = new CJSComplexProperty<PropType, ReadOnly>( Native, PropAllowInheritance, Update, Refresh );
|
||||
DeletePreviouslyAssignedProperty( PropertyName );
|
||||
void* mem = jscomplexproperty_suballoc();
|
||||
#include "nommgr.h"
|
||||
m_Properties[PropertyName] = new(mem) CJSComplexProperty<PropType, ReadOnly>( Native, PropAllowInheritance, Update, Refresh );
|
||||
#include "mmgr.h"
|
||||
}
|
||||
// PropertyName must not already exist! (verified in non-final release)
|
||||
template<typename PropType> void AddReadOnlyProperty( CStrW PropertyName, PropType* Native, bool PropAllowInheritance = true, NotifyFn Update = NULL, NotifyFn Refresh = NULL )
|
||||
{
|
||||
m_Properties[PropertyName] = new CJSComplexProperty<PropType, true>( Native, PropAllowInheritance, Update, Refresh );
|
||||
DeletePreviouslyAssignedProperty( PropertyName );
|
||||
void* mem = jscomplexproperty_suballoc();
|
||||
#include "nommgr.h"
|
||||
m_Properties[PropertyName] = new(mem) CJSComplexProperty<PropType, true>( Native, PropAllowInheritance, Update, Refresh );
|
||||
#include "mmgr.h"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -45,9 +45,6 @@ CBaseEntity::CBaseEntity()
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
AddProperty( L"traits.health.regen_rate", &m_healthRegenRate );
|
||||
AddProperty( L"traits.health.regen_start", &m_healthRegenStart );
|
||||
AddProperty( L"traits.health.decay_rate", &m_healthDecayRate );
|
||||
|
||||
for( int t = 0; t < EVENT_LAST; t++ )
|
||||
{
|
||||
|
@ -69,9 +69,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
AddProperty( L"traits.health.regen_rate", &m_healthRegenRate );
|
||||
AddProperty( L"traits.health.regen_start", &m_healthRegenStart );
|
||||
AddProperty( L"traits.health.decay_rate", &m_healthDecayRate );
|
||||
AddProperty( L"last_combat_time", &m_lastCombatTime );
|
||||
|
||||
for( int t = 0; t < EVENT_LAST; t++ )
|
||||
|
Loading…
Reference in New Issue
Block a user