Merge remote-tracking branch 'origin/master' into fix_replay
This commit is contained in:
commit
abd9ed189c
@ -58,8 +58,8 @@ BEGIN_AS_NAMESPACE
|
||||
|
||||
// AngelScript version
|
||||
|
||||
#define ANGELSCRIPT_VERSION 23000
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.30.0 WIP"
|
||||
#define ANGELSCRIPT_VERSION 23002
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.30.2"
|
||||
|
||||
// Data types
|
||||
|
||||
@ -543,7 +543,7 @@ struct asSMessageInfo
|
||||
extern "C"
|
||||
{
|
||||
// Engine
|
||||
AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version);
|
||||
AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version = ANGELSCRIPT_VERSION);
|
||||
AS_API const char *asGetLibraryVersion();
|
||||
AS_API const char *asGetLibraryOptions();
|
||||
|
||||
@ -585,20 +585,20 @@ template<typename T>
|
||||
asUINT asGetTypeTraits()
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5)
|
||||
// MSVC & XCode/Clang, and gnuc 5+
|
||||
// MSVC, XCode/Clang, and gnuc 5+
|
||||
// C++11 compliant code
|
||||
bool hasConstructor = std::is_default_constructible<T>::value && !std::is_trivially_default_constructible<T>::value;
|
||||
bool hasDestructor = std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value;
|
||||
bool hasAssignmentOperator = std::is_copy_assignable<T>::value && !std::is_trivially_copy_assignable<T>::value;
|
||||
bool hasCopyConstructor = std::is_copy_constructible<T>::value && !std::is_trivially_copy_constructible<T>::value;
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
// gnuc 4.8+
|
||||
// gnuc is using a mix of C++11 standard and pre-standard templates
|
||||
// gnuc 4.8 is using a mix of C++11 standard and pre-standard templates
|
||||
bool hasConstructor = std::is_default_constructible<T>::value && !std::has_trivial_default_constructor<T>::value;
|
||||
bool hasDestructor = std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value;
|
||||
bool hasAssignmentOperator = std::is_copy_assignable<T>::value && !std::has_trivial_copy_assign<T>::value;
|
||||
bool hasCopyConstructor = std::is_copy_constructible<T>::value && !std::has_trivial_copy_constructor<T>::value;
|
||||
#else
|
||||
// All other compilers and versions are assumed to use non C++11 compliant code until proven otherwise
|
||||
// Not fully C++11 compliant. The has_trivial checks were used while the standard was still
|
||||
// being elaborated, but were then removed in favor of the above is_trivially checks
|
||||
// http://stackoverflow.com/questions/12702103/writing-code-that-works-when-has-trivial-destructor-is-defined-instead-of-is
|
||||
@ -1556,8 +1556,8 @@ enum asEBCInstr
|
||||
asBC_POWdi = 197,
|
||||
asBC_POWi64 = 198,
|
||||
asBC_POWu64 = 199,
|
||||
|
||||
asBC_MAXBYTECODE = 200,
|
||||
asBC_Thiscall1 = 200,
|
||||
asBC_MAXBYTECODE = 201,
|
||||
|
||||
// Temporary tokens. Can't be output to the final program
|
||||
asBC_VarDecl = 251,
|
||||
@ -1851,8 +1851,8 @@ const asSBCInfo asBCInfo[256] =
|
||||
asBCINFO(POWdi, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(POWi64, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(POWu64, wW_rW_rW_ARG, 0),
|
||||
asBCINFO(Thiscall1, DW_ARG, -AS_PTR_SIZE-1),
|
||||
|
||||
asBCINFO_DUMMY(200),
|
||||
asBCINFO_DUMMY(201),
|
||||
asBCINFO_DUMMY(202),
|
||||
asBCINFO_DUMMY(203),
|
||||
|
@ -14,11 +14,15 @@ if(APPLE)
|
||||
option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF)
|
||||
endif()
|
||||
|
||||
set(ANGELSCRIPT_VERSION_MAJOR 2)
|
||||
set(ANGELSCRIPT_VERSION_MINOR 30)
|
||||
set(ANGELSCRIPT_VERSION_PATCH 0)
|
||||
file(READ ../../include/angelscript.h ANGELSCRIPT_H)
|
||||
string(REGEX MATCH "#define ANGELSCRIPT_VERSION_STRING \"([0-9]*).([0-9]*).([0-9]*)" ANGELSCRIPT_VERSION_REGEX ${ANGELSCRIPT_H})
|
||||
set(ANGELSCRIPT_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(ANGELSCRIPT_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(ANGELSCRIPT_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
set(PROJECT_VERSION ${ANGELSCRIPT_VERSION_MAJOR}.${ANGELSCRIPT_VERSION_MINOR}.${ANGELSCRIPT_VERSION_PATCH})
|
||||
|
||||
message(STATUS "Configuring angelscript ${PROJECT_VERSION}")
|
||||
|
||||
find_package(Threads)
|
||||
|
||||
set(ANGELSCRIPT_HEADERS
|
||||
@ -102,12 +106,13 @@ if(MSVC AND CMAKE_CL_64)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm")
|
||||
enable_language(ASM)
|
||||
if(CMAKE_ASM_COMPILER_WORKS)
|
||||
set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S)
|
||||
set_property(SOURCE ../../source/as_callfunc_arm_gcc.S APPEND PROPERTY COMPILE_FLAGS " -Wa,-mimplicit-it=always")
|
||||
else()
|
||||
message(FATAL ERROR "Android target requires a working assembler")
|
||||
message(FATAL ERROR "ARM target requires a working assembler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -156,4 +161,5 @@ endif()
|
||||
|
||||
#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin)
|
||||
|
||||
#add_subdirectory(../../../samples/game/projects/cmake/ ./game)
|
||||
|
||||
|
@ -363,9 +363,35 @@ int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int
|
||||
|
||||
CompileGlobalVariables();
|
||||
|
||||
// It is possible that the global variable initialization included anonymous functions that must be compiled too
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCCompiler compiler(engine);
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0);
|
||||
if( r < 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
// None of the functions should be added to the module if any error occurred,
|
||||
// or it was requested that the functions wouldn't be added to the scope
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
if( module->globalFunctions.GetIndex(func) >= 0 )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// Remove the variable from the module, if it was registered
|
||||
@ -549,22 +575,38 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
|
||||
funcDesc->paramNames = func->parameterNames;
|
||||
funcDesc->isExistingShared = false;
|
||||
|
||||
asCCompiler compiler(engine);
|
||||
compiler.CompileFunction(this, functions[0]->script, func->parameterNames, functions[0]->node, func, 0);
|
||||
// This must be done in a loop, as it is possible that additional functions get declared as lambda's in the code
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCCompiler compiler(engine);
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0);
|
||||
if( r < 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
// None of the functions should be added to the module if any error occurred,
|
||||
// or it was requested that the functions wouldn't be added to the scope
|
||||
if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 )
|
||||
{
|
||||
for( asUINT n = 0; n < functions.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
|
||||
if( module->globalFunctions.GetIndex(func) >= 0 )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// If the function was added to the module then remove it again
|
||||
if( compileFlags & asCOMP_ADD_TO_MODULE )
|
||||
{
|
||||
module->globalFunctions.Erase(module->globalFunctions.GetIndex(func));
|
||||
module->scriptFunctions.RemoveValue(func);
|
||||
func->ReleaseInternal();
|
||||
}
|
||||
|
||||
// Release the function pointer that would otherwise be returned if no errors occured
|
||||
func->ReleaseInternal();
|
||||
|
||||
return asERROR;
|
||||
@ -965,15 +1007,20 @@ int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &nam
|
||||
if( r < 0 )
|
||||
return asINVALID_DECLARATION;
|
||||
|
||||
// Get data type and property name
|
||||
// Get data type
|
||||
asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
|
||||
|
||||
asCScriptNode *nameNode = dataType->next;
|
||||
// Check if the property is declared 'by reference'
|
||||
bool isReference = (dataType->next->tokenType == ttAmp);
|
||||
|
||||
// Get the name of the property
|
||||
asCScriptNode *nameNode = isReference ? dataType->next->next : dataType->next;
|
||||
|
||||
// If an object property is registered, then use the
|
||||
// object's namespace, otherwise use the specified namespace
|
||||
type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetObjectType()->nameSpace : ns);
|
||||
name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
|
||||
type.MakeReference(isReference);
|
||||
|
||||
// Validate that the type really can be a registered property
|
||||
// We cannot use CanBeInstantiated, as it is allowed to register
|
||||
@ -1458,9 +1505,9 @@ sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns)
|
||||
|
||||
int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case
|
||||
// an error should be given if any of the arguments/return type is not
|
||||
// shared.
|
||||
// TODO: redesign: Allow funcdefs to be explicitly declared as 'shared'. In this case
|
||||
// an error should be given if any of the arguments/return type is not
|
||||
// shared.
|
||||
|
||||
// Find the name
|
||||
asASSERT( node->firstChild->nodeType == snDataType );
|
||||
@ -1516,6 +1563,7 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
|
||||
asCScriptFunction *func = module->funcDefs[funcDef->idx];
|
||||
asASSERT( func );
|
||||
|
||||
// TODO: It should be possible to declare funcdef as shared. In this case a compiler error will be given if any of the types it uses are not shared
|
||||
GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared, func->nameSpace);
|
||||
|
||||
// There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks
|
||||
@ -1523,27 +1571,47 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
|
||||
if( defaultArgs[n] )
|
||||
asDELETE(defaultArgs[n], asCString);
|
||||
|
||||
// TODO: Should we force the use of 'shared' for this check to be done?
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
// All funcdefs are shared, unless one of the parameter types or return type is not shared
|
||||
isShared = true;
|
||||
if( func->returnType.GetObjectType() && !func->returnType.GetObjectType()->IsShared() )
|
||||
isShared = false;
|
||||
if( func->returnType.GetFuncDef() && !func->returnType.GetFuncDef()->IsShared() )
|
||||
isShared = false;
|
||||
for( asUINT n = 0; isShared && n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
if( func->parameterTypes[n].GetObjectType() && !func->parameterTypes[n].GetObjectType()->IsShared() )
|
||||
isShared = false;
|
||||
if( func->parameterTypes[n].GetFuncDef() && !func->parameterTypes[n].GetFuncDef()->IsShared() )
|
||||
isShared = false;
|
||||
}
|
||||
func->isShared = isShared;
|
||||
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
if( func->isShared )
|
||||
{
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
funcDef->idx = f2->id;
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
if( !f2->isShared )
|
||||
continue;
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
funcDef->idx = f2->id;
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2463,7 +2531,7 @@ void asCBuilder::CompileInterfaces()
|
||||
sClassDeclaration *intfDecl = interfaceDeclarations[n];
|
||||
asCObjectType *intfType = intfDecl->objType;
|
||||
|
||||
// TODO: 2.28.1: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
|
||||
// TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here?
|
||||
// Co-opt the vfTableIdx value in our own methods to indicate the
|
||||
// index the function should have in the table chunk for this interface.
|
||||
for( asUINT d = 0; d < intfType->methods.GetLength(); d++ )
|
||||
@ -4124,6 +4192,34 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
|
||||
return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isProtected, isOverride, isFinal, isShared);
|
||||
}
|
||||
|
||||
asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns)
|
||||
{
|
||||
// Get the parameter names from the node
|
||||
asCArray<asCString> parameterNames;
|
||||
asCArray<asCString*> defaultArgs;
|
||||
asCScriptNode *args = node->firstChild;
|
||||
while( args && args->nodeType == snIdentifier )
|
||||
{
|
||||
asCString argName;
|
||||
argName.Assign(&file->code[args->tokenPos], args->tokenLength);
|
||||
parameterNames.PushLast(argName);
|
||||
defaultArgs.PushLast(0);
|
||||
args = args->next;
|
||||
}
|
||||
|
||||
// The statement block for the function must be disconnected, as the builder is going to be the owner of it
|
||||
args->DisconnectParent();
|
||||
|
||||
// Get the return and parameter types from the funcDef
|
||||
asCString funcName = name;
|
||||
int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, false, false, false, false, false, false, false, false);
|
||||
if( r < 0 )
|
||||
return 0;
|
||||
|
||||
// Return the function that was just created (but that will be compiled later)
|
||||
return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId];
|
||||
}
|
||||
|
||||
int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray<asCString> ¶meterNames, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool isConstMethod, bool isConstructor, bool isDestructor, bool isPrivate, bool isProtected, bool isOverride, bool isFinal, bool isShared)
|
||||
{
|
||||
// Determine default namespace if not specified
|
||||
@ -4734,11 +4830,15 @@ void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *ob
|
||||
// If searching with a scope informed, then the node and script must also be informed for potential error reporting
|
||||
asASSERT( errNode && script );
|
||||
|
||||
// If the scope contains ::identifier, then use the last identifier as the class name and the rest of is as the namespace
|
||||
// If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
|
||||
int n = scope.FindLast("::");
|
||||
asCString className = n >= 0 ? scope.SubString(n+2) : scope;
|
||||
asCString nsName = n >= 0 ? scope.SubString(0, n) : "";
|
||||
asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script);
|
||||
|
||||
// Check if the namespace actually exist, if not return silently as this cannot be the referring to a base class
|
||||
asSNameSpace *ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, false);
|
||||
if( ns == 0 )
|
||||
return;
|
||||
|
||||
// Find the base class with the specified scope
|
||||
while( objectType && (objectType->name != className || objectType->nameSpace != ns) )
|
||||
@ -4894,7 +4994,7 @@ asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCod
|
||||
return GetNameSpaceByString(scope, implicitNs, node, script);
|
||||
}
|
||||
|
||||
asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script)
|
||||
asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired)
|
||||
{
|
||||
asSNameSpace *ns = implicitNs;
|
||||
if( nsName == "::" )
|
||||
@ -4902,7 +5002,7 @@ asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameS
|
||||
else if( nsName != "" )
|
||||
{
|
||||
ns = engine->FindNameSpace(nsName.AddressOf());
|
||||
if( ns == 0 )
|
||||
if( ns == 0 && isRequired )
|
||||
{
|
||||
asCString msg;
|
||||
msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf());
|
||||
@ -5073,6 +5173,12 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
|
||||
ot = otInstance;
|
||||
}
|
||||
}
|
||||
else if( n && n->next && n->next->nodeType == snDataType )
|
||||
{
|
||||
asCString str;
|
||||
str.Format(TXT_TYPE_s_NOT_TEMPLATE, ot->name.AddressOf());
|
||||
WriteError(str, file, n);
|
||||
}
|
||||
|
||||
// Create object data type
|
||||
if( ot )
|
||||
|
@ -174,7 +174,7 @@ protected:
|
||||
asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file);
|
||||
|
||||
asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script);
|
||||
asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, bool isRequired = true);
|
||||
asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0);
|
||||
|
||||
asCObjectType *GetObjectType(const char *type, asSNameSpace *ns);
|
||||
@ -213,6 +213,7 @@ protected:
|
||||
int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns);
|
||||
asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns);
|
||||
void CompleteFuncDef(sFuncDef *funcDef);
|
||||
void CompileInterfaces();
|
||||
void CompileClasses(asUINT originalNumTempl);
|
||||
|
@ -1015,6 +1015,21 @@ void asCByteCode::OptimizeLocally(const asCArray<int> &tempVariableOffsets)
|
||||
ChangeFirstDeleteNext(curr, asBC_PSF);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
// VAR a, GETOBJREF 0 -> PshVPtr a
|
||||
else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 )
|
||||
{
|
||||
ChangeFirstDeleteNext(curr, asBC_PshVPtr);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
// VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF
|
||||
if( curr->next && curr->next->op == asBC_PSF &&
|
||||
curr->next->next && curr->next->next->op == asBC_GETREF &&
|
||||
curr->next->next->wArg[0] == AS_PTR_SIZE )
|
||||
{
|
||||
curr->op = asBC_PSF;
|
||||
DeleteInstruction(curr->next->next);
|
||||
instr = GoForward(curr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2220,6 +2235,13 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = *(asCScriptFunction**)ARG_DW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), func->GetDeclaration());
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_PshC4:
|
||||
case asBC_Cast:
|
||||
fprintf(file, " %-8s 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg)));
|
||||
@ -2233,6 +2255,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
case asBC_CALLSYS:
|
||||
case asBC_CALLBND:
|
||||
case asBC_CALLINTF:
|
||||
case asBC_Thiscall1:
|
||||
{
|
||||
int funcID = *(int*)ARG_DW(instr->arg);
|
||||
asCString decl = engine->GetFunctionDeclaration(funcID);
|
||||
@ -2268,10 +2291,17 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
{
|
||||
case asBC_OBJTYPE:
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg);
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
case asBC_FuncPtr:
|
||||
{
|
||||
asCScriptFunction *func = *(asCScriptFunction**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), func->GetDeclaration());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __GNUC__
|
||||
@ -2288,15 +2318,27 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
|
||||
|
||||
case asBCTYPE_wW_QW_ARG:
|
||||
case asBCTYPE_rW_QW_ARG:
|
||||
switch( instr->op )
|
||||
{
|
||||
case asBC_RefCpyV:
|
||||
case asBC_FREE:
|
||||
{
|
||||
asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg);
|
||||
fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __GNUC__
|
||||
#ifdef _LP64
|
||||
fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#else
|
||||
fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#endif
|
||||
#else
|
||||
fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg)));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case asBCTYPE_DW_DW_ARG:
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 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
|
||||
@ -130,6 +130,8 @@ public:
|
||||
int InstrW_W(asEBCInstr bc, int w, int b);
|
||||
int InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c);
|
||||
|
||||
asCScriptEngine *GetEngine() const { return engine; };
|
||||
|
||||
asCArray<int> lineNumbers;
|
||||
asCArray<int> sectionIdxs;
|
||||
int largestStackUsed;
|
||||
|
@ -130,10 +130,11 @@ int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv,
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr);
|
||||
#if defined(AS_ARM) && (defined(__GNUC__) || defined(AS_PSVITA))
|
||||
#if (defined(AS_ARM) || defined(AS_MIPS)) && (defined(__GNUC__) || defined(AS_PSVITA))
|
||||
// As the least significant bit in func is used to switch to THUMB mode
|
||||
// on ARM processors, the LSB in the __delta variable is used instead of
|
||||
// the one in __pfn on ARM processors.
|
||||
// MIPS also appear to use the base offset to indicate virtual method.
|
||||
if( (size_t(internal->baseOffset) & 1) )
|
||||
internal->callConv = (internalCallConv)(thisCallConv + 2);
|
||||
#endif
|
||||
@ -577,10 +578,11 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
// MIPS also work like ARM in this regard
|
||||
obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
obj = (void*)(asPWORD(obj) + sysFunc->baseOffset);
|
||||
@ -634,10 +636,11 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
}
|
||||
|
||||
// Add the base offset for multiple inheritance
|
||||
#if (defined(__GNUC__) && defined(AS_ARM)) || defined(AS_PSVITA)
|
||||
#if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
|
||||
// On GNUC + ARM the lsb of the offset is used to indicate a virtual function
|
||||
// and the whole offset is thus shifted one bit left to keep the original
|
||||
// offset resolution
|
||||
// MIPS also work like ARM in this regard
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1));
|
||||
#else
|
||||
tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset);
|
||||
@ -822,7 +825,15 @@ int CallSystemFunction(int id, asCContext *context)
|
||||
if( cleanCount )
|
||||
{
|
||||
args = context->m_regs.stackPointer;
|
||||
if( callConv >= ICC_THISCALL )
|
||||
|
||||
// Skip the hidden argument for the return pointer
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( descr->DoesReturnOnStack() )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
// Skip the object pointer on the stack
|
||||
// TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
|
||||
if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 )
|
||||
args += AS_PTR_SIZE;
|
||||
|
||||
asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -39,11 +39,13 @@
|
||||
The assembler routines for Linux were written by Carlos Luna in December 2012
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM)
|
||||
|
||||
#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__)
|
||||
|
||||
/* iOS, Android, and Marmalade goes here */
|
||||
/* iOS, Android, Marmalade, and Linux with soft-float ABI goes here */
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
@ -85,7 +87,12 @@ stackargsloop:
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
nomoreargs:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -133,7 +140,12 @@ stackargslooparmFuncObjLast:
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -180,7 +192,12 @@ stackargslooparmFuncR0ObjLast:
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -218,7 +235,12 @@ stackargslooparmFuncR0:
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
@ -255,14 +277,19 @@ stackargslooparmFuncR0R1:
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0R1:
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
#endif
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
#elif defined(__linux__) && !defined(__SOFTFP__)
|
||||
|
||||
/* The Linux code goes here */
|
||||
/* The Linux with hard-float ABI code goes here */
|
||||
|
||||
|
||||
/* These codes are suitable for armeabi + vfp / armeabihf */
|
||||
@ -340,7 +367,7 @@ stackargsloop:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargs:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
@ -427,8 +454,8 @@ stackargslooparmFuncObjLast:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncObjLast:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -521,8 +548,8 @@ stackargslooparmFuncR0ObjLast:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -597,8 +624,8 @@ stackargslooparmFuncR0:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -677,8 +704,8 @@ stackargslooparmFuncR0R1:
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0R1:
|
||||
#if defined (___ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc
|
||||
#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
|
||||
mov lr, pc /* older ARM didn't support blx */
|
||||
mov pc, r4
|
||||
#else
|
||||
blx r4
|
||||
@ -697,3 +724,6 @@ nomoreargsarmFuncR0R1:
|
||||
|
||||
#endif /* arm */
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
||||
|
@ -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
|
||||
@ -34,6 +34,8 @@
|
||||
This code was adapted from as_callfunc_arm_gcc (ARM, Linux hard float) by Brandon Bare on October 2014.
|
||||
*/
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#ifdef __psp2__
|
||||
|
||||
.syntax unified
|
||||
@ -61,7 +63,7 @@
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFunc:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */
|
||||
|
||||
@ -81,19 +83,19 @@ armFunc:
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #12]
|
||||
|
||||
stackargs:
|
||||
@ -128,11 +130,11 @@ nomoreargs:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncObjLast:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */
|
||||
|
||||
@ -157,28 +159,28 @@ armFuncObjLast:
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6,#4]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r1, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6,#8]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6,#12]
|
||||
|
||||
ittt lt
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */
|
||||
@ -220,11 +222,11 @@ nomoreargsarmFuncObjLast:
|
||||
|
||||
pop {r4-r8, r10,r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0ObjLast:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -252,35 +254,35 @@ armFuncR0ObjLast:
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6,#4]
|
||||
|
||||
it lt
|
||||
it lt
|
||||
movlt r2, r5
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6,#8]
|
||||
|
||||
ittt lt
|
||||
ittt lt
|
||||
movlt r3, r5
|
||||
movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */
|
||||
blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */
|
||||
|
||||
cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */
|
||||
|
||||
itt ge
|
||||
itt ge
|
||||
ldrge r7, [r6, #12]
|
||||
strge r7, [r6, #8]
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #0
|
||||
mov r5, #0
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */
|
||||
add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */
|
||||
|
||||
@ -318,11 +320,11 @@ nomoreargsarmFuncR0ObjLast:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -344,19 +346,19 @@ armFuncR0:
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #8]
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
stackargsarmFuncR0:
|
||||
@ -393,11 +395,11 @@ nomoreargsarmFuncR0:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
armFuncR0R1:
|
||||
.fnstart
|
||||
.fnstart
|
||||
|
||||
push {r4-r8, r10, r11, lr}
|
||||
|
||||
@ -421,23 +423,23 @@ armFuncR0R1:
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #4
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r2, [r6]
|
||||
cmp r7, #8
|
||||
|
||||
it ge
|
||||
it ge
|
||||
ldrge r3, [r6, #4]
|
||||
cmp r7, #12
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
cmp r7, #16
|
||||
|
||||
it ge
|
||||
it ge
|
||||
movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
|
||||
|
||||
itt lt
|
||||
itt lt
|
||||
ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */
|
||||
strlt r7, [r6, #12]
|
||||
|
||||
@ -475,6 +477,9 @@ nomoreargsarmFuncR0R1:
|
||||
|
||||
pop {r4-r8, r10, r11, pc}
|
||||
|
||||
.fnend
|
||||
.fnend
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2009 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
|
||||
@ -35,6 +35,8 @@
|
||||
// Adapted to GNUC by darktemplar216 in September 2009
|
||||
// Small fixed to work under XCode GCC by Gilad Novik in October 2009
|
||||
|
||||
#if !defined(AS_MAX_PORTABILITY)
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__)
|
||||
|
||||
.align 2
|
||||
@ -235,3 +237,6 @@ nomoreargsarmFuncR0R1:
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !AS_MAX_PORTABILITY */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -35,7 +35,9 @@
|
||||
// These functions handle the actual calling of system functions
|
||||
//
|
||||
// This version is MIPS specific and was originally written
|
||||
// by Manu Evans in April, 2006
|
||||
// by Manu Evans in April, 2006 for Playstation Portable (PSP)
|
||||
//
|
||||
// Support for Linux with MIPS was added by Andreas Jonsson in April, 2015
|
||||
//
|
||||
|
||||
|
||||
@ -52,10 +54,320 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if !defined(AS_ANDROID)
|
||||
#include <regdef.h>
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
#if defined(__linux__) && defined(_ABIO32)
|
||||
|
||||
// The MIPS ABI used by Linux is implemented here
|
||||
// (Tested on CI20 MIPS Creator with Debian Linux)
|
||||
//
|
||||
// ref: SYSTEM V
|
||||
// APPLICATION BINARY INTERFACE
|
||||
// MIPS RISC Processor
|
||||
// http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf
|
||||
//
|
||||
// ref: MIPS Instruction Reference
|
||||
// http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
|
||||
|
||||
union SFloatRegs
|
||||
{
|
||||
union { double d0; struct { float f0; asDWORD dummy0; };};
|
||||
union { double d1; struct { float f1; asDWORD dummy1; };};
|
||||
} ;
|
||||
|
||||
extern "C" asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
asDWORD GetReturnedFloat();
|
||||
asQWORD GetReturnedDouble();
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
|
||||
void *func = (void*)sysFunc->func;
|
||||
void **vftable;
|
||||
|
||||
asDWORD argBuffer[128]; // Ought to be big enough
|
||||
asASSERT( sysFunc->paramSize < 128 );
|
||||
|
||||
asDWORD argOffset = 0;
|
||||
|
||||
SFloatRegs floatRegs;
|
||||
asDWORD floatOffset = 0;
|
||||
|
||||
// If the application function returns the value in memory then
|
||||
// the first argument must be the pointer to that memory
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
asASSERT( retPointer );
|
||||
argBuffer[argOffset++] = (asPWORD)retPointer;
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
||||
callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
||||
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
int spos = 0;
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
asCDataType ¶mType = descr->parameterTypes[n];
|
||||
if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() )
|
||||
{
|
||||
if( paramType.GetObjectType()->flags & COMPLEX_MASK )
|
||||
{
|
||||
// The object is passed by reference
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure 8byte alignment for classes that need it
|
||||
if( (paramType.GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) )
|
||||
argOffset++;
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes());
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
argOffset += paramType.GetSizeInMemoryDWords();
|
||||
}
|
||||
}
|
||||
else if( paramType.GetTokenType() == ttQuestion )
|
||||
{
|
||||
// Copy both pointer and type id
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The first 2 floats or doubles are loaded into the float registers.
|
||||
// Actually this is only done if they are the first arguments to the function,
|
||||
// but it doesn't cause any harm to load them into the registers even if they
|
||||
// won't be used so we don't need to check if they really are the first args.
|
||||
if( floatOffset == 0 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f0 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d0 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
else if( floatOffset == 1 )
|
||||
{
|
||||
if( paramType.GetTokenType() == ttFloat )
|
||||
floatRegs.f1 = *reinterpret_cast<float*>(&args[spos]);
|
||||
else if( paramType.GetTokenType() == ttDouble )
|
||||
floatRegs.d1 = *reinterpret_cast<double*>(&args[spos]);
|
||||
floatOffset++;
|
||||
}
|
||||
|
||||
// Copy the value directly
|
||||
if( paramType.GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
// Make sure the argument is 8byte aligned
|
||||
if( argOffset & 1 )
|
||||
argOffset++;
|
||||
*reinterpret_cast<asQWORD*>(&argBuffer[argOffset]) = *reinterpret_cast<asQWORD*>(&args[spos]);
|
||||
argOffset += 2;
|
||||
spos += 2;
|
||||
}
|
||||
else
|
||||
argBuffer[argOffset++] = args[spos++];
|
||||
}
|
||||
}
|
||||
|
||||
if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the last argument
|
||||
argBuffer[argOffset++] = (asPWORD)obj;
|
||||
}
|
||||
|
||||
if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
||||
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
||||
{
|
||||
// Add the second object pointer
|
||||
argBuffer[argOffset++] = (asPWORD)secondObject;
|
||||
}
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL:
|
||||
case ICC_CDECL_RETURNINMEM:
|
||||
case ICC_STDCALL:
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJLAST:
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJFIRST:
|
||||
case ICC_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_THISCALL_OBJLAST:
|
||||
case ICC_THISCALL_OBJLAST_RETURNINMEM:
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs);
|
||||
break;
|
||||
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST:
|
||||
case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(void***)obj;
|
||||
retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// If the return is a float value we need to get the value from the FP register
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
if( sysFunc->hostReturnSize == 1 )
|
||||
*(asDWORD*)&retQW = GetReturnedFloat();
|
||||
else
|
||||
retQW = GetReturnedDouble();
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
asDWORD GetReturnedFloat()
|
||||
{
|
||||
asDWORD f;
|
||||
|
||||
asm("swc1 $f0, %0\n" : "=m"(f));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs);
|
||||
// $2,$3 $4 $5 $6 $7
|
||||
asm(
|
||||
" .text\n"
|
||||
//" .align 2\n"
|
||||
" .cfi_startproc\n"
|
||||
" .global mipsFunc\n"
|
||||
" .ent mipsFunc\n"
|
||||
"mipsFunc:\n"
|
||||
//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n"
|
||||
//" .mask 0x00000000,0\n"
|
||||
//" .fmask 0x00000000,0\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $4, 7\n" // t4 ($12) = argSize ($4) + 7
|
||||
" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block
|
||||
// It is required that the caller reserves space for at least 16 bytes even if there are less than 4 arguments
|
||||
// and add 8 bytes for the return pointer and s0 ($16) backup
|
||||
" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) holds the total size of the stack frame (including return pointer)
|
||||
// save the s0 register (so we can use it to remember where our return pointer is lives)
|
||||
" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is)
|
||||
" .cfi_offset 16, -4\n"
|
||||
// store the return pointer
|
||||
" sw $31, -8($sp)\n"
|
||||
" .cfi_offset 31, -8\n"
|
||||
// keep original stack pointer
|
||||
" move $16, $sp\n"
|
||||
" .cfi_def_cfa_register 16\n"
|
||||
// push the stack
|
||||
" subu $sp, $sp, $13\n"
|
||||
|
||||
// store the argument in temporary registers
|
||||
" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code)
|
||||
" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer
|
||||
" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer
|
||||
" move $14, $7\n" // t6 ($14) holds the values for the float registers
|
||||
|
||||
// load integer registers
|
||||
" lw $4, 0($15)\n" // a0 ($4)
|
||||
" lw $5, 4($15)\n" // a1 ($5)
|
||||
" lw $6, 8($15)\n" // a2 ($6)
|
||||
" lw $7, 12($15)\n" // a3 ($7)
|
||||
|
||||
// load float registers
|
||||
" ldc1 $f12, 8($14)\n"
|
||||
" ldc1 $f14, 0($14)\n"
|
||||
|
||||
// skip stack parameters if there are 4 or less as they are moved into the registers
|
||||
" addi $14, $3, -16\n" // The first 4 args were already loaded into registers
|
||||
" blez $14, andCall\n"
|
||||
" nop\n"
|
||||
|
||||
// push stack parameters
|
||||
"pushArgs:\n"
|
||||
" addi $3, -4\n"
|
||||
// load from $15 + stack bytes ($3)
|
||||
" addu $14, $15, $3\n"
|
||||
" lw $14, 0($14)\n"
|
||||
// store to $sp + stack bytes ($3)
|
||||
" addu $13, $sp, $3\n"
|
||||
" sw $14, 0($13)\n"
|
||||
// if there are more, loop...
|
||||
" bne $3, $0, pushArgs\n"
|
||||
" nop\n"
|
||||
|
||||
// and call the function
|
||||
"andCall:\n"
|
||||
" jalr $25\n"
|
||||
" nop\n"
|
||||
|
||||
// restore original stack pointer
|
||||
" move $sp, $16\n"
|
||||
// restore the return pointer
|
||||
" lw $31, -8($sp)\n"
|
||||
// restore the original value of $16
|
||||
" lw $16, -4($sp)\n"
|
||||
// and return from the function
|
||||
" jr $31\n"
|
||||
" nop\n"
|
||||
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end mipsFunc\n"
|
||||
" .cfi_endproc\n"
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#else // !(defined(__linux__) && defined(_ABIO32))
|
||||
|
||||
// The MIPS ABI used by PSP and PS2 is implemented here
|
||||
|
||||
#define AS_MIPS_MAX_ARGS 32
|
||||
#define AS_NUM_REG_FLOATS 8
|
||||
#define AS_NUM_REG_INTS 8
|
||||
@ -191,33 +503,12 @@ asDWORD GetReturnedFloat()
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
asDWORD GetReturnedFloat();
|
||||
|
||||
asm(
|
||||
" .align 4\n"
|
||||
" .global GetReturnedFloat\n"
|
||||
"GetReturnedFloat:\n"
|
||||
" .set noreorder\n"
|
||||
" .set nomacro\n"
|
||||
" j $ra\n"
|
||||
" mfc1 $v0, $f0\n"
|
||||
" .set macro\n"
|
||||
" .set reorder\n"
|
||||
" .end Func\n"
|
||||
*/
|
||||
|
||||
|
||||
// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4
|
||||
// so this isn't really used...
|
||||
asQWORD GetReturnedDouble()
|
||||
{
|
||||
asQWORD d = 0;
|
||||
|
||||
printf("Broken!!!");
|
||||
/*
|
||||
asm("sw $v0, %0\n" : "=m"(d));
|
||||
*/
|
||||
asm("sdc1 $f0, %0\n" : "=m"(d));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -352,7 +643,7 @@ asm(
|
||||
" .set nomacro\n"
|
||||
// align the stack frame to 8 bytes
|
||||
" addiu $12, $6, 7\n"
|
||||
" li $13, -8\n" // 0xfffffffffffffffc
|
||||
" li $13, -8\n" // 0xfffffffffffffff8
|
||||
" and $12, $12, $13\n" // t4 holds the size of the argument block
|
||||
// and add 8 bytes for the return pointer and s0 backup
|
||||
" addiu $13, $12, 8\n" // t5 holds the total size of the stack frame (including return pointer)
|
||||
@ -432,6 +723,8 @@ asm(
|
||||
" .size mipsFunc, .-mipsFunc\n"
|
||||
);
|
||||
|
||||
#endif // PSP and PS2 MIPS ABI
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_MIPS
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -73,14 +73,18 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
|
||||
__asm__ __volatile__ (
|
||||
|
||||
" movq %0, %%rcx \n" // rcx = cnt
|
||||
" movq %0, %%rcx \n" // rcx = cnt
|
||||
" movq %1, %%r10 \n" // r10 = args
|
||||
" movq %2, %%r11 \n" // r11 = func
|
||||
|
||||
// Backup stack pointer in R15 that is guaranteed to maintain its value over function calls
|
||||
" movq %%rsp, %%r15 \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Make sure the stack unwind logic knows we've backed up the stack pointer in register r15
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register r15 \n"
|
||||
#endif
|
||||
|
||||
// Skip the first 128 bytes on the stack frame, called "red zone",
|
||||
// that might be used by the compiler to store temporary values
|
||||
@ -100,7 +104,7 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
" jle endstack \n"
|
||||
" subl $1, %%esi \n"
|
||||
" xorl %%edx, %%edx \n"
|
||||
" leaq 8(, %%rsi, 8), %%rcx \n"
|
||||
" leaq 8(, %%rsi, 8), %%rcx \n"
|
||||
"loopstack: \n"
|
||||
" movq 112(%%r10, %%rdx), %%rax \n"
|
||||
" pushq %%rax \n"
|
||||
@ -128,12 +132,16 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i
|
||||
" movsd 56(%%rax), %%xmm7 \n"
|
||||
|
||||
// Call the function
|
||||
" call *%%r11 \n"
|
||||
" call *%%r11 \n"
|
||||
|
||||
// Restore stack pointer
|
||||
" mov %%r15, %%rsp \n"
|
||||
#ifdef __OPTIMIZE__
|
||||
// Inform the stack unwind logic that the stack pointer has been restored
|
||||
// This should only be done if any optimization is done. If no optimization (-O0) is used,
|
||||
// then the compiler already backups the rsp before entering the inline assembler code
|
||||
" .cfi_def_cfa_register rsp \n"
|
||||
#endif
|
||||
|
||||
// Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value
|
||||
" movl %5, %%ecx \n"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -1263,13 +1263,13 @@ endcopy:
|
||||
"subl $4, %%ecx \n"
|
||||
"jne copyloop3 \n"
|
||||
"endcopy3: \n"
|
||||
#if defined(__MINGW32__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4)
|
||||
// MinGW made some strange choices with 4.7, and the thiscall calling convention
|
||||
// when returning an object in memory is completely different from when not returning
|
||||
// in memory
|
||||
"pushl 0(%%ebx) \n" // push obj on the stack
|
||||
"movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
|
||||
"call *12(%%ebx) \n" // call the function
|
||||
#ifdef AS_MINGW47
|
||||
// MinGW made some strange choices with 4.7 and the thiscall calling convention,
|
||||
// returning an object in memory is completely different from when not returning
|
||||
// in memory
|
||||
"pushl 0(%%ebx) \n" // push obj on the stack
|
||||
"movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
|
||||
"call *12(%%ebx) \n" // call the function
|
||||
#else
|
||||
"movl 0(%%ebx), %%ecx \n" // move obj into ECX
|
||||
#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
@ -1286,7 +1286,7 @@ endcopy:
|
||||
"addl $4, %%esp \n" // pop the object pointer
|
||||
#endif
|
||||
#endif
|
||||
#endif // MINGW
|
||||
#endif // AS_MINGW47
|
||||
// Pop the alignment bytes
|
||||
"popl %%esp \n"
|
||||
"popl %%ebx \n"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -43,7 +43,9 @@
|
||||
// various fixes in asm ppcFunc
|
||||
// fix for variable arguments
|
||||
//
|
||||
|
||||
// Modified by Anthony Clark May 2015
|
||||
// Fixed the issue where int64 and uint64 could not be passed nativly
|
||||
// few minor fixes within asm ppcFunc to handle int64 and uint64
|
||||
|
||||
|
||||
// XBox 360 calling convention
|
||||
@ -87,7 +89,6 @@
|
||||
// References:
|
||||
// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf
|
||||
//
|
||||
// TODO: The code doesn't handle int64 and uint64 parameters
|
||||
// TODO: The code doesn't handle objects passed by value (unless they are max 4 bytes in size)
|
||||
|
||||
|
||||
@ -128,7 +129,7 @@ enum argTypes
|
||||
// pArgs is the array of the argument values
|
||||
// pArgTypes is an array containing a byte indicating the type (enum argTypes) for each argument.
|
||||
// dwFunc is the address of the function that will be called
|
||||
asQWORD __declspec( naked ) ppcFunc(const asDWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes)
|
||||
asQWORD __declspec( naked ) ppcFunc(const asQWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
@ -202,7 +203,7 @@ ppcNextArg:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ppcArgIsInteger:
|
||||
// Get the arg from the stack
|
||||
lwz r12, 0(r26)
|
||||
ld r12, 0(r26)
|
||||
|
||||
// r23 holds the integer arg count so far
|
||||
cmplwi cr6, r23, 0
|
||||
@ -251,11 +252,11 @@ ppcArgIsInteger:
|
||||
b ppcLoadIntRegUpd
|
||||
|
||||
ppcLoadIntRegUpd:
|
||||
stw r12, 0(r31) // push on the stack
|
||||
std r12, 0(r31) // push on the stack
|
||||
addi r31, r31, 8 // inc stack by 1 reg
|
||||
|
||||
addi r23, r23, 1 // Increment used int register count
|
||||
addi r26, r26, 4 // Increment pArgs
|
||||
addi r26, r26, 8 // Increment pArgs
|
||||
b ppcNextArg // Call next arg
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -511,7 +512,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
|
||||
// Pack the arguments into an array that ppcFunc() can use to load each CPU register properly
|
||||
asBYTE ppcArgsType[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG + AS_PPC_ENDOFARGS];
|
||||
asDWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG];
|
||||
asQWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG];
|
||||
int argsCnt = 0;
|
||||
|
||||
// If the function returns an object in memory, we allocate the memory and put the ptr to the front (will go to r3)
|
||||
@ -625,35 +626,34 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: How should int64 and uint64 be passed natively?
|
||||
// Currently the code doesn't handle these types
|
||||
|
||||
// TODO: The code also ignore the fact that large objects
|
||||
// passed by value has been copied to the stack
|
||||
// in the above loop.
|
||||
|
||||
*pCurArgType++ = ppcINTARG;
|
||||
|
||||
*((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue);
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue);
|
||||
|
||||
if( !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// If the arg is less that 4 bytes, then move the
|
||||
// bytes to the higher bytes within the dword
|
||||
// If the arg is not 4 bytes which we coppied, lets do it again the right way
|
||||
asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes();
|
||||
if( numBytes == 1 )
|
||||
{
|
||||
pCurFixedArgValue[3] = pCurFixedArgValue[0];
|
||||
pCurFixedArgValue[0] = 0;
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 2 )
|
||||
{
|
||||
*(asWORD*)&pCurFixedArgValue[2] = *(asWORD*)&pCurFixedArgValue[0];
|
||||
*(asWORD*)&pCurFixedArgValue[0] = 0;
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue);
|
||||
}
|
||||
else if( numBytes == 8 )
|
||||
{
|
||||
*((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue);
|
||||
pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later
|
||||
}
|
||||
}
|
||||
|
||||
pCurFixedArgValue += 4;
|
||||
pCurFixedArgValue += 8;
|
||||
pCurStackArgValue += 4;
|
||||
|
||||
// if it is a variable argument, account for the typeId
|
||||
@ -703,7 +703,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
||||
// Add the object pointer as the last argument
|
||||
ppcArgsType[argsCnt++] = ppcINTARG;
|
||||
ppcArgsType[argsCnt] = ppcENDARG;
|
||||
*((asPWORD*)pCurFixedArgValue) = (asPWORD)obj;
|
||||
*((asQWORD*)pCurFixedArgValue) = (asPWORD)obj;
|
||||
retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType );
|
||||
break;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -73,14 +73,9 @@ struct asSExprContext
|
||||
{
|
||||
asSExprContext(asCScriptEngine *engine) : bc(engine)
|
||||
{
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
property_arg = 0;
|
||||
property_arg = 0;
|
||||
|
||||
Clear();
|
||||
}
|
||||
~asSExprContext()
|
||||
{
|
||||
@ -90,43 +85,95 @@ struct asSExprContext
|
||||
void Clear()
|
||||
{
|
||||
bc.ClearAll();
|
||||
type.SetDummy();
|
||||
type.Set(asCDataType());
|
||||
deferredParams.SetLength(0);
|
||||
if( property_arg )
|
||||
asDELETE(property_arg, asSExprContext);
|
||||
property_arg = 0;
|
||||
deferredParams.SetLength(0);
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
methodName = "";
|
||||
enumValue = "";
|
||||
property_arg = 0;
|
||||
exprNode = 0;
|
||||
origExpr = 0;
|
||||
property_get = 0;
|
||||
property_set = 0;
|
||||
property_const = false;
|
||||
property_handle = false;
|
||||
property_ref = false;
|
||||
methodName = "";
|
||||
enumValue = "";
|
||||
isVoidExpression = false;
|
||||
isCleanArg = false;
|
||||
}
|
||||
bool IsClassMethod()
|
||||
bool IsClassMethod() const
|
||||
{
|
||||
if( type.dataType.GetObjectType() == 0 ) return false;
|
||||
if( methodName == "" ) return false;
|
||||
if( type.dataType.GetObjectType() == &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
|
||||
return true;
|
||||
}
|
||||
bool IsGlobalFunc()
|
||||
bool IsGlobalFunc() const
|
||||
{
|
||||
if( type.dataType.GetObjectType() == 0 ) return false;
|
||||
if( methodName == "" ) return false;
|
||||
if( type.dataType.GetObjectType() != &type.dataType.GetObjectType()->engine->functionBehaviours ) return false;
|
||||
return true;
|
||||
}
|
||||
void SetLambda(asCScriptNode *funcDecl)
|
||||
{
|
||||
asASSERT( funcDecl && funcDecl->nodeType == snFunction );
|
||||
asASSERT( bc.GetLastInstr() == -1 );
|
||||
|
||||
Clear();
|
||||
type.SetUndefinedFuncHandle(bc.GetEngine());
|
||||
exprNode = funcDecl;
|
||||
}
|
||||
bool IsLambda() const
|
||||
{
|
||||
if( type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
void SetVoidExpression()
|
||||
{
|
||||
Clear();
|
||||
type.SetVoid();
|
||||
isVoidExpression = true;
|
||||
}
|
||||
bool IsVoidExpression() const
|
||||
{
|
||||
if( isVoidExpression && type.IsVoid() && exprNode == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
void Merge(asSExprContext *after)
|
||||
{
|
||||
type = after->type;
|
||||
property_get = after->property_get;
|
||||
property_set = after->property_set;
|
||||
property_const = after->property_const;
|
||||
property_handle = after->property_handle;
|
||||
property_ref = after->property_ref;
|
||||
property_arg = after->property_arg;
|
||||
exprNode = after->exprNode;
|
||||
methodName = after->methodName;
|
||||
enumValue = after->enumValue;
|
||||
isVoidExpression = after->isVoidExpression;
|
||||
isCleanArg = after->isCleanArg;
|
||||
|
||||
after->property_arg = 0;
|
||||
|
||||
// Do not copy the origExpr member
|
||||
}
|
||||
|
||||
asCByteCode bc;
|
||||
asCTypeInfo type;
|
||||
int property_get;
|
||||
int property_set;
|
||||
bool property_const; // If the object that is being accessed through property accessor is read-only
|
||||
bool property_handle; // If the property accessor is called on an object stored in a handle
|
||||
bool property_ref; // If the property accessor is called on a reference
|
||||
bool property_const; // If the object that is being accessed through property accessor is read-only
|
||||
bool property_handle; // If the property accessor is called on an object stored in a handle
|
||||
bool property_ref; // If the property accessor is called on a reference
|
||||
bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls
|
||||
bool isCleanArg; // Set to true if the expression has only been initialized with default constructor
|
||||
asSExprContext *property_arg;
|
||||
asCArray<asSDeferredParam> deferredParams;
|
||||
asCScriptNode *exprNode;
|
||||
@ -212,8 +259,8 @@ protected:
|
||||
int CompileExpressionPostOp(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileExpressionValue(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileFunctionCall(asCScriptNode *node, asSExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = "");
|
||||
void CompileConstructCall(asCScriptNode *node, asSExprContext *out);
|
||||
void CompileConversion(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileConstructCall(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileConversion(asCScriptNode *node, asSExprContext *out);
|
||||
int CompileOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
void CompileMathOperator(asCScriptNode *node, asSExprContext *l, asSExprContext *r, asSExprContext *out, eTokenType opToken = ttUnrecognizedToken);
|
||||
@ -239,6 +286,7 @@ protected:
|
||||
void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination);
|
||||
|
||||
// Helper functions
|
||||
void ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix);
|
||||
void ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node);
|
||||
int ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node);
|
||||
int ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode);
|
||||
@ -288,6 +336,7 @@ protected:
|
||||
asUINT ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode);
|
||||
void ImplicitConversionConstant(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType);
|
||||
void ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node);
|
||||
asUINT ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true);
|
||||
|
||||
void LineInstr(asCByteCode *bc, size_t pos);
|
||||
|
||||
@ -307,16 +356,18 @@ protected:
|
||||
bool hasCompileErrors;
|
||||
|
||||
int nextLabel;
|
||||
int numLambdas;
|
||||
|
||||
asCVariableScope *variables;
|
||||
asCBuilder *builder;
|
||||
asCScriptEngine *engine;
|
||||
asCScriptCode *script;
|
||||
asCVariableScope *variables;
|
||||
asCBuilder *builder;
|
||||
asCScriptEngine *engine;
|
||||
asCScriptCode *script;
|
||||
asCScriptFunction *outFunc;
|
||||
|
||||
bool m_isConstructor;
|
||||
bool m_isConstructorCalled;
|
||||
sClassDeclaration *m_classDecl;
|
||||
bool m_isConstructor;
|
||||
bool m_isConstructorCalled;
|
||||
sClassDeclaration *m_classDecl;
|
||||
sGlobalVariableDescription *m_globalVar;
|
||||
|
||||
asCArray<int> breakLabels;
|
||||
asCArray<int> continueLabels;
|
||||
@ -353,7 +404,7 @@ protected:
|
||||
|
||||
bool isCompilingDefaultArg;
|
||||
bool isProcessingDeferredParams;
|
||||
int noCodeOutput;
|
||||
int noCodeOutput;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -586,6 +586,7 @@
|
||||
#define AS_NO_MEMORY_H
|
||||
#define AS_MIPS
|
||||
#define AS_PSP
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
// PSVita
|
||||
#elif defined(__psp2__)
|
||||
#define AS_PSVITA
|
||||
@ -799,6 +800,14 @@
|
||||
// As of version 4.7 MinGW changed the ABI, presumably
|
||||
// to be better aligned with how MSVC works
|
||||
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4
|
||||
#define AS_MINGW47
|
||||
#endif
|
||||
|
||||
#if (__clang_major__ == 3 && __clang_minor__ > 4) || __clang_major > 3
|
||||
#define AS_MINGW47
|
||||
#endif
|
||||
|
||||
#ifdef AS_MINGW47
|
||||
#undef CALLEE_POPS_HIDDEN_RETURN_POINTER
|
||||
#define THISCALL_CALLEE_POPS_ARGUMENTS
|
||||
#else
|
||||
@ -845,7 +854,7 @@
|
||||
// STDCALL is not available on 64bit Linux
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
#elif defined(__ARMEL__) || defined(__arm__)
|
||||
#elif (defined(__ARMEL__) || defined(__arm__)) && !(defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__))
|
||||
#define AS_ARM
|
||||
|
||||
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
|
||||
@ -884,11 +893,24 @@
|
||||
|
||||
#elif defined(__mips__)
|
||||
#define AS_MIPS
|
||||
#define AS_BIG_ENDIAN
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
// Native calling conventions for Linux/Mips do not work yet.
|
||||
#define AS_MAX_PORTABILITY
|
||||
#ifdef _ABIO32
|
||||
#define AS_MIPS
|
||||
|
||||
// All structures are returned in memory regardless of size or complexity
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#else
|
||||
// For other ABIs the native calling convention is not available (yet)
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
#else
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
@ -936,6 +958,7 @@
|
||||
// Support native calling conventions on MIPS architecture
|
||||
#if (defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__)) && !defined(__LP64__)
|
||||
#define AS_MIPS
|
||||
#define AS_USE_DOUBLE_AS_FLOAT
|
||||
#else
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
@ -988,6 +1011,9 @@
|
||||
#if (defined(_ARM_) || defined(__arm__))
|
||||
// Android ARM
|
||||
|
||||
// TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S
|
||||
#define AS_NO_EXCEPTIONS
|
||||
|
||||
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
|
||||
@ -1013,6 +1039,26 @@
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#elif defined(__mips__)
|
||||
#define AS_MIPS
|
||||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
#ifdef _ABIO32
|
||||
#define AS_MIPS
|
||||
|
||||
// All structures are returned in memory regardless of size or complexity
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0
|
||||
#undef AS_NO_THISCALL_FUNCTOR_METHOD
|
||||
#else
|
||||
// For other ABIs the native calling convention is not available (yet)
|
||||
#define AS_MAX_PORTABILITY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Haiku OS
|
||||
@ -1047,7 +1093,7 @@
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
#elif defined(__LP64__)
|
||||
#elif defined(__x86_64__)
|
||||
#define AS_X64_GCC
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
@ -1112,11 +1158,6 @@
|
||||
// Nothing special here
|
||||
#endif
|
||||
|
||||
// MIPS architecture (generally PS2 and PSP consoles, potentially supports N64 as well)
|
||||
#if defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__) || defined(__PSP__) || defined(__psp__) || defined(_EE_) || defined(_PSP) || defined(_PS2)
|
||||
#define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles
|
||||
#endif
|
||||
|
||||
// PowerPC, e.g. Mac, GameCube, PS3, XBox 360, Wii
|
||||
#if defined(__PPC__) || defined(__ppc__) || defined(_PPC_) || defined(EPPC)
|
||||
#define AS_BIG_ENDIAN
|
||||
|
@ -134,17 +134,32 @@ public:
|
||||
|
||||
#endif
|
||||
|
||||
// interface
|
||||
AS_API asIScriptContext *asGetActiveContext()
|
||||
{
|
||||
asCThreadLocalData *tld = asCThreadManager::GetLocalData();
|
||||
if( tld->activeContexts.GetLength() == 0 )
|
||||
|
||||
// tld can be 0 if asGetActiveContext is called before any engine has been created.
|
||||
|
||||
// Observe! I've seen a case where an application linked with the library twice
|
||||
// and thus ended up with two separate instances of the code and global variables.
|
||||
// The application somehow mixed the two instances so that a function called from
|
||||
// a script ended up calling asGetActiveContext from the other instance that had
|
||||
// never been initialized.
|
||||
|
||||
if( tld == 0 || tld->activeContexts.GetLength() == 0 )
|
||||
return 0;
|
||||
return tld->activeContexts[tld->activeContexts.GetLength()-1];
|
||||
}
|
||||
|
||||
// internal
|
||||
// Note: There is no asPopActiveContext(), just call tld->activeContexts.PopLast() instead
|
||||
asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx)
|
||||
{
|
||||
asCThreadLocalData *tld = asCThreadManager::GetLocalData();
|
||||
asASSERT( tld );
|
||||
if( tld == 0 )
|
||||
return 0;
|
||||
tld->activeContexts.PushLast(ctx);
|
||||
return tld;
|
||||
}
|
||||
@ -1304,8 +1319,9 @@ int asCContext::Execute()
|
||||
}
|
||||
|
||||
// Pop the active context
|
||||
asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == this);
|
||||
tld->activeContexts.PopLast();
|
||||
asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength()-1] == this);
|
||||
if( tld )
|
||||
tld->activeContexts.PopLast();
|
||||
|
||||
if( m_status == asEXECUTION_FINISHED )
|
||||
{
|
||||
@ -4301,6 +4317,67 @@ void asCContext::ExecuteNext()
|
||||
}
|
||||
l_bc += 2;
|
||||
break;
|
||||
case asBC_Thiscall1:
|
||||
// This instruction is a faster version of asBC_CALLSYS. It is faster because
|
||||
// it has much less runtime overhead with determining the calling convention
|
||||
// and no dynamic code for loading the parameters. The instruction can only
|
||||
// be used to call functions with the following signatures:
|
||||
//
|
||||
// type &obj::func(int)
|
||||
// type &obj::func(uint)
|
||||
// void obj::func(int)
|
||||
// void obj::func(uint)
|
||||
{
|
||||
// Get function ID from the argument
|
||||
int i = asBC_INTARG(l_bc);
|
||||
|
||||
// Need to move the values back to the context as the called functions
|
||||
// may use the debug interface to inspect the registers
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Pop the thispointer from the stack
|
||||
void *obj = *(void**)l_sp;
|
||||
l_sp += AS_PTR_SIZE;
|
||||
|
||||
// Pop the int arg from the stack
|
||||
int arg = *(int*)l_sp;
|
||||
l_sp++;
|
||||
|
||||
// Call the method
|
||||
m_callingSystemFunction = m_engine->scriptFunctions[i];
|
||||
void *ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction);
|
||||
m_callingSystemFunction = 0;
|
||||
*(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr;
|
||||
|
||||
// Update the program position after the call so that line number is correct
|
||||
l_bc += 2;
|
||||
|
||||
if( m_regs.doProcessSuspend )
|
||||
{
|
||||
// Should the execution be suspended?
|
||||
if( m_doSuspend )
|
||||
{
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
m_status = asEXECUTION_SUSPENDED;
|
||||
return;
|
||||
}
|
||||
// An exception might have been raised
|
||||
if( m_status != asEXECUTION_ACTIVE )
|
||||
{
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Don't let the optimizer optimize for size,
|
||||
// since it requires extra conditions and jumps
|
||||
@ -4887,7 +4964,7 @@ int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
|
||||
|
||||
if( sectionName )
|
||||
{
|
||||
// The section index can be -1 if the exception was raised in a generated function, e.g. factstub for templates
|
||||
// The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates
|
||||
if( m_exceptionSectionIdx >= 0 )
|
||||
*sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf();
|
||||
else
|
||||
|
@ -227,7 +227,7 @@ asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const
|
||||
str += "const";
|
||||
}
|
||||
|
||||
if( isReference )
|
||||
if( isReference )
|
||||
str += "&";
|
||||
|
||||
return str;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -74,11 +74,19 @@ typedef double float64_t;
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(AS_PROFILE)
|
||||
// Currently only do profiling with MSVC++
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <direct.h>
|
||||
#include "as_string.h"
|
||||
#include "as_map.h"
|
||||
#include "as_string_util.h"
|
||||
@ -144,7 +152,7 @@ public:
|
||||
return time;
|
||||
}
|
||||
|
||||
void End(const char *name, double beginTime)
|
||||
void End(const char * /*name*/, double beginTime)
|
||||
{
|
||||
double time = GetTime();
|
||||
|
||||
@ -247,7 +255,7 @@ protected:
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#else // _MSC_VER && AS_PROFILE
|
||||
#else // !(_MSC_VER && AS_PROFILE)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
@ -257,20 +265,6 @@ END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // AS_PSVITA
|
||||
#endif // _WIN32_WCE
|
||||
#endif // AS_WII
|
||||
|
||||
#else // !defined(AS_DEBUG)
|
||||
|
||||
// Define it so nothing is done
|
||||
#define TimeIt(x)
|
||||
|
||||
#endif // !defined(AS_DEBUG)
|
||||
|
||||
#endif
|
||||
#endif // defined(AS_DEBUG_H)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -486,23 +486,18 @@ int asCGarbageCollector::ReportAndReleaseUndestroyedObjects()
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
|
||||
// Add additional info for builtin types
|
||||
if( gcObj.type->name == "_builtin_function_" )
|
||||
if( gcObj.type->name == "$func" )
|
||||
{
|
||||
// Unfortunately we can't show the function declaration here, because the engine may have released the parameter list already so the declaration would only be misleading
|
||||
// We need to show the function type too as for example delegates do not have a name
|
||||
msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetName(), reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetFuncType());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "_builtin_objecttype_" )
|
||||
else if( gcObj.type->name == "$obj" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCObjectType*>(gcObj.obj)->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "_builtin_globalprop_" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCGlobalProperty*>(gcObj.obj)->name.AddressOf());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
|
||||
// Release the reference that the GC holds if the release functions is still available
|
||||
if( gcObj.type->beh.release && engine->scriptFunctions[gcObj.type->beh.release] )
|
||||
|
@ -46,32 +46,6 @@
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// TODO: 2.30.0: redesign: Improved method for discarding modules (faster clean-up, less abuse of garbage collector)
|
||||
//
|
||||
// I need to separate the reference counter for internal references and outside references:
|
||||
//
|
||||
// - Internal references are for example, when the module refers to a function or object since it is declared in the module, or when
|
||||
// a function refers to another function since it is being called in the code.
|
||||
// - Outside references are for example object instances holding a reference to the object type, or a context currently
|
||||
// executing a function.
|
||||
//
|
||||
// If no object instances are alive or no contexts are alive it is known that functions from a discarded module
|
||||
// can be called, so they can be destroyed without any need to execute the complex garbage collection routines.
|
||||
//
|
||||
// If there are live objects, the entire module should be kept for safe keeping, though no longer visible.
|
||||
//
|
||||
// TODO: It may not be necessary to keep track of internal references. Without keeping track of internal references, can I still
|
||||
// handle RemoveFunction and RemoveGlobalVariable correctly?
|
||||
//
|
||||
// TODO: How to avoid global variables keeping code alive? For example a script object, or a funcdef?
|
||||
// Can I do a quick check of the object types and functions to count number of outside references, and then do another
|
||||
// check over the global variables to subtract the outside references coming from these? What if the outside reference
|
||||
// is added by an application type in a global variable that the engine doesn't know about? Example, a global dictionary
|
||||
// holding object instances. Should discarding a module immediately destroy the content of the global variables? What if
|
||||
// a live object tries to access the global variable after it has been discarded? Throwing a script exception is acceptable?
|
||||
// Perhaps I need to allow the user to provide a clean-up routine that will be executed before destroying the objects.
|
||||
// Or I might just put that responsibility on the application.
|
||||
|
||||
|
||||
// internal
|
||||
asCModule::asCModule(const char *name, asCScriptEngine *engine)
|
||||
@ -315,7 +289,7 @@ int asCModule::Build()
|
||||
|
||||
// Don't allow the module to be rebuilt if there are still
|
||||
// external references that will need the previous code
|
||||
// TODO: 2.30.0: interface: The asIScriptModule must have a method for querying if the module is used
|
||||
// TODO: interface: The asIScriptModule must have a method for querying if the module is used
|
||||
if( HasExternalReferences(false) )
|
||||
{
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
|
||||
@ -944,9 +918,6 @@ int asCModule::GetGlobalVarIndexByName(const char *name) const
|
||||
// interface
|
||||
int asCModule::RemoveGlobalVar(asUINT index)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Before removing the variable, clear it to free the object
|
||||
// The property shouldn't be orphaned.
|
||||
|
||||
asCGlobalProperty *prop = scriptGlobals.Get(index);
|
||||
if( !prop )
|
||||
return asINVALID_ARG;
|
||||
@ -1273,6 +1244,33 @@ int asCModule::AddScriptFunction(asCScriptFunction *func)
|
||||
func->AddRefInternal();
|
||||
engine->AddScriptFunction(func);
|
||||
|
||||
// If the function that is being added is an already compiled shared function
|
||||
// then it is necessary to look for anonymous functions that may be declared
|
||||
// within it and add those as well
|
||||
if( func->isShared && func->funcType == asFUNC_SCRIPT )
|
||||
{
|
||||
// Loop through the byte code and check all the
|
||||
// asBC_FuncPtr instructions for anonymous functions
|
||||
asDWORD *bc = func->scriptData->byteCode.AddressOf();
|
||||
asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
|
||||
for( asUINT n = 0; n < bcLength; )
|
||||
{
|
||||
int c = *(asBYTE*)&bc[n];
|
||||
if( c == asBC_FuncPtr )
|
||||
{
|
||||
asCScriptFunction *f = reinterpret_cast<asCScriptFunction*>(asBC_PTRARG(&bc[n]));
|
||||
// Anonymous functions start with $
|
||||
// There are never two equal anonymous functions so it is not necessary to look for duplicates
|
||||
if( f && f->name[0] == '$' )
|
||||
{
|
||||
AddScriptFunction(f);
|
||||
globalFunctions.Put(f);
|
||||
}
|
||||
}
|
||||
n += asBCTypeSize[asBCInfo[c].type];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1700,16 +1698,6 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li
|
||||
// interface
|
||||
int asCModule::RemoveFunction(asIScriptFunction *func)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Check if there are any references before removing the function
|
||||
// if there are, just hide it from the visible but do not destroy or
|
||||
// remove it from the module.
|
||||
//
|
||||
// Only if the function has no live references, nor internal references
|
||||
// can it be immediately removed, and its internal references released.
|
||||
//
|
||||
// Check if any previously hidden functions are without references,
|
||||
// if so they should removed too.
|
||||
|
||||
// Find the global function
|
||||
asCScriptFunction *f = static_cast<asCScriptFunction*>(func);
|
||||
int idx = globalFunctions.GetIndex(f);
|
||||
@ -1734,6 +1722,7 @@ int asCModule::AddFuncDef(const asCString &name, asSNameSpace *ns)
|
||||
|
||||
func->name = name;
|
||||
func->nameSpace = ns;
|
||||
func->module = this;
|
||||
|
||||
funcDefs.PushLast(func);
|
||||
|
||||
|
@ -53,6 +53,7 @@ asCObjectType::asCObjectType()
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
size = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
@ -74,6 +75,7 @@ asCObjectType::asCObjectType(asCScriptEngine *engine)
|
||||
this->engine = engine;
|
||||
module = 0;
|
||||
derivedFrom = 0;
|
||||
typeId = -1; // start as -1 to signal that it hasn't been defined
|
||||
|
||||
acceptValueSubType = true;
|
||||
acceptRefSubType = true;
|
||||
@ -241,7 +243,8 @@ void asCObjectType::DestroyInternal()
|
||||
userData.SetLength(0);
|
||||
|
||||
// Remove the type from the engine
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
if( typeId != -1 )
|
||||
engine->RemoveFromTypeIdMap(this);
|
||||
|
||||
// Clear the engine pointer to mark the object type as invalid
|
||||
engine = 0;
|
||||
@ -252,7 +255,6 @@ asCObjectType::~asCObjectType()
|
||||
if( engine == 0 )
|
||||
return;
|
||||
|
||||
// TODO: 2.30.0: redesign: Shouldn't this have been done already?
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
@ -322,12 +324,18 @@ asUINT asCObjectType::GetSize() const
|
||||
// interface
|
||||
int asCObjectType::GetTypeId() const
|
||||
{
|
||||
// We need a non const pointer to create the asCDataType object.
|
||||
// We're not breaking anything here because this function is not
|
||||
// modifying the object, so this const cast is safe.
|
||||
asCObjectType *ot = const_cast<asCObjectType*>(this);
|
||||
if( typeId == -1 )
|
||||
{
|
||||
// We need a non const pointer to create the asCDataType object.
|
||||
// We're not breaking anything here because this function is not
|
||||
// modifying the object, so this const cast is safe.
|
||||
asCObjectType *ot = const_cast<asCObjectType*>(this);
|
||||
|
||||
return engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false));
|
||||
// The engine will define the typeId for this object type
|
||||
engine->GetTypeIdFromDataType(asCDataType::CreateObject(ot, false));
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
// interface
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -191,6 +191,7 @@ public:
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
int alignment;
|
||||
#endif
|
||||
mutable int typeId;
|
||||
asCArray<asCObjectProperty*> properties;
|
||||
asCArray<int> methods;
|
||||
asCArray<asCObjectType*> interfaces;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -261,6 +261,13 @@ int asCParser::ParsePropertyDeclaration(asCScriptCode *script)
|
||||
scriptNode->AddChildLast(ParseType(true));
|
||||
if( isSyntaxError ) return -1;
|
||||
|
||||
// Allow optional '&' to indicate that the property is indirect, i.e. stored as reference
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
RewindTo(&t);
|
||||
if( t.type == ttAmp )
|
||||
scriptNode->AddChildLast(ParseToken(ttAmp));
|
||||
|
||||
// Allow optional namespace to be defined before the identifier in case
|
||||
// the declaration is to be used for searching for an existing property
|
||||
ParseOptionalScope(scriptNode);
|
||||
@ -269,7 +276,6 @@ int asCParser::ParsePropertyDeclaration(asCScriptCode *script)
|
||||
if( isSyntaxError ) return -1;
|
||||
|
||||
// The declaration should end after the identifier
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
if( t.type != ttEnd )
|
||||
{
|
||||
@ -402,9 +408,11 @@ asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, boo
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
// If the datatype is a template type, then parse the subtype within the < >
|
||||
GetToken(&t);
|
||||
RewindTo(&t);
|
||||
asCScriptNode *type = node->lastChild;
|
||||
tempString.Assign(&script->code[type->tokenPos], type->tokenLength);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type != ttLessThan )
|
||||
@ -602,7 +610,7 @@ asCScriptNode *asCParser::ParseIdentifier()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: PARAMLIST ::= '(' ('void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]}) ')'
|
||||
// BNF: PARAMLIST ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')'
|
||||
asCScriptNode *asCParser::ParseParameterList()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snParameterList);
|
||||
@ -1104,10 +1112,13 @@ bool asCParser::CheckTemplateType(sToken &t)
|
||||
tempString.Assign(&script->code[t.pos], t.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
{
|
||||
// Expect the sub type within < >
|
||||
// If the next token is a < then parse the sub-type too
|
||||
GetToken(&t);
|
||||
if( t.type != ttLessThan )
|
||||
return false;
|
||||
{
|
||||
RewindTo(&t);
|
||||
return true;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -1232,7 +1243,7 @@ asCScriptNode *asCParser::ParseCast()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')'
|
||||
// BNF: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA
|
||||
asCScriptNode *asCParser::ParseExprValue()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snExprValue);
|
||||
@ -1250,44 +1261,54 @@ asCScriptNode *asCParser::ParseExprValue()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( t1.type == ttIdentifier || t1.type == ttScope )
|
||||
{
|
||||
// Determine the last identifier in order to check if it is a type
|
||||
sToken t;
|
||||
if( t1.type == ttScope ) t = t2; else t = t1;
|
||||
RewindTo(&t);
|
||||
GetToken(&t2);
|
||||
while( t.type == ttIdentifier )
|
||||
// Check if the expression is an anonymous function
|
||||
if( IsLambda() )
|
||||
{
|
||||
t2 = t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttScope )
|
||||
GetToken(&t);
|
||||
else
|
||||
break;
|
||||
node->AddChildLast(ParseLambda());
|
||||
}
|
||||
|
||||
bool isDataType = IsDataType(t2);
|
||||
bool isTemplateType = false;
|
||||
if( isDataType )
|
||||
{
|
||||
// Is this a template type?
|
||||
tempString.Assign(&script->code[t2.pos], t2.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
isTemplateType = true;
|
||||
}
|
||||
|
||||
// Rewind so the real parsing can be done, after deciding what to parse
|
||||
RewindTo(&t1);
|
||||
|
||||
// Check if this is a construct call
|
||||
if( isDataType && (t.type == ttOpenParanthesis || // type()
|
||||
t.type == ttOpenBracket) ) // type[]()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( isTemplateType && t.type == ttLessThan ) // type<t>()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( IsFunctionCall() )
|
||||
node->AddChildLast(ParseFunctionCall());
|
||||
else
|
||||
node->AddChildLast(ParseVariableAccess());
|
||||
{
|
||||
// Determine the last identifier in order to check if it is a type
|
||||
sToken t;
|
||||
if( t1.type == ttScope ) t = t2; else t = t1;
|
||||
RewindTo(&t);
|
||||
GetToken(&t2);
|
||||
while( t.type == ttIdentifier )
|
||||
{
|
||||
t2 = t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttScope )
|
||||
GetToken(&t);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
bool isDataType = IsDataType(t2);
|
||||
bool isTemplateType = false;
|
||||
if( isDataType )
|
||||
{
|
||||
// Is this a template type?
|
||||
tempString.Assign(&script->code[t2.pos], t2.length);
|
||||
if( engine->IsTemplateType(tempString.AddressOf()) )
|
||||
isTemplateType = true;
|
||||
}
|
||||
|
||||
GetToken(&t2);
|
||||
|
||||
// Rewind so the real parsing can be done, after deciding what to parse
|
||||
RewindTo(&t1);
|
||||
|
||||
// Check if this is a construct call
|
||||
if( isDataType && (t.type == ttOpenParanthesis || // type()
|
||||
(t.type == ttOpenBracket && t2.type == ttCloseBracket)) ) // type[]()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( isTemplateType && t.type == ttLessThan ) // type<t>()
|
||||
node->AddChildLast(ParseConstructCall());
|
||||
else if( IsFunctionCall() )
|
||||
node->AddChildLast(ParseFunctionCall());
|
||||
else
|
||||
node->AddChildLast(ParseVariableAccess());
|
||||
}
|
||||
}
|
||||
else if( t1.type == ttCast )
|
||||
node->AddChildLast(ParseCast());
|
||||
@ -1355,6 +1376,83 @@ asCScriptNode *asCParser::ParseConstant()
|
||||
return node;
|
||||
}
|
||||
|
||||
bool asCParser::IsLambda()
|
||||
{
|
||||
bool isLambda = false;
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) )
|
||||
{
|
||||
sToken t2;
|
||||
GetToken(&t2);
|
||||
if( t2.type == ttOpenParanthesis )
|
||||
{
|
||||
// Skip until )
|
||||
while( t2.type != ttCloseParanthesis && t2.type != ttEnd )
|
||||
GetToken(&t2);
|
||||
|
||||
// The next token must be a {
|
||||
GetToken(&t2);
|
||||
if( t2.type == ttStartStatementBlock )
|
||||
isLambda = true;
|
||||
}
|
||||
}
|
||||
|
||||
RewindTo(&t);
|
||||
return isLambda;
|
||||
}
|
||||
|
||||
// BNF: LAMBDA ::= 'function' '(' [IDENTIFIER {',' IDENTIFIER}] ')' STATBLOCK
|
||||
asCScriptNode *asCParser::ParseLambda()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snFunction);
|
||||
if( node == 0 ) return 0;
|
||||
|
||||
sToken t;
|
||||
GetToken(&t);
|
||||
|
||||
if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) )
|
||||
{
|
||||
Error(ExpectedToken("function"), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type != ttOpenParanthesis )
|
||||
{
|
||||
Error(ExpectedToken("("), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type == ttIdentifier )
|
||||
{
|
||||
RewindTo(&t);
|
||||
node->AddChildLast(ParseIdentifier());
|
||||
|
||||
GetToken(&t);
|
||||
while( t.type == ttListSeparator )
|
||||
{
|
||||
node->AddChildLast(ParseIdentifier());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
}
|
||||
}
|
||||
|
||||
if( t.type != ttCloseParanthesis )
|
||||
{
|
||||
Error(ExpectedToken(")"), &t);
|
||||
return node;
|
||||
}
|
||||
|
||||
// We should just find the end of the statement block here. The statements
|
||||
// will be parsed on request by the compiler once it starts the compilation.
|
||||
node->AddChildLast(SuperficiallyParseStatementBlock());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
asCScriptNode *asCParser::ParseStringConstant()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snConstant);
|
||||
@ -1618,7 +1716,7 @@ asCScriptNode *asCParser::ParseCondition()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: EXPR ::= (TYPE '=' INILIST) | (EXPRTERM {EXPROP EXPRTERM})
|
||||
// BNF: EXPR ::= (TYPE '=' INITLIST) | (EXPRTERM {EXPROP EXPRTERM})
|
||||
asCScriptNode *asCParser::ParseExpression()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snExpression);
|
||||
@ -2459,7 +2557,22 @@ bool asCParser::IsVirtualPropertyDecl()
|
||||
// as it may wrongly identify the statement as a non-declaration if the user typed
|
||||
// the name incorrectly. The real type is validated in ParseDeclaration where a
|
||||
// proper error message can be given.
|
||||
if( !IsRealType(t1.type) && t1.type != ttIdentifier )
|
||||
if( t1.type == ttScope )
|
||||
GetToken(&t1);
|
||||
|
||||
if( t1.type == ttIdentifier )
|
||||
{
|
||||
sToken t2;
|
||||
GetToken(&t2);
|
||||
while( t1.type == ttIdentifier && t2.type == ttScope )
|
||||
{
|
||||
GetToken(&t1);
|
||||
GetToken(&t2);
|
||||
}
|
||||
|
||||
RewindTo(&t2);
|
||||
}
|
||||
else if( !IsRealType(t1.type) )
|
||||
{
|
||||
RewindTo(&t);
|
||||
return false;
|
||||
@ -3201,61 +3314,37 @@ asCScriptNode *asCParser::SuperficiallyParseVarInit()
|
||||
if( t.type == ttAssignment )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type == ttStartStatementBlock )
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the expression
|
||||
int indentParan = 0;
|
||||
int indentBrace = 0;
|
||||
while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
|
||||
{
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the initialization list
|
||||
int indent = 1;
|
||||
while( indent )
|
||||
if( t.type == ttOpenParanthesis )
|
||||
indentParan++;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
indentParan--;
|
||||
else if( t.type == ttStartStatementBlock )
|
||||
indentBrace++;
|
||||
else if( t.type == ttEndStatementBlock )
|
||||
indentBrace--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
GetToken(&t);
|
||||
if( t.type == ttStartStatementBlock )
|
||||
indent++;
|
||||
else if( t.type == ttEndStatementBlock )
|
||||
indent--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_INIT_LIST, &start);
|
||||
break;
|
||||
}
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sToken start = t;
|
||||
|
||||
// Find the end of the expression
|
||||
int indent = 0;
|
||||
while( indent || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
if( t.type == ttOpenParanthesis )
|
||||
indent++;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
indent--;
|
||||
else if( t.type == ttNonTerminatedStringConstant )
|
||||
{
|
||||
Error(TXT_NONTERMINATED_STRING, &t);
|
||||
break;
|
||||
}
|
||||
else if( t.type == ttEnd )
|
||||
{
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_EXPRESSION, &start);
|
||||
break;
|
||||
}
|
||||
GetToken(&t);
|
||||
Error(TXT_UNEXPECTED_END_OF_FILE, &t);
|
||||
Info(TXT_WHILE_PARSING_EXPRESSION, &start);
|
||||
break;
|
||||
}
|
||||
|
||||
// Rewind so that the next token read is the list separator, end statement, or end statement block
|
||||
RewindTo(&t);
|
||||
GetToken(&t);
|
||||
}
|
||||
|
||||
// Rewind so that the next token read is the list separator, end statement, or end statement block
|
||||
RewindTo(&t);
|
||||
}
|
||||
else if( t.type == ttOpenParanthesis )
|
||||
{
|
||||
@ -3872,7 +3961,7 @@ asCScriptNode *asCParser::ParseIf()
|
||||
return node;
|
||||
}
|
||||
|
||||
// BNF: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN] ')' STATEMENT
|
||||
// BNF: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT
|
||||
asCScriptNode *asCParser::ParseFor()
|
||||
{
|
||||
asCScriptNode *node = CreateNode(snFor);
|
||||
@ -3911,18 +4000,27 @@ asCScriptNode *asCParser::ParseFor()
|
||||
{
|
||||
RewindTo(&t);
|
||||
|
||||
asCScriptNode *n = CreateNode(snExpressionStatement);
|
||||
if( n == 0 ) return 0;
|
||||
node->AddChildLast(n);
|
||||
n->AddChildLast(ParseAssignment());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type != ttCloseParanthesis )
|
||||
// Parse N increment statements separated by ,
|
||||
for(;;)
|
||||
{
|
||||
Error(ExpectedToken(")"), &t);
|
||||
Error(InsteadFound(t), &t);
|
||||
return node;
|
||||
asCScriptNode *n = CreateNode(snExpressionStatement);
|
||||
if( n == 0 ) return 0;
|
||||
node->AddChildLast(n);
|
||||
n->AddChildLast(ParseAssignment());
|
||||
if( isSyntaxError ) return node;
|
||||
|
||||
GetToken(&t);
|
||||
if( t.type == ttListSeparator )
|
||||
continue;
|
||||
else if( t.type == ttCloseParanthesis )
|
||||
break;
|
||||
else
|
||||
{
|
||||
const char *tokens[] = {",", ")"};
|
||||
Error(ExpectedOneOf(tokens, 2), &t);
|
||||
Error(InsteadFound(t), &t);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -133,6 +133,8 @@ protected:
|
||||
bool IsVarDecl();
|
||||
bool IsVirtualPropertyDecl();
|
||||
bool IsFuncDecl(bool isMethod);
|
||||
bool IsLambda();
|
||||
bool IsFunctionCall();
|
||||
|
||||
// Expressions
|
||||
asCScriptNode *ParseAssignment();
|
||||
@ -151,13 +153,13 @@ protected:
|
||||
asCScriptNode *ParseCast();
|
||||
asCScriptNode *ParseConstant();
|
||||
asCScriptNode *ParseStringConstant();
|
||||
asCScriptNode *ParseLambda();
|
||||
|
||||
bool IsConstant(int tokenType);
|
||||
bool IsOperator(int tokenType);
|
||||
bool IsPreOperator(int tokenType);
|
||||
bool IsPostOperator(int tokenType);
|
||||
bool IsAssignOperator(int tokenType);
|
||||
bool IsFunctionCall();
|
||||
|
||||
bool CheckTemplateType(sToken &t);
|
||||
#endif
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "as_bytecode.h"
|
||||
#include "as_scriptobject.h"
|
||||
#include "as_texts.h"
|
||||
#include "as_debug.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
@ -65,6 +66,8 @@ void asCReader::ReadData(void *data, asUINT size)
|
||||
|
||||
int asCReader::Read(bool *wasDebugInfoStripped)
|
||||
{
|
||||
TimeIt("asCReader::Read");
|
||||
|
||||
// Before starting the load, make sure that
|
||||
// any existing resources have been freed
|
||||
module->InternalReset();
|
||||
@ -124,6 +127,8 @@ int asCReader::Error(const char *msg)
|
||||
|
||||
int asCReader::ReadInner()
|
||||
{
|
||||
TimeIt("asCReader::ReadInner");
|
||||
|
||||
// This function will load each entity one by one from the stream.
|
||||
// If any error occurs, it will return to the caller who is
|
||||
// responsible for cleaning up the partially loaded entities.
|
||||
@ -258,31 +263,38 @@ int asCReader::ReadInner()
|
||||
asCScriptFunction *func = ReadFunction(isNew, false, true);
|
||||
if( func )
|
||||
{
|
||||
func->module = module;
|
||||
module->funcDefs.PushLast(func);
|
||||
engine->funcDefs.PushLast(func);
|
||||
|
||||
// TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module
|
||||
// Check if there is another identical funcdef from another module and if so reuse that instead
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
if( func->isShared )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
if( !f2->isShared )
|
||||
continue;
|
||||
|
||||
savedFunctions[savedFunctions.IndexOf(func)] = f2;
|
||||
if( f2->name == func->name &&
|
||||
f2->nameSpace == func->nameSpace &&
|
||||
f2->IsSignatureExceptNameEqual(func) )
|
||||
{
|
||||
// Replace our funcdef for the existing one
|
||||
module->funcDefs[module->funcDefs.IndexOf(func)] = f2;
|
||||
f2->AddRefInternal();
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
savedFunctions[savedFunctions.IndexOf(func)] = f2;
|
||||
|
||||
func->ReleaseInternal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -549,6 +561,8 @@ int asCReader::ReadInner()
|
||||
|
||||
void asCReader::ReadUsedStringConstants()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedStringConstants");
|
||||
|
||||
asCString str;
|
||||
|
||||
asUINT count;
|
||||
@ -563,6 +577,8 @@ void asCReader::ReadUsedStringConstants()
|
||||
|
||||
void asCReader::ReadUsedFunctions()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedFunctions");
|
||||
|
||||
asUINT count;
|
||||
count = ReadEncodedUInt();
|
||||
usedFunctions.SetLength(count);
|
||||
@ -606,25 +622,44 @@ void asCReader::ReadUsedFunctions()
|
||||
for( asUINT i = 0; i < module->bindInformations.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = module->bindInformations[i]->importedFunctionSignature;
|
||||
if( !func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
if( func.objectType != f->objectType ||
|
||||
func.funcType != f->funcType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
const asCArray<asCScriptFunction *> &funcs = module->funcDefs;
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = funcs[i];
|
||||
if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
// Funcdefs are always global so there is no need to compare object type
|
||||
asASSERT( f->objectType == 0 );
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: optimize: Global functions should be searched for in module->globalFunctions
|
||||
// TODO: optimize: funcdefs should be searched for in module->funcDefs
|
||||
// TODO: optimize: object methods should be searched for directly in the object type
|
||||
for( asUINT i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = module->scriptFunctions[i];
|
||||
if( !func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
if( func.objectType != f->objectType ||
|
||||
func.funcType != f->funcType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
@ -634,17 +669,157 @@ void asCReader::ReadUsedFunctions()
|
||||
}
|
||||
else
|
||||
{
|
||||
for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
|
||||
if( func.funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[i];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureEqual(f) ||
|
||||
func.objectType != f->objectType ||
|
||||
func.nameSpace != f->nameSpace )
|
||||
continue;
|
||||
// This is a funcdef (registered or shared)
|
||||
const asCArray<asCScriptFunction *> &funcs = engine->funcDefs;
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = funcs[i];
|
||||
if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
// Funcdefs are always global so there is no need to compare object type
|
||||
asASSERT( f->objectType == 0 );
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.name[0] == '$' )
|
||||
{
|
||||
// This is a special function
|
||||
|
||||
// Check for string factory
|
||||
if( func.name == "$str" && engine->stringFactory &&
|
||||
func.IsSignatureExceptNameAndObjectTypeEqual(engine->stringFactory) )
|
||||
usedFunctions[n] = engine->stringFactory;
|
||||
else if( func.name == "$beh0" && func.objectType )
|
||||
{
|
||||
// This is a class constructor, so we can search directly in the object type's constructors
|
||||
for( asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$fact" || func.name == "$beh3" )
|
||||
{
|
||||
// This is a factory (or stub), so look for the function in the return type's factories
|
||||
asCObjectType *objType = func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( func.name == "$list" )
|
||||
{
|
||||
// listFactory is used for both factory is global and returns a handle and constructor that is a method
|
||||
asCObjectType *objType = func.objectType ? func.objectType : func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$beh2" )
|
||||
{
|
||||
// This is a destructor, so check the object type's destructor
|
||||
asCObjectType *objType = func.objectType;
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$beh4" )
|
||||
{
|
||||
// This is a list factory, so check the return type's list factory
|
||||
asCObjectType *objType = func.returnType.GetObjectType();
|
||||
if( objType )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory];
|
||||
if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.name == "$dlgte" )
|
||||
{
|
||||
// This is the delegate factory
|
||||
asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY);
|
||||
asASSERT( f && func.IsSignatureEqual(f) );
|
||||
usedFunctions[n] = f;
|
||||
}
|
||||
}
|
||||
else if( func.objectType == 0 )
|
||||
{
|
||||
// This is a global function
|
||||
const asCArray<asUINT> &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name);
|
||||
for( asUINT i = 0; i < funcs.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]);
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureExceptNameAndObjectTypeEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( func.objectType )
|
||||
{
|
||||
// It is a class member, so we can search directly in the object type's members
|
||||
// TODO: virtual function is different that implemented method
|
||||
for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]];
|
||||
if( f == 0 ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( usedFunctions[n] == 0 )
|
||||
{
|
||||
// TODO: clean up: This part of the code should never happen. All functions should
|
||||
// be found in the above logic. The only valid reason to come here
|
||||
// is if the bytecode is wrong and the function doesn't exist anyway.
|
||||
// This loop is kept temporarily until we can be certain all scenarios
|
||||
// are covered.
|
||||
for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ )
|
||||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[i];
|
||||
if( f == 0 ||
|
||||
func.objectType != f->objectType ||
|
||||
func.nameSpace != f->nameSpace ||
|
||||
!func.IsSignatureEqual(f) )
|
||||
continue;
|
||||
|
||||
usedFunctions[n] = f;
|
||||
break;
|
||||
}
|
||||
|
||||
// No function is expected to be found
|
||||
asASSERT(usedFunctions[n] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,6 +1148,13 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
|
||||
{
|
||||
func->vfTableIdx = ReadEncodedUInt();
|
||||
}
|
||||
else if( func->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
asBYTE bits;
|
||||
ReadData(&bits, 1);
|
||||
if( bits )
|
||||
func->isShared = true;
|
||||
}
|
||||
|
||||
if( addToModule )
|
||||
{
|
||||
@ -1520,28 +1702,25 @@ asQWORD asCReader::ReadEncodedUInt64()
|
||||
|
||||
void asCReader::ReadString(asCString* str)
|
||||
{
|
||||
char b;
|
||||
ReadData(&b, 1);
|
||||
if( b == '\0' )
|
||||
asUINT len = ReadEncodedUInt();
|
||||
if( len & 1 )
|
||||
{
|
||||
str->SetLength(0);
|
||||
asUINT idx = len/2;
|
||||
if( idx < savedStrings.GetLength() )
|
||||
*str = savedStrings[idx];
|
||||
else
|
||||
Error(TXT_INVALID_BYTECODE_d);
|
||||
}
|
||||
else if( b == 'n' )
|
||||
else if( len > 0 )
|
||||
{
|
||||
asUINT len = ReadEncodedUInt();
|
||||
len /= 2;
|
||||
str->SetLength(len);
|
||||
stream->Read(str->AddressOf(), len);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
}
|
||||
else
|
||||
{
|
||||
asUINT n = ReadEncodedUInt();
|
||||
if( n < savedStrings.GetLength() )
|
||||
*str = savedStrings[n];
|
||||
else
|
||||
Error(TXT_INVALID_BYTECODE_d);
|
||||
}
|
||||
str->SetLength(0);
|
||||
}
|
||||
|
||||
void asCReader::ReadGlobalProperty()
|
||||
@ -1625,7 +1804,7 @@ void asCReader::ReadDataType(asCDataType *dt)
|
||||
ReadData(&bits, 1);
|
||||
|
||||
asCScriptFunction *funcDef = 0;
|
||||
if( tokenType == ttIdentifier && objType && objType->name == "_builtin_function_" )
|
||||
if( tokenType == ttIdentifier && objType && objType->name == "$func" )
|
||||
{
|
||||
asCScriptFunction func(engine, module, asFUNC_DUMMY);
|
||||
ReadFunctionSignature(&func);
|
||||
@ -1790,7 +1969,7 @@ asCObjectType* asCReader::ReadObjectType()
|
||||
ReadString(&ns);
|
||||
asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf());
|
||||
|
||||
if( typeName.GetLength() && typeName != "_builtin_object_" && typeName != "_builtin_function_" )
|
||||
if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" )
|
||||
{
|
||||
// Find the object type
|
||||
ot = module->GetObjectType(typeName.AddressOf(), nameSpace);
|
||||
@ -1806,11 +1985,11 @@ asCObjectType* asCReader::ReadObjectType()
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if( typeName == "_builtin_object_" )
|
||||
else if( typeName == "$obj" )
|
||||
{
|
||||
ot = &engine->scriptTypeBehaviours;
|
||||
}
|
||||
else if( typeName == "_builtin_function_" )
|
||||
else if( typeName == "$func" )
|
||||
{
|
||||
ot = &engine->functionBehaviours;
|
||||
}
|
||||
@ -2073,6 +2252,8 @@ void asCReader::ReadByteCode(asCScriptFunction *func)
|
||||
|
||||
void asCReader::ReadUsedTypeIds()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedTypeIds");
|
||||
|
||||
asUINT count = ReadEncodedUInt();
|
||||
usedTypeIds.Allocate(count, false);
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
@ -2085,6 +2266,8 @@ void asCReader::ReadUsedTypeIds()
|
||||
|
||||
void asCReader::ReadUsedGlobalProps()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedGlobalProps");
|
||||
|
||||
int c = ReadEncodedUInt();
|
||||
|
||||
usedGlobalProperties.Allocate(c, false);
|
||||
@ -2124,6 +2307,8 @@ void asCReader::ReadUsedGlobalProps()
|
||||
|
||||
void asCReader::ReadUsedObjectProps()
|
||||
{
|
||||
TimeIt("asCReader::ReadUsedObjectProps");
|
||||
|
||||
asUINT c = ReadEncodedUInt();
|
||||
|
||||
usedObjectProperties.SetLength(c);
|
||||
@ -2293,7 +2478,8 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
|
||||
}
|
||||
else if( c == asBC_CALL ||
|
||||
c == asBC_CALLINTF ||
|
||||
c == asBC_CALLSYS )
|
||||
c == asBC_CALLSYS ||
|
||||
c == asBC_Thiscall1 )
|
||||
{
|
||||
// Translate the index to the func id
|
||||
int *fid = (int*)&bc[n+1];
|
||||
@ -2800,7 +2986,8 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
|
||||
{
|
||||
// Determine the true delta from the instruction arguments
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLBND ||
|
||||
bc == asBC_ALLOC ||
|
||||
bc == asBC_CALLINTF ||
|
||||
@ -3030,6 +3217,7 @@ asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD
|
||||
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF )
|
||||
{
|
||||
// Find the function from the function id in bytecode
|
||||
@ -3085,11 +3273,13 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
|
||||
// Find out which function that will be called
|
||||
asCScriptFunction *calledFunc = 0;
|
||||
int stackDelta = 0;
|
||||
for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); )
|
||||
{
|
||||
asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF ||
|
||||
bc == asBC_ALLOC ||
|
||||
bc == asBC_CALLBND ||
|
||||
@ -3106,6 +3296,10 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
return offset - (1 - AS_PTR_SIZE);
|
||||
}
|
||||
|
||||
// Keep track of the stack size between the
|
||||
// instruction that needs to be adjusted and the call
|
||||
stackDelta += asBCInfo[bc].stackInc;
|
||||
|
||||
n += asBCTypeSize[asBCInfo[bc].type];
|
||||
}
|
||||
|
||||
@ -3118,16 +3312,30 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
// Count the number of pointers pushed on the stack above the
|
||||
// current offset, and then adjust the offset accordingly
|
||||
asUINT numPtrs = 0;
|
||||
int currOffset = 0;
|
||||
int currOffset = -stackDelta;
|
||||
if( offset > currOffset && calledFunc->GetObjectType() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
}
|
||||
if( offset > currOffset && calledFunc->DoesReturnOnStack() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
}
|
||||
for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
@ -3136,8 +3344,15 @@ int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
if( !calledFunc->parameterTypes[p].IsPrimitive() ||
|
||||
calledFunc->parameterTypes[p].IsReference() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset++;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
#if AS_PTR_SIZE == 2
|
||||
// For 64bit platforms it is necessary to increment the currOffset by one more
|
||||
// DWORD since the stackDelta was counting the full 64bit size of the pointer
|
||||
else if( stackDelta )
|
||||
currOffset++;
|
||||
#endif
|
||||
|
||||
// The variable arg ? has an additiona 32bit integer with the typeid
|
||||
if( calledFunc->parameterTypes[p].IsAnyType() )
|
||||
@ -3197,6 +3412,8 @@ void asCWriter::WriteData(const void *data, asUINT size)
|
||||
|
||||
int asCWriter::Write()
|
||||
{
|
||||
TimeIt("asCWriter::Write");
|
||||
|
||||
unsigned long i, count;
|
||||
|
||||
// Store everything in the same order that the builder parses scripts
|
||||
@ -3207,101 +3424,149 @@ int asCWriter::Write()
|
||||
WriteData(&stripDebugInfo, sizeof(stripDebugInfo));
|
||||
|
||||
// Store enums
|
||||
count = (asUINT)module->enumTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 1);
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 2);
|
||||
TimeIt("store enums");
|
||||
|
||||
count = (asUINT)module->enumTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 1);
|
||||
WriteObjectTypeDeclaration(module->enumTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Store type declarations first
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
// Store only the name of the class/interface types
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 1);
|
||||
TimeIt("type declarations");
|
||||
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
// Store only the name of the class/interface types
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Store func defs
|
||||
count = (asUINT)module->funcDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
WriteFunction(module->funcDefs[i]);
|
||||
{
|
||||
TimeIt("func defs");
|
||||
|
||||
count = (asUINT)module->funcDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
WriteFunction(module->funcDefs[i]);
|
||||
}
|
||||
|
||||
// Now store all interface methods
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
if( module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
TimeIt("interface methods");
|
||||
|
||||
count = (asUINT)module->classTypes.GetLength();
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
if( module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Then store the class methods and behaviours
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
TimeIt("class methods and behaviours");
|
||||
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Then store the class properties
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 3);
|
||||
TimeIt("class properties");
|
||||
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
if( !module->classTypes[i]->IsInterface() )
|
||||
WriteObjectTypeDeclaration(module->classTypes[i], 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Store typedefs
|
||||
count = (asUINT)module->typeDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 1);
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 2);
|
||||
TimeIt("type defs");
|
||||
|
||||
count = (asUINT)module->typeDefs.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 1);
|
||||
WriteObjectTypeDeclaration(module->typeDefs[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
// scriptGlobals[]
|
||||
count = (asUINT)module->scriptGlobals.GetSize();
|
||||
WriteEncodedInt64(count);
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
WriteGlobalProperty(*it);
|
||||
{
|
||||
TimeIt("script globals");
|
||||
|
||||
count = (asUINT)module->scriptGlobals.GetSize();
|
||||
WriteEncodedInt64(count);
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
WriteGlobalProperty(*it);
|
||||
}
|
||||
|
||||
// scriptFunctions[]
|
||||
count = 0;
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
count++;
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
WriteFunction(module->scriptFunctions[i]);
|
||||
{
|
||||
TimeIt("scriptFunctions");
|
||||
|
||||
count = 0;
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); i++ )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
count++;
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < module->scriptFunctions.GetLength(); ++i )
|
||||
if( module->scriptFunctions[i]->objectType == 0 )
|
||||
WriteFunction(module->scriptFunctions[i]);
|
||||
}
|
||||
|
||||
// globalFunctions[]
|
||||
count = (int)module->globalFunctions.GetSize();
|
||||
asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
|
||||
WriteEncodedInt64(count);
|
||||
while( funcIt )
|
||||
{
|
||||
WriteFunction(*funcIt);
|
||||
funcIt++;
|
||||
TimeIt("globalFunctions");
|
||||
|
||||
count = (int)module->globalFunctions.GetSize();
|
||||
asCSymbolTable<asCScriptFunction>::iterator funcIt = module->globalFunctions.List();
|
||||
WriteEncodedInt64(count);
|
||||
while( funcIt )
|
||||
{
|
||||
WriteFunction(*funcIt);
|
||||
funcIt++;
|
||||
}
|
||||
}
|
||||
|
||||
// bindInformations[]
|
||||
count = (asUINT)module->bindInformations.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
WriteFunction(module->bindInformations[i]->importedFunctionSignature);
|
||||
WriteString(&module->bindInformations[i]->importFromModule);
|
||||
TimeIt("bindInformations");
|
||||
|
||||
count = (asUINT)module->bindInformations.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
WriteFunction(module->bindInformations[i]->importedFunctionSignature);
|
||||
WriteString(&module->bindInformations[i]->importFromModule);
|
||||
}
|
||||
}
|
||||
|
||||
// usedTypes[]
|
||||
count = (asUINT)usedTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
WriteObjectType(usedTypes[i]);
|
||||
{
|
||||
TimeIt("usedTypes");
|
||||
|
||||
count = (asUINT)usedTypes.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( i = 0; i < count; ++i )
|
||||
WriteObjectType(usedTypes[i]);
|
||||
}
|
||||
|
||||
// usedTypeIds[]
|
||||
WriteUsedTypeIds();
|
||||
@ -3335,6 +3600,8 @@ int asCWriter::FindStringConstantIndex(int id)
|
||||
|
||||
void asCWriter::WriteUsedStringConstants()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedStringConstants");
|
||||
|
||||
asUINT count = (asUINT)usedStringConstants.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( asUINT i = 0; i < count; ++i )
|
||||
@ -3343,6 +3610,8 @@ void asCWriter::WriteUsedStringConstants()
|
||||
|
||||
void asCWriter::WriteUsedFunctions()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedFunctions");
|
||||
|
||||
asUINT count = (asUINT)usedFunctions.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
|
||||
@ -3572,6 +3841,12 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
|
||||
// TODO: Do we really need to store this? It can probably be reconstructed by the reader
|
||||
WriteEncodedInt64(func->vfTableIdx);
|
||||
}
|
||||
else if( func->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
char bits = 0;
|
||||
bits += func->isShared ? 1 : 0;
|
||||
WriteData(&bits,1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteObjectTypeDeclaration(asCObjectType *ot, int phase)
|
||||
@ -3755,39 +4030,28 @@ void asCWriter::WriteEncodedInt64(asINT64 i)
|
||||
|
||||
void asCWriter::WriteString(asCString* str)
|
||||
{
|
||||
// TODO: All strings should be stored in a separate section, and when
|
||||
// they are used an offset into that section should be stored.
|
||||
// This will make it unnecessary to store the extra byte to
|
||||
// identify new versus old strings.
|
||||
|
||||
if( str->GetLength() == 0 )
|
||||
{
|
||||
char z = '\0';
|
||||
WriteData(&z, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check if the string hasn't been saved already
|
||||
asSMapNode<asCStringPointer, int> *cursor = 0;
|
||||
if (stringToIdMap.MoveTo(&cursor, asCStringPointer(str)))
|
||||
{
|
||||
// Save a reference to the existing string
|
||||
char b = 'r';
|
||||
WriteData(&b, 1);
|
||||
WriteEncodedInt64(cursor->value);
|
||||
// The lowest bit is set to 1 to indicate a reference
|
||||
WriteEncodedInt64(cursor->value*2+1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save a new string
|
||||
char b = 'n';
|
||||
WriteData(&b, 1);
|
||||
|
||||
// The lowest bit is set to 0 to indicate a new string
|
||||
asUINT len = (asUINT)str->GetLength();
|
||||
WriteEncodedInt64(len);
|
||||
stream->Write(str->AddressOf(), (asUINT)len);
|
||||
WriteEncodedInt64(len*2);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1);
|
||||
if( len > 0 )
|
||||
{
|
||||
stream->Write(str->AddressOf(), (asUINT)len);
|
||||
|
||||
savedStrings.PushLast(*str);
|
||||
stringToIdMap.Insert(asCStringPointer(str), int(savedStrings.GetLength()) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop)
|
||||
@ -3851,7 +4115,7 @@ void asCWriter::WriteDataType(const asCDataType *dt)
|
||||
bits.isReadOnly = dt->IsReadOnly();
|
||||
WriteData(&bits, 1);
|
||||
|
||||
if( t == ttIdentifier && dt->GetObjectType()->name == "_builtin_function_" )
|
||||
if( t == ttIdentifier && dt->GetObjectType()->name == "$func" )
|
||||
{
|
||||
WriteFunctionSignature(dt->GetFuncDef());
|
||||
}
|
||||
@ -3883,17 +4147,17 @@ void asCWriter::WriteObjectType(asCObjectType* ot)
|
||||
WriteEncodedInt64(ot->templateSubTypes.GetLength());
|
||||
for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ )
|
||||
{
|
||||
if( ot->templateSubTypes[0].IsObject() || ot->templateSubTypes[0].IsEnumType() )
|
||||
if( ot->templateSubTypes[n].IsObject() || ot->templateSubTypes[n].IsEnumType() )
|
||||
{
|
||||
ch = 's';
|
||||
WriteData(&ch, 1);
|
||||
WriteDataType(&ot->templateSubTypes[0]);
|
||||
WriteDataType(&ot->templateSubTypes[n]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = 't';
|
||||
WriteData(&ch, 1);
|
||||
eTokenType t = ot->templateSubTypes[0].GetTokenType();
|
||||
eTokenType t = ot->templateSubTypes[n].GetTokenType();
|
||||
WriteEncodedInt64(t);
|
||||
}
|
||||
}
|
||||
@ -4053,11 +4317,13 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
|
||||
// Find out which function that will be called
|
||||
asCScriptFunction *calledFunc = 0;
|
||||
int stackDelta = 0;
|
||||
for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); )
|
||||
{
|
||||
asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n];
|
||||
if( bc == asBC_CALL ||
|
||||
bc == asBC_CALLSYS ||
|
||||
bc == asBC_Thiscall1 ||
|
||||
bc == asBC_CALLINTF )
|
||||
{
|
||||
// Find the function from the function id in bytecode
|
||||
@ -4120,6 +4386,10 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
return offset + (1 - AS_PTR_SIZE);
|
||||
}
|
||||
|
||||
// Keep track of the stack size between the
|
||||
// instruction that needs to be adjusted and the call
|
||||
stackDelta += asBCInfo[bc].stackInc;
|
||||
|
||||
n += asBCTypeSize[asBCInfo[bc].type];
|
||||
}
|
||||
|
||||
@ -4128,16 +4398,18 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
// Count the number of pointers pushed on the stack above the
|
||||
// current offset, and then adjust the offset accordingly
|
||||
asUINT numPtrs = 0;
|
||||
int currOffset = 0;
|
||||
int currOffset = -stackDelta;
|
||||
if( offset > currOffset && calledFunc->GetObjectType() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
}
|
||||
if( offset > currOffset && calledFunc->DoesReturnOnStack() )
|
||||
{
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
}
|
||||
for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
@ -4147,8 +4419,9 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
||||
calledFunc->parameterTypes[p].IsReference() )
|
||||
{
|
||||
// objects and references are passed by pointer
|
||||
numPtrs++;
|
||||
currOffset += AS_PTR_SIZE;
|
||||
if( currOffset > 0 )
|
||||
numPtrs++;
|
||||
|
||||
// The variable arg ? has an additional 32bit int with the typeid
|
||||
if( calledFunc->parameterTypes[p].IsAnyType() )
|
||||
@ -4262,7 +4535,8 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
|
||||
}
|
||||
else if( c == asBC_CALL || // DW_ARG
|
||||
c == asBC_CALLINTF || // DW_ARG
|
||||
c == asBC_CALLSYS ) // DW_ARG
|
||||
c == asBC_CALLSYS || // DW_ARG
|
||||
c == asBC_Thiscall1 ) // DW_ARG
|
||||
{
|
||||
// Translate the function id
|
||||
*(int*)(tmp+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmp+1)]);
|
||||
@ -4772,6 +5046,8 @@ void asCWriter::SListAdjuster::SetNextType(int typeId)
|
||||
|
||||
void asCWriter::WriteUsedTypeIds()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedTypeIds");
|
||||
|
||||
asUINT count = (asUINT)usedTypeIds.GetLength();
|
||||
WriteEncodedInt64(count);
|
||||
for( asUINT n = 0; n < count; n++ )
|
||||
@ -4792,6 +5068,8 @@ int asCWriter::FindGlobalPropPtrIndex(void *ptr)
|
||||
|
||||
void asCWriter::WriteUsedGlobalProps()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedGlobalProps");
|
||||
|
||||
int c = (int)usedGlobalProperties.GetLength();
|
||||
WriteEncodedInt64(c);
|
||||
|
||||
@ -4799,32 +5077,12 @@ void asCWriter::WriteUsedGlobalProps()
|
||||
{
|
||||
asPWORD *p = (asPWORD*)usedGlobalProperties[n];
|
||||
|
||||
// First search for the global in the module
|
||||
char moduleProp = 0;
|
||||
// Find the property descriptor from the address
|
||||
asCGlobalProperty *prop = 0;
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = module->scriptGlobals.List();
|
||||
for( ; it; it++ )
|
||||
asSMapNode<void*, asCGlobalProperty*> *cursor;
|
||||
if( engine->varAddressMap.MoveTo(&cursor, p) )
|
||||
{
|
||||
if( p == (*it)->GetAddressOfValue() )
|
||||
{
|
||||
prop = (*it);
|
||||
moduleProp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is not in the module, it must be an application registered property
|
||||
if( !prop )
|
||||
{
|
||||
asCSymbolTable<asCGlobalProperty>::iterator it = engine->registeredGlobalProps.List();
|
||||
for( ; it; it++ )
|
||||
{
|
||||
if( it->GetAddressOfValue() == p )
|
||||
{
|
||||
prop = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop = engine->varAddressMap.GetValue(cursor);
|
||||
}
|
||||
|
||||
asASSERT(prop);
|
||||
@ -4835,12 +5093,17 @@ void asCWriter::WriteUsedGlobalProps()
|
||||
WriteDataType(&prop->type);
|
||||
|
||||
// Also store whether the property is a module property or a registered property
|
||||
char moduleProp = 0;
|
||||
if( prop->realAddress == 0 )
|
||||
moduleProp = 1;
|
||||
WriteData(&moduleProp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void asCWriter::WriteUsedObjectProps()
|
||||
{
|
||||
TimeIt("asCWriter::WriteUsedObjectProps");
|
||||
|
||||
int c = (int)usedObjectProperties.GetLength();
|
||||
WriteEncodedInt64(c);
|
||||
|
||||
|
@ -118,6 +118,9 @@ AS_API const char * asGetLibraryOptions()
|
||||
#ifdef WIP_16BYTE_ALIGN
|
||||
"WIP_16BYTE_ALIGN "
|
||||
#endif
|
||||
#ifdef AS_BIG_ENDIAN
|
||||
"AS_BIG_ENDIAN "
|
||||
#endif
|
||||
|
||||
// Target system
|
||||
#ifdef AS_WIN
|
||||
@ -584,21 +587,22 @@ asCScriptEngine::asCScriptEngine()
|
||||
// Reserve function id 0 for no function
|
||||
scriptFunctions.PushLast(0);
|
||||
|
||||
// Reserve the first typeIds for the primitive types
|
||||
typeIdSeqNbr = asTYPEID_DOUBLE + 1;
|
||||
|
||||
// Make sure typeId for the built-in primitives are defined according to asETypeIdFlags
|
||||
int id = 0;
|
||||
UNUSED_VAR(id); // It is only used in debug mode
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)); asASSERT( id == asTYPEID_VOID );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)); asASSERT( id == asTYPEID_BOOL );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)); asASSERT( id == asTYPEID_INT8 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)); asASSERT( id == asTYPEID_INT16 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)); asASSERT( id == asTYPEID_INT32 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)); asASSERT( id == asTYPEID_INT64 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)); asASSERT( id == asTYPEID_UINT8 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)); asASSERT( id == asTYPEID_UINT16 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)); asASSERT( id == asTYPEID_UINT32 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)); asASSERT( id == asTYPEID_UINT64 );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)); asASSERT( id == asTYPEID_FLOAT );
|
||||
id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)); asASSERT( id == asTYPEID_DOUBLE );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)) == asTYPEID_VOID );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)) == asTYPEID_BOOL );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)) == asTYPEID_INT8 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)) == asTYPEID_INT16 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)) == asTYPEID_INT32 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)) == asTYPEID_INT64 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)) == asTYPEID_UINT8 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)) == asTYPEID_UINT32 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)) == asTYPEID_FLOAT );
|
||||
asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE );
|
||||
|
||||
defaultArrayObjectType = 0;
|
||||
|
||||
@ -608,9 +612,9 @@ asCScriptEngine::asCScriptEngine()
|
||||
|
||||
void asCScriptEngine::DeleteDiscardedModules()
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Prevent more than one thread from entering this function at the same time.
|
||||
// If a thread is already doing the work for the clean-up the other thread should
|
||||
// simply return, as the first thread will continue.
|
||||
// TODO: redesign: Prevent more than one thread from entering this function at the same time.
|
||||
// If a thread is already doing the work for the clean-up the other thread should
|
||||
// simply return, as the first thread will continue.
|
||||
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asUINT maxCount = discardedModules.GetLength();
|
||||
@ -646,7 +650,7 @@ void asCScriptEngine::DeleteDiscardedModules()
|
||||
|
||||
asCScriptEngine::~asCScriptEngine()
|
||||
{
|
||||
// TODO: 2.30.0: redesign: Clean up redundant code
|
||||
// TODO: clean-up: Clean up redundant code
|
||||
|
||||
asUINT n = 0;
|
||||
inDestructor = true;
|
||||
@ -690,12 +694,8 @@ asCScriptEngine::~asCScriptEngine()
|
||||
if( refCount.get() > 0 )
|
||||
WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN);
|
||||
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
while( mapTypeIdToDataType.MoveFirst(&cursor) )
|
||||
{
|
||||
asDELETE(mapTypeIdToDataType.GetValue(cursor),asCDataType);
|
||||
mapTypeIdToDataType.Erase(cursor);
|
||||
}
|
||||
mapTypeIdToObjectType.EraseAll();
|
||||
mapTypeIdToFunction.EraseAll();
|
||||
|
||||
// First remove what is not used, so that other groups can be deleted safely
|
||||
defaultGroup.RemoveConfiguration(this, true);
|
||||
@ -1976,7 +1976,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as
|
||||
listPattern->Destroy(this);
|
||||
return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl);
|
||||
}
|
||||
func.name.Format("_beh_%d_", behaviour);
|
||||
func.name.Format("$beh%d", behaviour);
|
||||
|
||||
if( behaviour != asBEHAVE_FACTORY && behaviour != asBEHAVE_LIST_FACTORY )
|
||||
{
|
||||
@ -3229,7 +3229,7 @@ int asCScriptEngine::RegisterStringFactory(const char *datatype, const asSFuncPt
|
||||
return ConfigError(asOUT_OF_MEMORY, "RegisterStringFactory", datatype, 0);
|
||||
}
|
||||
|
||||
func->name = "_string_factory_";
|
||||
func->name = "$str";
|
||||
func->sysFuncIntf = newInterface;
|
||||
|
||||
asCBuilder bld(this, 0);
|
||||
@ -3590,6 +3590,9 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT
|
||||
if( templateType->beh.listFactory )
|
||||
{
|
||||
asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory);
|
||||
|
||||
// Rename the function to easily identify it in LoadByteCode
|
||||
func->name = "$list";
|
||||
|
||||
ot->beh.listFactory = func->id;
|
||||
}
|
||||
@ -3787,7 +3790,7 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t
|
||||
|
||||
func->funcType = asFUNC_SCRIPT;
|
||||
func->AllocateScriptFunctionData();
|
||||
func->name = "factstub";
|
||||
func->name = "$fact";
|
||||
func->id = GetNextScriptFunctionId();
|
||||
AddScriptFunction(func);
|
||||
|
||||
@ -4230,6 +4233,62 @@ void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const
|
||||
#endif
|
||||
}
|
||||
|
||||
void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const
|
||||
{
|
||||
asASSERT( func != 0 );
|
||||
asSSystemFunctionInterface *i = func->sysFuncIntf;
|
||||
|
||||
#ifndef AS_NO_CLASS_METHODS
|
||||
if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL )
|
||||
{
|
||||
#if defined(__GNUC__) || defined(AS_PSVITA)
|
||||
// For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
|
||||
union
|
||||
{
|
||||
asSIMPLEMETHOD_t mthd;
|
||||
struct
|
||||
{
|
||||
asFUNCTION_t func;
|
||||
asPWORD baseOffset;
|
||||
} f;
|
||||
} p;
|
||||
p.f.func = (asFUNCTION_t)(i->func);
|
||||
p.f.baseOffset = asPWORD(i->baseOffset);
|
||||
void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd);
|
||||
return (((asCSimpleDummy*)obj)->*f)(param1);
|
||||
#else
|
||||
union
|
||||
{
|
||||
asSIMPLEMETHOD_t mthd;
|
||||
asFUNCTION_t func;
|
||||
} p;
|
||||
p.func = (asFUNCTION_t)(i->func);
|
||||
void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd;
|
||||
obj = (void*)(asPWORD(obj) + i->baseOffset);
|
||||
return (((asCSimpleDummy*)obj)->*f)(param1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if( i->callConv == ICC_GENERIC_METHOD )
|
||||
{
|
||||
asCGeneric gen(const_cast<asCScriptEngine*>(this), func, obj, reinterpret_cast<asDWORD*>(¶m1));
|
||||
void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
|
||||
f(&gen);
|
||||
return *(void **)gen.GetReturnPointer();
|
||||
}
|
||||
else if( i->callConv == ICC_CDECL_OBJLAST )
|
||||
{
|
||||
void *(*f)(int, void *) = (void *(*)(int, void *))(i->func);
|
||||
return f(param1, obj);
|
||||
}
|
||||
else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/
|
||||
{
|
||||
void *(*f)(void *, int) = (void *(*)(void *, int))(i->func);
|
||||
return f(obj, param1);
|
||||
}
|
||||
}
|
||||
|
||||
void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const
|
||||
{
|
||||
asCScriptFunction *s = scriptFunctions[func];
|
||||
@ -4496,82 +4555,154 @@ void asCScriptEngine::GCEnumCallback(void *reference)
|
||||
}
|
||||
|
||||
|
||||
// TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it
|
||||
int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const
|
||||
{
|
||||
if( dtIn.IsNullHandle() ) return 0;
|
||||
if( dtIn.IsNullHandle() ) return asTYPEID_VOID;
|
||||
|
||||
// Register the base form
|
||||
asCDataType dt(dtIn);
|
||||
if( dt.GetObjectType() )
|
||||
dt.MakeHandle(false);
|
||||
|
||||
// Find the existing type id
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
mapTypeIdToDataType.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
if( dtIn.GetObjectType() == 0 )
|
||||
{
|
||||
if( mapTypeIdToDataType.GetValue(cursor)->IsEqualExceptRefAndConst(dt) )
|
||||
// Primitives have pre-fixed typeIds
|
||||
switch( dtIn.GetTokenType() )
|
||||
{
|
||||
int typeId = mapTypeIdToDataType.GetKey(cursor);
|
||||
if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) )
|
||||
case ttVoid: return asTYPEID_VOID;
|
||||
case ttBool: return asTYPEID_BOOL;
|
||||
case ttInt8: return asTYPEID_INT8;
|
||||
case ttInt16: return asTYPEID_INT16;
|
||||
case ttInt: return asTYPEID_INT32;
|
||||
case ttInt64: return asTYPEID_INT64;
|
||||
case ttUInt8: return asTYPEID_UINT8;
|
||||
case ttUInt16: return asTYPEID_UINT16;
|
||||
case ttUInt: return asTYPEID_UINT32;
|
||||
case ttUInt64: return asTYPEID_UINT64;
|
||||
case ttFloat: return asTYPEID_FLOAT;
|
||||
case ttDouble: return asTYPEID_DOUBLE;
|
||||
default:
|
||||
// All types should be covered by the above. The variable type is not really a type
|
||||
asASSERT(dtIn.GetTokenType() == ttQuestion);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int typeId = -1;
|
||||
asCObjectType *ot = dtIn.GetObjectType();
|
||||
if( ot != &functionBehaviours )
|
||||
{
|
||||
// Object's hold the typeId themselves
|
||||
typeId = ot->typeId;
|
||||
|
||||
if( typeId == -1 )
|
||||
{
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
// Make sure another thread didn't determine the typeId while we were waiting for the lock
|
||||
if( ot->typeId == -1 )
|
||||
{
|
||||
// The ASHANDLE types behave like handles, but are really
|
||||
// value types so the typeId is never returned as a handle
|
||||
if( dtIn.IsObjectHandle() )
|
||||
typeId |= asTYPEID_OBJHANDLE;
|
||||
if( dtIn.IsHandleToConst() )
|
||||
typeId |= asTYPEID_HANDLETOCONST;
|
||||
typeId = typeIdSeqNbr++;
|
||||
if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
|
||||
else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE;
|
||||
else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this?
|
||||
else typeId |= asTYPEID_APPOBJECT;
|
||||
|
||||
ot->typeId = typeId;
|
||||
|
||||
mapTypeIdToObjectType.Insert(typeId, ot);
|
||||
}
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This a funcdef, so we'll need to look in the map for the funcdef
|
||||
|
||||
// TODO: optimize: It shouldn't be necessary to exclusive lock when the typeId already exists
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
|
||||
// Find the existing type id
|
||||
asCScriptFunction *func = dtIn.GetFuncDef();
|
||||
asASSERT(func);
|
||||
asSMapNode<int,asCScriptFunction*> *cursor = 0;
|
||||
mapTypeIdToFunction.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
{
|
||||
if( mapTypeIdToFunction.GetValue(cursor) == func )
|
||||
{
|
||||
typeId = mapTypeIdToFunction.GetKey(cursor);
|
||||
break;
|
||||
}
|
||||
|
||||
return typeId;
|
||||
mapTypeIdToFunction.MoveNext(&cursor, cursor);
|
||||
}
|
||||
|
||||
mapTypeIdToDataType.MoveNext(&cursor, cursor);
|
||||
// The type id doesn't exist, create it
|
||||
if( typeId == -1 )
|
||||
{
|
||||
// Setup the type id for the funcdef
|
||||
typeId = typeIdSeqNbr++;
|
||||
typeId |= asTYPEID_APPOBJECT;
|
||||
mapTypeIdToFunction.Insert(typeId, func);
|
||||
}
|
||||
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
|
||||
// The type id doesn't exist, create it
|
||||
|
||||
// Setup the basic type id
|
||||
int typeId = typeIdSeqNbr++;
|
||||
if( dt.GetObjectType() )
|
||||
// Add flags according to the requested type
|
||||
if( dtIn.GetObjectType() && !(dtIn.GetObjectType()->flags & asOBJ_ASHANDLE) )
|
||||
{
|
||||
if( dt.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
|
||||
else if( dt.GetObjectType()->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE;
|
||||
else if( dt.GetObjectType()->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this?
|
||||
else typeId |= asTYPEID_APPOBJECT;
|
||||
// The ASHANDLE types behave like handles, but are really
|
||||
// value types so the typeId is never returned as a handle
|
||||
if( dtIn.IsObjectHandle() )
|
||||
typeId |= asTYPEID_OBJHANDLE;
|
||||
if( dtIn.IsHandleToConst() )
|
||||
typeId |= asTYPEID_HANDLETOCONST;
|
||||
}
|
||||
|
||||
// Insert the basic object type
|
||||
asCDataType *newDt = asNEW(asCDataType)(dt);
|
||||
if( newDt == 0 )
|
||||
{
|
||||
// Out of memory
|
||||
return 0;
|
||||
}
|
||||
|
||||
newDt->MakeReference(false);
|
||||
newDt->MakeReadOnly(false);
|
||||
newDt->MakeHandle(false);
|
||||
|
||||
mapTypeIdToDataType.Insert(typeId, newDt);
|
||||
|
||||
// Call recursively to get the correct typeId
|
||||
return GetTypeIdFromDataType(dtIn);
|
||||
return typeId;
|
||||
}
|
||||
|
||||
asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const
|
||||
{
|
||||
int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR);
|
||||
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
if( mapTypeIdToDataType.MoveTo(&cursor, baseId) )
|
||||
if( typeId <= asTYPEID_DOUBLE )
|
||||
{
|
||||
asCDataType dt(*mapTypeIdToDataType.GetValue(cursor));
|
||||
eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble};
|
||||
return asCDataType::CreatePrimitive(type[typeId], false);
|
||||
}
|
||||
|
||||
// First check if the typeId is an object type
|
||||
asCObjectType *ot = 0;
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asSMapNode<int,asCObjectType*> *cursor = 0;
|
||||
if( mapTypeIdToObjectType.MoveTo(&cursor, baseId) )
|
||||
ot = mapTypeIdToObjectType.GetValue(cursor);
|
||||
RELEASESHARED(engineRWLock);
|
||||
|
||||
if( ot )
|
||||
{
|
||||
asCDataType dt = asCDataType::CreateObject(ot, false);
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
dt.MakeHandle(true, true);
|
||||
if( typeId & asTYPEID_HANDLETOCONST )
|
||||
dt.MakeHandleToConst(true);
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
// Then check if it is a funcdef
|
||||
asCScriptFunction *func = 0;
|
||||
ACQUIRESHARED(engineRWLock);
|
||||
asSMapNode<int,asCScriptFunction*> *cursor2 = 0;
|
||||
if( mapTypeIdToFunction.MoveTo(&cursor2, baseId) )
|
||||
func = mapTypeIdToFunction.GetValue(cursor2);
|
||||
RELEASESHARED(engineRWLock);
|
||||
|
||||
if( func )
|
||||
{
|
||||
asCDataType dt = asCDataType::CreateFuncDef(func);
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
dt.MakeHandle(true, true);
|
||||
if( typeId & asTYPEID_HANDLETOCONST )
|
||||
dt.MakeHandleToConst(true);
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
@ -4586,19 +4717,19 @@ asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const
|
||||
|
||||
void asCScriptEngine::RemoveFromTypeIdMap(asCObjectType *type)
|
||||
{
|
||||
asSMapNode<int,asCDataType*> *cursor = 0;
|
||||
mapTypeIdToDataType.MoveFirst(&cursor);
|
||||
ACQUIREEXCLUSIVE(engineRWLock);
|
||||
asSMapNode<int,asCObjectType*> *cursor = 0;
|
||||
mapTypeIdToObjectType.MoveFirst(&cursor);
|
||||
while( cursor )
|
||||
{
|
||||
asCDataType *dt = mapTypeIdToDataType.GetValue(cursor);
|
||||
asSMapNode<int,asCDataType*> *old = cursor;
|
||||
mapTypeIdToDataType.MoveNext(&cursor, cursor);
|
||||
if( dt->GetObjectType() == type )
|
||||
if( mapTypeIdToObjectType.GetValue(cursor) == type )
|
||||
{
|
||||
asDELETE(dt,asCDataType);
|
||||
mapTypeIdToDataType.Erase(old);
|
||||
mapTypeIdToObjectType.Erase(cursor);
|
||||
break;
|
||||
}
|
||||
mapTypeIdToObjectType.MoveNext(&cursor, cursor);
|
||||
}
|
||||
RELEASEEXCLUSIVE(engineRWLock);
|
||||
}
|
||||
|
||||
// interface
|
||||
@ -5318,7 +5449,6 @@ void asCScriptEngine::RemoveScriptFunction(asCScriptFunction *func)
|
||||
// internal
|
||||
void asCScriptEngine::RemoveFuncdef(asCScriptFunction *funcdef)
|
||||
{
|
||||
// TODO: 2.30.0: redesign: How to avoid removing a funcdef that is shared by multiple modules?
|
||||
funcDefs.RemoveValue(funcdef);
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,7 @@ public:
|
||||
bool CallObjectMethodRetBool(void *obj, int func) const;
|
||||
int CallObjectMethodRetInt(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int func) const;
|
||||
void *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const;
|
||||
void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const;
|
||||
|
||||
@ -400,16 +401,17 @@ public:
|
||||
// This array stores the template instances types that have been automatically generated from template types
|
||||
asCArray<asCObjectType *> generatedTemplateTypes;
|
||||
// Stores the funcdefs
|
||||
// TODO: 2.30.0: redesign: Only shared funcdefs should be stored here
|
||||
// a funcdef becomes shared if all arguments and the return type are shared (or application registered)
|
||||
// TODO: redesign: Only shared funcdefs should be stored here
|
||||
// a funcdef becomes shared if all arguments and the return type are shared (or application registered)
|
||||
asCArray<asCScriptFunction *> funcDefs; // doesn't increase ref count
|
||||
|
||||
// Stores the names of the script sections for debugging purposes
|
||||
asCArray<asCString *> scriptSectionNames;
|
||||
|
||||
// Type identifiers
|
||||
mutable int typeIdSeqNbr;
|
||||
mutable asCMap<int, asCDataType*> mapTypeIdToDataType;
|
||||
mutable int typeIdSeqNbr;
|
||||
mutable asCMap<int, asCObjectType*> mapTypeIdToObjectType;
|
||||
mutable asCMap<int, asCScriptFunction*> mapTypeIdToFunction;
|
||||
|
||||
// Garbage collector
|
||||
asCGarbageCollector gc;
|
||||
|
@ -105,7 +105,7 @@ static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen)
|
||||
gen->SetReturnAddress(CreateDelegate(func, obj));
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: operator==
|
||||
/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject();
|
||||
@ -124,7 +124,7 @@ void RegisterScriptFunction(asCScriptEngine *engine)
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->functionBehaviours.engine = engine;
|
||||
engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC | asOBJ_SCRIPT_FUNCTION;
|
||||
engine->functionBehaviours.name = "_builtin_function_";
|
||||
engine->functionBehaviours.name = "$func";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
@ -133,7 +133,7 @@ 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
|
||||
// TODO: 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 );
|
||||
@ -226,7 +226,7 @@ asIScriptFunction *asCScriptFunction::GetDelegateFunction() const
|
||||
return funcForDelegate;
|
||||
}
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: operator==
|
||||
/*
|
||||
// internal
|
||||
bool asCScriptFunction::operator==(const asCScriptFunction &other) const
|
||||
@ -419,7 +419,6 @@ asCScriptFunction::~asCScriptFunction()
|
||||
// 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();
|
||||
|
||||
// Finally set the engine pointer to 0 because it must not be accessed again
|
||||
@ -678,7 +677,7 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
if( !(returnType.GetTokenType() == ttVoid &&
|
||||
objectType &&
|
||||
(name == objectType->name || (name.GetLength() > 0 && name[0] == '~') ||
|
||||
name == "_beh_0_" || name == "_beh_2_")) )
|
||||
name == "$beh0" || name == "$beh2")) )
|
||||
{
|
||||
str = returnType.Format(nameSpace, includeNamespace);
|
||||
str += " ";
|
||||
@ -699,13 +698,13 @@ asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool incl
|
||||
}
|
||||
if( name == "" )
|
||||
str += "_unnamed_function_(";
|
||||
else if( name.SubString(0,5) == "_beh_" && name.GetLength() == 7 )
|
||||
else if( name.SubString(0,4) == "$beh" && name.GetLength() == 5 )
|
||||
{
|
||||
if( name[5] == '0' + asBEHAVE_CONSTRUCT )
|
||||
if( name[4] == '0' + asBEHAVE_CONSTRUCT )
|
||||
str += objectType->name + "(";
|
||||
else if( name[5] == '0' + asBEHAVE_FACTORY )
|
||||
else if( name[4] == '0' + asBEHAVE_FACTORY )
|
||||
str += returnType.GetObjectType()->name + "(";
|
||||
else if( name[5] == '0' + asBEHAVE_DESTRUCT )
|
||||
else if( name[4] == '0' + asBEHAVE_DESTRUCT )
|
||||
str += "~" + objectType->name + "(";
|
||||
else
|
||||
str += name + "(";
|
||||
@ -1008,7 +1007,7 @@ void asCScriptFunction::ComputeSignatureId()
|
||||
// internal
|
||||
bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const
|
||||
{
|
||||
if( !IsSignatureExceptNameEqual(func) || name != func->name ) return false;
|
||||
if( name != func->name || !IsSignatureExceptNameEqual(func) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1043,9 +1042,9 @@ bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptF
|
||||
bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray<asCDataType> ¶mTypes, const asCArray<asETypeModifiers> ¶mInOut, const asCObjectType *objType, bool readOnly) const
|
||||
{
|
||||
if( this->isReadOnly != readOnly ) return false;
|
||||
if( (this->objectType != 0) != (objType != 0) ) return false;
|
||||
if( this->inOutFlags != paramInOut ) return false;
|
||||
if( this->parameterTypes != paramTypes ) return false;
|
||||
if( (this->objectType != 0) != (objType != 0) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1299,7 +1298,11 @@ void asCScriptFunction::ReleaseReferences()
|
||||
if( group != 0 ) group->Release();
|
||||
|
||||
if( funcId )
|
||||
engine->scriptFunctions[funcId]->ReleaseInternal();
|
||||
{
|
||||
asCScriptFunction *fptr = engine->scriptFunctions[funcId];
|
||||
if( fptr )
|
||||
fptr->ReleaseInternal();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -186,12 +186,12 @@ public:
|
||||
|
||||
void DestroyHalfCreated();
|
||||
|
||||
// TODO: 2.29.0: operator==
|
||||
// TODO: 2.29.0: The asIScriptFunction should provide operator== and operator!= that should do a
|
||||
// a value comparison. Two delegate objects that point to the same object and class method should compare as equal
|
||||
// TODO: 2.29.0: The operator== should also be provided in script as opEquals to allow the same comparison in script
|
||||
// To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods
|
||||
// Perhaps reusing 'auto' to mean the same type as the object
|
||||
// TODO: operator==
|
||||
// TODO: The asIScriptFunction should provide operator== and operator!= that should do a
|
||||
// a value comparison. Two delegate objects that point to the same object and class method should compare as equal
|
||||
// TODO: The operator== should also be provided in script as opEquals to allow the same comparison in script
|
||||
// To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods
|
||||
// Perhaps reusing 'auto' to mean the same type as the object
|
||||
//bool operator==(const asCScriptFunction &other) const;
|
||||
|
||||
void DestroyInternal();
|
||||
@ -329,7 +329,7 @@ public:
|
||||
asSSystemFunctionInterface *sysFuncIntf;
|
||||
};
|
||||
|
||||
const char * const DELEGATE_FACTORY = "%delegate_factory";
|
||||
const char * const DELEGATE_FACTORY = "$dlgte";
|
||||
asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -173,6 +173,24 @@ static void ScriptObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
static void ScriptObject_Assignment_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
*self = *other;
|
||||
|
||||
*(asCScriptObject**)gen->GetAddressOfReturnLocation() = self;
|
||||
}
|
||||
|
||||
static void ScriptObject_Construct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0);
|
||||
asCScriptObject *self = (asCScriptObject*)gen->GetObject();
|
||||
|
||||
ScriptObject_Construct(objType, self);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void RegisterScriptObject(asCScriptEngine *engine)
|
||||
@ -182,7 +200,7 @@ void RegisterScriptObject(asCScriptEngine *engine)
|
||||
UNUSED_VAR(r); // It is only used in debug mode
|
||||
engine->scriptTypeBehaviours.engine = engine;
|
||||
engine->scriptTypeBehaviours.flags = asOBJ_SCRIPT_OBJECT | asOBJ_REF | asOBJ_GC;
|
||||
engine->scriptTypeBehaviours.name = "_builtin_object_";
|
||||
engine->scriptTypeBehaviours.name = "$obj";
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct), asCALL_CDECL_OBJLAST, 0); asASSERT( r >= 0 );
|
||||
r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptObject,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 );
|
||||
@ -216,14 +234,6 @@ void RegisterScriptObject(asCScriptEngine *engine)
|
||||
#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);
|
||||
@ -744,16 +754,6 @@ void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -154,9 +154,6 @@ asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject
|
||||
|
||||
void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self);
|
||||
|
||||
void ScriptObject_Construct_Generic(asIScriptGeneric *gen);
|
||||
void ScriptObject_Assignment_Generic(asIScriptGeneric *gen);
|
||||
|
||||
void RegisterScriptObject(asCScriptEngine *engine);
|
||||
|
||||
asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine);
|
||||
|
@ -142,6 +142,7 @@
|
||||
#define TXT_INVALID_CONTINUE "Invalid 'continue'"
|
||||
#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence"
|
||||
#define TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name"
|
||||
#define TXT_INVALID_EXPRESSION_LAMBDA "Invalid expression: stand-alone anonymous function"
|
||||
#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method"
|
||||
#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations"
|
||||
#define TXT_INVALID_SCOPE "Invalid scope resolution"
|
||||
@ -252,6 +253,7 @@
|
||||
#define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones."
|
||||
#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern"
|
||||
#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module"
|
||||
#define TXT_TYPE_s_NOT_TEMPLATE "Type '%s' is not a template type"
|
||||
|
||||
#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file"
|
||||
#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -311,6 +311,7 @@ const char * const OVERRIDE_TOKEN = "override";
|
||||
const char * const GET_TOKEN = "get";
|
||||
const char * const SET_TOKEN = "set";
|
||||
const char * const ABSTRACT_TOKEN = "abstract";
|
||||
const char * const FUNCTION_TOKEN = "function";
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -53,7 +53,6 @@ asCTypeInfo::asCTypeInfo()
|
||||
isExplicitHandle = false;
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
@ -68,7 +67,6 @@ void asCTypeInfo::Set(const asCDataType &dt)
|
||||
isExplicitHandle = false;
|
||||
qwordValue = 0;
|
||||
isLValue = false;
|
||||
isVoidExpression = false;
|
||||
isRefToLocal = false;
|
||||
}
|
||||
|
||||
@ -135,6 +133,18 @@ void asCTypeInfo::SetUndefinedFuncHandle(asCScriptEngine *engine)
|
||||
isLValue = false;
|
||||
}
|
||||
|
||||
bool asCTypeInfo::IsUndefinedFuncHandle() const
|
||||
{
|
||||
if( isConstant == false ) return false;
|
||||
if( qwordValue == 0 ) return false;
|
||||
if( isLValue ) return false;
|
||||
if( dataType.GetObjectType() == 0 ) return false;
|
||||
if( dataType.GetObjectType()->name != "$func" ) return false;
|
||||
if( dataType.GetFuncDef() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetNullConstant()
|
||||
{
|
||||
Set(asCDataType::CreateNullHandle());
|
||||
@ -153,17 +163,19 @@ bool asCTypeInfo::IsNullConstant() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetVoidExpression()
|
||||
void asCTypeInfo::SetVoid()
|
||||
{
|
||||
Set(asCDataType::CreatePrimitive(ttVoid, false));
|
||||
isLValue = false;
|
||||
isConstant = false;
|
||||
isVoidExpression = true;
|
||||
isConstant = true;
|
||||
}
|
||||
|
||||
bool asCTypeInfo::IsVoidExpression() const
|
||||
bool asCTypeInfo::IsVoid() const
|
||||
{
|
||||
return isVoidExpression;
|
||||
if( dataType.GetTokenType() == ttVoid )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void asCTypeInfo::SetDummy()
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2014 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
|
||||
@ -61,11 +61,12 @@ struct asCTypeInfo
|
||||
void SetConstantD(const asCDataType &dataType, double value);
|
||||
void SetNullConstant();
|
||||
void SetUndefinedFuncHandle(asCScriptEngine *engine);
|
||||
void SetVoidExpression();
|
||||
void SetVoid();
|
||||
void SetDummy();
|
||||
|
||||
bool IsUndefinedFuncHandle() const;
|
||||
bool IsNullConstant() const;
|
||||
bool IsVoidExpression() const;
|
||||
bool IsVoid() const;
|
||||
|
||||
asCDataType dataType;
|
||||
bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc
|
||||
@ -73,9 +74,8 @@ struct asCTypeInfo
|
||||
bool isConstant : 1;
|
||||
bool isVariable : 1;
|
||||
bool isExplicitHandle : 1;
|
||||
bool isVoidExpression : 1;
|
||||
bool isRefToLocal : 1; // The reference may be to a local variable
|
||||
short dummy : 9;
|
||||
short dummy : 10;
|
||||
short stackOffset;
|
||||
union
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user