123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /*
- 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
|