| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2010 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- The original version of this library can be located at:
- http://www.angelcode.com/angelscript/
- Andreas Jonsson
- [email protected]
- */
- #include <new>
- #include "as_config.h"
- #include "as_scriptengine.h"
- #include "as_scriptobject.h"
- BEGIN_AS_NAMESPACE
- // This helper function will call the default factory, that is a script function
- asIScriptObject *ScriptObjectFactory(asCObjectType *objType, asCScriptEngine *engine)
- {
- asIScriptContext *ctx;
- // TODO: optimize: There should be a pool for the context so it doesn't
- // have to be allocated just for creating the script object
- // TODO: It must be possible for the application to debug the creation of the object too
- int r = engine->CreateContext(&ctx, true);
- if( r < 0 )
- return 0;
- r = ctx->Prepare(objType->beh.factory);
- if( r < 0 )
- {
- ctx->Release();
- return 0;
- }
- r = ctx->Execute();
- if( r != asEXECUTION_FINISHED )
- {
- ctx->Release();
- return 0;
- }
- asIScriptObject *ptr = (asIScriptObject*)ctx->GetReturnAddress();
- // Increase the reference, because the context will release it's pointer
- ptr->AddRef();
- ctx->Release();
- return ptr;
- }
- #ifdef AS_MAX_PORTABILITY
- static void ScriptObject_AddRef_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- self->AddRef();
- }
- static void ScriptObject_Release_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- self->Release();
- }
- static void ScriptObject_GetRefCount_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
- }
- static void ScriptObject_SetFlag_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- self->SetFlag();
- }
- static void ScriptObject_GetFlag_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
- }
- static void ScriptObject_EnumReferences_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
- self->EnumReferences(engine);
- }
- static void ScriptObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
- self->ReleaseAllHandles(engine);
- }
- #endif
- void RegisterScriptObject(asCScriptEngine *engine)
- {
- // Register the default script class behaviours
- int r;
- engine->scriptTypeBehaviours.engine = engine;
- engine->scriptTypeBehaviours.flags = asOBJ_SCRIPT_OBJECT | asOBJ_REF | asOBJ_GC;
- engine->scriptTypeBehaviours.name = "_builtin_object_";
- #ifndef AS_MAX_PORTABILITY
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptObject,AddRef), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptObject,Release), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
- // Register GC behaviours
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptObject,GetRefCount), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptObject,SetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptObject,GetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptObject,EnumReferences), asCALL_THISCALL); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptObject,ReleaseAllHandles), asCALL_THISCALL); asASSERT( r >= 0 );
- #else
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptObject_AddRef_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptObject_Release_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- // Register GC behaviours
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptObject_GetRefCount_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptObject_SetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptObject_GetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptObject_EnumReferences_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptObject_ReleaseAllHandles_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
- #endif
- }
- void ScriptObject_Construct_Generic(asIScriptGeneric *gen)
- {
- asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0);
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- ScriptObject_Construct(objType, self);
- }
- void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self)
- {
- new(self) asCScriptObject(objType);
- }
- asCScriptObject::asCScriptObject(asCObjectType *ot)
- {
- refCount.set(1);
- objType = ot;
- objType->AddRef();
- isDestructCalled = false;
- // Notify the garbage collector of this object
- if( objType->flags & asOBJ_GC )
- objType->engine->gc.AddScriptObjectToGC(this, objType);
- // Construct all properties
- asCScriptEngine *engine = objType->engine;
- for( asUINT n = 0; n < objType->properties.GetLength(); n++ )
- {
- asCObjectProperty *prop = objType->properties[n];
- if( prop->type.IsObject() )
- {
- size_t *ptr = (size_t*)(((char*)this) + prop->byteOffset);
- if( prop->type.IsObjectHandle() )
- *ptr = 0;
- else
- {
- // Allocate the object and call it's constructor
- *ptr = (size_t)AllocateObject(prop->type.GetObjectType(), engine);
- }
- }
- }
- }
- void asCScriptObject::Destruct()
- {
- // Call the destructor, which will also call the GCObject's destructor
- this->~asCScriptObject();
- // Free the memory
- userFree(this);
- }
- asCScriptObject::~asCScriptObject()
- {
- objType->Release();
- // The engine pointer should be available from the objectType
- asCScriptEngine *engine = objType->engine;
- // Destroy all properties
- for( asUINT n = 0; n < objType->properties.GetLength(); n++ )
- {
- asCObjectProperty *prop = objType->properties[n];
- if( prop->type.IsObject() )
- {
- // Destroy the object
- void **ptr = (void**)(((char*)this) + prop->byteOffset);
- if( *ptr )
- {
- FreeObject(*ptr, prop->type.GetObjectType(), engine);
- *(asDWORD*)ptr = 0;
- }
- }
- }
- }
- asIScriptEngine *asCScriptObject::GetEngine() const
- {
- return objType->engine;
- }
- int asCScriptObject::AddRef() const
- {
- // Increase counter and clear flag set by GC
- gcFlag = false;
- return refCount.atomicInc();
- }
- int asCScriptObject::Release() const
- {
- // Clear the flag set by the GC
- gcFlag = false;
- // Call the script destructor behaviour if the reference counter is 1.
- if( refCount.get() == 1 && !isDestructCalled )
- {
- // This cast is OK since we are the last reference
- const_cast<asCScriptObject*>(this)->CallDestructor();
- }
- // Now do the actual releasing
- int r = refCount.atomicDec();
- if( r == 0 )
- {
- // This cast is OK since we are the last reference
- const_cast<asCScriptObject*>(this)->Destruct();
- return 0;
- }
- return r;
- }
- void asCScriptObject::CallDestructor()
- {
- // Make sure the destructor is called once only, even if the
- // reference count is increased and then decreased again
- isDestructCalled = true;
- asIScriptContext *ctx = 0;
- // Call the destructor for this class and all the super classes
- asCObjectType *ot = objType;
- while( ot )
- {
- int funcIndex = ot->beh.destruct;
- if( funcIndex )
- {
- if( ctx == 0 )
- {
- // Setup a context for calling the default constructor
- asCScriptEngine *engine = objType->engine;
- int r = engine->CreateContext(&ctx, true);
- if( r < 0 ) return;
- }
- int r = ctx->Prepare(funcIndex);
- if( r >= 0 )
- {
- ctx->SetObject(this);
- ctx->Execute();
- // There's not much to do if the execution doesn't
- // finish, so we just ignore the result
- }
- }
- ot = ot->derivedFrom;
- }
- if( ctx )
- {
- ctx->Release();
- }
- }
- asIObjectType *asCScriptObject::GetObjectType() const
- {
- return objType;
- }
- int asCScriptObject::GetRefCount()
- {
- return refCount.get();
- }
- void asCScriptObject::SetFlag()
- {
- gcFlag = true;
- }
- bool asCScriptObject::GetFlag()
- {
- return gcFlag;
- }
- // interface
- int asCScriptObject::GetTypeId() const
- {
- asCDataType dt = asCDataType::CreateObject(objType, false);
- return objType->engine->GetTypeIdFromDataType(dt);
- }
- int asCScriptObject::GetPropertyCount() const
- {
- // TODO: interface: Should return asUINT, as the function cannot fail
- return (int)objType->properties.GetLength();
- }
- int asCScriptObject::GetPropertyTypeId(asUINT prop) const
- {
- if( prop >= objType->properties.GetLength() )
- return asINVALID_ARG;
- return objType->engine->GetTypeIdFromDataType(objType->properties[prop]->type);
- }
- const char *asCScriptObject::GetPropertyName(asUINT prop) const
- {
- if( prop >= objType->properties.GetLength() )
- return 0;
- return objType->properties[prop]->name.AddressOf();
- }
- void *asCScriptObject::GetAddressOfProperty(asUINT prop)
- {
- if( prop >= objType->properties.GetLength() )
- return 0;
- // Objects are stored by reference, so this must be dereferenced
- asCDataType *dt = &objType->properties[prop]->type;
- if( dt->IsObject() && !dt->IsObjectHandle() )
- return *(void**)(((char*)this) + objType->properties[prop]->byteOffset);
- return (void*)(((char*)this) + objType->properties[prop]->byteOffset);
- }
- void asCScriptObject::EnumReferences(asIScriptEngine *engine)
- {
- // We'll notify the GC of all object handles that we're holding
- for( asUINT n = 0; n < objType->properties.GetLength(); n++ )
- {
- asCObjectProperty *prop = objType->properties[n];
- if( prop->type.IsObject() )
- {
- void *ptr = *(void**)(((char*)this) + prop->byteOffset);
- if( ptr )
- ((asCScriptEngine*)engine)->GCEnumCallback(ptr);
- }
- }
- }
- void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine)
- {
- for( asUINT n = 0; n < objType->properties.GetLength(); n++ )
- {
- asCObjectProperty *prop = objType->properties[n];
- if( prop->type.IsObject() && prop->type.IsObjectHandle() )
- {
- void **ptr = (void**)(((char*)this) + prop->byteOffset);
- if( *ptr )
- {
- ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release);
- *ptr = 0;
- }
- }
- }
- }
- void ScriptObject_Assignment_Generic(asIScriptGeneric *gen)
- {
- asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0);
- asCScriptObject *self = (asCScriptObject*)gen->GetObject();
- *self = *other;
- *(asCScriptObject**)gen->GetAddressOfReturnLocation() = self;
- }
- asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self)
- {
- return (*self = *other);
- }
- asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other)
- {
- if( &other != this )
- {
- asASSERT( other.objType->DerivesFrom(objType) );
- asCScriptEngine *engine = objType->engine;
- // Copy all properties
- for( asUINT n = 0; n < objType->properties.GetLength(); n++ )
- {
- asCObjectProperty *prop = objType->properties[n];
- if( prop->type.IsObject() )
- {
- void **dst = (void**)(((char*)this) + prop->byteOffset);
- void **src = (void**)(((char*)&other) + prop->byteOffset);
- if( !prop->type.IsObjectHandle() )
- CopyObject(*src, *dst, prop->type.GetObjectType(), engine);
- else
- CopyHandle((asPWORD*)src, (asPWORD*)dst, prop->type.GetObjectType(), engine);
- }
- else
- {
- void *dst = ((char*)this) + prop->byteOffset;
- void *src = ((char*)&other) + prop->byteOffset;
- memcpy(dst, src, prop->type.GetSizeInMemoryBytes());
- }
- }
- }
- return *this;
- }
- int asCScriptObject::CopyFrom(asIScriptObject *other)
- {
- if( other == 0 ) return asINVALID_ARG;
- if( GetTypeId() != other->GetTypeId() )
- return asINVALID_TYPE;
- *this = *(asCScriptObject*)other;
- return 0;
- }
- void *asCScriptObject::AllocateObject(asCObjectType *objType, asCScriptEngine *engine)
- {
- void *ptr = 0;
- if( objType->flags & asOBJ_SCRIPT_OBJECT )
- {
- ptr = ScriptObjectFactory(objType, engine);
- }
- else if( objType->flags & asOBJ_TEMPLATE )
- {
- // Templates store the original factory that takes the object
- // type as a hidden parameter in the construct behaviour
- ptr = engine->CallGlobalFunctionRetPtr(objType->beh.construct, objType);
- }
- else if( objType->flags & asOBJ_REF )
- {
- ptr = engine->CallGlobalFunctionRetPtr(objType->beh.factory);
- }
- else
- {
- ptr = engine->CallAlloc(objType);
- int funcIndex = objType->beh.construct;
- if( funcIndex )
- engine->CallObjectMethod(ptr, funcIndex);
- }
- return ptr;
- }
- void asCScriptObject::FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine)
- {
- if( !objType->beh.release )
- {
- if( objType->beh.destruct )
- engine->CallObjectMethod(ptr, objType->beh.destruct);
- engine->CallFree(ptr);
- }
- else
- {
- engine->CallObjectMethod(ptr, objType->beh.release);
- }
- }
- void asCScriptObject::CopyObject(void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine)
- {
- // TODO: If the object doesn't have the copy behaviour, and it is not a
- // POD object then the copy must not be performed
- int funcIndex = objType->beh.copy;
- if( funcIndex )
- engine->CallObjectMethod(dst, src, funcIndex);
- else
- memcpy(dst, src, objType->size);
- }
- void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine)
- {
- if( *dst )
- engine->CallObjectMethod(*(void**)dst, objType->beh.release);
- *dst = *src;
- if( *dst )
- engine->CallObjectMethod(*(void**)dst, objType->beh.addref);
- }
- END_AS_NAMESPACE
|