Updated to AngelScript 2.26.2.
Small fixes to "Quickstart in C++" documentation.
This commit is contained in:
Родитель
34df8b5e82
Коммит
42448b8924
|
@ -473,7 +473,7 @@ setup_executable ()
|
|||
|
||||
Before recreating the build files with CMake, create an empty HelloWorld.cpp into the HelloWorld directory. Now you can re-run CMake. If using Visual Studio, the HelloWorld project should now appear in the Urho3D solution, and you can start writing the actual application into HelloWorld.cpp.
|
||||
|
||||
To start with, we need the include files for all the engine classes we are going to use, plus Windows.h for the WinMain function:
|
||||
First we need to include the header files for all the engine classes we are going to use, plus Main.h, which helps to create the main function in a cross-platform compatible way. Additionally, including DebugNew.h enables debug allocation in Visual Studio debug builds. This helps to track down memory leaks by adding file name and line number information to each heap memory allocation in our own code.
|
||||
|
||||
\code
|
||||
#include "Camera.h"
|
||||
|
@ -524,7 +524,7 @@ public:
|
|||
};
|
||||
\endcode
|
||||
|
||||
Before the actual HelloWorld implementation, we define the program entry point. The earlier included Main.h contains a DEFINE_MAIN macro which helps to create a cross-platform entry point (on Windows it will be WinMain(), on Linux just main() etc.) It parses the command line and then returns control to the user-defined function.
|
||||
Before the actual HelloWorld implementation, we define the program entry point. The earlier included Main.h contains a DEFINE_MAIN macro which creates the platform-specific main function (on Windows it will be WinMain(), on Linux just main() etc.) It parses the command line and then returns control to our function.
|
||||
|
||||
\code
|
||||
int Run()
|
||||
|
|
|
@ -48,6 +48,7 @@ For release history and major changes, see \ref History.
|
|||
|
||||
Urho3D development, contributions and bugfixes by:
|
||||
- Lasse Öörni (loorni@gmail.com, AgentC at GameDev.net)
|
||||
- Wei Tjong Yao
|
||||
- Colin Barrett
|
||||
- Carlo Carollo
|
||||
- Alex Fuller
|
||||
|
@ -55,7 +56,6 @@ Urho3D development, contributions and bugfixes by:
|
|||
- Jason Kinzer
|
||||
- Vladimir Pobedinsky
|
||||
- Miika Santala
|
||||
- Wei Tjong Yao
|
||||
- Magic.Lixin
|
||||
- primitivewaste
|
||||
- skaiware
|
||||
|
@ -75,7 +75,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org/) and Horde3D (http://
|
|||
|
||||
Urho3D uses the following third-party libraries:
|
||||
|
||||
- AngelScript 2.26.1 WIP (http://www.angelcode.com/angelscript/)
|
||||
- AngelScript 2.26.2 (http://www.angelcode.com/angelscript/)
|
||||
- Bullet 2.80 (http://www.bulletphysics.org/)
|
||||
- FreeType 2.3.12 (http://www.freetype.org/)
|
||||
- GLEW 1.9.0 (http://glew.sourceforge.net/)
|
||||
|
|
|
@ -11,6 +11,7 @@ Credits
|
|||
|
||||
Urho3D development, contributions and bugfixes by:
|
||||
- Lasse Öörni (loorni@gmail.com)
|
||||
- Wei Tjong Yao
|
||||
- Colin Barrett
|
||||
- Carlo Carollo
|
||||
- Alex Fuller
|
||||
|
@ -18,7 +19,6 @@ Urho3D development, contributions and bugfixes by:
|
|||
- Jason Kinzer
|
||||
- Vladimir Pobedinsky
|
||||
- Miika Santala
|
||||
- Wei Tjong Yao
|
||||
- Magic.Lixin
|
||||
- primitivewaste
|
||||
- skaiware
|
||||
|
@ -48,7 +48,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org) and Horde3D
|
|||
http://timothylottes.blogspot.com/2011/04/nvidia-fxaa-ii-for-console.html
|
||||
|
||||
Urho3D uses the following third-party libraries:
|
||||
- AngelScript 2.26.1 WIP (http://www.angelcode.com/angelscript/)
|
||||
- AngelScript 2.26.2 (http://www.angelcode.com/angelscript/)
|
||||
- Bullet 2.80 (http://www.bulletphysics.org/)
|
||||
- FreeType 2.3.12 (http://www.freetype.org/)
|
||||
- GLEW 1.9.0 (http://glew.sourceforge.net/)
|
||||
|
|
|
@ -59,8 +59,8 @@ BEGIN_AS_NAMESPACE
|
|||
|
||||
// AngelScript version
|
||||
|
||||
#define ANGELSCRIPT_VERSION 22601
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.26.1 WIP"
|
||||
#define ANGELSCRIPT_VERSION 22602
|
||||
#define ANGELSCRIPT_VERSION_STRING "2.26.2"
|
||||
|
||||
// Data types
|
||||
|
||||
|
@ -97,7 +97,8 @@ enum asEEngineProp
|
|||
asEP_EXPAND_DEF_ARRAY_TO_TMPL = 15,
|
||||
asEP_AUTO_GARBAGE_COLLECT = 16,
|
||||
asEP_DISALLOW_GLOBAL_VARS = 17,
|
||||
asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT = 18
|
||||
asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT = 18,
|
||||
asEP_COMPILER_WARNINGS = 19
|
||||
};
|
||||
|
||||
// Calling conventions
|
||||
|
|
|
@ -239,6 +239,9 @@ int asCBuilder::Build()
|
|||
// The builder needs to check for each of the global variable, what functions
|
||||
// that are accessed, and what global variables are access by these functions.
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
if( numErrors > 0 )
|
||||
return asERROR;
|
||||
|
||||
|
@ -282,6 +285,9 @@ int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int
|
|||
|
||||
CompileGlobalVariables();
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// Remove the variable from the module, if it was registered
|
||||
|
@ -403,14 +409,15 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
|
|||
funcDesc->name = func->name;
|
||||
funcDesc->funcId = func->id;
|
||||
funcDesc->paramNames = parameterNames;
|
||||
funcDesc->isExistingShared = false;
|
||||
|
||||
asCCompiler compiler(engine);
|
||||
if( compiler.CompileFunction(this, functions[0]->script, parameterNames, functions[0]->node, func, 0) >= 0 )
|
||||
{
|
||||
// Return the function
|
||||
*outFunc = func;
|
||||
}
|
||||
else
|
||||
compiler.CompileFunction(this, functions[0]->script, parameterNames, functions[0]->node, func, 0);
|
||||
|
||||
if( numWarnings > 0 && engine->ep.compilerWarnings == 2 )
|
||||
WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0);
|
||||
|
||||
if( numErrors > 0 )
|
||||
{
|
||||
// If the function was added to the module then remove it again
|
||||
if( compileFlags & asCOMP_ADD_TO_MODULE )
|
||||
|
@ -426,6 +433,9 @@ int asCBuilder::CompileFunction(const char *sectionName, const char *code, int l
|
|||
return asERROR;
|
||||
}
|
||||
|
||||
// Return the function
|
||||
*outFunc = func;
|
||||
|
||||
return asSUCCESS;
|
||||
}
|
||||
|
||||
|
@ -677,6 +687,9 @@ void asCBuilder::CompileFunctions()
|
|||
sFunctionDescription *current = functions[n];
|
||||
if( current == 0 ) continue;
|
||||
|
||||
// Don't compile the function again if it was an existing shared function
|
||||
if( current->isExistingShared ) continue;
|
||||
|
||||
asCCompiler compiler(engine);
|
||||
asCScriptFunction *func = engine->scriptFunctions[current->funcId];
|
||||
|
||||
|
@ -711,7 +724,7 @@ void asCBuilder::CompileFunctions()
|
|||
else if( current->name == current->objType->name )
|
||||
{
|
||||
asCScriptNode *node = classDecl->node;
|
||||
|
||||
|
||||
int r = 0, c = 0;
|
||||
if( node )
|
||||
current->script->ConvertPosToRowCol(node->tokenPos, &r, &c);
|
||||
|
@ -1317,6 +1330,33 @@ void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
|
|||
|
||||
// Don't copy the default arg expression as it is not allowed for function definitions
|
||||
}
|
||||
|
||||
// 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++ )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
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->AddRef();
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
func->Release();
|
||||
|
||||
// funcdefs aren't destroyed when the refCount reaches zero so we need to manually delete them
|
||||
asDELETE(func, asCScriptFunction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1515,12 +1555,12 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameS
|
|||
if( st == 0 )
|
||||
return asOUT_OF_MEMORY;
|
||||
|
||||
// By default all script classes are marked as garbage collected.
|
||||
// By default all script classes are marked as garbage collected.
|
||||
// Only after the complete structure and relationship between classes
|
||||
// is known, can the flag be cleared for those objects that truly cannot
|
||||
// form circular references. This is important because a template
|
||||
// callback may be called with a script class before the compilation
|
||||
// complete, and until it is known, the callback must assume the class
|
||||
// is known, can the flag be cleared for those objects that truly cannot
|
||||
// form circular references. This is important because a template
|
||||
// callback may be called with a script class before the compilation
|
||||
// complete, and until it is known, the callback must assume the class
|
||||
// is garbage collected.
|
||||
st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC;
|
||||
|
||||
|
@ -2020,7 +2060,7 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err
|
|||
|
||||
if( decl->isExistingShared )
|
||||
{
|
||||
// If the class is an existing shared class, then just check if the
|
||||
// If the class is an existing shared class, then just check if the
|
||||
// interface exists in the original declaration too
|
||||
if( !decl->objType->Implements(intfType) )
|
||||
{
|
||||
|
@ -2032,18 +2072,11 @@ void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *err
|
|||
}
|
||||
else
|
||||
{
|
||||
// If the interface is already in the class, then don't add it again
|
||||
// If the interface is already in the class then don't add it again
|
||||
if( decl->objType->Implements(intfType) )
|
||||
{
|
||||
int r, c;
|
||||
decl->script->ConvertPosToRowCol(errNode->tokenPos, &r, &c);
|
||||
asCString msg;
|
||||
msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, intfType->GetName());
|
||||
WriteWarning(decl->script->name, msg, r, c);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the interface to the class
|
||||
// Add the interface to the class
|
||||
decl->objType->interfaces.PushLast(intfType);
|
||||
|
||||
// Add the inherited interfaces too
|
||||
|
@ -2107,7 +2140,7 @@ void asCBuilder::CompileInterfaces()
|
|||
WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
if( ok )
|
||||
{
|
||||
// Make sure none of the implemented interfaces implement from this one
|
||||
|
@ -2140,7 +2173,7 @@ void asCBuilder::CompileInterfaces()
|
|||
}
|
||||
}
|
||||
|
||||
// Order the interfaces with inheritances so that the inherited
|
||||
// Order the interfaces with inheritances so that the inherited
|
||||
// of inherited interfaces can be added properly
|
||||
for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
|
||||
{
|
||||
|
@ -2170,7 +2203,7 @@ void asCBuilder::CompileInterfaces()
|
|||
sClassDeclaration *intfDecl = interfaceDeclarations[n];
|
||||
asCObjectType *intfType = intfDecl->objType;
|
||||
|
||||
// As new interfaces will be added to the end of the list, all
|
||||
// As new interfaces will be added to the end of the list, all
|
||||
// interfaces will be traversed the same as recursively
|
||||
for( asUINT m = 0; m < intfType->interfaces.GetLength(); m++ )
|
||||
{
|
||||
|
@ -2382,8 +2415,8 @@ void asCBuilder::CompileClasses()
|
|||
// types that contain this will accept this type
|
||||
decl->validState = 1;
|
||||
|
||||
// We'll still validate the declaration to make sure nothing new is
|
||||
// added to the shared class that wasn't there in the previous
|
||||
// We'll still validate the declaration to make sure nothing new is
|
||||
// added to the shared class that wasn't there in the previous
|
||||
// compilation. We do not care if something that is there in the previous
|
||||
// declaration is not included in the new declaration though.
|
||||
}
|
||||
|
@ -2400,18 +2433,7 @@ void asCBuilder::CompileClasses()
|
|||
for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ )
|
||||
{
|
||||
if( !decl->objType->Implements(baseType->interfaces[n]) )
|
||||
{
|
||||
decl->objType->interfaces.PushLast(baseType->interfaces[n]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warn if derived class already implements the interface
|
||||
int r, c;
|
||||
decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
|
||||
asCString msg;
|
||||
msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, baseType->interfaces[n]->GetName());
|
||||
WriteWarning(decl->script->name, msg, r, c);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Need to check for name conflict with new class methods
|
||||
|
@ -2719,7 +2741,7 @@ void asCBuilder::CompileClasses()
|
|||
// TODO: runtime optimize: This algorithm can be further improved by checking the types that inherits from
|
||||
// a base class. If the base class is not shared all the classes that derive from it
|
||||
// are known at compile time, and can thus be checked for potential circular references too.
|
||||
//
|
||||
//
|
||||
// Observe, that doing this would conflict with another potential future feature, which is to
|
||||
// allow incremental builds, i.e. allow application to add or replace classes in an
|
||||
// existing module. However, the applications that want to use that should use a special
|
||||
|
@ -2736,13 +2758,13 @@ void asCBuilder::CompileClasses()
|
|||
if( decl->isExistingShared ) continue;
|
||||
|
||||
asCObjectType *ot = decl->objType;
|
||||
|
||||
|
||||
// Is there some path in which this structure is involved in circular references?
|
||||
bool gc = false;
|
||||
for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
|
||||
{
|
||||
asCDataType dt = ot->properties[p]->type;
|
||||
if( !dt.IsObject() )
|
||||
if( !dt.IsObject() )
|
||||
continue;
|
||||
|
||||
if( dt.IsObjectHandle() )
|
||||
|
@ -2753,8 +2775,8 @@ void asCBuilder::CompileClasses()
|
|||
|
||||
if( prop->flags & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// For script objects, treat non-final classes as if they can contain references
|
||||
// as it is not known what derived classes might do. For final types, check all
|
||||
// For script objects, treat non-final classes as if they can contain references
|
||||
// as it is not known what derived classes might do. For final types, check all
|
||||
// properties to determine if any of those can cause a circular reference.
|
||||
if( prop->flags & asOBJ_NOINHERIT )
|
||||
{
|
||||
|
@ -2793,7 +2815,7 @@ void asCBuilder::CompileClasses()
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if( prop->flags & asOBJ_GC )
|
||||
else if( prop->flags & asOBJ_GC )
|
||||
{
|
||||
// If a type is not a script object, adopt its GC flag
|
||||
gc = true;
|
||||
|
@ -3135,6 +3157,7 @@ void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *fi
|
|||
func->name = objType->name;
|
||||
func->objType = objType;
|
||||
func->funcId = funcId;
|
||||
func->isExistingShared = false;
|
||||
|
||||
// Add a default factory as well
|
||||
funcId = engine->GetNextScriptFunctionId();
|
||||
|
@ -3565,10 +3588,12 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod
|
|||
|
||||
// Set the default namespace
|
||||
if( ns == 0 )
|
||||
{
|
||||
if( objType )
|
||||
ns = objType->nameSpace;
|
||||
else
|
||||
ns = engine->nameSpaces[0];
|
||||
}
|
||||
|
||||
GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, isShared, ns);
|
||||
|
||||
|
@ -3579,10 +3604,12 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
|
|||
{
|
||||
// Determine default namespace if not specified
|
||||
if( ns == 0 )
|
||||
{
|
||||
if( objType )
|
||||
ns = objType->nameSpace;
|
||||
else
|
||||
ns = engine->nameSpaces[0];
|
||||
}
|
||||
|
||||
if( isExistingShared )
|
||||
{
|
||||
|
@ -3679,6 +3706,7 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
|
|||
f->isShared &&
|
||||
f->name == name &&
|
||||
f->nameSpace == ns &&
|
||||
f->objectType == objType &&
|
||||
f->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, 0, false) )
|
||||
{
|
||||
funcId = func->funcId = f->id;
|
||||
|
@ -3747,6 +3775,8 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
|
|||
{
|
||||
asCScriptFunction *f = engine->scriptFunctions[funcId];
|
||||
module->AddScriptFunction(f);
|
||||
|
||||
// TODO: clean up: This should be done by AddScriptFunction() itself
|
||||
module->globalFunctions.Put(f);
|
||||
f->AddRef();
|
||||
}
|
||||
|
@ -3758,6 +3788,8 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
|
|||
|
||||
if( objType )
|
||||
{
|
||||
asASSERT( !isExistingShared );
|
||||
|
||||
engine->scriptFunctions[funcId]->AddRef();
|
||||
if( isConstructor )
|
||||
{
|
||||
|
@ -3830,13 +3862,6 @@ int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file,
|
|||
|
||||
int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared)
|
||||
{
|
||||
if( isExistingShared )
|
||||
{
|
||||
// TODO: shared: Should validate that the function really exists in the class/interface
|
||||
node->Destroy(engine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( engine->ep.propertyAccessorMode != 2 )
|
||||
{
|
||||
WriteError(TXT_PROPERTY_ACCESSOR_DISABLED, file, node);
|
||||
|
@ -3847,10 +3872,12 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
|
|||
asASSERT( (objType && ns == 0) || isGlobalFunction );
|
||||
|
||||
if( ns == 0 )
|
||||
{
|
||||
if( objType )
|
||||
ns = objType->nameSpace;
|
||||
else
|
||||
ns = engine->nameSpaces[0];
|
||||
}
|
||||
|
||||
bool isPrivate = false;
|
||||
asCString emulatedName;
|
||||
|
@ -3967,7 +3994,32 @@ int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file
|
|||
WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node);
|
||||
|
||||
if( success )
|
||||
RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, isConst, false, false, isPrivate, isOverride, isFinal, false);
|
||||
{
|
||||
if( !isExistingShared )
|
||||
RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, isConst, false, false, isPrivate, isOverride, isFinal, false);
|
||||
else
|
||||
{
|
||||
// Should validate that the function really exists in the class/interface
|
||||
bool found = false;
|
||||
for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]];
|
||||
if( func->name == name &&
|
||||
func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, isConst) )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
asCString str;
|
||||
str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, objType->GetName());
|
||||
WriteError(str, file, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = next;
|
||||
};
|
||||
|
@ -3992,7 +4044,7 @@ int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCS
|
|||
|
||||
GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate, isOverride, isFinal, isShared, ns);
|
||||
CheckNameConflict(name.AddressOf(), node, file, ns);
|
||||
|
||||
|
||||
// Check that the same function hasn't been registered already in the namespace
|
||||
asCArray<int> funcs;
|
||||
GetFunctionDescriptions(name.AddressOf(), funcs, ns);
|
||||
|
@ -4025,10 +4077,10 @@ asCScriptFunction *asCBuilder::GetFunctionDescription(int id)
|
|||
{
|
||||
// TODO: import: This should be improved when the imported functions are removed
|
||||
// Get the description from the engine
|
||||
if( (id & 0xFFFF0000) == 0 )
|
||||
if( (id & FUNC_IMPORTED) == 0 )
|
||||
return engine->scriptFunctions[id];
|
||||
else
|
||||
return engine->importedFunctions[id & 0xFFFF]->importedFunctionSignature;
|
||||
return engine->importedFunctions[id & ~FUNC_IMPORTED]->importedFunctionSignature;
|
||||
}
|
||||
|
||||
void asCBuilder::GetFunctionDescriptions(const char *name, asCArray<int> &funcs, asSNameSpace *ns)
|
||||
|
@ -4153,10 +4205,10 @@ void asCBuilder::WriteInfo(const asCString &message, asCScriptCode *file, asCScr
|
|||
void asCBuilder::WriteError(const asCString &message, asCScriptCode *file, asCScriptNode *node)
|
||||
{
|
||||
int r = 0, c = 0;
|
||||
if( node )
|
||||
if( node && file )
|
||||
file->ConvertPosToRowCol(node->tokenPos, &r, &c);
|
||||
|
||||
WriteError(file->name, message, r, c);
|
||||
WriteError(file ? file->name : "", message, r, c);
|
||||
}
|
||||
|
||||
void asCBuilder::WriteError(const asCString &scriptname, const asCString &message, int r, int c)
|
||||
|
@ -4172,13 +4224,16 @@ void asCBuilder::WriteError(const asCString &scriptname, const asCString &messag
|
|||
|
||||
void asCBuilder::WriteWarning(const asCString &scriptname, const asCString &message, int r, int c)
|
||||
{
|
||||
numWarnings++;
|
||||
if( engine->ep.compilerWarnings )
|
||||
{
|
||||
numWarnings++;
|
||||
|
||||
// Need to pass the preMessage first
|
||||
if( preMessage.isSet )
|
||||
WriteInfo(preMessage.scriptname, preMessage.message, preMessage.r, preMessage.c, false);
|
||||
// Need to pass the preMessage first
|
||||
if( preMessage.isSet )
|
||||
WriteInfo(preMessage.scriptname, preMessage.message, preMessage.r, preMessage.c, false);
|
||||
|
||||
engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_WARNING, message.AddressOf());
|
||||
engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_WARNING, message.AddressOf());
|
||||
}
|
||||
}
|
||||
|
||||
asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next)
|
||||
|
@ -4323,7 +4378,7 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
|
|||
// Return a dummy
|
||||
return asCDataType::CreatePrimitive(ttInt, false);
|
||||
}
|
||||
|
||||
|
||||
asASSERT( subTypes.GetLength() == ot->templateSubTypes.GetLength() );
|
||||
|
||||
// Check if any of the given subtypes are different from the template's declared subtypes
|
||||
|
@ -4336,7 +4391,7 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( isDifferent )
|
||||
{
|
||||
// This is a template instance
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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 @@
|
|||
// These functions handle the actual calling of system functions on the arm platform
|
||||
//
|
||||
// Written by Fredrik Ehnbom in June 2009, based on as_callfunc_x86.cpp
|
||||
//
|
||||
// The code was complemented to support Linux with ARM by Carlos Luna in December, 2012.
|
||||
|
||||
|
||||
// This code has to conform to both AAPCS and the modified ABI for iOS
|
||||
|
@ -44,7 +46,6 @@
|
|||
// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
|
||||
// iOS: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
|
||||
|
||||
|
||||
#include "as_config.h"
|
||||
|
||||
#ifndef AS_MAX_PORTABILITY
|
||||
|
@ -55,13 +56,17 @@
|
|||
#include "as_texts.h"
|
||||
#include "as_tokendef.h"
|
||||
|
||||
#if !defined(AS_LINUX)
|
||||
|
||||
// The code for iOS, Android, Marmalade and Windows Phone goes here
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
extern "C" asQWORD armFunc(const asDWORD *, int, asFUNCTION_t);
|
||||
extern "C" asQWORD armFuncR0(const asDWORD *, int, asFUNCTION_t, asDWORD r0);
|
||||
extern "C" asQWORD armFuncR0R1(const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
|
||||
extern "C" asQWORD armFuncObjLast(const asDWORD *, int, asFUNCTION_t, asDWORD obj);
|
||||
extern "C" asQWORD armFuncR0ObjLast(const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
|
||||
extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t);
|
||||
extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
|
||||
extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
|
||||
extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
|
||||
extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
{
|
||||
|
@ -69,9 +74,9 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asQWORD retQW = 0;
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asFUNCTION_t *vftable;
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
|
@ -84,11 +89,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
// Android needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
|
||||
// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this
|
||||
// doesn't have to be done for functions that don't have any 64bit types
|
||||
#ifndef AS_ANDROID
|
||||
#if !defined(AS_ANDROID)
|
||||
if( sysFunc->takesObjByVal )
|
||||
#endif
|
||||
{
|
||||
#ifdef AS_ANDROID
|
||||
#if defined(AS_ANDROID)
|
||||
// mask is used as a toggler to skip uneven registers.
|
||||
int mask = 1;
|
||||
|
||||
|
@ -113,8 +118,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
paramSize = 0;
|
||||
int spos = 0;
|
||||
int dpos = 2;
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
|
@ -126,7 +133,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef AS_ANDROID
|
||||
#if defined(AS_ANDROID)
|
||||
if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) &&
|
||||
((dpos & 1) == mask) )
|
||||
{
|
||||
|
@ -147,7 +154,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifdef AS_ANDROID
|
||||
#if defined(AS_ANDROID)
|
||||
// Should an alignment be performed?
|
||||
if( !descr->parameterTypes[n].IsObjectHandle() &&
|
||||
!descr->parameterTypes[n].IsReference() &&
|
||||
|
@ -228,6 +235,344 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#elif defined(AS_LINUX)
|
||||
|
||||
// The Linux code goes here
|
||||
|
||||
#define VFP_OFFSET 70
|
||||
#define STACK_OFFSET 6
|
||||
#define PARAM_BUFFER_SIZE 104
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t);
|
||||
extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
|
||||
extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
|
||||
extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
|
||||
extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
|
||||
|
||||
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
|
||||
{
|
||||
asCScriptEngine *engine = context->m_engine;
|
||||
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
||||
int callConv = sysFunc->callConv;
|
||||
|
||||
asQWORD retQW = 0;
|
||||
asFUNCTION_t func = sysFunc->func;
|
||||
int paramSize = sysFunc->paramSize;
|
||||
asFUNCTION_t *vftable;
|
||||
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
int freeFloatSlot = VFP_OFFSET;
|
||||
int freeDoubleSlot = VFP_OFFSET;
|
||||
int stackPos = STACK_OFFSET;
|
||||
int stackSize = 0;
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
// We´ll divide paramBuffer into several segments:
|
||||
//
|
||||
// 0-1 Unused
|
||||
// 2-5 (+8 / +0 asm) values that should be placed in R0 - R3
|
||||
// 6-67 (+24 / +16 asm) values that should be placed on the stack
|
||||
// 68 (+272 / +264 asm) number of values stored in r registers (R0 - R3)
|
||||
// 69 (+276 / +268 asm) number of args stored on the stack
|
||||
// 70-85 (+280 / +272 asm) values that should be placed in VFP registers (16)
|
||||
// 86-87 (+344 / +336 asm) sp original value - sp final value - for debugging
|
||||
// 88-103 (+352 / +344 asm) Check area for free-used VFP registers
|
||||
//
|
||||
// Total number of elements: 104
|
||||
//
|
||||
// When passing the paramBuffer to the asm routines via the args pointer we are
|
||||
// offsetting the start of the array to being at element # 2. That´s why in asm
|
||||
// all addresses must have an offset of -2 words (-8 bytes).
|
||||
//---------------------------------------------------------------------------- RPi
|
||||
|
||||
asDWORD paramBuffer[PARAM_BUFFER_SIZE];
|
||||
memset(paramBuffer, 0, sizeof(asDWORD) * PARAM_BUFFER_SIZE);
|
||||
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
{
|
||||
// TODO: runtime optimize: This check should be done in PrepareSystemFunction
|
||||
if ( !( descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK ) &&
|
||||
( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
|
||||
descr->returnType.GetSizeInMemoryBytes() <= 8 )
|
||||
callConv--;
|
||||
|
||||
// The return is made in memory
|
||||
callConv++;
|
||||
}
|
||||
|
||||
// Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
|
||||
// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this
|
||||
// doesn't have to be done for functions that don't have any 64bit types
|
||||
{
|
||||
// mask is used as a toggler to skip uneven registers.
|
||||
int mask = 1;
|
||||
|
||||
// Check for object pointer as first argument
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_THISCALL:
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
mask = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Check for hidden address in case of return by value
|
||||
if( sysFunc->hostReturnInMemory )
|
||||
mask = !mask;
|
||||
|
||||
paramSize = 0;
|
||||
int spos = 0;
|
||||
int dpos = 2;
|
||||
|
||||
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
|
||||
if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
#ifdef COMPLEX_OBJS_PASSED_BY_REF
|
||||
if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
|
||||
{
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALIGN8) )
|
||||
{
|
||||
if ( (dpos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
if ( (stackPos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the object's memory to the buffer
|
||||
if (descr->parameterTypes[n].GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS)
|
||||
{
|
||||
int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot;
|
||||
|
||||
if ( descr->parameterTypes[n].GetSizeInMemoryDWords() <= ( (VFP_OFFSET + 16) - target) )
|
||||
{
|
||||
memcpy(¶mBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
memset(¶mBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords());
|
||||
target += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
freeFloatSlot = freeDoubleSlot = target;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(¶mBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
|
||||
dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
|
||||
}
|
||||
|
||||
// Delete the original memory
|
||||
engine->CallFree(*(char**)(args+spos));
|
||||
spos++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// Are there any "s" registers available?
|
||||
if ( freeFloatSlot < (VFP_OFFSET + 16) )
|
||||
{
|
||||
if (freeFloatSlot == freeDoubleSlot)
|
||||
freeDoubleSlot += 2;
|
||||
|
||||
paramBuffer[freeFloatSlot + 18] = (asDWORD)1;
|
||||
paramBuffer[freeFloatSlot++] = args[spos++];
|
||||
|
||||
while(freeFloatSlot < (VFP_OFFSET + 16) && paramBuffer[freeFloatSlot + 18] != 0)
|
||||
freeFloatSlot++;
|
||||
}
|
||||
// If not, then store the float arg in the stack area
|
||||
else
|
||||
{
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() )
|
||||
{
|
||||
// Are there any "d" registers available?
|
||||
if ( freeDoubleSlot < (VFP_OFFSET + 15) )
|
||||
{
|
||||
if (freeFloatSlot == freeDoubleSlot)
|
||||
freeFloatSlot += 2;
|
||||
|
||||
// Copy two dwords for the double
|
||||
paramBuffer[freeDoubleSlot + 18] = (asDWORD)1;
|
||||
paramBuffer[freeDoubleSlot + 19] = (asDWORD)1;
|
||||
paramBuffer[freeDoubleSlot++] = args[spos++];
|
||||
paramBuffer[freeDoubleSlot++] = args[spos++];
|
||||
|
||||
while(freeDoubleSlot < (VFP_OFFSET + 15) && paramBuffer[freeDoubleSlot + 18] != 0)
|
||||
freeDoubleSlot += 2;
|
||||
}
|
||||
// If not, then store the double arg in the stack area
|
||||
else
|
||||
{
|
||||
if ( (stackPos & 1) == mask )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize += 2;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the value directly to "r" registers or the stack, checking for alignment
|
||||
if (paramSize < 4)
|
||||
{
|
||||
// Should an alignment be performed?
|
||||
if( (dpos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
|
||||
!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!descr->parameterTypes[n].IsAnyType() )
|
||||
{
|
||||
// 64 bit value align
|
||||
dpos++;
|
||||
paramSize++;
|
||||
}
|
||||
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should an alignment be performed?
|
||||
if( (stackPos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
|
||||
!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
|
||||
!descr->parameterTypes[n].IsAnyType() )
|
||||
{
|
||||
// 64 bit value align
|
||||
stackPos++;
|
||||
stackSize++;
|
||||
}
|
||||
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
|
||||
{
|
||||
if (paramSize < 5)
|
||||
paramBuffer[dpos++] = args[spos++];
|
||||
else
|
||||
paramBuffer[stackPos++] = args[spos++];
|
||||
}
|
||||
}// else...
|
||||
}// Loop
|
||||
|
||||
// Keep a free location at the beginning
|
||||
args = ¶mBuffer[2];
|
||||
}
|
||||
|
||||
paramBuffer[69] = static_cast<asDWORD>(stackSize<<2);
|
||||
|
||||
switch( callConv )
|
||||
{
|
||||
case ICC_CDECL_RETURNINMEM: // fall through
|
||||
case ICC_STDCALL_RETURNINMEM:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer);
|
||||
break;
|
||||
case ICC_CDECL: // fall through
|
||||
case ICC_STDCALL:
|
||||
retQW = armFunc(args, paramSize<<2, func);
|
||||
break;
|
||||
case ICC_THISCALL: // fall through
|
||||
case ICC_CDECL_OBJFIRST:
|
||||
retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_THISCALL_RETURNINMEM:
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJFIRST_RETURNINMEM:
|
||||
retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj);
|
||||
break;
|
||||
case ICC_VIRTUAL_THISCALL_RETURNINMEM:
|
||||
// Get virtual function table from the object pointer
|
||||
vftable = *(asFUNCTION_t**)obj;
|
||||
// On GNUC the address where the return value will be placed should be put in R0
|
||||
retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST:
|
||||
retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj);
|
||||
break;
|
||||
case ICC_CDECL_OBJLAST_RETURNINMEM:
|
||||
retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
|
||||
break;
|
||||
default:
|
||||
context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
|
||||
}
|
||||
|
||||
// On Linux with arm the float and double values are returns in the
|
||||
// floating point registers, s0 and s1. Objects that contain only
|
||||
// float types and are not considered complex are also returned in the
|
||||
// floating point registers.
|
||||
if( sysFunc->hostReturnFloat )
|
||||
{
|
||||
retQW = paramBuffer[VFP_OFFSET];
|
||||
|
||||
if ( sysFunc->hostReturnSize > 1 )
|
||||
retQW = *( (asQWORD*)¶mBuffer[VFP_OFFSET] );
|
||||
}
|
||||
else if ( descr->returnType.IsObject() )
|
||||
{
|
||||
// TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction
|
||||
if ( !descr->returnType.IsObjectHandle() &&
|
||||
!descr->returnType.IsReference() &&
|
||||
!(descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK) &&
|
||||
(descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS) )
|
||||
memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() );
|
||||
}
|
||||
|
||||
return retQW;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // AS_LINUX
|
||||
|
||||
#endif // AS_ARM
|
||||
#endif // AS_MAX_PORTABILITY
|
||||
|
||||
|
|
|
@ -1,253 +1,611 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
The original version of this library can be located at:
|
||||
http://www.angelcode.com/angelscript/
|
||||
|
||||
Andreas Jonsson
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Assembly routines for the ARM call convention
|
||||
Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
Adapted to GNUC by darktemplar216 in September 2009
|
||||
|
||||
Modified by Lasse Oorni for 8-byte stack alignment in May 2012
|
||||
*/
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__)
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
.global armFuncR0R1
|
||||
.global armFuncObjLast
|
||||
.global armFuncR0ObjLast
|
||||
|
||||
armFunc:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
beq nomoreargs
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargs
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
nomoreargs:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
armFuncObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* objlast. might get overwritten */
|
||||
mov r5, r3 /* objlast to temp reg */
|
||||
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
movlt r1, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
armFuncR0ObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r5, [sp,#6*4] /* objlast to temp reg */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
mov r1, r5 /* objlast. might get overwritten */
|
||||
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
armFuncR0:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
armFuncR0R1:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
ldr r1, [sp, #6*4] /* r1 explicitly set too */
|
||||
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #2*4 /* skip the 2 registers already loaded into r2-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0R1:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
#endif
|
||||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2013 Andreas Jonsson
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
The original version of this library can be located at:
|
||||
http://www.angelcode.com/angelscript/
|
||||
|
||||
Andreas Jonsson
|
||||
andreas@angelcode.com
|
||||
*/
|
||||
|
||||
/*
|
||||
Assembly routines for the ARM call convention
|
||||
Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
Adapted to GNUC by darktemplar216 in September 2009
|
||||
|
||||
Modified by Lasse Oorni for 8-byte stack alignment in May 2012
|
||||
|
||||
The assembler routines for Linux were written by Carlos Luna in December 2012
|
||||
*/
|
||||
|
||||
#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM)
|
||||
|
||||
#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID)
|
||||
|
||||
/* iOS, Android, and Marmalade goes here */
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
.global armFuncR0R1
|
||||
.global armFuncObjLast
|
||||
.global armFuncR0ObjLast
|
||||
|
||||
armFunc:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
beq nomoreargs
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargs
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
nomoreargs:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
armFuncObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* objlast. might get overwritten */
|
||||
mov r5, r3 /* objlast to temp reg */
|
||||
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
movlt r1, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
armFuncR0ObjLast:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r5, [sp,#6*4] /* objlast to temp reg */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
mov r1, r5 /* objlast. might get overwritten */
|
||||
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
movlt r2, r5
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
movlt r3, r5
|
||||
blt nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */
|
||||
str r5, [sp,#-8]
|
||||
sub sp, sp, r8 /* adjust frame */
|
||||
cmp r7, #0 /* we may also have come here with no extra params */
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
armFuncR0:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
|
||||
armFuncR0R1:
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
ldr r1, [sp, #6*4] /* r1 explicitly set too */
|
||||
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
sub r7, r7, #2*4 /* skip the 2 registers already loaded into r2-r3 */
|
||||
add r8, r7, #4 /* ensure 8-byte stack alignment */
|
||||
bic r8, r8, #4
|
||||
sub sp, sp, r8
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
nomoreargsarmFuncR0R1:
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
/* The Linux code goes here */
|
||||
|
||||
.global armFunc
|
||||
.global armFuncR0
|
||||
.global armFuncR0R1
|
||||
.global armFuncObjLast
|
||||
.global armFuncR0ObjLast
|
||||
|
||||
armFunc:
|
||||
stmfd sp!, {r4-r8, r10, lr}
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
fldmiad r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargs
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r1, [r6, #4]
|
||||
cmp r7, #12
|
||||
ldrge r2, [r6, #8]
|
||||
cmp r7, #16
|
||||
ldrge r3, [r6, #12]
|
||||
|
||||
stackargs:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargs
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
sub sp, sp, #8
|
||||
bic sp, sp, #7
|
||||
sub r8, r8, sp
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
|
||||
stackargsloop:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargsloop
|
||||
mov sp, r12
|
||||
|
||||
nomoreargs:
|
||||
blx r4
|
||||
fstmiad r10, {d0-d7} /* Copy contents of registers d0-d7 to the address stored in r10 */
|
||||
add sp, sp, r8
|
||||
|
||||
ldmfd sp!, {r4-r8, r10, pc}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------*/
|
||||
|
||||
armFuncObjLast:
|
||||
stmfd sp!, {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* objlast. might get overwritten */
|
||||
mov r5, #0 /* This will hold an offset of #4 only if objlast couldn´t be placed into an "r" register */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
fldmiad r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsFuncObjLast
|
||||
|
||||
mov r5, r3 /* store objlast in r5 temporarily */
|
||||
|
||||
/* Load the first 4 arguments into r0-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r1, [r6,#4]
|
||||
movlt r1, r5
|
||||
cmp r7, #12
|
||||
ldrge r2, [r6,#8]
|
||||
movlt r2, r5
|
||||
cmp r7, #16
|
||||
ldrge r3, [r6,#12]
|
||||
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 */
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
mov r5, #4 /* Set r5 with an offset of #4, so objlast can be loaded into the stack */
|
||||
|
||||
stackargsFuncObjLast:
|
||||
ldr r7, [r6, #268] /* Load stack size into r7 */
|
||||
add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */
|
||||
cmp r7, #0 /* Check for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
sub sp, sp, #8
|
||||
bic sp, sp, #7
|
||||
sub r8, r8, sp
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */
|
||||
|
||||
stackargslooparmFuncObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncObjLast
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncObjLast:
|
||||
blx r4
|
||||
fstmiad r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
add sp, sp, r8
|
||||
|
||||
ldmfd sp!, {r4-r8, r10,r11, pc}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
|
||||
armFuncR0ObjLast:
|
||||
stmfd sp!, {r4-r8, r10, r11, lr}
|
||||
|
||||
ldr r5, [sp,#32] /* objlast to temp reg */
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
mov r1, r5 /* objlast. might get overwritten */
|
||||
mov r5, #0 /* This will hold an offset of #4 or #8 if objlast or one arg couldn´t be placed into an "r" register */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
fldmiad r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsFuncR0ObjLast
|
||||
|
||||
mov r5, r1 /* store objlast in r5 temporarily */
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r2, [r6,#4]
|
||||
movlt r2, r5
|
||||
cmp r7, #12
|
||||
ldrge r3, [r6,#8]
|
||||
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 */
|
||||
ldrge r7, [r6, #12]
|
||||
strge r7, [r6, #8]
|
||||
|
||||
str r5, [r6, #12] /* Put objlast in r6 + 12 */
|
||||
|
||||
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 */
|
||||
|
||||
stackargsFuncR0ObjLast:
|
||||
ldr r7, [r6, #268] /* Load stack size into r7 */
|
||||
add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */
|
||||
cmp r7, #0 /* Check for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0ObjLast
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
sub sp, sp, #8
|
||||
bic sp, sp, #7
|
||||
sub r8, r8, sp
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */
|
||||
|
||||
stackargslooparmFuncR0ObjLast:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0ObjLast
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0ObjLast:
|
||||
blx r4
|
||||
fstmiad r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
add sp, sp, r8
|
||||
|
||||
ldmfd sp!, {r4-r8, r10, r11, pc}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
|
||||
armFuncR0:
|
||||
stmfd sp!, {r4-r8, r10, r11, lr}
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
mov r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
fldmiad r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r0-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsarmFuncR0
|
||||
|
||||
/* Load the first 3 arguments into r1-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r1, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r2, [r6, #4]
|
||||
cmp r7, #12
|
||||
ldrge r3, [r6, #8]
|
||||
cmp r7, #16
|
||||
movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */
|
||||
|
||||
stackargsarmFuncR0:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
add r5, r11 /* Add the offset placed in r11 (could be #0 or #4) */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
sub sp, sp, #8
|
||||
bic sp, sp, #7
|
||||
sub r8, r8, sp
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4) */
|
||||
|
||||
stackargslooparmFuncR0:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0:
|
||||
blx r4
|
||||
fstmiad r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
add sp, sp, r8
|
||||
|
||||
ldmfd sp!, {r4-r8, r10, r11, pc}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
|
||||
armFuncR0R1:
|
||||
stmfd sp!, {r4-r8, r10, r11, lr}
|
||||
|
||||
mov r6, r0 /* arg table */
|
||||
movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */
|
||||
mov r4, r2 /* function address */
|
||||
mov r8, #0
|
||||
mov r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */
|
||||
|
||||
mov r0, r3 /* r0 explicitly set */
|
||||
ldr r1, [sp, #32] /* r1 explicitly set too */
|
||||
|
||||
/* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
|
||||
add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
|
||||
fldmiad r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */
|
||||
|
||||
/* If there are no arguments to set into r2-r3 */
|
||||
/* go check if there are arguments for the stack */
|
||||
beq stackargsarmFuncR0R1
|
||||
|
||||
/* Load the first 2 arguments into r2-r3 */
|
||||
cmp r7, #4
|
||||
ldrge r2, [r6]
|
||||
cmp r7, #8
|
||||
ldrge r3, [r6, #4]
|
||||
cmp r7, #12
|
||||
movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */
|
||||
cmp r7, #16
|
||||
movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
|
||||
ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */
|
||||
strlt r7, [r6, #12]
|
||||
|
||||
stackargsarmFuncR0R1:
|
||||
ldr r5, [r6, #268] /* Load stack size into r5 */
|
||||
add r5, r11 /* Add the offset placed in r11 (could be #0 or #4 or #8) */
|
||||
movs r7, r5 /* Load stack size into r7, checking for 0 args */
|
||||
|
||||
/* If there are no args for the stack, branch */
|
||||
beq nomoreargsarmFuncR0R1
|
||||
|
||||
/* Load the rest of the arguments onto the stack */
|
||||
/* Ensure 8-byte stack alignment */
|
||||
mov r8, sp
|
||||
sub sp, sp, r7
|
||||
sub sp, sp, #8
|
||||
bic sp, sp, #7
|
||||
sub r8, r8, sp
|
||||
mov r12, sp /* copy size != frame size, so store frame start sp */
|
||||
add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */
|
||||
sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */
|
||||
|
||||
stackargslooparmFuncR0R1:
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne stackargslooparmFuncR0R1
|
||||
mov sp, r12
|
||||
|
||||
nomoreargsarmFuncR0R1:
|
||||
blx r4
|
||||
fstmiad r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */
|
||||
add sp, sp, r8
|
||||
|
||||
ldmfd sp!, {r4-r8, r10, r11, pc}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,242 +1,242 @@
|
|||
;
|
||||
; AngelCode Scripting Library
|
||||
; Copyright (c) 2003-2009 Andreas Jonsson
|
||||
;
|
||||
; This software is provided 'as-is', without any express or implied
|
||||
; warranty. In no event will the authors be held liable for any
|
||||
; damages arising from the use of this software.
|
||||
;
|
||||
; Permission is granted to anyone to use this software for any
|
||||
; purpose, including commercial applications, and to alter it and
|
||||
; redistribute it freely, subject to the following restrictions:
|
||||
;
|
||||
; 1. The origin of this software must not be misrepresented; you
|
||||
; must not claim that you wrote the original software. If you use
|
||||
; this software in a product, an acknowledgment in the product
|
||||
; documentation would be appreciated but is not required.
|
||||
;
|
||||
; 2. Altered source versions must be plainly marked as such, and
|
||||
; must not be misrepresented as being the original software.
|
||||
;
|
||||
; 3. This notice may not be removed or altered from any source
|
||||
; distribution.
|
||||
;
|
||||
; The original version of this library can be located at:
|
||||
; http://www.angelcode.com/angelscript/
|
||||
;
|
||||
; Andreas Jonsson
|
||||
; andreas@angelcode.com
|
||||
;
|
||||
|
||||
|
||||
; Assembly routines for the ARM call convention
|
||||
; Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
; MSVC currently doesn't support inline assembly for the ARM platform
|
||||
; so this separate file is needed.
|
||||
|
||||
|
||||
AREA |.rdata|, DATA, READONLY
|
||||
EXPORT |armFunc|
|
||||
EXPORT armFuncR0
|
||||
EXPORT armFuncR0R1
|
||||
EXPORT armFuncObjLast
|
||||
EXPORT armFuncR0ObjLast
|
||||
|
||||
|
||||
AREA |.text|, CODE, ARM
|
||||
|
||||
|armFunc| PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
beq |nomoreargs|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop|
|
||||
|nomoreargs|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncObjLast PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; objlast. might get overwritten
|
||||
str r3, [sp, #-4]! ; objlast again.
|
||||
|
||||
beq |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
ldrlt r1, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncObjLast|
|
||||
|nomoreargs@armFuncObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0ObjLast PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r7, [sp,#6*4]
|
||||
str r7, [sp,#-4]!
|
||||
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp] ; objlast. might get overwritten
|
||||
|
||||
beq |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0ObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0ObjLast|
|
||||
|nomoreargs@armFuncR0ObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0 PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
|
||||
beq |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0|
|
||||
|nomoreargs@armFuncR0|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0R1 PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp, #6*4] ; r1 explicitly set too
|
||||
|
||||
beq |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the first 2 arguments into r2-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #2*4 ; skip the 2 registers already loaded into r2-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0R1|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0R1|
|
||||
|nomoreargs@armFuncR0R1|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
END
|
||||
;
|
||||
; AngelCode Scripting Library
|
||||
; Copyright (c) 2003-2009 Andreas Jonsson
|
||||
;
|
||||
; This software is provided 'as-is', without any express or implied
|
||||
; warranty. In no event will the authors be held liable for any
|
||||
; damages arising from the use of this software.
|
||||
;
|
||||
; Permission is granted to anyone to use this software for any
|
||||
; purpose, including commercial applications, and to alter it and
|
||||
; redistribute it freely, subject to the following restrictions:
|
||||
;
|
||||
; 1. The origin of this software must not be misrepresented; you
|
||||
; must not claim that you wrote the original software. If you use
|
||||
; this software in a product, an acknowledgment in the product
|
||||
; documentation would be appreciated but is not required.
|
||||
;
|
||||
; 2. Altered source versions must be plainly marked as such, and
|
||||
; must not be misrepresented as being the original software.
|
||||
;
|
||||
; 3. This notice may not be removed or altered from any source
|
||||
; distribution.
|
||||
;
|
||||
; The original version of this library can be located at:
|
||||
; http://www.angelcode.com/angelscript/
|
||||
;
|
||||
; Andreas Jonsson
|
||||
; andreas@angelcode.com
|
||||
;
|
||||
|
||||
|
||||
; Assembly routines for the ARM call convention
|
||||
; Written by Fredrik Ehnbom in June 2009
|
||||
|
||||
; MSVC currently doesn't support inline assembly for the ARM platform
|
||||
; so this separate file is needed.
|
||||
|
||||
|
||||
AREA |.rdata|, DATA, READONLY
|
||||
EXPORT |armFunc|
|
||||
EXPORT armFuncR0
|
||||
EXPORT armFuncR0R1
|
||||
EXPORT armFuncObjLast
|
||||
EXPORT armFuncR0ObjLast
|
||||
|
||||
|
||||
AREA |.text|, CODE, ARM
|
||||
|
||||
|armFunc| PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
beq |nomoreargs|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop|
|
||||
|nomoreargs|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncObjLast PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; objlast. might get overwritten
|
||||
str r3, [sp, #-4]! ; objlast again.
|
||||
|
||||
beq |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the first 4 arguments into r0-r3
|
||||
cmp r7, #4
|
||||
ldrge r0, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r1, [r6],#4
|
||||
ldrlt r1, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #4*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncObjLast|
|
||||
|nomoreargs@armFuncObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0ObjLast PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
ldr r7, [sp,#6*4]
|
||||
str r7, [sp,#-4]!
|
||||
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp] ; objlast. might get overwritten
|
||||
|
||||
beq |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
ldrlt r2, [sp]
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ldrlt r3, [sp]
|
||||
ble |nomoreargs@armFuncR0ObjLast|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0ObjLast|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0ObjLast|
|
||||
|nomoreargs@armFuncR0ObjLast|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
add sp, sp, #4
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0 PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
|
||||
beq |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the first 3 arguments into r1-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r1, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #3*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0|
|
||||
|nomoreargs@armFuncR0|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
armFuncR0R1 PROC
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
mov r6, r0 ; arg table
|
||||
movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments)
|
||||
mov r4, r2 ; function address
|
||||
mov r8, #0
|
||||
|
||||
mov r0, r3 ; r0 explicitly set
|
||||
ldr r1, [sp, #6*4] ; r1 explicitly set too
|
||||
|
||||
beq |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the first 2 arguments into r2-r3
|
||||
cmp r7, #1*4
|
||||
ldrge r2, [r6],#4
|
||||
cmp r7, #2*4
|
||||
ldrge r3, [r6],#4
|
||||
ble |nomoreargs@armFuncR0R1|
|
||||
|
||||
; Load the rest of the arguments onto the stack
|
||||
sub r7, r7, #2*4 ; skip the 2 registers already loaded into r2-r3
|
||||
sub sp, sp, r7
|
||||
mov r8, r7
|
||||
|stackargsloop@armFuncR0R1|
|
||||
ldr r5, [r6], #4
|
||||
str r5, [sp], #4
|
||||
subs r7, r7, #4
|
||||
bne |stackargsloop@armFuncR0R1|
|
||||
|nomoreargs@armFuncR0R1|
|
||||
sub sp, sp, r8
|
||||
blx r4
|
||||
add sp, sp, r8
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
ENDP
|
||||
|
||||
END
|
||||
|
|
|
@ -59,7 +59,8 @@ typedef asQWORD ( *funcptr_t )( void );
|
|||
|
||||
static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, int cnt, funcptr_t func, asQWORD &retQW2, bool returnFloat)
|
||||
{
|
||||
asQWORD retQW1 = 0;
|
||||
// Need to flag the variable as volatile so the compiler doesn't optimize out the variable
|
||||
volatile asQWORD retQW1 = 0;
|
||||
|
||||
// Reference: http://www.x86-64.org/documentation/abi.pdf
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -45,20 +45,26 @@
|
|||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
static asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func)
|
||||
static asQWORD __attribute__((noinline)) CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func)
|
||||
{
|
||||
asQWORD ret = 0;
|
||||
volatile asQWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"# Move function param to non-scratch register\n"
|
||||
"mov %4,%%r14 # r14 = function\n" // Copy func into r14
|
||||
"# Move the parameters into registers before the rsp is modified\n"
|
||||
"mov %1, %%r10\n" // r10 = args
|
||||
"mov %2, %%r11\n" // r11 = floatArgs
|
||||
"xor %%r12, %%r12\n"
|
||||
"mov %3, %%r12d\n"
|
||||
"mov %4, %%r14\n" // r14 = func
|
||||
|
||||
"# Store the stack pointer in r15 since it is guaranteed not to change over a function call\n"
|
||||
"mov %%rsp, %%r15\n"
|
||||
|
||||
"# Allocate space on the stack for the arguments\n"
|
||||
"# Make room for at least 4 arguments even if there are less. When\n"
|
||||
"# the compiler does optimizations for speed it may use these for \n"
|
||||
"# temporary storage.\n"
|
||||
"xor %%rdi, %%rdi\n"
|
||||
"mov %3, %%edi\n"
|
||||
"mov %%r12, %%rdi\n"
|
||||
"add $32,%%edi\n"
|
||||
|
||||
"# Make sure the stack pointer is 16byte aligned so the\n"
|
||||
|
@ -71,21 +77,16 @@ static asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, const int
|
|||
"sub %%rdi,%%rsp\n"
|
||||
|
||||
"# Jump straight to calling the function if no parameters\n"
|
||||
"cmp $0,%3 # Compare paramSize with 0\n"
|
||||
"cmp $0,%%r12 # Compare paramSize with 0\n"
|
||||
"je callfunc # Jump to call funtion if (paramSize == 0)\n"
|
||||
|
||||
"# Move params to non-scratch registers\n"
|
||||
"mov %1,%%rsi # rsi = pArgs\n" // Copy args into rsi
|
||||
"mov %2,%%r11 # r11 = pFloatArgs (can be NULL)\n" // Copy floatArgs into r11
|
||||
"mov %3,%%r12d # r12 = paramSize\n" // Copy paramSize into r12
|
||||
|
||||
"# Copy arguments from script stack to application stack\n"
|
||||
"# Order is (first to last):\n"
|
||||
"# rcx, rdx, r8, r9 & everything else goes on stack\n"
|
||||
"movq (%%rsi),%%rcx\n"
|
||||
"movq 8(%%rsi),%%rdx\n"
|
||||
"movq 16(%%rsi),%%r8\n"
|
||||
"movq 24(%%rsi),%%r9\n"
|
||||
"movq (%%r10),%%rcx\n"
|
||||
"movq 8(%%r10),%%rdx\n"
|
||||
"movq 16(%%r10),%%r8\n"
|
||||
"movq 24(%%r10),%%r9\n"
|
||||
|
||||
"# Negate the 4 params from the size to be copied\n"
|
||||
"sub $32,%%r12d\n"
|
||||
|
@ -94,15 +95,15 @@ static asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, const int
|
|||
|
||||
"# Now copy all remaining params onto stack allowing space for first four\n"
|
||||
"# params to be flushed back to the stack if required by the callee.\n"
|
||||
"add $32,%%rsi # Position input pointer 4 args ahead\n"
|
||||
"add $32,%%r10 # Position input pointer 4 args ahead\n"
|
||||
"mov %%rsp,%%r13 # Put the stack pointer into r13\n"
|
||||
"add $32,%%r13 # Leave space for first 4 args on stack\n"
|
||||
|
||||
"copyoverflow:\n"
|
||||
"movq (%%rsi),%%r15 # Read param from source stack into r15\n"
|
||||
"movq %%r15,(%%r13) # Copy param to real stack\n"
|
||||
"movq (%%r10),%%rdi # Read param from source stack into rdi\n"
|
||||
"movq %%rdi,(%%r13) # Copy param to real stack\n"
|
||||
"add $8,%%r13 # Move virtual stack pointer\n"
|
||||
"add $8,%%rsi # Move source stack pointer\n"
|
||||
"add $8,%%r10 # Move source stack pointer\n"
|
||||
"sub $8,%%r12d # Decrement remaining count\n"
|
||||
"jnz copyoverflow # Continue if more params\n"
|
||||
|
||||
|
@ -118,12 +119,16 @@ static asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, const int
|
|||
|
||||
"callfunc:\n"
|
||||
"call *%%r14\n"
|
||||
"lea %0, %%rbx\n" // Load the address of the ret variable into rbx
|
||||
"movq %%rax,(%%rbx)\n" // Copy the returned value into the ret variable
|
||||
|
||||
: // no output
|
||||
"# restore stack pointer\n"
|
||||
"mov %%r15, %%rsp\n"
|
||||
|
||||
"lea %0, %%rbx\n" // Load the address of the ret variable into rbx
|
||||
"movq %%rax,(%%rbx)\n" // Copy the returned value into the ret variable
|
||||
|
||||
: // no output
|
||||
: "m" (ret), "r" (args), "r" (floatArgs), "r" (paramSize), "r" (func)
|
||||
: "rdi", "rsi", "rsp", "rbx", "r11", "%r12", "r13", "r14", "r15"
|
||||
: "rdi", "rsi", "rsp", "rbx", "r10", "r11", "%r12", "r13", "r14", "r15"
|
||||
);
|
||||
|
||||
return ret;
|
||||
|
@ -131,41 +136,31 @@ static asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, const int
|
|||
|
||||
static asDWORD GetReturnedFloat()
|
||||
{
|
||||
float retval = 0.0f;
|
||||
asDWORD ret = 0;
|
||||
volatile asDWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"lea %0, %%rax\n"
|
||||
"movss %%xmm0, (%%rax)"
|
||||
: /* no output */
|
||||
: "m" (retval)
|
||||
: "m" (ret)
|
||||
: "%rax"
|
||||
);
|
||||
|
||||
// We need to avoid implicit conversions from float to unsigned - we need
|
||||
// a bit-wise-correct-and-complete copy of the value
|
||||
memcpy( &ret, &retval, sizeof( ret ) );
|
||||
|
||||
return ( asDWORD )ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static asQWORD GetReturnedDouble()
|
||||
{
|
||||
double retval = 0.0f;
|
||||
asQWORD ret = 0;
|
||||
volatile asQWORD ret = 0;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"lea %0, %%rax\n"
|
||||
"movlpd %%xmm0, (%%rax)"
|
||||
: /* no optput */
|
||||
: "m" (retval)
|
||||
: "m" (ret)
|
||||
: "%rax"
|
||||
);
|
||||
|
||||
// We need to avoid implicit conversions from double to unsigned long long - we need
|
||||
// a bit-wise-correct-and-complete copy of the value
|
||||
memcpy( &ret, &retval, sizeof( ret ) );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -195,7 +190,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
|
||||
if( callConv == ICC_THISCALL ||
|
||||
callConv == ICC_THISCALL_RETURNINMEM ||
|
||||
callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL ||
|
||||
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM )
|
||||
{
|
||||
// Add the object pointer as the first parameter
|
||||
|
@ -276,7 +271,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
// though this is only done for first 4 arguments, the rest are placed on the stack
|
||||
if( paramSize < 4 && descr->parameterTypes[n].IsFloatType() )
|
||||
floatArgBuffer[dpos] = args[spos];
|
||||
|
||||
|
||||
dpos++;
|
||||
spos++;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -237,7 +237,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -348,7 +348,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -453,7 +453,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -558,7 +558,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -675,7 +675,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -787,7 +787,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -903,7 +903,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -1001,7 +1001,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
@ -1122,7 +1122,7 @@ endcopy:
|
|||
|
||||
asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
|
||||
{
|
||||
volatile asQWORD retQW;
|
||||
volatile asQWORD retQW = 0;
|
||||
|
||||
#if defined ASM_INTEL
|
||||
|
||||
|
|
|
@ -127,6 +127,10 @@ int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *s
|
|||
// Insert a JitEntry at the start of the function for JIT compilers
|
||||
byteCode.InstrPTR(asBC_JitEntry, 0);
|
||||
|
||||
// Add a variable scope that might be needed to declare dummy variables
|
||||
// in case the member initialization refers to undefined symbols.
|
||||
AddVariableScope();
|
||||
|
||||
// Initialize the class members that have no explicit expression first. This will allow the
|
||||
// base class' constructor to access these members without worry they will be uninitialized.
|
||||
// This can happen if the base class' constructor calls a method that is overridden by the derived class
|
||||
|
@ -286,6 +290,7 @@ void asCCompiler::FinalizeFunction()
|
|||
}
|
||||
|
||||
// Copy byte code to the function
|
||||
asASSERT( outFunc->byteCode.GetLength() == 0 );
|
||||
outFunc->byteCode.SetLength(byteCode.GetSize());
|
||||
byteCode.Output(outFunc->byteCode.AddressOf());
|
||||
outFunc->AddReferences();
|
||||
|
@ -985,6 +990,7 @@ void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableSc
|
|||
*hasReturn = false;
|
||||
bool isFinished = false;
|
||||
bool hasUnreachableCode = false;
|
||||
bool hasReturnBefore = false;
|
||||
|
||||
if( ownVariableScope )
|
||||
{
|
||||
|
@ -1001,8 +1007,11 @@ void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableSc
|
|||
if( node->nodeType != snExpressionStatement || node->firstChild )
|
||||
{
|
||||
hasUnreachableCode = true;
|
||||
Error(TXT_UNREACHABLE_CODE, node);
|
||||
Warning(TXT_UNREACHABLE_CODE, node);
|
||||
}
|
||||
|
||||
if( *hasReturn )
|
||||
hasReturnBefore = true;
|
||||
}
|
||||
|
||||
if( node->nodeType == snBreak || node->nodeType == snContinue )
|
||||
|
@ -1014,6 +1023,10 @@ void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableSc
|
|||
else
|
||||
CompileStatement(node, hasReturn, &statement);
|
||||
|
||||
// Ignore missing returns in unreachable code paths
|
||||
if( !(*hasReturn) && hasReturnBefore )
|
||||
*hasReturn = true;
|
||||
|
||||
LineInstr(bc, node->tokenPos);
|
||||
bc->AddCode(&statement);
|
||||
|
||||
|
@ -1687,6 +1700,20 @@ int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext
|
|||
isCompilingDefaultArg = true;
|
||||
asSExprContext expr(engine);
|
||||
r = CompileExpression(arg, &expr);
|
||||
|
||||
// Make sure the expression can be implicitly converted to the parameter type
|
||||
if( r >= 0 )
|
||||
{
|
||||
asCArray<int> funcs;
|
||||
funcs.PushLast(func->id);
|
||||
asCArray<asSOverloadCandidate> matches;
|
||||
if( MatchArgument(funcs, matches, &expr.type, n) == 0 )
|
||||
{
|
||||
Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
|
||||
r = -1;
|
||||
}
|
||||
}
|
||||
|
||||
isCompilingDefaultArg = false;
|
||||
|
||||
script = origScript;
|
||||
|
@ -2029,7 +2056,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|||
int r = asSUCCESS;
|
||||
|
||||
// Add the default values for arguments not explicitly supplied
|
||||
asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
||||
r = CompileDefaultArgs(node, args, func);
|
||||
|
||||
|
@ -2055,7 +2082,6 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|||
ctx.bc.InstrSHORT(asBC_PSF, 0);
|
||||
ctx.bc.Instr(asBC_RDSPtr);
|
||||
ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
||||
ctx.bc.Instr(asBC_PopRPtr);
|
||||
}
|
||||
ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
|
||||
ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
|
||||
|
@ -2553,7 +2579,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
|
|||
CompileAssignment(snode->firstChild, &expr);
|
||||
|
||||
// Verify that the expression is a primitive type
|
||||
if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
|
||||
if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
|
||||
{
|
||||
Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
|
||||
return;
|
||||
|
@ -2564,7 +2590,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
|
|||
// TODO: Need to support 64bit integers
|
||||
// Convert the expression to a 32bit variable
|
||||
asCDataType to;
|
||||
if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
|
||||
if( expr.type.dataType.IsIntegerType() )
|
||||
to.SetTokenType(ttInt);
|
||||
else if( expr.type.dataType.IsUnsignedType() )
|
||||
to.SetTokenType(ttUInt);
|
||||
|
@ -2608,7 +2634,7 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
|
|||
Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
|
||||
|
||||
// Verify that the result is an integral number
|
||||
if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
|
||||
if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
|
||||
Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
|
||||
|
||||
ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
|
||||
|
@ -2832,7 +2858,7 @@ void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
|
|||
if( !hasUnreachableCode && (hasReturn || isFinished) )
|
||||
{
|
||||
hasUnreachableCode = true;
|
||||
Error(TXT_UNREACHABLE_CODE, node);
|
||||
Warning(TXT_UNREACHABLE_CODE, node);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3391,7 +3417,7 @@ void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ct
|
|||
// If the expression was holding off on releasing a
|
||||
// previously used object, we need to release it now
|
||||
if( ctx->type.isTemporary )
|
||||
ReleaseTemporaryVariable(ctx->type, &ctx->bc);
|
||||
ReleaseTemporaryVariable(ctx->type, &ctx->bc);
|
||||
}
|
||||
|
||||
// Push the reference to the temporary variable on the stack
|
||||
|
@ -4428,11 +4454,11 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
asUINT cost = asCC_NO_CONV;
|
||||
if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
|
||||
cost = asCC_INT_FLOAT_CONV;
|
||||
else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
|
||||
else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
|
||||
cost = asCC_INT_FLOAT_CONV;
|
||||
else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
|
||||
cost = asCC_SIGNED_CONV;
|
||||
else if( to.IsIntegerType() && (ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
|
||||
else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
|
||||
cost = asCC_SIGNED_CONV;
|
||||
else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
|
||||
cost = asCC_PRIMITIVE_SIZE_CONV;
|
||||
|
@ -4473,12 +4499,11 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
}
|
||||
}
|
||||
|
||||
if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
|
||||
if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
|
||||
(to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
|
||||
{
|
||||
if( ctx->type.dataType.IsIntegerType() ||
|
||||
ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsEnumType() )
|
||||
ctx->type.dataType.IsUnsignedType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
|
@ -4524,8 +4549,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
if( ctx->type.dataType.IsIntegerType() ||
|
||||
ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsEnumType() )
|
||||
ctx->type.dataType.IsUnsignedType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
|
@ -4563,8 +4587,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
if( ctx->type.dataType.IsIntegerType() ||
|
||||
ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsEnumType() )
|
||||
ctx->type.dataType.IsUnsignedType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
|
@ -4610,8 +4633,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
if( ctx->type.dataType.IsIntegerType() ||
|
||||
ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsEnumType() )
|
||||
ctx->type.dataType.IsUnsignedType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
|
@ -4648,7 +4670,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
}
|
||||
else if( to.IsFloatType() )
|
||||
{
|
||||
if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
ConvertToTempVariable(ctx);
|
||||
ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
|
||||
|
@ -4689,7 +4711,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
}
|
||||
else if( to.IsDoubleType() )
|
||||
{
|
||||
if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
ConvertToTempVariable(ctx);
|
||||
ReleaseTemporaryVariable(ctx->type, &ctx->bc);
|
||||
|
@ -4731,12 +4753,11 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|||
}
|
||||
else
|
||||
{
|
||||
if( (to.IsIntegerType() || to.IsUnsignedType() ||
|
||||
if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
|
||||
to.IsFloatType() || to.IsDoubleType() ||
|
||||
(to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
|
||||
(ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
|
||||
ctx->type.dataType.IsEnumType()) )
|
||||
ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
|
||||
{
|
||||
ctx->type.dataType.SetTokenType(to.GetTokenType());
|
||||
ctx->type.dataType.SetObjectType(to.GetObjectType());
|
||||
|
@ -5470,11 +5491,106 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDat
|
|||
return cost;
|
||||
}
|
||||
|
||||
asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, bool /*allowObjectConstruct*/)
|
||||
asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
|
||||
{
|
||||
// TODO: This function should call the constructor/factory that has been marked as available
|
||||
// for implicit conversions. The code will likely be similar to CallCopyConstructor()
|
||||
return asCC_NO_CONV;
|
||||
// Reference types currently don't allow implicit conversion from primitive to object
|
||||
// TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
|
||||
asCObjectType *objType = to.GetObjectType();
|
||||
asASSERT( objType );
|
||||
if( !objType || (objType->flags & asOBJ_REF) )
|
||||
return asCC_NO_CONV;
|
||||
|
||||
// For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
|
||||
asCArray<int> funcs;
|
||||
for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
|
||||
{
|
||||
asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
|
||||
if( func->parameterTypes.GetLength() == 1 &&
|
||||
func->parameterTypes[0].IsPrimitive() &&
|
||||
!(func->inOutFlags[0] & asTM_OUTREF) )
|
||||
{
|
||||
funcs.PushLast(func->id);
|
||||
}
|
||||
}
|
||||
|
||||
if( funcs.GetLength() == 0 )
|
||||
return asCC_NO_CONV;
|
||||
|
||||
// Check if it is possible to choose a best match
|
||||
asSExprContext arg(engine);
|
||||
arg.type = ctx->type;
|
||||
asCArray<asSExprContext*> args;
|
||||
args.PushLast(&arg);
|
||||
asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, objType, false, true, false);
|
||||
if( funcs.GetLength() != 1 )
|
||||
return asCC_NO_CONV;
|
||||
|
||||
if( !generateCode )
|
||||
{
|
||||
ctx->type.Set(to);
|
||||
return cost;
|
||||
}
|
||||
|
||||
// TODO: clean up: This part is similar to CompileCosntructCall(). It should be put in a common function
|
||||
|
||||
bool onHeap = true;
|
||||
|
||||
// Value types and script types are allocated through the constructor
|
||||
asCTypeInfo tempObj;
|
||||
tempObj.dataType = to;
|
||||
tempObj.stackOffset = (short)AllocateVariable(to, true);
|
||||
tempObj.dataType.MakeReference(true);
|
||||
tempObj.isTemporary = true;
|
||||
tempObj.isVariable = true;
|
||||
|
||||
onHeap = IsVariableOnHeap(tempObj.stackOffset);
|
||||
|
||||
// Push the address of the object on the stack
|
||||
if( onHeap )
|
||||
ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
|
||||
|
||||
PrepareFunctionCall(funcs[0], &ctx->bc, args);
|
||||
MoveArgsToStack(funcs[0], &ctx->bc, args, false);
|
||||
|
||||
if( !(objType->flags & asOBJ_REF) )
|
||||
{
|
||||
// If the object is allocated on the stack, then call the constructor as a normal function
|
||||
if( onHeap )
|
||||
{
|
||||
int offset = 0;
|
||||
asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
|
||||
for( asUINT n = 0; n < args.GetLength(); n++ )
|
||||
offset += descr->parameterTypes[n].GetSizeOnStackDWords();
|
||||
|
||||
ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
|
||||
}
|
||||
else
|
||||
ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
|
||||
|
||||
PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
|
||||
|
||||
// Add tag that the object has been initialized
|
||||
ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
|
||||
|
||||
// The constructor doesn't return anything,
|
||||
// so we have to manually inform the type of
|
||||
// the return value
|
||||
ctx->type = tempObj;
|
||||
if( !onHeap )
|
||||
ctx->type.dataType.MakeReference(false);
|
||||
|
||||
// Push the address of the object on the stack again
|
||||
ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( objType->flags & asOBJ_SCOPED );
|
||||
|
||||
// Call the factory to create the reference type
|
||||
PerformFunctionCall(funcs[0], ctx, false, &args);
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
|
||||
|
@ -5491,14 +5607,13 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
// References cannot be constants
|
||||
if( from->type.dataType.IsReference() ) return;
|
||||
|
||||
if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
|
||||
if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
|
||||
(to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
|
||||
{
|
||||
if( from->type.dataType.IsFloatType() ||
|
||||
from->type.dataType.IsDoubleType() ||
|
||||
from->type.dataType.IsUnsignedType() ||
|
||||
from->type.dataType.IsIntegerType() ||
|
||||
from->type.dataType.IsEnumType() )
|
||||
from->type.dataType.IsIntegerType() )
|
||||
{
|
||||
// Transform the value
|
||||
// Float constants can be implicitly converted to int
|
||||
|
@ -5555,10 +5670,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
|
||||
from->type.intValue = (short)from->type.wordValue;
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
// Enum type is already an integer type
|
||||
}
|
||||
|
||||
// Set the resulting type
|
||||
if( to.IsEnumType() )
|
||||
|
@ -5640,11 +5751,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
|
||||
from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
from->type.qwordValue = from->type.intValue;
|
||||
from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
|
||||
}
|
||||
else if( from->type.dataType.IsIntegerType() )
|
||||
{
|
||||
// Convert to 64bit
|
||||
|
@ -5696,13 +5802,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
// Try once more, in case of a smaller type
|
||||
ImplicitConversionConstant(from, to, node, convType);
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
|
||||
|
||||
// Try once more, in case of a smaller type
|
||||
ImplicitConversionConstant(from, to, node, convType);
|
||||
}
|
||||
else if( from->type.dataType.IsIntegerType() )
|
||||
{
|
||||
// Verify that it is possible to convert to unsigned without loosing negative
|
||||
|
@ -5794,11 +5893,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
|
||||
from->type.qwordValue = uic;
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
from->type.qwordValue = (asINT64)from->type.intValue;
|
||||
from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
|
||||
}
|
||||
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
// Convert to 64bit
|
||||
|
@ -5858,18 +5952,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
|
||||
from->type.floatValue = fc;
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
float fc = float(from->type.intValue);
|
||||
|
||||
if( int(fc) != from->type.intValue )
|
||||
{
|
||||
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
|
||||
}
|
||||
|
||||
from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
|
||||
from->type.floatValue = fc;
|
||||
}
|
||||
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
// Must properly convert value in case the from value is smaller
|
||||
|
@ -5952,18 +6034,6 @@ void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCData
|
|||
from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
|
||||
from->type.doubleValue = fc;
|
||||
}
|
||||
else if( from->type.dataType.IsEnumType() )
|
||||
{
|
||||
double fc = double(from->type.intValue);
|
||||
|
||||
if( int(fc) != from->type.intValue )
|
||||
{
|
||||
if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
|
||||
}
|
||||
|
||||
from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
|
||||
from->type.doubleValue = fc;
|
||||
}
|
||||
else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
|
||||
{
|
||||
// Must properly convert value in case the from value is smaller
|
||||
|
@ -6909,27 +6979,45 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
|
|||
}
|
||||
|
||||
ctx->type.Set(prop->type);
|
||||
ctx->type.dataType.MakeReference(true);
|
||||
ctx->type.isLValue = true;
|
||||
|
||||
if( ctx->type.dataType.IsPrimitive() )
|
||||
{
|
||||
// Load the address of the variable into the register
|
||||
ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
|
||||
|
||||
ctx->type.dataType.MakeReference(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Push the address of the variable on the stack
|
||||
ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
|
||||
|
||||
// If the object is a value type, then we must validate the existance,
|
||||
// as it could potentially be accessed before it is initialized.
|
||||
if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
|
||||
// If the object is a value type or a non-handle variable to a reference type,
|
||||
// then we must validate the existance as it could potentially be accessed
|
||||
// before it is initialized.
|
||||
if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
|
||||
!ctx->type.dataType.IsObjectHandle() )
|
||||
{
|
||||
// TODO: runtime optimize: This is not necessary for application registered properties
|
||||
ctx->bc.Instr(asBC_ChkRefS);
|
||||
}
|
||||
|
||||
// If the address pushed on the stack is to a value type or an object
|
||||
// handle, then mark the expression as a reference. Addresses to a reference
|
||||
// type aren't marked as references to get correct behaviour
|
||||
if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
|
||||
ctx->type.dataType.IsObjectHandle() )
|
||||
{
|
||||
ctx->type.dataType.MakeReference(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
|
||||
|
||||
// It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
|
||||
ctx->bc.Instr(asBC_RDSPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7107,16 +7195,23 @@ int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx
|
|||
|
||||
// Do we need 64 bits?
|
||||
if( val>>32 )
|
||||
ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
|
||||
{
|
||||
// Only if the value uses the last bit of a 64bit word do we consider the number unsigned
|
||||
if( val>>63 )
|
||||
ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
|
||||
else
|
||||
ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
|
||||
}
|
||||
else
|
||||
ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
|
||||
ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
|
||||
}
|
||||
else if( vnode->tokenType == ttBitsConstant )
|
||||
{
|
||||
asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
|
||||
asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
|
||||
|
||||
// Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
|
||||
// TODO: Check for overflow
|
||||
asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
|
||||
asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
|
||||
|
||||
// Do we need 64 bits?
|
||||
if( val>>32 )
|
||||
|
@ -7504,12 +7599,16 @@ void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *no
|
|||
}
|
||||
}
|
||||
|
||||
// Remove last line break and the line after that if it only contains whitespaces
|
||||
// Remove the line after the last line break if it only contains whitespaces
|
||||
int end;
|
||||
for( end = (int)str.GetLength() - 1; end >= 0; end-- )
|
||||
{
|
||||
if( str[end] == '\n' )
|
||||
{
|
||||
// Don't remove the last line break
|
||||
end++;
|
||||
break;
|
||||
}
|
||||
|
||||
if( str[end] != ' ' &&
|
||||
str[end] != '\t' &&
|
||||
|
@ -7942,7 +8041,7 @@ void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
|
|||
int r = asSUCCESS;
|
||||
|
||||
// Add the default values for arguments not explicitly supplied
|
||||
asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
||||
r = CompileDefaultArgs(node, args, func);
|
||||
|
||||
|
@ -8175,7 +8274,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
|
|||
int r = asSUCCESS;
|
||||
|
||||
// Add the default values for arguments not explicitly supplied
|
||||
asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
|
||||
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
||||
r = CompileDefaultArgs(node, args, func);
|
||||
|
||||
|
@ -8186,9 +8285,9 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
|
|||
// by first storing the function pointer in a local variable (if it isn't already in one)
|
||||
if( r == asSUCCESS )
|
||||
{
|
||||
if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
|
||||
if( func->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
if( objectType )
|
||||
if( objectType && funcPtr.property_get <= 0 )
|
||||
{
|
||||
Dereference(ctx, true); // Dereference the object pointer to access the member
|
||||
|
||||
|
@ -8196,18 +8295,32 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
|
|||
objectType = 0;
|
||||
}
|
||||
|
||||
Dereference(&funcPtr, true);
|
||||
ConvertToVariable(&funcPtr);
|
||||
ctx->bc.AddCode(&funcPtr.bc);
|
||||
if( !funcPtr.type.isTemporary )
|
||||
ctx->bc.Instr(asBC_PopPtr);
|
||||
if( funcPtr.property_get > 0 )
|
||||
{
|
||||
ProcessPropertyGetAccessor(&funcPtr, node);
|
||||
Dereference(&funcPtr, true);
|
||||
|
||||
// The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
|
||||
funcPtr.bc.Instr(asBC_PopPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Dereference(&funcPtr, true);
|
||||
ConvertToVariable(&funcPtr);
|
||||
|
||||
// The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
|
||||
if( !funcPtr.type.isTemporary )
|
||||
funcPtr.bc.Instr(asBC_PopPtr);
|
||||
}
|
||||
|
||||
MergeExprBytecodeAndType(ctx, &funcPtr);
|
||||
}
|
||||
|
||||
MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
|
||||
|
||||
// If the function pointer was copied to a local variable for the call, then
|
||||
// release it again (temporary local variable)
|
||||
if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
|
||||
if( (funcs[0] & FUNC_IMPORTED) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
|
||||
{
|
||||
ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
|
||||
}
|
||||
|
@ -8399,7 +8512,6 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
|
|||
// Make sure the type is a math type
|
||||
if( !(ctx->type.dataType.IsIntegerType() ||
|
||||
ctx->type.dataType.IsUnsignedType() ||
|
||||
ctx->type.dataType.IsEnumType() ||
|
||||
ctx->type.dataType.IsFloatType() ||
|
||||
ctx->type.dataType.IsDoubleType() ) )
|
||||
{
|
||||
|
@ -8414,7 +8526,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
|
|||
|
||||
// TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
|
||||
|
||||
if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
|
||||
if( ctx->type.dataType.IsUnsignedType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
|
||||
to = asCDataType::CreatePrimitive(ttInt8, false);
|
||||
|
@ -8509,7 +8621,7 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx
|
|||
|
||||
asCDataType to = ctx->type.dataType;
|
||||
|
||||
if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
|
||||
if( ctx->type.dataType.IsIntegerType() )
|
||||
{
|
||||
if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
|
||||
to = asCDataType::CreatePrimitive(ttUInt8, false);
|
||||
|
@ -9513,7 +9625,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
|
|||
int r = asSUCCESS;
|
||||
|
||||
// Add the default values for arguments not explicitly supplied
|
||||
asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
||||
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
||||
r = CompileDefaultArgs(node, args, func);
|
||||
|
||||
|
@ -10287,26 +10399,41 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
{
|
||||
// TODO: If a constant is only using 32bits, then a 32bit operation is preferred
|
||||
|
||||
// TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
|
||||
|
||||
// Implicitly convert the operands to a number type
|
||||
asCDataType to;
|
||||
if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
|
||||
|
||||
// If either operand is a non-primitive then use the primitive type
|
||||
if( !lctx->type.dataType.IsPrimitive() )
|
||||
to.SetTokenType(rctx->type.dataType.GetTokenType());
|
||||
else if( !rctx->type.dataType.IsPrimitive() )
|
||||
to.SetTokenType(lctx->type.dataType.GetTokenType());
|
||||
else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
|
||||
to.SetTokenType(ttDouble);
|
||||
else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
|
||||
to.SetTokenType(ttFloat);
|
||||
else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
|
||||
// Convert to int64 if both are signed or if one is non-constant and signed
|
||||
if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
|
||||
(lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
|
||||
(rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
|
||||
to.SetTokenType(ttInt64);
|
||||
else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
|
||||
else
|
||||
to.SetTokenType(ttUInt64);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
|
||||
lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
|
||||
// Convert to int32 if both are signed or if one is non-constant and signed
|
||||
if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
|
||||
(lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
|
||||
(rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
|
||||
to.SetTokenType(ttInt);
|
||||
else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
|
||||
to.SetTokenType(ttUInt);
|
||||
else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
|
||||
to.SetTokenType(ttBool);
|
||||
}
|
||||
|
||||
// If doing an operation with double constant and float variable, the constant should be converted to float
|
||||
|
@ -10324,8 +10451,11 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
if( rctx->type.dataType.IsReference() )
|
||||
ConvertToVariable(rctx);
|
||||
|
||||
ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
|
||||
ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
|
||||
if( to.IsPrimitive() )
|
||||
{
|
||||
ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
|
||||
ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
|
||||
}
|
||||
reservedVariables.SetLength(l);
|
||||
|
||||
// Verify that the conversion was successful
|
||||
|
@ -10497,7 +10627,8 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
v = lctx->type.intValue * rctx->type.intValue;
|
||||
else if( op == ttSlash )
|
||||
{
|
||||
if( rctx->type.intValue == 0 )
|
||||
// TODO: Should probably report an error, rather than silently convert the value to 0
|
||||
if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
|
||||
v = 0;
|
||||
else
|
||||
if( lctx->type.dataType.IsIntegerType() )
|
||||
|
@ -10507,7 +10638,8 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
}
|
||||
else if( op == ttPercent )
|
||||
{
|
||||
if( rctx->type.intValue == 0 )
|
||||
// TODO: Should probably report an error, rather than silently convert the value to 0
|
||||
if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
|
||||
v = 0;
|
||||
else
|
||||
if( lctx->type.dataType.IsIntegerType() )
|
||||
|
@ -10533,7 +10665,8 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
v = lctx->type.qwordValue * rctx->type.qwordValue;
|
||||
else if( op == ttSlash )
|
||||
{
|
||||
if( rctx->type.qwordValue == 0 )
|
||||
// TODO: Should probably report an error, rather than silently convert the value to 0
|
||||
if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
|
||||
v = 0;
|
||||
else
|
||||
if( lctx->type.dataType.IsIntegerType() )
|
||||
|
@ -10543,7 +10676,8 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|||
}
|
||||
else if( op == ttPercent )
|
||||
{
|
||||
if( rctx->type.qwordValue == 0 )
|
||||
// TODO: Should probably report an error, rather than silently convert the value to 0
|
||||
if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
|
||||
v = 0;
|
||||
else
|
||||
if( lctx->type.dataType.IsIntegerType() )
|
||||
|
@ -10888,21 +11022,32 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
|
|||
|
||||
// Implicitly convert the operands to a number type
|
||||
asCDataType to;
|
||||
if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
|
||||
|
||||
// If either operand is a non-primitive then use the primitive type
|
||||
if( !lctx->type.dataType.IsPrimitive() )
|
||||
to.SetTokenType(rctx->type.dataType.GetTokenType());
|
||||
else if( !rctx->type.dataType.IsPrimitive() )
|
||||
to.SetTokenType(lctx->type.dataType.GetTokenType());
|
||||
else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
|
||||
to.SetTokenType(ttDouble);
|
||||
else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
|
||||
to.SetTokenType(ttFloat);
|
||||
else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
|
||||
{
|
||||
if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
|
||||
// Convert to int64 if both are signed or if one is non-constant and signed
|
||||
if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
|
||||
(lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
|
||||
(rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
|
||||
to.SetTokenType(ttInt64);
|
||||
else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
|
||||
else
|
||||
to.SetTokenType(ttUInt64);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
|
||||
lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
|
||||
// Convert to int32 if both are signed or if one is non-constant and signed
|
||||
if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
|
||||
(lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
|
||||
(rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
|
||||
to.SetTokenType(ttInt);
|
||||
else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
|
||||
to.SetTokenType(ttUInt);
|
||||
|
@ -10915,37 +11060,34 @@ void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext
|
|||
(rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
|
||||
to.SetTokenType(ttFloat);
|
||||
|
||||
// Is it an operation on signed values?
|
||||
asASSERT( to.GetTokenType() != ttUnrecognizedToken );
|
||||
|
||||
// Do we have a mismatch between the sign of the operand?
|
||||
bool signMismatch = false;
|
||||
if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
|
||||
for( int n = 0; !signMismatch && n < 2; n++ )
|
||||
{
|
||||
if( lctx->type.dataType.GetTokenType() == ttUInt64 )
|
||||
asSExprContext *op = n ? rctx : lctx;
|
||||
|
||||
if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
|
||||
{
|
||||
if( !lctx->type.isConstant )
|
||||
signMismatch = true;
|
||||
else if( lctx->type.qwordValue & (asQWORD(1)<<63) )
|
||||
signMismatch = true;
|
||||
}
|
||||
if( lctx->type.dataType.GetTokenType() == ttUInt )
|
||||
{
|
||||
if( !lctx->type.isConstant )
|
||||
signMismatch = true;
|
||||
else if( lctx->type.dwordValue & (asDWORD(1)<<31) )
|
||||
signMismatch = true;
|
||||
}
|
||||
if( rctx->type.dataType.GetTokenType() == ttUInt64 )
|
||||
{
|
||||
if( !rctx->type.isConstant )
|
||||
signMismatch = true;
|
||||
else if( rctx->type.qwordValue & (asQWORD(1)<<63) )
|
||||
signMismatch = true;
|
||||
}
|
||||
if( rctx->type.dataType.GetTokenType() == ttUInt )
|
||||
{
|
||||
if( !rctx->type.isConstant )
|
||||
signMismatch = true;
|
||||
else if( rctx->type.dwordValue & (asDWORD(1)<<31) )
|
||||
signMismatch = true;
|
||||
// We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
|
||||
signMismatch = true;
|
||||
if( op->type.isConstant )
|
||||
{
|
||||
if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
|
||||
{
|
||||
if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
|
||||
signMismatch = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !(op->type.dwordValue & (1<<31)) )
|
||||
signMismatch = false;
|
||||
}
|
||||
|
||||
// It's not necessary to check for floats or double, because if
|
||||
// it was then the types for the conversion will never be unsigned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11549,7 +11691,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
|
|||
int argSize = descr->GetSpaceNeededForArguments();
|
||||
|
||||
if( descr->objectType && descr->returnType.IsReference() &&
|
||||
!(ctx->type.isVariable || ctx->type.isTemporary) &&
|
||||
!(ctx->type.isVariable || ctx->type.isTemporary) &&
|
||||
(ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
|
||||
!(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
|
||||
!(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
|
||||
|
@ -11655,7 +11797,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
|
|||
// Allocate a temporary variable for the returned object
|
||||
// The returned object will actually be allocated on the heap, so
|
||||
// we must force the allocation of the variable to do the same
|
||||
returnOffset = AllocateVariable(descr->returnType, true, true);
|
||||
returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
|
||||
ctx->type.SetVariable(descr->returnType, returnOffset, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -404,16 +404,16 @@
|
|||
|
||||
// Marmalade doesn't use the Windows libraries
|
||||
#define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d)
|
||||
|
||||
// Marmalade doesn't seem to have proper support for
|
||||
// atomic instructions or read/write locks, so we turn off
|
||||
|
||||
// Marmalade doesn't seem to have proper support for
|
||||
// atomic instructions or read/write locks, so we turn off
|
||||
// multithread support
|
||||
//#define AS_POSIX_THREADS
|
||||
#define AS_NO_THREADS
|
||||
#define AS_NO_ATOMIC
|
||||
|
||||
// Marmalade has it's own way of identifying the CPU target
|
||||
// Note, when building for ARM, the gnuc compiler will always
|
||||
// Note, when building for ARM, the gnuc compiler will always
|
||||
// be used so we don't need to check for it here
|
||||
#if defined(I3D_ARCH_X86)
|
||||
#define AS_X86
|
||||
|
@ -566,7 +566,7 @@
|
|||
// WII U
|
||||
#if defined(__ghs__)
|
||||
#define AS_WIIU
|
||||
|
||||
|
||||
// Native calling conventions are not yet supported
|
||||
#define AS_MAX_PORTABILITY
|
||||
|
||||
|
@ -581,7 +581,7 @@
|
|||
#undef STDCALL
|
||||
#define STDCALL
|
||||
|
||||
// Marmalade doesn't seem to have proper support for
|
||||
// Marmalade doesn't seem to have proper support for
|
||||
// atomic instructions or read/write locks
|
||||
#define AS_NO_THREADS
|
||||
#define AS_NO_ATOMIC
|
||||
|
@ -591,7 +591,7 @@
|
|||
#define AS_X86
|
||||
#elif defined(I3D_ARCH_ARM)
|
||||
#define AS_ARM
|
||||
|
||||
|
||||
// Marmalade appear to use the same ABI as Android when built for ARM
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
|
@ -733,7 +733,6 @@
|
|||
|
||||
#elif defined(__x86_64__)
|
||||
#define AS_X64_MINGW
|
||||
#define AS_CALLEE_DESTROY_OBJ_BY_VAL
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 3
|
||||
#define COMPLEX_OBJS_PASSED_BY_REF
|
||||
|
@ -744,17 +743,18 @@
|
|||
#define AS_WINDOWS_THREADS
|
||||
|
||||
// Linux
|
||||
#elif defined(__linux__) && !defined(ANDROID)
|
||||
#elif defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
|
||||
#if defined(i386) && !defined(__LP64__)
|
||||
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define CDECL_RETURN_SIMPLE_IN_MEMORY
|
||||
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
|
||||
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
|
||||
// Support native calling conventions on Intel 32bit CPU
|
||||
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
|
||||
#define AS_X86
|
||||
|
@ -762,10 +762,6 @@
|
|||
#define AS_X64_GCC
|
||||
#define HAS_128_BIT_PRIMITIVES
|
||||
#define SPLIT_OBJS_BY_MEMBER_TYPES
|
||||
#undef COMPLEX_MASK
|
||||
#define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#undef COMPLEX_RETURN_MASK
|
||||
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
|
||||
#define AS_LARGE_OBJS_PASSED_BY_REF
|
||||
#define AS_LARGE_OBJ_MIN_SIZE 5
|
||||
// STDCALL is not available on 64bit Linux
|
||||
|
@ -873,7 +869,7 @@
|
|||
#define STDCALL
|
||||
|
||||
// Android
|
||||
#elif defined(ANDROID)
|
||||
#elif defined(ANDROID) || defined(__ANDROID__)
|
||||
#define AS_ANDROID
|
||||
#define AS_NO_ATOMIC
|
||||
|
||||
|
@ -997,7 +993,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// If the platform doesn't support atomic instructions we can't allow
|
||||
// If the platform doesn't support atomic instructions we can't allow
|
||||
// multithreading as the reference counters won't be threadsafe
|
||||
#if defined(AS_NO_ATOMIC) && !defined(AS_NO_THREADS)
|
||||
#define AS_NO_THREADS
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -40,6 +40,7 @@
|
|||
#include "as_config.h"
|
||||
#include "as_configgroup.h"
|
||||
#include "as_scriptengine.h"
|
||||
#include "as_texts.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
|
@ -156,6 +157,8 @@ void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed)
|
|||
#endif
|
||||
|
||||
engine->objectTypes.RemoveIndex(idx);
|
||||
if( engine->defaultArrayObjectType == t )
|
||||
engine->defaultArrayObjectType = 0;
|
||||
|
||||
if( t->flags & asOBJ_TYPEDEF )
|
||||
engine->registeredTypeDefs.RemoveValue(t);
|
||||
|
@ -188,12 +191,31 @@ void asCConfigGroup::ValidateNoUsage(asCScriptEngine *engine, asCObjectType *typ
|
|||
if( func->name == "_beh_2_" || func->name == "_beh_3_" || func->objectType == type )
|
||||
continue;
|
||||
|
||||
asASSERT( func->returnType.GetObjectType() != type );
|
||||
// Ignore function definitions too, as they aren't released until the engine is destroyed
|
||||
if( func->funcType == asFUNC_FUNCDEF )
|
||||
continue;
|
||||
|
||||
for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
|
||||
if( func->returnType.GetObjectType() == type )
|
||||
{
|
||||
asASSERT(func->parameterTypes[p].GetObjectType() != type);
|
||||
asCString msg;
|
||||
// We can only use the function name here, because the types used by the function may have been deleted already
|
||||
msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
}
|
||||
else
|
||||
{
|
||||
for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
|
||||
{
|
||||
if( func->parameterTypes[p].GetObjectType() == type )
|
||||
{
|
||||
asCString msg;
|
||||
// We can only use the function name here, because the types used by the function may have been deleted already
|
||||
msg.Format(TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s, type->name.AddressOf(), func->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check also usage of the type in global variables
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
|
||||
~asCDebugStats()
|
||||
{
|
||||
// This code writes out some statistics for the VM.
|
||||
// This code writes out some statistics for the VM.
|
||||
// It's useful for determining what needs to be optimized.
|
||||
|
||||
_mkdir("AS_DEBUG");
|
||||
|
@ -174,6 +174,7 @@ asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
|
|||
m_originalStackPointer = 0;
|
||||
m_inExceptionHandler = false;
|
||||
m_isStackMemoryNotAllocated = false;
|
||||
m_needToCleanupArgs = false;
|
||||
m_currentFunction = 0;
|
||||
m_callingSystemFunction = 0;
|
||||
m_regs.objectRegister = 0;
|
||||
|
@ -202,7 +203,7 @@ bool asCContext::IsNested(asUINT *nestCount) const
|
|||
return false;
|
||||
|
||||
// Search for a marker on the call stack
|
||||
// This loop starts at 2 because the 0th entry is not stored in m_callStack,
|
||||
// This loop starts at 2 because the 0th entry is not stored in m_callStack,
|
||||
// and then we need to subtract one more to get the base of each frame
|
||||
for( asUINT n = 2; n <= c; n++ )
|
||||
{
|
||||
|
@ -252,7 +253,7 @@ void asCContext::DetachEngine()
|
|||
|
||||
// Free all resources
|
||||
Unprepare();
|
||||
}
|
||||
}
|
||||
while( IsNested() );
|
||||
|
||||
// Free the stack blocks
|
||||
|
@ -346,13 +347,13 @@ int asCContext::Prepare(asIScriptFunction *func)
|
|||
|
||||
if( m_initialFunction && m_initialFunction == func )
|
||||
{
|
||||
// If the same function is executed again, we can skip a lot of the setup
|
||||
// If the same function is executed again, we can skip a lot of the setup
|
||||
m_currentFunction = m_initialFunction;
|
||||
|
||||
// Reset stack pointer
|
||||
m_regs.stackPointer = m_originalStackPointer;
|
||||
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// otherwise something is wrong with the way it is being updated
|
||||
asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
|
||||
}
|
||||
|
@ -367,7 +368,7 @@ int asCContext::Prepare(asIScriptFunction *func)
|
|||
// Reset stack pointer
|
||||
m_regs.stackPointer = m_originalStackPointer;
|
||||
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// otherwise something is wrong with the way it is being updated
|
||||
asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
|
||||
}
|
||||
|
@ -439,10 +440,12 @@ int asCContext::Unprepare()
|
|||
return asCONTEXT_ACTIVE;
|
||||
|
||||
// Only clean the stack if the context was prepared but not executed until the end
|
||||
if( m_status != asEXECUTION_UNINITIALIZED &&
|
||||
if( m_status != asEXECUTION_UNINITIALIZED &&
|
||||
m_status != asEXECUTION_FINISHED )
|
||||
CleanStack();
|
||||
|
||||
asASSERT( m_needToCleanupArgs == false );
|
||||
|
||||
// Release the returned object (if any)
|
||||
CleanReturnObject();
|
||||
|
||||
|
@ -454,7 +457,7 @@ int asCContext::Unprepare()
|
|||
// Reset stack pointer
|
||||
m_regs.stackPointer = m_originalStackPointer;
|
||||
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// Make sure the stack pointer is pointing to the original position,
|
||||
// otherwise something is wrong with the way it is being updated
|
||||
asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
|
||||
}
|
||||
|
@ -469,7 +472,7 @@ int asCContext::Unprepare()
|
|||
m_status = asEXECUTION_UNINITIALIZED;
|
||||
|
||||
m_regs.stackFramePointer = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -600,7 +603,7 @@ void *asCContext::GetAddressOfReturnValue()
|
|||
// An object is stored in the objectRegister
|
||||
if( !dt->IsReference() && dt->IsObject() )
|
||||
{
|
||||
// Need to dereference objects
|
||||
// Need to dereference objects
|
||||
if( !dt->IsObjectHandle() )
|
||||
{
|
||||
if( m_initialFunction->DoesReturnOnStack() )
|
||||
|
@ -962,7 +965,7 @@ int asCContext::SetArgObject(asUINT arg, void *obj)
|
|||
if( obj && beh->addref )
|
||||
m_engine->CallObjectMethod(obj, beh->addref);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
obj = m_engine->CreateScriptObjectCopy(obj, m_engine->GetTypeIdFromDataType(*dt));
|
||||
}
|
||||
|
@ -1012,8 +1015,8 @@ void *asCContext::GetAddressOfArg(asUINT arg)
|
|||
|
||||
// We should return the address of the location where the argument value will be placed
|
||||
|
||||
// All registered types are always sent by reference, even if
|
||||
// the function is declared to receive the argument by value.
|
||||
// All registered types are always sent by reference, even if
|
||||
// the function is declared to receive the argument by value.
|
||||
return &m_regs.stackFramePointer[offset];
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1041,7 @@ int asCContext::Abort()
|
|||
// interface
|
||||
int asCContext::Suspend()
|
||||
{
|
||||
// This function just sets some internal flags and is safe
|
||||
// This function just sets some internal flags and is safe
|
||||
// to call from a secondary thread, even if the library has
|
||||
// been built without multi-thread support.
|
||||
|
||||
|
@ -1133,7 +1136,7 @@ int asCContext::Execute()
|
|||
|
||||
// Call the function directly
|
||||
CallSystemFunction(m_currentFunction->id, this, 0);
|
||||
|
||||
|
||||
// Was the call successful?
|
||||
if( m_status == asEXECUTION_ACTIVE )
|
||||
{
|
||||
|
@ -1156,7 +1159,7 @@ int asCContext::Execute()
|
|||
|
||||
if( m_lineCallback )
|
||||
{
|
||||
// Call the line callback one last time before leaving
|
||||
// Call the line callback one last time before leaving
|
||||
// so anyone listening can catch the state change
|
||||
CallLineCallback();
|
||||
}
|
||||
|
@ -1220,7 +1223,7 @@ int asCContext::PushState()
|
|||
// Push the current script function that is calling the system function
|
||||
PushCallState();
|
||||
|
||||
// Push the system function too, which will serve both as a marker and
|
||||
// Push the system function too, which will serve both as a marker and
|
||||
// informing which system function that created the nested call
|
||||
if( m_callStack.GetLength() == m_callStack.GetCapacity() )
|
||||
{
|
||||
|
@ -1381,7 +1384,7 @@ int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **secti
|
|||
func = (asCScriptFunction*)s[1];
|
||||
bytePos = (asDWORD*)s[2];
|
||||
|
||||
// Subract 1 from the bytePos, because we want the line where
|
||||
// Subract 1 from the bytePos, because we want the line where
|
||||
// the call was made, and not the instruction after the call
|
||||
bytePos -= 1;
|
||||
}
|
||||
|
@ -1397,8 +1400,14 @@ int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **secti
|
|||
int sectionIdx;
|
||||
asDWORD line = func->GetLineNumber(int(bytePos - func->byteCode.AddressOf()), §ionIdx);
|
||||
if( column ) *column = (line >> 20);
|
||||
if( sectionName )
|
||||
*sectionName = sectionIdx >= 0 ? m_engine->scriptSectionNames[sectionIdx]->AddressOf() : 0;
|
||||
if( sectionName )
|
||||
{
|
||||
asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) );
|
||||
if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() )
|
||||
*sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf();
|
||||
else
|
||||
*sectionName = 0;
|
||||
}
|
||||
return (line & 0xFFFFF);
|
||||
}
|
||||
|
||||
|
@ -1423,7 +1432,7 @@ bool asCContext::ReserveStackSpace(asUINT size)
|
|||
m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize;
|
||||
}
|
||||
|
||||
// Check if there is enough space on the current stack block, otherwise move
|
||||
// Check if there is enough space on the current stack block, otherwise move
|
||||
// to the next one. New and larger blocks will be allocated as necessary
|
||||
while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] )
|
||||
{
|
||||
|
@ -1464,10 +1473,10 @@ bool asCContext::ReserveStackSpace(asUINT size)
|
|||
|
||||
// Update the stack pointer to point to the new block.
|
||||
// Leave enough room above the stackpointer to copy the arguments from the previous stackblock
|
||||
m_regs.stackPointer = m_stackBlocks[m_stackIndex] +
|
||||
(m_stackBlockSize<<m_stackIndex) -
|
||||
m_currentFunction->GetSpaceNeededForArguments() -
|
||||
(m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
|
||||
m_regs.stackPointer = m_stackBlocks[m_stackIndex] +
|
||||
(m_stackBlockSize<<m_stackIndex) -
|
||||
m_currentFunction->GetSpaceNeededForArguments() -
|
||||
(m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
|
||||
(m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
|
||||
}
|
||||
|
||||
|
@ -1480,7 +1489,7 @@ void asCContext::CallScriptFunction(asCScriptFunction *func)
|
|||
// Push the framepointer, function id and programCounter on the stack
|
||||
PushCallState();
|
||||
|
||||
// Update the current function and program position before increasing the stack
|
||||
// Update the current function and program position before increasing the stack
|
||||
// so the exception handler will know what to do if there is a stack overflow
|
||||
m_currentFunction = func;
|
||||
m_regs.programPointer = m_currentFunction->byteCode.AddressOf();
|
||||
|
@ -1490,7 +1499,7 @@ void asCContext::CallScriptFunction(asCScriptFunction *func)
|
|||
if( !ReserveStackSpace(func->stackNeeded) )
|
||||
return;
|
||||
|
||||
// If a new stack block was allocated then we'll need to move
|
||||
// If a new stack block was allocated then we'll need to move
|
||||
// over the function arguments to the new block
|
||||
if( m_regs.stackPointer != oldStackPointer )
|
||||
{
|
||||
|
@ -1535,18 +1544,20 @@ void asCContext::CallInterfaceMethod(asCScriptFunction *func)
|
|||
asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer;
|
||||
if( obj == 0 )
|
||||
{
|
||||
// Tell the exception handler to clean up the arguments to this method
|
||||
m_needToCleanupArgs = true;
|
||||
SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
asCObjectType *objType = obj->objType;
|
||||
|
||||
// TODO: runtime optimize: The object type should have a list of only those methods that
|
||||
// TODO: runtime optimize: The object type should have a list of only those methods that
|
||||
// implement interface methods. This list should be ordered by
|
||||
// the signatureId so that a binary search can be made, instead
|
||||
// of a linear search.
|
||||
//
|
||||
// When this is done, we must also make sure the signatureId of a
|
||||
// When this is done, we must also make sure the signatureId of a
|
||||
// function never changes, e.g. when if the signature functions are
|
||||
// released.
|
||||
|
||||
|
@ -1569,6 +1580,8 @@ void asCContext::CallInterfaceMethod(asCScriptFunction *func)
|
|||
|
||||
if( realFunc == 0 )
|
||||
{
|
||||
// Tell the exception handler to clean up the arguments to this method
|
||||
m_needToCleanupArgs = true;
|
||||
SetInternalException(TXT_NULL_POINTER_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
@ -1592,7 +1605,7 @@ void asCContext::ExecuteNext()
|
|||
{
|
||||
|
||||
#ifdef AS_DEBUG
|
||||
// Gather statistics on executed bytecode
|
||||
// Gather statistics on executed bytecode
|
||||
stats.Instr(*(asBYTE*)l_bc);
|
||||
|
||||
// Used to verify that the size of the instructions are correct
|
||||
|
@ -1683,7 +1696,7 @@ void asCContext::ExecuteNext()
|
|||
l_bc += 1 + AS_PTR_SIZE;
|
||||
break;
|
||||
|
||||
// Load the address of a global variable in the register, then
|
||||
// Load the address of a global variable in the register, then
|
||||
// copy the value of the global variable into a local variable
|
||||
case asBC_LdGRdR4:
|
||||
*(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc);
|
||||
|
@ -2166,7 +2179,7 @@ void asCContext::ExecuteNext()
|
|||
// Comparisons
|
||||
case asBC_CMPd:
|
||||
{
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// in order to get proper behaviour for infinity values.
|
||||
double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc));
|
||||
|
@ -2190,7 +2203,7 @@ void asCContext::ExecuteNext()
|
|||
|
||||
case asBC_CMPf:
|
||||
{
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// in order to get proper behaviour for infinity values.
|
||||
float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc));
|
||||
|
@ -2227,7 +2240,7 @@ void asCContext::ExecuteNext()
|
|||
|
||||
case asBC_CMPIf:
|
||||
{
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// Do a comparison of the values, rather than a subtraction
|
||||
// in order to get proper behaviour for infinity values.
|
||||
float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
float f2 = asBC_FLOATARG(l_bc);
|
||||
|
@ -2335,9 +2348,11 @@ void asCContext::ExecuteNext()
|
|||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
int funcId = m_engine->importedFunctions[i&0xFFFF]->boundFunctionId;
|
||||
int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId;
|
||||
if( funcId == -1 )
|
||||
{
|
||||
// Tell the exception handler to clean up the arguments to this function
|
||||
m_needToCleanupArgs = true;
|
||||
SetInternalException(TXT_UNBOUND_FUNCTION);
|
||||
return;
|
||||
}
|
||||
|
@ -2557,7 +2572,7 @@ void asCContext::ExecuteNext()
|
|||
// Pop address of destination pointer from the stack
|
||||
void **d = (void**)*(asPWORD*)l_sp;
|
||||
l_sp += AS_PTR_SIZE;
|
||||
|
||||
|
||||
// Read wanted pointer from the stack
|
||||
void *s = (void*)*(asPWORD*)l_sp;
|
||||
|
||||
|
@ -2631,8 +2646,8 @@ void asCContext::ExecuteNext()
|
|||
break;
|
||||
|
||||
case asBC_ClrVPtr:
|
||||
// TODO: runtime optimize: Is this instruction really necessary?
|
||||
// CallScriptFunction() can clear the null handles upon entry, just as is done for
|
||||
// TODO: runtime optimize: Is this instruction really necessary?
|
||||
// CallScriptFunction() can clear the null handles upon entry, just as is done for
|
||||
// all other object variables
|
||||
// Clear pointer variable
|
||||
*(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
|
||||
|
@ -2920,6 +2935,22 @@ void asCContext::ExecuteNext()
|
|||
SetInternalException(TXT_DIVIDE_BY_ZERO);
|
||||
return;
|
||||
}
|
||||
else if( divider == -1 )
|
||||
{
|
||||
// Need to check if the value that is divided is 0x80000000
|
||||
// as dividing it with -1 will cause an overflow exception
|
||||
if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
|
||||
{
|
||||
// Need to move the values back to the context
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Raise exception
|
||||
SetInternalException(TXT_DIVIDE_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
|
||||
}
|
||||
l_bc += 2;
|
||||
|
@ -2939,6 +2970,22 @@ void asCContext::ExecuteNext()
|
|||
SetInternalException(TXT_DIVIDE_BY_ZERO);
|
||||
return;
|
||||
}
|
||||
else if( divider == -1 )
|
||||
{
|
||||
// Need to check if the value that is divided is 0x80000000
|
||||
// as dividing it with -1 will cause an overflow exception
|
||||
if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
|
||||
{
|
||||
// Need to move the values back to the context
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Raise exception
|
||||
SetInternalException(TXT_DIVIDE_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
|
||||
}
|
||||
l_bc += 2;
|
||||
|
@ -3227,7 +3274,7 @@ void asCContext::ExecuteNext()
|
|||
}
|
||||
else
|
||||
{
|
||||
// The object register should already be null, so there
|
||||
// The object register should already be null, so there
|
||||
// is no need to clear it if the cast is unsuccessful
|
||||
asASSERT( m_regs.objectRegister == 0 );
|
||||
}
|
||||
|
@ -3278,7 +3325,7 @@ void asCContext::ExecuteNext()
|
|||
break;
|
||||
|
||||
case asBC_u64TOf:
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
{
|
||||
// MSVC6 doesn't permit UINT64 to double
|
||||
asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
|
||||
|
@ -3299,7 +3346,7 @@ void asCContext::ExecuteNext()
|
|||
break;
|
||||
|
||||
case asBC_u64TOd:
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
#if _MSC_VER <= 1200 // MSVC6
|
||||
{
|
||||
// MSVC6 doesn't permit UINT64 to double
|
||||
asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
|
@ -3363,6 +3410,23 @@ void asCContext::ExecuteNext()
|
|||
SetInternalException(TXT_DIVIDE_BY_ZERO);
|
||||
return;
|
||||
}
|
||||
else if( divider == -1 )
|
||||
{
|
||||
// Need to check if the value that is divided is 1<<63
|
||||
// as dividing it with -1 will cause an overflow exception
|
||||
if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
|
||||
{
|
||||
// Need to move the values back to the context
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Raise exception
|
||||
SetInternalException(TXT_DIVIDE_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
|
||||
}
|
||||
l_bc += 2;
|
||||
|
@ -3382,6 +3446,22 @@ void asCContext::ExecuteNext()
|
|||
SetInternalException(TXT_DIVIDE_BY_ZERO);
|
||||
return;
|
||||
}
|
||||
else if( divider == -1 )
|
||||
{
|
||||
// Need to check if the value that is divided is 1<<63
|
||||
// as dividing it with -1 will cause an overflow exception
|
||||
if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
|
||||
{
|
||||
// Need to move the values back to the context
|
||||
m_regs.programPointer = l_bc;
|
||||
m_regs.stackPointer = l_sp;
|
||||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
// Raise exception
|
||||
SetInternalException(TXT_DIVIDE_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
|
||||
}
|
||||
l_bc += 2;
|
||||
|
@ -3490,7 +3570,7 @@ void asCContext::ExecuteNext()
|
|||
m_regs.stackFramePointer = l_fp;
|
||||
|
||||
(m_currentFunction->jitFunction)(&m_regs, jitArg);
|
||||
|
||||
|
||||
l_bc = m_regs.programPointer;
|
||||
l_sp = m_regs.stackPointer;
|
||||
l_fp = m_regs.stackFramePointer;
|
||||
|
@ -3498,7 +3578,7 @@ void asCContext::ExecuteNext()
|
|||
// If status isn't active anymore then we must stop
|
||||
if( m_status != asEXECUTION_ACTIVE )
|
||||
return;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3520,6 +3600,12 @@ void asCContext::ExecuteNext()
|
|||
|
||||
if( func == 0 )
|
||||
{
|
||||
// Need to update the program pointer anyway for the exception handler
|
||||
m_regs.programPointer++;
|
||||
|
||||
// Tell the exception handler to clean up the arguments to this method
|
||||
m_needToCleanupArgs = true;
|
||||
|
||||
// TODO: funcdef: Should we have a different exception string?
|
||||
SetInternalException(TXT_UNBOUND_FUNCTION);
|
||||
return;
|
||||
|
@ -3537,7 +3623,7 @@ void asCContext::ExecuteNext()
|
|||
|
||||
m_regs.stackPointer += CallSystemFunction(func->id, this, 0);
|
||||
|
||||
// Update program position after the call so the line number
|
||||
// Update program position after the call so the line number
|
||||
// is correct in case the system function queries it
|
||||
m_regs.programPointer++;
|
||||
}
|
||||
|
@ -3674,7 +3760,7 @@ void asCContext::ExecuteNext()
|
|||
case asBC_LoadRObjR:
|
||||
{
|
||||
// PshVPtr x
|
||||
asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
|
||||
// Make sure the pointer is not null
|
||||
if( tmp == 0 )
|
||||
|
@ -3701,7 +3787,7 @@ void asCContext::ExecuteNext()
|
|||
case asBC_LoadVObjR:
|
||||
{
|
||||
// PSF x
|
||||
asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc));
|
||||
|
||||
// ADDSi y
|
||||
tmp = tmp + asBC_SWORDARG1(l_bc);
|
||||
|
@ -3720,7 +3806,7 @@ void asCContext::ExecuteNext()
|
|||
|
||||
// Determine destination from argument
|
||||
void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
|
||||
|
||||
|
||||
// Read wanted pointer from the stack
|
||||
void *s = (void*)*(asPWORD*)l_sp;
|
||||
|
||||
|
@ -3848,7 +3934,7 @@ void asCContext::ExecuteNext()
|
|||
#ifdef AS_DEBUG
|
||||
asDWORD instr = *(asBYTE*)old;
|
||||
if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ &&
|
||||
instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr &&
|
||||
instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr &&
|
||||
instr != asBC_JitEntry )
|
||||
{
|
||||
asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] );
|
||||
|
@ -3936,7 +4022,7 @@ void asCContext::CleanStack()
|
|||
CleanStackFrame();
|
||||
|
||||
// Set the status to exception so that the stack unwind is done correctly.
|
||||
// This shouldn't be done for the current function, which is why we only
|
||||
// This shouldn't be done for the current function, which is why we only
|
||||
// do this after the first CleanStackFrame() is done.
|
||||
m_status = asEXECUTION_EXCEPTION;
|
||||
|
||||
|
@ -3984,14 +4070,14 @@ bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel)
|
|||
|
||||
asUINT declaredAt = func->variables[varIndex]->declaredAtProgramPos;
|
||||
|
||||
// If the program position is after the variable declaration it is necessary
|
||||
// determine if the program position is still inside the statement block where
|
||||
// If the program position is after the variable declaration it is necessary
|
||||
// determine if the program position is still inside the statement block where
|
||||
// the variable was delcared.
|
||||
for( int n = 0; n < (int)func->objVariableInfo.GetLength(); n++ )
|
||||
{
|
||||
if( func->objVariableInfo[n].programPos >= declaredAt )
|
||||
{
|
||||
// If the current block ends between the declaredAt and current
|
||||
// If the current block ends between the declaredAt and current
|
||||
// program position, then we know the variable is no longer visible
|
||||
int level = 0;
|
||||
for( ; n < (int)func->objVariableInfo.GetLength(); n++ )
|
||||
|
@ -4028,7 +4114,7 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
|
|||
if( m_status == asEXECUTION_EXCEPTION )
|
||||
{
|
||||
// Don't consider the last instruction as executed, as it failed with an exception
|
||||
// It's not actually necessary to decrease the exact size of the instruction. Just
|
||||
// It's not actually necessary to decrease the exact size of the instruction. Just
|
||||
// before the current position is enough to disconsider it.
|
||||
pos--;
|
||||
}
|
||||
|
@ -4040,7 +4126,7 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
|
|||
pos = asUINT((asDWORD*)s[2] - func->byteCode.AddressOf());
|
||||
|
||||
// Don't consider the last instruction as executed, as the function that was called by it
|
||||
// is still being executed. If we consider it as executed already, then a value object
|
||||
// is still being executed. If we consider it as executed already, then a value object
|
||||
// returned by value would be considered alive, which it is not.
|
||||
pos--;
|
||||
}
|
||||
|
@ -4051,8 +4137,8 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
|
|||
for( int n = 0; n < (int)func->objVariableInfo.GetLength(); n++ )
|
||||
{
|
||||
// Find the first variable info with a larger position than the current
|
||||
// As the variable info are always placed on the instruction right after the
|
||||
// one that initialized or freed the object, the current position needs to be
|
||||
// As the variable info are always placed on the instruction right after the
|
||||
// one that initialized or freed the object, the current position needs to be
|
||||
// considered as valid.
|
||||
if( func->objVariableInfo[n].programPos > pos )
|
||||
{
|
||||
|
@ -4089,7 +4175,7 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
|
|||
}
|
||||
break;
|
||||
case asBLOCK_BEGIN: // Start block
|
||||
// We should ignore start blocks, since it just means the
|
||||
// We should ignore start blocks, since it just means the
|
||||
// program was within the block when the exception ocurred
|
||||
break;
|
||||
case asBLOCK_END: // End block
|
||||
|
@ -4116,6 +4202,110 @@ void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLe
|
|||
}
|
||||
}
|
||||
|
||||
void asCContext::CleanArgsOnStack()
|
||||
{
|
||||
if( !m_needToCleanupArgs )
|
||||
return;
|
||||
|
||||
// Find the instruction just before the current program pointer
|
||||
asDWORD *instr = m_currentFunction->byteCode.AddressOf();
|
||||
asDWORD *prevInstr = 0;
|
||||
while( instr < m_regs.programPointer )
|
||||
{
|
||||
prevInstr = instr;
|
||||
instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type];
|
||||
}
|
||||
|
||||
// Determine what function was being called
|
||||
asCScriptFunction *func = 0;
|
||||
asBYTE bc = *(asBYTE*)prevInstr;
|
||||
if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF )
|
||||
{
|
||||
int funcId = asBC_INTARG(prevInstr);
|
||||
func = m_engine->scriptFunctions[funcId];
|
||||
}
|
||||
else if( bc == asBC_CALLBND )
|
||||
{
|
||||
int funcId = asBC_INTARG(prevInstr);
|
||||
func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
|
||||
}
|
||||
else if( bc == asBC_CallPtr )
|
||||
{
|
||||
asUINT v;
|
||||
int var = asBC_SWORDARG0(prevInstr);
|
||||
|
||||
// Find the funcdef from the local variable
|
||||
for( v = 0; v < m_currentFunction->objVariablePos.GetLength(); v++ )
|
||||
if( m_currentFunction->objVariablePos[v] == var )
|
||||
{
|
||||
func = m_currentFunction->funcVariableTypes[v];
|
||||
break;
|
||||
}
|
||||
|
||||
if( func == 0 )
|
||||
{
|
||||
// Look in parameters
|
||||
int paramPos = 0;
|
||||
if( m_currentFunction->objectType )
|
||||
paramPos -= AS_PTR_SIZE;
|
||||
if( m_currentFunction->DoesReturnOnStack() )
|
||||
paramPos -= AS_PTR_SIZE;
|
||||
for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ )
|
||||
{
|
||||
if( var == paramPos )
|
||||
{
|
||||
func = m_currentFunction->parameterTypes[v].GetFuncDef();
|
||||
break;
|
||||
}
|
||||
paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
asASSERT( false );
|
||||
|
||||
asASSERT( func );
|
||||
|
||||
// Clean parameters
|
||||
int offset = 0;
|
||||
if( func->objectType )
|
||||
offset += AS_PTR_SIZE;
|
||||
if( func->DoesReturnOnStack() )
|
||||
offset += AS_PTR_SIZE;
|
||||
for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
|
||||
{
|
||||
if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsReference() )
|
||||
{
|
||||
if( *(asPWORD*)&m_regs.stackPointer[offset] )
|
||||
{
|
||||
// Call the object's destructor
|
||||
asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour();
|
||||
if( func->parameterTypes[n].GetObjectType()->flags & asOBJ_REF )
|
||||
{
|
||||
asASSERT( (func->parameterTypes[n].GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
|
||||
|
||||
if( beh->release )
|
||||
m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release);
|
||||
*(asPWORD*)&m_regs.stackPointer[offset] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( beh->destruct )
|
||||
m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct);
|
||||
|
||||
// Free the memory
|
||||
m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]);
|
||||
*(asPWORD*)&m_regs.stackPointer[offset] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += func->parameterTypes[n].GetSizeOnStackDWords();
|
||||
}
|
||||
|
||||
m_needToCleanupArgs = false;
|
||||
}
|
||||
|
||||
void asCContext::CleanStackFrame()
|
||||
{
|
||||
// Clean object variables on the stack
|
||||
|
@ -4123,6 +4313,10 @@ void asCContext::CleanStackFrame()
|
|||
// is not set, then there is nothing to clean up on the stack frame
|
||||
if( !m_isStackMemoryNotAllocated && m_regs.programPointer )
|
||||
{
|
||||
// If the exception occurred while calling a function it is necessary
|
||||
// to clean up the arguments that were put on the stack.
|
||||
CleanArgsOnStack();
|
||||
|
||||
// Restore the stack pointer
|
||||
m_regs.stackPointer += m_currentFunction->variableSpace;
|
||||
|
||||
|
@ -4517,7 +4711,7 @@ void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel)
|
|||
{
|
||||
// Determine if the object is really on the heap
|
||||
bool onHeap = false;
|
||||
if( func->variables[varIndex]->type.IsObject() &&
|
||||
if( func->variables[varIndex]->type.IsObject() &&
|
||||
!func->variables[varIndex]->type.IsObjectHandle() )
|
||||
{
|
||||
onHeap = true;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -147,6 +147,7 @@ public:
|
|||
void ExecuteNext();
|
||||
void CleanStack();
|
||||
void CleanStackFrame();
|
||||
void CleanArgsOnStack();
|
||||
void CleanReturnObject();
|
||||
void DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel);
|
||||
|
||||
|
@ -185,6 +186,7 @@ public:
|
|||
|
||||
// Exception handling
|
||||
bool m_isStackMemoryNotAllocated;
|
||||
bool m_needToCleanupArgs;
|
||||
bool m_inExceptionHandler;
|
||||
asCString m_exceptionString;
|
||||
int m_exceptionFunction;
|
||||
|
|
|
@ -456,21 +456,6 @@ bool asCDataType::IsPrimitive() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool asCDataType::IsSamePrimitiveBaseType(const asCDataType &dt) const
|
||||
{
|
||||
if( !IsPrimitive() || !dt.IsPrimitive() ) return false;
|
||||
|
||||
if( IsIntegerType() && dt.IsIntegerType() ) return true;
|
||||
if( IsUnsignedType() && dt.IsUnsignedType() ) return true;
|
||||
if( IsFloatType() && dt.IsFloatType() ) return true;
|
||||
if( IsDoubleType() && dt.IsDoubleType() ) return true;
|
||||
if( IsBooleanType() && dt.IsBooleanType() ) return true;
|
||||
if( IsFloatType() && dt.IsDoubleType() ) return true;
|
||||
if( IsDoubleType() && dt.IsFloatType() ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asCDataType::IsIntegerType() const
|
||||
{
|
||||
if( tokenType == ttInt ||
|
||||
|
@ -479,7 +464,8 @@ bool asCDataType::IsIntegerType() const
|
|||
tokenType == ttInt64 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
// Enums are also integer types
|
||||
return IsEnumType();
|
||||
}
|
||||
|
||||
bool asCDataType::IsUnsignedType() const
|
||||
|
|
|
@ -93,7 +93,6 @@ public:
|
|||
bool IsEnumType() const;
|
||||
bool IsAnyType() const {return tokenType == ttQuestion;}
|
||||
|
||||
bool IsSamePrimitiveBaseType(const asCDataType &dt) const;
|
||||
bool IsEqualExceptRef(const asCDataType &) const;
|
||||
bool IsEqualExceptRefAndConst(const asCDataType &) const;
|
||||
bool IsEqualExceptConst(const asCDataType &) const;
|
||||
|
|
|
@ -426,11 +426,32 @@ int asCGarbageCollector::ReportAndReleaseUndestroyedObjects()
|
|||
{
|
||||
asSObjTypePair gcObj = GetOldObjectAtIdx(n);
|
||||
|
||||
int refCount = 0;
|
||||
if( gcObj.type->beh.gcGetRefCount && engine->scriptFunctions[gcObj.type->beh.gcGetRefCount] )
|
||||
refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount);
|
||||
|
||||
// Report the object as not being properly destroyed
|
||||
asCString msg;
|
||||
msg.Format(TXT_GC_CANNOT_FREE_OBJ_OF_TYPE_s, gcObj.type->name.AddressOf());
|
||||
msg.Format(TXT_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d, gcObj.type->name.AddressOf(), refCount - 1);
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf());
|
||||
|
||||
// Add additional info for builtin types
|
||||
if( gcObj.type->name == "_builtin_function_" )
|
||||
{
|
||||
msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast<asCScriptFunction*>(gcObj.obj)->GetName());
|
||||
engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
|
||||
}
|
||||
else if( gcObj.type->name == "_builtin_objecttype_" )
|
||||
{
|
||||
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] )
|
||||
engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);
|
||||
|
|
|
@ -440,7 +440,7 @@ void asCModule::InternalReset()
|
|||
{
|
||||
if( bindInformations[n] )
|
||||
{
|
||||
asUINT id = bindInformations[n]->importedFunctionSignature->id & 0xFFFF;
|
||||
asUINT id = bindInformations[n]->importedFunctionSignature->id & ~FUNC_IMPORTED;
|
||||
engine->importedFunctions[id] = 0;
|
||||
engine->freeImportedFunctionIdxs.PushLast(id);
|
||||
|
||||
|
@ -465,8 +465,8 @@ void asCModule::InternalReset()
|
|||
// Free funcdefs
|
||||
for( n = 0; n < funcDefs.GetLength(); n++ )
|
||||
{
|
||||
// TODO: funcdefs: These may be shared between modules, so we can't just remove them
|
||||
engine->funcDefs.RemoveValue(funcDefs[n]);
|
||||
// The funcdefs are not removed from the engine at this moment as they may still be referred
|
||||
// to by other types. The engine's ClearUnusedTypes will take care of the clean up.
|
||||
funcDefs[n]->Release();
|
||||
}
|
||||
funcDefs.SetLength(0);
|
||||
|
|
|
@ -216,7 +216,38 @@ int asCReader::ReadInner()
|
|||
bool isNew;
|
||||
asCScriptFunction *func = ReadFunction(isNew, false, true);
|
||||
if( func )
|
||||
{
|
||||
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++ )
|
||||
{
|
||||
asCScriptFunction *f2 = engine->funcDefs[n];
|
||||
if( f2 == 0 || func == f2 )
|
||||
continue;
|
||||
|
||||
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->AddRef();
|
||||
|
||||
engine->funcDefs.RemoveValue(func);
|
||||
|
||||
savedFunctions[savedFunctions.IndexOf(func)] = f2;
|
||||
|
||||
func->Release();
|
||||
|
||||
// Funcdefs aren't deleted when the ref count reaches zero so we must manually delete it here
|
||||
asDELETE(func,asCScriptFunction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
error = true;
|
||||
}
|
||||
|
@ -696,7 +727,16 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a
|
|||
length = ReadEncodedUInt();
|
||||
func->sectionIdxs.SetLength(length);
|
||||
for( i = 0; i < length; ++i )
|
||||
func->sectionIdxs[i] = ReadEncodedUInt();
|
||||
{
|
||||
if( (i & 1) == 0 )
|
||||
func->sectionIdxs[i] = ReadEncodedUInt();
|
||||
else
|
||||
{
|
||||
asCString str;
|
||||
ReadString(&str);
|
||||
func->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReadData(&func->isShared, 1);
|
||||
|
@ -2532,7 +2572,7 @@ asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD
|
|||
{
|
||||
// Find the function from the engine's bind array
|
||||
int funcId = asBC_INTARG(&func->byteCode[programPos]);
|
||||
return engine->importedFunctions[funcId&0xFFFF]->importedFunctionSignature;
|
||||
return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
|
||||
}
|
||||
else if( bc == asBC_CallPtr )
|
||||
{
|
||||
|
@ -2988,7 +3028,15 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
|
|||
if( (i & 1) == 0 )
|
||||
WriteEncodedInt64(bytecodeNbrByPos[func->sectionIdxs[i]]);
|
||||
else
|
||||
WriteEncodedInt64(func->sectionIdxs[i]);
|
||||
{
|
||||
if( func->sectionIdxs[i] >= 0 )
|
||||
WriteString(engine->scriptSectionNames[func->sectionIdxs[i]]);
|
||||
else
|
||||
{
|
||||
char c = 0;
|
||||
WriteData(&c, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3512,7 +3560,7 @@ int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD prog
|
|||
{
|
||||
// Find the function from the engine's bind array
|
||||
int funcId = asBC_INTARG(&func->byteCode[n]);
|
||||
calledFunc = engine->importedFunctions[funcId&0xFFFF]->importedFunctionSignature;
|
||||
calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
|
||||
break;
|
||||
}
|
||||
else if( bc == asBC_CallPtr )
|
||||
|
|
|
@ -342,6 +342,13 @@ int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value)
|
|||
ep.alwaysImplDefaultConstruct = value ? true : false;
|
||||
break;
|
||||
|
||||
case asEP_COMPILER_WARNINGS:
|
||||
if( value <= 2 )
|
||||
ep.compilerWarnings = (int)value;
|
||||
else
|
||||
return asINVALID_ARG;
|
||||
break;
|
||||
|
||||
default:
|
||||
return asINVALID_ARG;
|
||||
}
|
||||
|
@ -406,6 +413,9 @@ asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const
|
|||
|
||||
case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT:
|
||||
return ep.alwaysImplDefaultConstruct;
|
||||
|
||||
case asEP_COMPILER_WARNINGS:
|
||||
return ep.compilerWarnings;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -439,6 +449,7 @@ asCScriptEngine::asCScriptEngine()
|
|||
ep.autoGarbageCollect = true;
|
||||
ep.disallowGlobalVars = false;
|
||||
ep.alwaysImplDefaultConstruct = false;
|
||||
ep.compilerWarnings = 1; // 0 = no warnings, 1 = warning, 2 = treat as error
|
||||
}
|
||||
|
||||
gc.engine = this;
|
||||
|
@ -674,6 +685,21 @@ asCScriptEngine::~asCScriptEngine()
|
|||
objectTypeBehaviours.ReleaseAllFunctions();
|
||||
globalPropertyBehaviours.ReleaseAllFunctions();
|
||||
|
||||
// Destroy the funcdefs
|
||||
// As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released
|
||||
// TODO: refactor: This really should be done by ClearUnusedTypes() as soon as the funcdef is no longer is use.
|
||||
// Perhaps to make it easier to manage the memory for funcdefs each function definition should
|
||||
// have it's own object type. That would make the funcdef much more similar to the other types
|
||||
// and could then be handled in much the same way. When this is done the funcdef should also be
|
||||
// changed so that it doesn't take up a function id, i.e. don't keep a reference to it in scriptFunctions.
|
||||
for( n = 0; n < funcDefs.GetLength(); n++ )
|
||||
if( funcDefs[n] )
|
||||
{
|
||||
asASSERT( funcDefs[n]->GetRefCount() == 0 );
|
||||
asDELETE(funcDefs[n], asCScriptFunction);
|
||||
}
|
||||
funcDefs.SetLength(0);
|
||||
|
||||
// Free string constants
|
||||
for( n = 0; n < stringConstants.GetLength(); n++ )
|
||||
asDELETE(stringConstants[n],asCString);
|
||||
|
@ -1012,6 +1038,10 @@ int asCScriptEngine::ClearUnusedTypes()
|
|||
if( func->name == "factstub" )
|
||||
continue;
|
||||
|
||||
// Ignore funcdefs because these will only be destroyed when the engine is released
|
||||
if( func->funcType == asFUNC_FUNCDEF )
|
||||
continue;
|
||||
|
||||
asCObjectType *ot = func->returnType.GetObjectType();
|
||||
if( ot != 0 && ot != func->objectType )
|
||||
if( func->name != ot->name )
|
||||
|
@ -1509,7 +1539,7 @@ int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD
|
|||
objectTypes.PushLast(type);
|
||||
currentGroup->objTypes.PushLast(type);
|
||||
registeredObjTypes.PushLast(type);
|
||||
|
||||
|
||||
// Define the template subtypes
|
||||
for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ )
|
||||
{
|
||||
|
@ -1809,7 +1839,7 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as
|
|||
|
||||
// If the parameter is object, and const reference for input or inout,
|
||||
// and same type as this class, then this is a copy constructor.
|
||||
if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() &&
|
||||
if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() &&
|
||||
(func.inOutFlags[0] & asTM_INREF) && paramType.GetObjectType() == objectType )
|
||||
beh->copyconstruct = func.id;
|
||||
}
|
||||
|
@ -3006,7 +3036,7 @@ void asCScriptEngine::OrphanTemplateInstances(asCObjectType *subType)
|
|||
// If the template type isn't owned by any module it can't be orphaned
|
||||
if( templateTypes[n]->module == 0 )
|
||||
continue;
|
||||
|
||||
|
||||
for( asUINT subTypeIdx = 0; subTypeIdx < templateTypes[n]->templateSubTypes.GetLength(); subTypeIdx++ )
|
||||
{
|
||||
if( templateTypes[n]->templateSubTypes[subTypeIdx].GetObjectType() == subType )
|
||||
|
@ -3193,7 +3223,7 @@ asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateT
|
|||
|
||||
// Increase ref counter for sub type if it is an object type
|
||||
for( n = 0; n < ot->templateSubTypes.GetLength(); n++ )
|
||||
if( ot->templateSubTypes[n].GetObjectType() )
|
||||
if( ot->templateSubTypes[n].GetObjectType() )
|
||||
ot->templateSubTypes[n].GetObjectType()->AddRef();
|
||||
|
||||
templateTypes.PushLast(ot);
|
||||
|
@ -3233,6 +3263,7 @@ asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, a
|
|||
}
|
||||
}
|
||||
asASSERT( found );
|
||||
UNUSED_VAR( found );
|
||||
}
|
||||
else if( orig.GetObjectType() == tmpl )
|
||||
{
|
||||
|
@ -3735,7 +3766,7 @@ void asCScriptEngine::CallGlobalFunction(void *param1, void *param2, asSSystemFu
|
|||
else
|
||||
{
|
||||
// We must guarantee the order of the arguments which is why we copy them to this
|
||||
// array. Otherwise the compiler may put them anywhere it likes, or even keep them
|
||||
// array. Otherwise the compiler may put them anywhere it likes, or even keep them
|
||||
// in the registers which causes problem.
|
||||
void *params[2] = {param1, param2};
|
||||
|
||||
|
@ -3764,7 +3795,7 @@ bool asCScriptEngine::CallGlobalFunctionRetBool(void *param1, void *param2, asSS
|
|||
// fails, because the stack given to asCGeneric is not prepared with two 64bit arguments.
|
||||
|
||||
// We must guarantee the order of the arguments which is why we copy them to this
|
||||
// array. Otherwise the compiler may put them anywhere it likes, or even keep them
|
||||
// array. Otherwise the compiler may put them anywhere it likes, or even keep them
|
||||
// in the registers which causes problem.
|
||||
void *params[2] = {param1, param2};
|
||||
asCGeneric gen(this, s, 0, (asDWORD*)params);
|
||||
|
@ -4370,7 +4401,7 @@ asDWORD asCScriptEngine::SetDefaultAccessMask(asDWORD defaultMask)
|
|||
|
||||
int asCScriptEngine::GetNextScriptFunctionId()
|
||||
{
|
||||
// This function only returns the next function id that
|
||||
// This function only returns the next function id that
|
||||
// should be used. It doesn't update the internal arrays.
|
||||
if( freeScriptFunctionIds.GetLength() )
|
||||
return freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1];
|
||||
|
@ -4384,7 +4415,7 @@ void asCScriptEngine::SetScriptFunction(asCScriptFunction *func)
|
|||
if( freeScriptFunctionIds.GetLength() && freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1] == func->id )
|
||||
freeScriptFunctionIds.PopLast();
|
||||
|
||||
if( func->id == scriptFunctions.GetLength() )
|
||||
if( asUINT(func->id) == scriptFunctions.GetLength() )
|
||||
scriptFunctions.PushLast(func);
|
||||
else
|
||||
{
|
||||
|
@ -4397,7 +4428,7 @@ void asCScriptEngine::SetScriptFunction(asCScriptFunction *func)
|
|||
void asCScriptEngine::FreeScriptFunctionId(int id)
|
||||
{
|
||||
if( id < 0 ) return;
|
||||
id &= 0xFFFF;
|
||||
id &= ~FUNC_IMPORTED;
|
||||
if( id >= (int)scriptFunctions.GetLength() ) return;
|
||||
|
||||
if( scriptFunctions[id] )
|
||||
|
|
|
@ -452,6 +452,7 @@ public:
|
|||
bool autoGarbageCollect;
|
||||
bool disallowGlobalVars;
|
||||
bool alwaysImplDefaultConstruct;
|
||||
int compilerWarnings;
|
||||
} ep;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -229,7 +229,9 @@ int asCScriptFunction::Release() const
|
|||
gcFlag = false;
|
||||
asASSERT( funcType != asFUNC_IMPORTED );
|
||||
int r = refCount.atomicDec();
|
||||
if( r == 0 && funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted
|
||||
if( r == 0 &&
|
||||
funcType != asFUNC_FUNCDEF && // Funcdefs are treated as object types and will be deleted by ClearUnusedTypes()
|
||||
funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted
|
||||
asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
|
||||
|
||||
return r;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2012 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -160,9 +160,20 @@ double asStringScanDouble(const char *string, size_t *numScanned)
|
|||
return value;
|
||||
}
|
||||
|
||||
// Converts a character to the decimal number based on the radix
|
||||
// Returns -1 if the character is not valid for the radix
|
||||
static int asCharToNbr(char ch, int radix)
|
||||
{
|
||||
if( ch >= '0' && ch <= '9' ) return ((ch -= '0') < radix ? ch : -1);
|
||||
if( ch >= 'A' && ch <= 'Z' ) return ((ch -= 'A'-10) < radix ? ch : -1);
|
||||
if( ch >= 'a' && ch <= 'z' ) return ((ch -= 'a'-10) < radix ? ch : -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix
|
||||
asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned)
|
||||
{
|
||||
asASSERT(base == 10 || base == 16);
|
||||
asASSERT(base == 10 || base == 16 || base == 0);
|
||||
|
||||
const char *end = string;
|
||||
|
||||
|
@ -175,19 +186,27 @@ asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned)
|
|||
res += *end++ - '0';
|
||||
}
|
||||
}
|
||||
else if( base == 16 )
|
||||
else
|
||||
{
|
||||
while( (*end >= '0' && *end <= '9') ||
|
||||
(*end >= 'a' && *end <= 'f') ||
|
||||
(*end >= 'A' && *end <= 'F') )
|
||||
if( base == 0 && string[0] == '0')
|
||||
{
|
||||
res *= 16;
|
||||
if( *end >= '0' && *end <= '9' )
|
||||
res += *end++ - '0';
|
||||
else if( *end >= 'a' && *end <= 'f' )
|
||||
res += *end++ - 'a' + 10;
|
||||
else if( *end >= 'A' && *end <= 'F' )
|
||||
res += *end++ - 'A' + 10;
|
||||
// Determine the radix from the prefix
|
||||
switch( string[1] )
|
||||
{
|
||||
case 'b': case 'B': base = 2; break;
|
||||
case 'o': case 'O': base = 8; break;
|
||||
case 'd': case 'D': base = 10; break;
|
||||
case 'x': case 'X': base = 16; break;
|
||||
}
|
||||
end += 2;
|
||||
}
|
||||
|
||||
asASSERT( base );
|
||||
|
||||
if( base )
|
||||
{
|
||||
for( int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++ )
|
||||
res = res * base + nbr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#define TXT_DECL_IN_SWITCH "Variables cannot be declared in switch cases, except inside statement blocks"
|
||||
#define TXT_DEFAULT_MUST_BE_LAST "The default case must be the last one"
|
||||
#define TXT_DEF_ARG_MISSING_IN_FUNC_s "All subsequent parameters after the first default value must have default values in function '%s'"
|
||||
#define TXT_DEF_ARG_TYPE_DOESNT_MATCH "The type of the default argument expression doesn't match the function parameter type"
|
||||
#define TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM "The destructor must not have any parameters"
|
||||
#define TXT_DUPLICATE_SWITCH_CASE "Duplicate switch case"
|
||||
|
||||
|
@ -110,7 +111,6 @@
|
|||
#define TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST "Illegal target type for reference cast"
|
||||
#define TXT_ILLEGAL_VARIABLE_NAME_s "Illegal variable name '%s'."
|
||||
#define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'"
|
||||
#define TXT_INTERFACE_s_ALREADY_IMPLEMENTED "The interface '%s' is already implemented"
|
||||
#define TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE "Interfaces can only implement other interfaces"
|
||||
#define TXT_INVALID_BREAK "Invalid 'break'"
|
||||
#define TXT_INVALID_CHAR_LITERAL "Invalid character literal"
|
||||
|
@ -222,6 +222,7 @@
|
|||
|
||||
#define TXT_VALUE_TOO_LARGE_FOR_TYPE "Value is too large for data type"
|
||||
|
||||
#define TXT_WARNINGS_TREATED_AS_ERROR "Warnings are treated as errors by the application"
|
||||
#define TXT_WHILE_PARSING_ARG_LIST "While parsing argument list"
|
||||
#define TXT_WHILE_PARSING_EXPRESSION "While parsing expression"
|
||||
#define TXT_WHILE_PARSING_INIT_LIST "While parsing initialization list"
|
||||
|
@ -236,32 +237,35 @@
|
|||
|
||||
// Engine message
|
||||
|
||||
#define TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT "Autohandles cannot be used with types that have been registered with NOCOUNT"
|
||||
#define TXT_INVALID_CONFIGURATION "Invalid configuration. Verify the registered application interface."
|
||||
#define TXT_VALUE_TYPE_MUST_HAVE_SIZE "A value type must be registered with a non-zero size"
|
||||
#define TXT_TYPE_s_IS_MISSING_BEHAVIOURS "Type '%s' is missing behaviours"
|
||||
#define TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE "The behaviour is not compatible with the type"
|
||||
#define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected type must have the addref, release, and all gc behaviours"
|
||||
#define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour"
|
||||
#define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours"
|
||||
#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have the default constructor and destructor behaviours"
|
||||
#define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration"
|
||||
#define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration"
|
||||
#define TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT "Autohandles cannot be used with types that have been registered with NOCOUNT"
|
||||
#define TXT_INVALID_CONFIGURATION "Invalid configuration. Verify the registered application interface."
|
||||
#define TXT_VALUE_TYPE_MUST_HAVE_SIZE "A value type must be registered with a non-zero size"
|
||||
#define TXT_TYPE_s_IS_MISSING_BEHAVIOURS "Type '%s' is missing behaviours"
|
||||
#define TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE "The behaviour is not compatible with the type"
|
||||
#define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected type must have the addref, release, and all gc behaviours"
|
||||
#define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour"
|
||||
#define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours"
|
||||
#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have the default constructor and destructor behaviours"
|
||||
#define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration"
|
||||
#define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration"
|
||||
// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to pass by value to application in native calling convention"
|
||||
#define TXT_DONT_SUPPORT_TYPE_s_BY_VAL "Don't support passing type '%s' by value to application in native calling convention on this platform"
|
||||
#define TXT_DONT_SUPPORT_TYPE_s_BY_VAL "Don't support passing type '%s' by value to application in native calling convention on this platform"
|
||||
// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to return by value from application in native calling convention"
|
||||
#define TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL "Don't support returning type '%s' by value from application in native calling convention on this platform"
|
||||
#define TXT_GC_CANNOT_FREE_OBJ_OF_TYPE_s "GC cannot free an object of type '%s', it is kept alive by the application"
|
||||
#define TXT_OBJECT_TYPE_s_DOESNT_EXIST "Object type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_TYPE_s_DOESNT_EXIST "Template type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST "Template subtype '%s' doesn't exist"
|
||||
#define TXT_FAILED_READ_SUBTYPE_OF_TEMPLATE_s "Failed to read subtype of template type '%s'"
|
||||
#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instanciate invalid template type '%s<%s>'"
|
||||
#define TXT_FAILED_IN_FUNC_s_d "Failed in call to function '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_d "Failed in call to function '%s' with '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %d)"
|
||||
#define TXT_GC_RECEIVED_NULL_PTR "AddScriptObjectToGC called with null pointer"
|
||||
#define TXT_EXCEPTION_IN_NESTED_CALL "An exception occurred in a nested call"
|
||||
#define TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL "Don't support returning type '%s' by value from application in native calling convention on this platform"
|
||||
#define TXT_GC_CANNOT_FREE_OBJ_OF_TYPE_s "GC cannot destroy an object of type '%s' as it doesn't know how many references to there are."
|
||||
#define TXT_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d "GC cannot destroy an object of type '%s' as it can't see all references. Current ref count is %d."
|
||||
#define TXT_OBJECT_TYPE_s_DOESNT_EXIST "Object type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_TYPE_s_DOESNT_EXIST "Template type '%s' doesn't exist"
|
||||
#define TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST "Template subtype '%s' doesn't exist"
|
||||
#define TXT_FAILED_READ_SUBTYPE_OF_TEMPLATE_s "Failed to read subtype of template type '%s'"
|
||||
#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instanciate invalid template type '%s<%s>'"
|
||||
#define TXT_FAILED_IN_FUNC_s_d "Failed in call to function '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_d "Failed in call to function '%s' with '%s' (Code: %d)"
|
||||
#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %d)"
|
||||
#define TXT_GC_RECEIVED_NULL_PTR "AddScriptObjectToGC called with null pointer"
|
||||
#define TXT_EXCEPTION_IN_NESTED_CALL "An exception occurred in a nested call"
|
||||
#define TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s "Type '%s' is still used by function '%s'"
|
||||
#define TXT_PREV_TYPE_IS_NAMED_s "The builtin type in previous message is named '%s'"
|
||||
|
||||
// Internal names
|
||||
|
||||
|
@ -274,6 +278,7 @@
|
|||
#define TXT_STACK_OVERFLOW "Stack overflow"
|
||||
#define TXT_NULL_POINTER_ACCESS "Null pointer access"
|
||||
#define TXT_DIVIDE_BY_ZERO "Divide by zero"
|
||||
#define TXT_DIVIDE_OVERFLOW "Overflow in integer division"
|
||||
#define TXT_UNRECOGNIZED_BYTE_CODE "Unrecognized byte code"
|
||||
#define TXT_INVALID_CALLING_CONVENTION "Invalid calling convention"
|
||||
#define TXT_UNBOUND_FUNCTION "Unbound function called"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2011 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -91,6 +91,14 @@ const char *asCTokenizer::GetDefinition(int tokenType)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool asCTokenizer::IsDigitInRadix(char ch, int radix) const
|
||||
{
|
||||
if( ch >= '0' && ch <= '9' ) return (ch -= '0') < radix;
|
||||
if( ch >= 'A' && ch <= 'Z' ) return (ch -= 'A'-10) < radix;
|
||||
if( ch >= 'a' && ch <= 'z' ) return (ch -= 'a'-10) < radix;
|
||||
return false;
|
||||
}
|
||||
|
||||
eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) const
|
||||
{
|
||||
asASSERT(source != 0);
|
||||
|
@ -214,21 +222,30 @@ bool asCTokenizer::IsConstant(const char *source, size_t sourceLength, size_t &t
|
|||
// Starting with number
|
||||
if( (source[0] >= '0' && source[0] <= '9') || (source[0] == '.' && sourceLength > 1 && source[1] >= '0' && source[1] <= '9') )
|
||||
{
|
||||
// Is it a hexadecimal number?
|
||||
if( source[0] == '0' && sourceLength > 1 && (source[1] == 'x' || source[1] == 'X') )
|
||||
// Is it a based number?
|
||||
if( source[0] == '0' && sourceLength > 1 )
|
||||
{
|
||||
size_t n;
|
||||
for( n = 2; n < sourceLength; n++ )
|
||||
{
|
||||
if( !(source[n] >= '0' && source[n] <= '9') &&
|
||||
!(source[n] >= 'a' && source[n] <= 'f') &&
|
||||
!(source[n] >= 'A' && source[n] <= 'F') )
|
||||
break;
|
||||
}
|
||||
// Determine the radix for the constant
|
||||
int radix = 0;
|
||||
switch( source[1] )
|
||||
{
|
||||
case 'b': case 'B': radix = 2; break;
|
||||
case 'o': case 'O': radix = 8; break;
|
||||
case 'd': case 'D': radix = 10; break;
|
||||
case 'x': case 'X': radix = 16; break;
|
||||
}
|
||||
|
||||
tokenType = ttBitsConstant;
|
||||
tokenLength = n;
|
||||
return true;
|
||||
if( radix )
|
||||
{
|
||||
size_t n;
|
||||
for( n = 2; n < sourceLength; n++ )
|
||||
if( !IsDigitInRadix(source[n], radix) )
|
||||
break;
|
||||
|
||||
tokenType = ttBitsConstant;
|
||||
tokenLength = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t n;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
AngelCode Scripting Library
|
||||
Copyright (c) 2003-2011 Andreas Jonsson
|
||||
Copyright (c) 2003-2013 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
|
||||
|
@ -66,6 +66,7 @@ protected:
|
|||
bool IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const;
|
||||
bool IsDigitInRadix(char ch, int radix) const;
|
||||
|
||||
const asCScriptEngine *engine;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче