Update to latest angelscript

This commit is contained in:
Marianne Gagnon
2015-05-11 19:40:43 -04:00
parent f269b44208
commit c48037984d
71 changed files with 11405 additions and 6307 deletions

View File

@@ -1,6 +1,6 @@
/*
AngelCode Scripting Library
Copyright (c) 2003-2013 Andreas Jonsson
Copyright (c) 2003-2015 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
@@ -105,6 +105,15 @@ static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen)
gen->SetReturnAddress(CreateDelegate(func, obj));
}
// TODO: 2.29.0: operator==
/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen)
{
asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject();
asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0);
*(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther;
}
*/
#endif
@@ -124,6 +133,8 @@ void RegisterScriptFunction(asCScriptEngine *engine)
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 );
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 );
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 );
// TODO: 2.29.0: Need some way to allow the arg type to adapt when the funcdefs are instantiated
// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asMETHOD(asCScriptFunction,operator==), asCALL_THISCALL); asASSERT( r >= 0 );
#else
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
@@ -132,6 +143,7 @@ void RegisterScriptFunction(asCScriptEngine *engine)
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 );
// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asFUNCTION(ScriptFunction_opEquals_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
#endif
// Register the builtin function for creating delegates
@@ -214,6 +226,24 @@ asIScriptFunction *asCScriptFunction::GetDelegateFunction() const
return funcForDelegate;
}
// TODO: 2.29.0: operator==
/*
// internal
bool asCScriptFunction::operator==(const asCScriptFunction &other) const
{
if( this == &other ) return true;
if( this->funcType == asFUNC_DELEGATE && other.funcType == asFUNC_DELEGATE )
{
if( this->objForDelegate == other.objForDelegate &&
this->funcForDelegate == other.funcForDelegate )
return true;
}
return false;
}
*/
// internal
int asCScriptFunction::RegisterListPattern(const char *decl, asCScriptNode *listNodes)
{
@@ -243,8 +273,23 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char
{
if( listNodes->nodeType == snIdentifier )
{
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT);
node = node->next;
asCString token(&decl[listNodes->tokenPos], listNodes->tokenLength);
if( token == "repeat" )
{
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT);
node = node->next;
}
else if( token == "repeat_same" )
{
// TODO: list: Should make sure this is a sub-list
node->next = asNEW(asSListPatternNode)(asLPT_REPEAT_SAME);
node = node->next;
}
else
{
// Shouldn't happen as the parser already reported the error
asASSERT(false);
}
}
else if( listNodes->nodeType == snDataType )
{
@@ -287,15 +332,27 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char
// internal
asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType)
{
refCount.set(1);
funcType = _funcType;
if( funcType == asFUNC_DELEGATE )
{
// Delegates behave like object instances, rather than script code
externalRefCount.set(1);
internalRefCount.set(0);
}
else
{
internalRefCount.set(1);
externalRefCount.set(0);
}
this->engine = engine;
this->scriptData = 0;
funcType = _funcType;
module = mod;
objectType = 0;
name = "";
isReadOnly = false;
isPrivate = false;
isProtected = false;
isFinal = false;
isOverride = false;
sysFuncIntf = 0;
@@ -315,8 +372,8 @@ asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, as
if( funcType == asFUNC_SCRIPT )
AllocateScriptFunctionData();
// Notify the GC of script functions
if( (funcType == asFUNC_SCRIPT && mod == 0) || (funcType == asFUNC_DELEGATE) )
// Notify the GC of delegates
if( funcType == asFUNC_DELEGATE )
engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
}
@@ -348,35 +405,58 @@ void asCScriptFunction::DeallocateScriptFunctionData()
// internal
asCScriptFunction::~asCScriptFunction()
{
// Imported functions are not reference counted, nor are dummy
// functions that are allocated on the stack
// Dummy functions that are allocated on the stack are not reference counted
asASSERT( funcType == asFUNC_DUMMY ||
funcType == asFUNC_IMPORTED ||
refCount.get() == 0 );
(externalRefCount.get() == 0 && internalRefCount.get() == 0) );
// Remove the script function from the engine's scriptFunctions array here
// Don't remove it before, because there may still be functions referring to it
// by index until now. If it was removed in DestroyInternal, those would not
// be able to release the refcount, thus causing memory leak.
if( engine && id != 0 && funcType != asFUNC_DUMMY )
engine->RemoveScriptFunction(this);
// If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do
if( engine == 0 ) return;
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
DestroyInternal();
// Tell engine to free the function id. This will make it impossible to
// refer to the function by id. Where this is done, it is quite possible
// they will leak.
if( funcType != -1 && funcType != asFUNC_IMPORTED && id )
engine->FreeScriptFunctionId(id);
id = 0;
// Finally set the engine pointer to 0 because it must not be accessed again
engine = 0;
}
// internal
void asCScriptFunction::DestroyHalfCreated()
{
asASSERT( externalRefCount.get() == 0 && internalRefCount.get() == 1 );
// Set the funcType to dummy so the destructor won't complain
funcType = asFUNC_DUMMY;
// If the bytecode exist remove it before destroying, otherwise it
// will fail when the destructor releases the references as the bytecode
// is not fully constructed.
if( scriptData )
scriptData->byteCode.SetLength(0);
asDELETE(this, asCScriptFunction);
}
// internal
void asCScriptFunction::DestroyInternal()
{
// Clean up user data
if( userData && engine->cleanFunctionFunc )
engine->cleanFunctionFunc(this);
userData = 0;
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
{
if( userData[n+1] )
{
for( asUINT c = 0; c < engine->cleanFunctionFuncs.GetLength(); c++ )
if( engine->cleanFunctionFuncs[c].type == userData[n] )
engine->cleanFunctionFuncs[c].cleanFunc(this);
}
}
userData.SetLength(0);
// Release all references the function holds to other objects
ReleaseReferences();
@@ -392,6 +472,12 @@ void asCScriptFunction::DestroyInternal()
asDELETE(sysFuncIntf,asSSystemFunctionInterface);
sysFuncIntf = 0;
if( objectType )
{
objectType->ReleaseInternal();
objectType = 0;
}
DeallocateScriptFunctionData();
// Deallocate list pattern data
@@ -413,38 +499,54 @@ int asCScriptFunction::GetId() const
int asCScriptFunction::AddRef() const
{
gcFlag = false;
asASSERT( funcType != asFUNC_IMPORTED );
return refCount.atomicInc();
return externalRefCount.atomicInc();
}
// interface
int asCScriptFunction::Release() const
{
gcFlag = false;
asASSERT( funcType != asFUNC_IMPORTED );
int r = refCount.atomicDec();
int r = externalRefCount.atomicDec();
if( r == 0 &&
funcType != asFUNC_FUNCDEF && // Funcdefs are treated as object types and will be deleted by ClearUnusedTypes()
funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
{
// There are no more external references, if there are also no
// internal references then it is time to delete the function
if( internalRefCount.get() == 0 )
{
// If there are no internal references, then no module is owning the function
// For example if the function was dynamically compiled without adding it to the scope of the module
asASSERT( module == 0 );
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
}
}
return r;
}
// internal
void asCScriptFunction::Orphan(asIScriptModule *mod)
int asCScriptFunction::AddRefInternal()
{
if( mod && module == mod )
return internalRefCount.atomicInc();
}
// internal
int asCScriptFunction::ReleaseInternal()
{
int r = internalRefCount.atomicDec();
if( r == 0 &&
funcType != asFUNC_DUMMY )
{
module = 0;
if( funcType == asFUNC_SCRIPT && refCount.get() > 1 )
// There are no more internal references, if there are also no
// external references then it is time to delete the function
if( externalRefCount.get() == 0 )
{
// This function is being orphaned, so notify the GC so it can check for circular references
engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
}
}
Release();
return r;
}
// interface
@@ -531,6 +633,12 @@ bool asCScriptFunction::IsPrivate() const
return isPrivate;
}
// interface
bool asCScriptFunction::IsProtected() const
{
return isProtected;
}
// internal
int asCScriptFunction::GetSpaceNeededForArguments()
{
@@ -560,7 +668,7 @@ bool asCScriptFunction::DoesReturnOnStack() const
}
// internal
asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace) const
asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace, bool includeParamNames) const
{
asCString str;
@@ -572,12 +680,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
(name == objectType->name || (name.GetLength() > 0 && name[0] == '~') ||
name == "_beh_0_" || name == "_beh_2_")) )
{
str = returnType.Format();
str = returnType.Format(nameSpace, includeNamespace);
str += " ";
}
if( objectType && includeObjectName )
{
if( includeNamespace )
if( includeNamespace && objectType->nameSpace->name != "" )
str += objectType->nameSpace->name + "::";
if( objectType->name != "" )
@@ -585,7 +693,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
else
str += "_unnamed_type_::";
}
else if( includeNamespace )
else if( includeNamespace && nameSpace->name != "" )
{
str += nameSpace->name + "::";
}
@@ -610,7 +718,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
asUINT n;
for( n = 0; n < parameterTypes.GetLength() - 1; n++ )
{
str += parameterTypes[n].Format();
str += parameterTypes[n].Format(nameSpace, includeNamespace);
if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
{
if( inOutFlags[n] == asTM_INREF ) str += "in";
@@ -618,6 +726,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
}
if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 )
{
str += " ";
str += parameterNames[n];
}
if( defaultArgs.GetLength() > n && defaultArgs[n] )
{
asCString tmp;
@@ -629,7 +743,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
}
// Add the last parameter
str += parameterTypes[n].Format();
str += parameterTypes[n].Format(nameSpace, includeNamespace);
if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
{
if( inOutFlags[n] == asTM_INREF ) str += "in";
@@ -637,6 +751,12 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
}
if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 )
{
str += " ";
str += parameterNames[n];
}
if( defaultArgs.GetLength() > n && defaultArgs[n] )
{
asCString tmp;
@@ -654,18 +774,33 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
if( listPattern )
{
asSListPatternNode *n = listPattern;
bool first = true;
while( n )
{
if( n->type == asLPT_START )
{
str += " {";
first = true;
}
else if( n->type == asLPT_END )
{
str += " }";
first = false;
}
else if( n->type == asLPT_REPEAT )
str += " repeat";
else if( n->type == asLPT_REPEAT_SAME )
str += " repeat_same";
else if( n->type == asLPT_TYPE )
{
str += " ";
str += reinterpret_cast<asSListPatternDataTypeNode*>(n)->dataType.Format();
if( first )
{
str += " ";
first = false;
}
else
str += ", ";
str += reinterpret_cast<asSListPatternDataTypeNode*>(n)->dataType.Format(nameSpace, includeNamespace);
}
n = n->next;
@@ -694,7 +829,7 @@ int asCScriptFunction::FindNextLineWithCode(int line) const
{
static int cmp(const void *a, const void *b) { return *(int*)a - *(int*)b; }
};
qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp);
std::qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp);
if( line < lineNbrs[0] && line < (scriptData->declaredAt&0xFFFFF)) return -1;
if( line > lineNbrs[lineNbrs.GetLength()-1] ) return -1;
@@ -811,7 +946,7 @@ const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) c
return 0;
asCString *tempString = &asCThreadManager::GetLocalData()->string;
*tempString = scriptData->variables[index]->type.Format(includeNamespace);
*tempString = scriptData->variables[index]->type.Format(nameSpace, includeNamespace);
*tempString += " " + scriptData->variables[index]->name;
return tempString->AddressOf();
@@ -928,15 +1063,31 @@ void asCScriptFunction::AddReferences()
// Only count references if there is any bytecode
if( scriptData && scriptData->byteCode.GetLength() )
{
if( returnType.IsObject() )
returnType.GetObjectType()->AddRef();
if( returnType.GetObjectType() )
{
returnType.GetObjectType()->AddRefInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType());
if( group != 0 ) group->AddRef();
}
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
if( parameterTypes[p].IsObject() )
parameterTypes[p].GetObjectType()->AddRef();
if( parameterTypes[p].GetObjectType() )
{
parameterTypes[p].GetObjectType()->AddRefInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType());
if( group != 0 ) group->AddRef();
}
for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ )
scriptData->objVariableTypes[v]->AddRef();
if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type
{
scriptData->objVariableTypes[v]->AddRefInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]);
if( group != 0 ) group->AddRef();
}
// Go through the byte code and add references to all resources used by the function
asCArray<asDWORD> &bc = scriptData->byteCode;
@@ -951,7 +1102,9 @@ void asCScriptFunction::AddReferences()
case asBC_RefCpyV:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
objType->AddRef();
asASSERT( objType );
if( objType )
objType->AddRefInternal();
}
break;
@@ -959,11 +1112,13 @@ void asCScriptFunction::AddReferences()
case asBC_ALLOC:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
objType->AddRef();
asASSERT( objType );
if( objType )
objType->AddRefInternal();
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( func )
engine->scriptFunctions[func]->AddRef();
int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( funcId )
engine->scriptFunctions[funcId]->AddRefInternal();
}
break;
@@ -1002,7 +1157,9 @@ void asCScriptFunction::AddReferences()
asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId);
if( group != 0 ) group->AddRef();
engine->scriptFunctions[funcId]->AddRef();
asASSERT( funcId > 0 );
if( funcId > 0 )
engine->scriptFunctions[funcId]->AddRefInternal();
}
break;
@@ -1010,8 +1167,10 @@ void asCScriptFunction::AddReferences()
case asBC_CALL:
case asBC_CALLINTF:
{
int func = asBC_INTARG(&bc[n]);
engine->scriptFunctions[func]->AddRef();
int funcId = asBC_INTARG(&bc[n]);
asASSERT( funcId > 0 );
if( funcId > 0 )
engine->scriptFunctions[funcId]->AddRefInternal();
}
break;
@@ -1019,7 +1178,9 @@ void asCScriptFunction::AddReferences()
case asBC_FuncPtr:
{
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
func->AddRef();
asASSERT( func );
if( func )
func->AddRefInternal();
}
break;
}
@@ -1035,16 +1196,31 @@ void asCScriptFunction::ReleaseReferences()
// Only count references if there is any bytecode
if( scriptData && scriptData->byteCode.GetLength() )
{
if( returnType.IsObject() )
returnType.GetObjectType()->Release();
if( returnType.GetObjectType() )
{
returnType.GetObjectType()->ReleaseInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(returnType.GetObjectType());
if( group != 0 ) group->Release();
}
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
if( parameterTypes[p].IsObject() )
parameterTypes[p].GetObjectType()->Release();
if( parameterTypes[p].GetObjectType() )
{
parameterTypes[p].GetObjectType()->ReleaseInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(parameterTypes[p].GetObjectType());
if( group != 0 ) group->Release();
}
for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ )
if( scriptData->objVariableTypes[v] )
scriptData->objVariableTypes[v]->Release();
if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type
{
scriptData->objVariableTypes[v]->ReleaseInternal();
asCConfigGroup *group = engine->FindConfigGroupForObjectType(scriptData->objVariableTypes[v]);
if( group != 0 ) group->Release();
}
// Go through the byte code and release references to all resources used by the function
asCArray<asDWORD> &bc = scriptData->byteCode;
@@ -1060,7 +1236,7 @@ void asCScriptFunction::ReleaseReferences()
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
if( objType )
objType->Release();
objType->ReleaseInternal();
}
break;
@@ -1069,14 +1245,14 @@ void asCScriptFunction::ReleaseReferences()
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
if( objType )
objType->Release();
objType->ReleaseInternal();
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( func )
int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( funcId > 0 )
{
asCScriptFunction *fptr = engine->scriptFunctions[func];
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
if( fptr )
fptr->Release();
fptr->ReleaseInternal();
// The engine may have been forced to destroy the function internals early
// and this may will make it impossible to find the function by id anymore.
@@ -1123,7 +1299,7 @@ void asCScriptFunction::ReleaseReferences()
if( group != 0 ) group->Release();
if( funcId )
engine->scriptFunctions[funcId]->Release();
engine->scriptFunctions[funcId]->ReleaseInternal();
}
break;
@@ -1131,12 +1307,12 @@ void asCScriptFunction::ReleaseReferences()
case asBC_CALL:
case asBC_CALLINTF:
{
int func = asBC_INTARG(&bc[n]);
if( func )
int funcId = asBC_INTARG(&bc[n]);
if( funcId )
{
asCScriptFunction *fptr = engine->scriptFunctions[func];
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
if( fptr )
fptr->Release();
fptr->ReleaseInternal();
// The engine may have been forced to destroy the function internals early
// and this may will make it impossible to find the function by id anymore.
@@ -1152,7 +1328,7 @@ void asCScriptFunction::ReleaseReferences()
{
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
if( func )
func->Release();
func->ReleaseInternal();
}
break;
}
@@ -1197,6 +1373,42 @@ asUINT asCScriptFunction::GetParamCount() const
}
// interface
int asCScriptFunction::GetParam(asUINT index, int *typeId, asDWORD *flags, const char **name, const char **defaultArg) const
{
if( index >= parameterTypes.GetLength() )
return asINVALID_ARG;
if( typeId )
*typeId = engine->GetTypeIdFromDataType(parameterTypes[index]);
if( flags )
{
*flags = inOutFlags[index];
*flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0;
}
if( name )
{
// The parameter names are not stored if loading from bytecode without debug information
if( index < parameterNames.GetLength() )
*name = parameterNames[index].AddressOf();
else
*name = 0;
}
if( defaultArg )
{
if( index < defaultArgs.GetLength() && defaultArgs[index] )
*defaultArg = defaultArgs[index]->AddressOf();
else
*defaultArg = 0;
}
return asSUCCESS;
}
#ifdef AS_DEPRECATED
// Deprecated since 2014-04-06, 2.29.0
int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
{
if( index >= parameterTypes.GetLength() )
@@ -1210,6 +1422,7 @@ int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
return engine->GetTypeIdFromDataType(parameterTypes[index]);
}
#endif
// interface
asIScriptEngine *asCScriptFunction::GetEngine() const
@@ -1218,10 +1431,10 @@ asIScriptEngine *asCScriptFunction::GetEngine() const
}
// interface
const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace) const
const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace, bool includeParamNames) const
{
asCString *tempString = &asCThreadManager::GetLocalData()->string;
*tempString = GetDeclarationStr(includeObjectName, includeNamespace);
*tempString = GetDeclarationStr(includeObjectName, includeNamespace, includeParamNames);
return tempString->AddressOf();
}
@@ -1267,6 +1480,33 @@ void asCScriptFunction::JITCompile()
if( !jit )
return;
// Make sure the function has been compiled with JitEntry instructions
// For functions that has JitEntry this will be a quick test
asUINT length;
asDWORD *byteCode = GetByteCode(&length);
asDWORD *end = byteCode + length;
bool foundJitEntry = false;
while( byteCode < end )
{
// Determine the instruction
asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode);
if( op == asBC_JitEntry )
{
foundJitEntry = true;
break;
}
// Move to next instruction
byteCode += asBCTypeSize[asBCInfo[op].type];
}
if( !foundJitEntry )
{
asCString msg;
msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration());
engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
}
// Release the previous function, if any
if( scriptData->jitFunction )
{
@@ -1277,9 +1517,7 @@ void asCScriptFunction::JITCompile()
// Compile for native system
int r = jit->CompileFunction(this, &scriptData->jitFunction);
if( r < 0 )
{
asASSERT( scriptData->jitFunction == 0 );
}
}
// interface
@@ -1297,17 +1535,55 @@ asDWORD *asCScriptFunction::GetByteCode(asUINT *length)
}
// interface
void *asCScriptFunction::SetUserData(void *data)
void *asCScriptFunction::SetUserData(void *data, asPWORD type)
{
void *oldData = userData;
userData = data;
return oldData;
// As a thread might add a new new user data at the same time as another
// it is necessary to protect both read and write access to the userData member
ACQUIREEXCLUSIVE(engine->engineRWLock);
// It is not intended to store a lot of different types of userdata,
// so a more complex structure like a associative map would just have
// more overhead than a simple array.
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
{
if( userData[n] == type )
{
void *oldData = reinterpret_cast<void*>(userData[n+1]);
userData[n+1] = reinterpret_cast<asPWORD>(data);
RELEASEEXCLUSIVE(engine->engineRWLock);
return oldData;
}
}
userData.PushLast(type);
userData.PushLast(reinterpret_cast<asPWORD>(data));
RELEASEEXCLUSIVE(engine->engineRWLock);
return 0;
}
// interface
void *asCScriptFunction::GetUserData() const
void *asCScriptFunction::GetUserData(asPWORD type) const
{
return userData;
// There may be multiple threads reading, but when
// setting the user data nobody must be reading.
ACQUIRESHARED(engine->engineRWLock);
for( asUINT n = 0; n < userData.GetLength(); n += 2 )
{
if( userData[n] == type )
{
RELEASESHARED(engine->engineRWLock);
return reinterpret_cast<void*>(userData[n+1]);
}
}
RELEASESHARED(engine->engineRWLock);
return 0;
}
// internal
@@ -1326,7 +1602,9 @@ asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr)
// internal
int asCScriptFunction::GetRefCount()
{
return refCount.get();
asASSERT( funcType == asFUNC_DELEGATE );
return externalRefCount.get();
}
// internal
@@ -1344,192 +1622,24 @@ bool asCScriptFunction::GetFlag()
// internal
void asCScriptFunction::EnumReferences(asIScriptEngine *)
{
// Notify the GC of all object types used
if( returnType.IsObject() )
engine->GCEnumCallback(returnType.GetObjectType());
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
if( parameterTypes[p].IsObject() )
engine->GCEnumCallback(parameterTypes[p].GetObjectType());
if( scriptData )
{
for( asUINT t = 0; t < scriptData->objVariableTypes.GetLength(); t++ )
engine->GCEnumCallback(scriptData->objVariableTypes[t]);
// Notify the GC of all script functions that is accessed
asCArray<asDWORD> &bc = scriptData->byteCode;
for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] )
{
switch( *(asBYTE*)&bc[n] )
{
case asBC_OBJTYPE:
case asBC_FREE:
case asBC_REFCPY:
case asBC_RefCpyV:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
engine->GCEnumCallback(objType);
}
break;
case asBC_ALLOC:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
engine->GCEnumCallback(objType);
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( func )
engine->GCEnumCallback(engine->scriptFunctions[func]);
}
break;
case asBC_CALL:
case asBC_CALLINTF:
{
int func = asBC_INTARG(&bc[n]);
if( func )
engine->GCEnumCallback(engine->scriptFunctions[func]);
}
break;
// Function pointers
case asBC_FuncPtr:
{
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
if( func )
engine->GCEnumCallback(func);
}
break;
// Global variables
case asBC_PGA:
case asBC_PshGPtr:
case asBC_LDG:
case asBC_PshG4:
case asBC_LdGRdR4:
case asBC_CpyGtoV4:
case asBC_CpyVtoG4:
case asBC_SetG4:
// Need to enumerate the reference for each global variable
{
// TODO: optimize: Keep an array of accessed global properties
void *gvarPtr = (void*)asBC_PTRARG(&bc[n]);
asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
engine->GCEnumCallback(prop);
}
break;
}
}
}
asASSERT( funcType == asFUNC_DELEGATE );
// Delegate
if( objForDelegate )
engine->GCEnumCallback(objForDelegate);
if( funcForDelegate )
engine->GCEnumCallback(funcForDelegate);
}
// internal
void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
{
asASSERT( funcType == asFUNC_DELEGATE );
// Release paramaters
if( scriptData && scriptData->byteCode.GetLength() )
{
if( returnType.IsObject() )
{
returnType.GetObjectType()->Release();
returnType = asCDataType::CreatePrimitive(ttVoid, false);
}
for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
if( parameterTypes[p].IsObject() )
{
parameterTypes[p].GetObjectType()->Release();
parameterTypes[p] = asCDataType::CreatePrimitive(ttInt, false);
}
for( asUINT n = 0; n < scriptData->objVariableTypes.GetLength(); n++ )
scriptData->objVariableTypes[n]->Release();
scriptData->objVariableTypes.SetLength(0);
// Release all script functions
asCArray<asDWORD> &bc = scriptData->byteCode;
for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] )
{
switch( *(asBYTE*)&bc[n] )
{
// Object types
case asBC_OBJTYPE:
case asBC_FREE:
case asBC_REFCPY:
case asBC_RefCpyV:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
if( objType )
{
objType->Release();
*(asPWORD*)&bc[n+1] = 0;
}
}
break;
case asBC_ALLOC:
{
asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]);
if( objType )
{
objType->Release();
*(asPWORD*)&bc[n+1] = 0;
}
int func = asBC_INTARG(&bc[n]+AS_PTR_SIZE);
if( func )
{
engine->scriptFunctions[func]->Release();
bc[n+AS_PTR_SIZE+1] = 0;
}
}
break;
case asBC_CALL:
case asBC_CALLINTF:
{
int func = asBC_INTARG(&bc[n]);
if( func )
{
engine->scriptFunctions[func]->Release();
bc[n+1] = 0;
}
}
break;
// Function pointers
case asBC_FuncPtr:
{
asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]);
if( func )
{
func->Release();
*(asPWORD*)&bc[n+1] = 0;
}
}
break;
// The global variables are not released here. It is enough that the global
// variable itself release the function to break the circle
}
}
}
// Delegate
if( objForDelegate )
engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType());
objForDelegate = 0;
if( funcForDelegate )
funcForDelegate->Release();
funcForDelegate = 0;
}
// internal
@@ -1539,6 +1649,7 @@ bool asCScriptFunction::IsShared() const
if( funcType == asFUNC_SYSTEM ) return true;
// All class methods for shared classes are also shared
asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 );
if( objectType && (objectType->flags & asOBJ_SHARED) ) return true;
// Functions that have been specifically marked as shared are shared