Advertisement

change memory allocator for CScriptArray addon

Started by January 27, 2014 06:11 AM
5 comments, last by WitchLord 10 years, 9 months ago

Hi smile.png , in our project - game. We are use only script addon, and we need use Our memory allocator

and

I create possible to change memory allocator for addon CScriptArray

scriptarray.patch

Index: scriptarray.cpp
===================================================================
--- scriptarray.cpp (revision 1823)
+++ scriptarray.cpp (working copy)
@@ -13,6 +13,14 @@
static void RegisterScriptArray_Native(asIScriptEngine *engine);
static void RegisterScriptArray_Generic(asIScriptEngine *engine);
+asALLOCFUNC_t CScriptArray::userAlloc = ::malloc;
+asFREEFUNC_t CScriptArray::userFree = ::free;
+
+void CScriptArray::asSetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc){
+ userAlloc = allocFunc;
+ userFree = freeFunc;
+}
+
struct SArrayBuffer
{
asDWORD maxElements;
@@ -36,13 +44,16 @@
static void CleanupObjectTypeArrayCache(asIObjectType *type)
{
SArrayCache *cache = reinterpret_cast<SArrayCache*>(type->GetUserData(ARRAY_CACHE));
- if( cache )
- delete cache;
+ if( cache ){
+ CScriptArray::userFree( cache );
+ cache = nullptr;
+ }
}
static CScriptArray* ScriptArrayFactory2(asIObjectType *ot, asUINT length)
{
- CScriptArray *a = new CScriptArray(length, ot);
+ void *data = CScriptArray::userAlloc( sizeof( CScriptArray ) );
+ CScriptArray *a = new( data ) CScriptArray(length, ot);
// It's possible the constructor raised a script exception, in which case we
// need to free the memory and return null instead, else we get a memory leak.
@@ -58,8 +69,8 @@
static CScriptArray* ScriptArrayListFactory(asIObjectType *ot, void *initList)
{
- CScriptArray *a = new CScriptArray(ot, initList);
-
+ void *data = CScriptArray::userAlloc( sizeof( CScriptArray ) );
+ CScriptArray *a = new( data ) CScriptArray(ot, initList);
// It's possible the constructor raised a script exception, in which case we
// need to free the memory and return null instead, else we get a memory leak.
asIScriptContext *ctx = asGetActiveContext();
@@ -74,8 +85,8 @@
static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType *ot, asUINT length, void *defVal)
{
- CScriptArray *a = new CScriptArray(length, defVal, ot);
-
+ void *data = CScriptArray::userAlloc( sizeof( CScriptArray ) );
+ CScriptArray *a = new( data ) CScriptArray(length, defVal, ot);
// It's possible the constructor raised a script exception, in which case we
// need to free the memory and return null instead, else we get a memory leak.
asIScriptContext *ctx = asGetActiveContext();
@@ -268,6 +279,7 @@
// Same as removeAt
r = engine->RegisterObjectMethod("array<T>", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 );
#endif
+
}
CScriptArray &CScriptArray::operator=(const CScriptArray &other)
@@ -523,11 +535,8 @@
// Allocate memory for the buffer
SArrayBuffer *newBuffer;
- #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
- newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
- #else
- newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*maxElements];
- #endif
+ newBuffer = (SArrayBuffer*)userAlloc( sizeof(SArrayBuffer)-1 + elementSize*maxElements );
+
if( newBuffer )
{
newBuffer->numElements = buffer->numElements;
@@ -545,8 +554,7 @@
memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize);
// Release the old buffer
- delete[] (asBYTE*)buffer;
-
+ userFree( buffer );
buffer = newBuffer;
}
@@ -584,11 +592,8 @@
{
// Allocate memory for the buffer
SArrayBuffer *newBuffer;
- #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
- newBuffer = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
- #else
- newBuffer = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta)];
- #endif
+ newBuffer = (SArrayBuffer*)userAlloc( sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta) );
+
if( newBuffer )
{
newBuffer->numElements = buffer->numElements + delta;
@@ -614,7 +619,7 @@
Construct(newBuffer, at, at+delta);
// Release the old buffer
- delete[] (asBYTE*)buffer;
+ userFree( buffer );
buffer = newBuffer;
}
@@ -752,19 +757,11 @@
{
if( subTypeId & asTYPEID_MASK_OBJECT )
{
- #if defined(__S3E__) // Marmalade doesn't understand (nothrow)
- *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
- #else
- *buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+sizeof(void*)*numElements];
- #endif
+ *buf = (SArrayBuffer*)userAlloc( sizeof(SArrayBuffer)-1+sizeof(void*)*numElements );
}
else
{
- #if defined(__S3E__)
- *buf = (SArrayBuffer*)new asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
- #else
- *buf = (SArrayBuffer*)new (nothrow) asBYTE[sizeof(SArrayBuffer)-1+elementSize*numElements];
- #endif
+ *buf = (SArrayBuffer*)userAlloc( sizeof(SArrayBuffer)-1+elementSize*numElements );
}
if( *buf )
@@ -786,9 +783,8 @@
void CScriptArray::DeleteBuffer(SArrayBuffer *buf)
{
Destruct(buf, 0, buf->numElements);
-
// Free the buffer
- delete[] (asBYTE*)buf;
+ userFree( buf );
}
// internal
@@ -1446,7 +1442,9 @@
}
// Create the cache
- cache = new SArrayCache();
+ void *data = CScriptArray::userAlloc( sizeof( SArrayCache ) );
+ cache = new( data ) SArrayCache();
+
memset(cache, 0, sizeof(SArrayCache));
// If the sub type is a handle to const, then the methods must be const too
@@ -1569,7 +1567,8 @@
{
// When reaching 0 no more references to this instance
// exists and the object should be destroyed
- delete this;
+ this->~CScriptArray();
+ userFree( (void*)this );
}
}
Index: scriptarray.h
===================================================================
--- scriptarray.h (revision 1823)
+++ scriptarray.h (working copy)
@@ -25,6 +25,9 @@
class CScriptArray
{
public:
+ static asALLOCFUNC_t userAlloc;
+ static asFREEFUNC_t userFree;
+ static void asSetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc);
CScriptArray(asIObjectType *ot, void *initBuf); // Called from script when initialized with list
CScriptArray(asUINT length, asIObjectType *ot);
CScriptArray(asUINT length, void *defVal, asIObjectType *ot);

Thanks. I'll have this checked in as soon as possible.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

Thank you for this change.

I've added this in revision 1855.

Thanks,

Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

I upgraded to revision 1855 and hooked up CScriptArray::SetMemoryFunctions() to my debug memory tracking. I'm seeing asymmetric calls to the alloc and release hooks.

For example:

alloc - ptr returned: 0x0f82cc48

alloc - ptr returned: 0x0f829ac0

free - 0x0f82cc48

free - 0x0f829ac0

free - 0x0f83cba4 // this did not route through the alloc hook and breaks my debug record keeping

I've had my debug tracking running for some time with the engine hooks, for what it's worth, and that's been solid.

UPDATE: I think I see what the problem is. Here is where the above 5 calls are coming from:

CScriptArray::CreateBuffer()
CScriptArray::Reserve()
CScriptArray::Reserve()
CScriptArray::~CScriptArray()
CScriptArray::Release() // userFree(const_cast<CScriptArray*>(this));
I'm new'ing up a CScriptArray in application code and later I call Release on it, which happens to dealloc the instance, but it's not correct (for my case) to userFree() the this pointer, because the array wasn't allocated via userAlloc() and a placement-new.
Since you can't overload placement new in C++, how should this situation be handled?
UPDATE2: I added the following to CScriptArray as a test and it worked with the memory hooks:

// header
static CScriptArray* MyFactory(asIObjectType *ot);

// cpp
CScriptArray* CScriptArray::MyFactory(asIObjectType *ot)
{
    return ScriptArrayFactory2(ot, asUINT(0));
}

// application C++ code
//CScriptArray* arr = new CScriptArray(0, ot);
CScriptArray* arr = CScriptArray::MyFactory(ot);

This is potentially error-prone though.. at the very least I'd put a huge warning right above CScriptArray::SetMemoryFunctions() ?

You're correct. To solve this it is necessary to use Factory functions. To guarantee that the factory functions are always used instead of manually allocating the object, the object constructors should be made protected so they can only be called by the Factory functions.

I'll make this change in the CScriptArray object. It will impact those who currently allocate the object manually, but it is for the best in the long run.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

I've made the changes in revision 1857. Now the CScriptArray should be allocated from the C++ side with a call to CScriptArray::Create(asIObjectType *ot) or one of the other variants.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement