aec7ca0ce9
Fixes: https://github.com/supertuxkart/stk-code/issues/2528 Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
218 lines
6.3 KiB
C++
218 lines
6.3 KiB
C++
/*
|
|
AngelCode Scripting Library
|
|
Copyright (c) 2003-2015 Andreas Jonsson
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any
|
|
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
|
|
*/
|
|
|
|
//
|
|
// Added support for thiscall methods by Jordi Oliveras Rovira in April, 2014.
|
|
//
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "as_config.h"
|
|
|
|
#ifndef AS_MAX_PORTABILITY
|
|
#ifdef AS_X64_MSVC
|
|
|
|
#include "as_callfunc.h"
|
|
#include "as_scriptengine.h"
|
|
#include "as_texts.h"
|
|
#include "as_context.h"
|
|
|
|
BEGIN_AS_NAMESPACE
|
|
|
|
// These functions are implemented in as_callfunc_x64_msvc.asm
|
|
extern "C" asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func);
|
|
extern "C" asDWORD GetReturnedFloat();
|
|
extern "C" asQWORD GetReturnedDouble();
|
|
|
|
asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
|
|
{
|
|
asCScriptEngine *engine = context->m_engine;
|
|
asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
|
|
|
|
asQWORD retQW = 0;
|
|
void *func = (void*)sysFunc->func;
|
|
asUINT paramSize = 0; // QWords
|
|
void **vftable;
|
|
|
|
asQWORD allArgBuffer[64];
|
|
asQWORD floatArgBuffer[4];
|
|
|
|
int callConv = sysFunc->callConv;
|
|
|
|
// Optimization to avoid check 12 values (all ICC_ that contains THISCALL)
|
|
if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) ||
|
|
(callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
|
|
{
|
|
// Add the object pointer as the first parameter
|
|
allArgBuffer[paramSize++] = (asQWORD)obj;
|
|
}
|
|
|
|
if( sysFunc->hostReturnInMemory )
|
|
{
|
|
// The return is made in memory
|
|
callConv++;
|
|
|
|
// Set the return pointer as the first argument
|
|
allArgBuffer[paramSize++] = (asQWORD)retPointer;
|
|
}
|
|
|
|
if( callConv == ICC_CDECL_OBJFIRST ||
|
|
callConv == ICC_CDECL_OBJFIRST_RETURNINMEM )
|
|
{
|
|
// Add the object pointer as the first parameter
|
|
allArgBuffer[paramSize++] = (asQWORD)obj;
|
|
}
|
|
else if( callConv == ICC_THISCALL_OBJFIRST ||
|
|
callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM )
|
|
{
|
|
// Add the object pointer as the first parameter
|
|
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
|
}
|
|
|
|
if( callConv == ICC_VIRTUAL_THISCALL ||
|
|
callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
|
{
|
|
// Get the true function pointer from the virtual function table
|
|
vftable = *(void***)obj;
|
|
func = vftable[asPWORD(func)>>2];
|
|
}
|
|
|
|
// Move the arguments to the buffer
|
|
asUINT dpos = paramSize;
|
|
asUINT spos = 0;
|
|
for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
|
|
{
|
|
asCDataType &dt = descr->parameterTypes[n];
|
|
if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
|
|
{
|
|
if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ||
|
|
(dt.GetTypeInfo()->flags & COMPLEX_MASK) )
|
|
{
|
|
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
|
spos += AS_PTR_SIZE;
|
|
paramSize++;
|
|
}
|
|
else
|
|
{
|
|
// Copy the object's memory to the buffer
|
|
memcpy(&allArgBuffer[dpos], *(void**)(args+spos), dt.GetSizeInMemoryBytes());
|
|
|
|
// Delete the original memory
|
|
engine->CallFree(*(char**)(args+spos));
|
|
spos += AS_PTR_SIZE;
|
|
asUINT dwords = dt.GetSizeInMemoryDWords();
|
|
asUINT qwords = (dwords >> 1) + (dwords & 1);
|
|
dpos += qwords;
|
|
paramSize += qwords;
|
|
}
|
|
}
|
|
else if( dt.GetTokenType() == ttQuestion )
|
|
{
|
|
// Copy the reference and the type id
|
|
allArgBuffer[dpos++] = *(asQWORD*)&args[spos];
|
|
spos += 2;
|
|
allArgBuffer[dpos++] = args[spos++];
|
|
paramSize += 2;
|
|
}
|
|
else
|
|
{
|
|
// Copy the value directly
|
|
asUINT dwords = dt.GetSizeOnStackDWords();
|
|
if( dwords > 1 )
|
|
{
|
|
allArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
|
|
|
// Double arguments are moved to a separate buffer in order to be placed in the XMM registers,
|
|
// though this is only done for first 4 arguments, the rest are placed on the stack
|
|
if( paramSize < 4 && dt.IsDoubleType() )
|
|
floatArgBuffer[dpos] = *(asQWORD*)&args[spos];
|
|
|
|
dpos++;
|
|
spos += 2;
|
|
}
|
|
else
|
|
{
|
|
allArgBuffer[dpos] = args[spos];
|
|
|
|
// Float arguments are moved to a separate buffer in order to be placed in the XMM registers,
|
|
// though this is only done for first 4 arguments, the rest are placed on the stack
|
|
if( paramSize < 4 && dt.IsFloatType() )
|
|
floatArgBuffer[dpos] = args[spos];
|
|
|
|
dpos++;
|
|
spos++;
|
|
}
|
|
|
|
paramSize++;
|
|
}
|
|
}
|
|
|
|
if( callConv == ICC_CDECL_OBJLAST ||
|
|
callConv == ICC_CDECL_OBJLAST_RETURNINMEM )
|
|
{
|
|
// Add the object pointer as the last parameter
|
|
allArgBuffer[paramSize++] = (asQWORD)obj;
|
|
}
|
|
else if( callConv == ICC_THISCALL_OBJLAST ||
|
|
callConv == ICC_THISCALL_OBJLAST_RETURNINMEM ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJLAST ||
|
|
callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM )
|
|
{
|
|
// Add the object pointer as the last parameter
|
|
allArgBuffer[paramSize++] = (asQWORD)secondObject;
|
|
}
|
|
|
|
retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func);
|
|
|
|
// If the return is a float value we need to get the value from the FP register
|
|
if( sysFunc->hostReturnFloat )
|
|
{
|
|
if( sysFunc->hostReturnSize == 1 )
|
|
*(asDWORD*)&retQW = GetReturnedFloat();
|
|
else
|
|
retQW = GetReturnedDouble();
|
|
}
|
|
|
|
return retQW;
|
|
}
|
|
|
|
END_AS_NAMESPACE
|
|
|
|
#endif // AS_X64_MSVC
|
|
#endif // AS_MAX_PORTABILITY
|
|
|
|
|