Updated to AngelScript 2.26.2.

Small fixes to "Quickstart in C++" documentation.
This commit is contained in:
Lasse Öörni 2013-03-31 22:09:28 +00:00
Родитель 34df8b5e82
Коммит 42448b8924
28 изменённых файлов: 2193 добавлений и 952 удалений

Просмотреть файл

@ -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

183
ThirdParty/AngelScript/source/as_builder.cpp поставляемый
Просмотреть файл

@ -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(&paramBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
memset(&paramBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords());
target += descr->parameterTypes[n].GetSizeInMemoryDWords();
freeFloatSlot = freeDoubleSlot = target;
}
else
{
memcpy(&paramBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords();
stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
}
}
else
{
memcpy(&paramBuffer[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 = &paramBuffer[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*)&paramBuffer[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, &paramBuffer[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

432
ThirdParty/AngelScript/source/as_compiler.cpp поставляемый
Просмотреть файл

@ -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);
}

36
ThirdParty/AngelScript/source/as_config.h поставляемый
Просмотреть файл

@ -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

310
ThirdParty/AngelScript/source/as_context.cpp поставляемый
Просмотреть файл

@ -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()), &sectionIdx);
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;

4
ThirdParty/AngelScript/source/as_context.h поставляемый
Просмотреть файл

@ -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;

18
ThirdParty/AngelScript/source/as_datatype.cpp поставляемый
Просмотреть файл

@ -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

1
ThirdParty/AngelScript/source/as_datatype.h поставляемый
Просмотреть файл

@ -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;

23
ThirdParty/AngelScript/source/as_gc.cpp поставляемый
Просмотреть файл

@ -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);

6
ThirdParty/AngelScript/source/as_module.cpp поставляемый
Просмотреть файл

@ -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);

56
ThirdParty/AngelScript/source/as_restore.cpp поставляемый
Просмотреть файл

@ -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;
}
}

55
ThirdParty/AngelScript/source/as_texts.h поставляемый
Просмотреть файл

@ -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;