summaryrefslogtreecommitdiff
path: root/bridges
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@novell.com>2011-01-22 03:20:19 +0200
committerTor Lillqvist <tlillqvist@novell.com>2011-01-22 03:20:19 +0200
commit28787edbd8a6bc1e3a6486d42f316cc54a7ff0e3 (patch)
treecda3dd17bb6969d517e1700d95ad7a677de5c91b /bridges
parent525f7823d6f4b9bc625bc8c99be6683b11d46d48 (diff)
More hacking on the C++-UNO bridge for x64 Windows
I think I might actually be able to manage without any assembly coding here, thanks to the clean design of the x64 Windows calling convention, and tricking the compiler (in a fully documented and stable way) by using varargs. uno2cpp.cxx might even be getting close to working now, but cpp2uno.cxx and except.cxx parts are just forced to compile by using dummy code.
Diffstat (limited to 'bridges')
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm2
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx19
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx24
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk3
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx173
5 files changed, 139 insertions, 82 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm
index 29e75ff38845..09f1177b9a9e 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm
@@ -110,7 +110,7 @@ extrn cpp_mediate: proc
; So instead of generating jumps into here, we should just make the
; C++ code copy the machine code that these three "naked" functions
-; compile after the snippet it is generating. Of course, that means
+; compile to after the snippet it is generating. Of course, that means
; the code here needs to be position independent, or (eek) that we
; would need to come up with some home-brewed minimal relocation
; mechanism.
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
index d3a445bed2c1..41f46c352b59 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
@@ -362,6 +362,8 @@ extern void *cpp_vtable_call;
//==================================================================================================
int const codeSnippetSize = 28;
+#if 0
+
unsigned char * codeSnippet(
unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
{
@@ -383,6 +385,8 @@ unsigned char * codeSnippet(
return code + codeSnippetSize;
}
+#endif
+
}
struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
@@ -420,6 +424,17 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock(
return slots + slotCount;
}
+#if 0
+
+#else
+
+static void whatthefuck(sal_Int64 i, ...)
+{
+
+}
+
+#endif
+
unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
Slot ** slots, unsigned char * code,
typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset,
@@ -428,8 +443,12 @@ unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
(*slots) -= functionCount;
Slot * s = *slots;
for (sal_Int32 i = 0; i < functionCount; ++i) {
+#if 0
(s++)->fn = code;
code = codeSnippet(code, functionOffset++, vtableOffset);
+#else
+ (s++)->fn = whatthefuck;
+#endif
}
return code;
}
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
index c7fea183d91f..0774eed1721e 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
@@ -264,11 +264,27 @@ void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis )
}
+#if 0
+
// These are machine code snippets in asmbits.asm
extern void *copyConstruct;
extern void *destruct;
+#else
+
+static void whatthefuck_copyctor(sal_Int64 i, ...)
+{
+
+}
+
+static void whatthefuck_dtor(sal_Int64 i, ...)
+{
+
+}
+
+#endif
+
//==================================================================================================
struct ExceptionType
{
@@ -284,7 +300,11 @@ struct ExceptionType
, _n2( -1 )
, _n3( 0 )
, _n4( pTypeDescr->nSize )
+#if 0
, _pCopyCtor( new ObjectFunction( pTypeDescr, copyConstruct ) )
+#else
+ , _pCopyCtor( (ObjectFunction*) whatthefuck_copyctor )
+#endif
, _n5( 0 )
{ _pTypeInfo = mscx_getRTTI( pTypeDescr->pTypeName ); }
inline ~ExceptionType() throw ()
@@ -305,7 +325,11 @@ struct RaiseInfo
//__________________________________________________________________________________________________
RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
: _n0( 0 )
+#if 0
, _pDtor( new ObjectFunction( pTypeDescr, destruct ) )
+#else
+ , _pDtor( (ObjectFunction*) whatthefuck_dtor )
+#endif
, _n2( 0 )
, _n3( 0 )
, _n4( 0 )
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk
index 44ea288e8cb5..6fff82fb0145 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk
@@ -54,8 +54,7 @@ SLOFILES= \
$(SLO)$/cpp2uno.obj \
$(SLO)$/uno2cpp.obj \
$(SLO)$/dllinit.obj \
- $(SLO)$/except.obj \
- $(SLO)$/asmbits.obj
+ $(SLO)$/except.obj
NOOPTFILES= \
$(SLO)$/except.obj
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
index 74b55397e6e8..74b6466efeff 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
@@ -101,65 +101,56 @@ static void cpp_call(
sal_Int32 nParams, typelib_MethodParameter * pParams,
void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) throw ()
{
- // max space for: [complex ret ptr], values|ptr ...
- // (but will be used less - some of the values will be in pGPR and pFPR)
- sal_uInt64 *pStack = (sal_uInt64 *) alloca( (nParams + 3) * sizeof(sal_uInt64) );
- sal_uInt64 *pStackStart = pStack;
-
- // Parameters to be passed in registers stored here
- sal_uInt64 pGPR[4];
- sal_uInt32 nGPR = 0;
- double pFPR[4];
- sal_uInt32 nFPR = 0;
-
- if (nParams > 20)
+ const int MAXPARAMS = 20;
+
+ if (nParams > MAXPARAMS)
{
+ // We have a hard limit on the number of parameters so that we
+ // don't need any assembler stuff but can call the function
+ // using normal C++.
+ // What is the proper way to abort with at least some
+ // information given to the user?
+ abort();
}
+ // table with optional complex return value ptr, this pointer, and the parameters
+ union {
+ sal_Int64 i;
+ void *p;
+ double d;
+ } aCppParams[MAXPARAMS+2], uRetVal;
+ int nCppParamIndex = 0;
- char * pCppStack = (char *)alloca( sizeof(sal_Int64) + (nParams * sizeof(sal_Int64)) );
- char * pCppStackStart = pCppStack;
-
- // Return
+ // Return type
typelib_TypeDescription * pReturnTypeDescr = 0;
TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
- void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
-
bool bSimpleReturn = true;
if (pReturnTypeDescr)
{
- if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
- {
- pCppReturn = pUnoReturn; // direct way for simple types
- }
- else
+ if (pReturnTypeDescr->nSize > 8)
{
// complex return via ptr
- pCppReturn = *(void **)pCppStack
- = (bridges::cpp_uno::shared::relatesToInterfaceType(
- pReturnTypeDescr )
- ? alloca( pReturnTypeDescr->nSize )
- : pUnoReturn); // direct way
- pCppStack += sizeof(void *);
+ bSimpleReturn = false;
+ aCppParams[nCppParamIndex++].p = alloca( pReturnTypeDescr->nSize );
}
}
- // stack space
+ // "this"
+ sal_Int64 * pCppThis = (sal_Int64 *) (pThis->getCppI()) + aVtableSlot.offset;
+ aCppParams[nCppParamIndex++].p = pCppThis;
- OSL_ENSURE( sizeof(void *) == sizeof(sal_Int64), "### unexpected size!" );
- // args
- void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
- // indizes of values this have to be converted (interface conversion cpp<=>uno)
- sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
- // type descriptions for reconversions
- typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+ // Indexes of values this have to be converted (interface conversion cpp<=>uno)
+ int pTempCppIndexes[MAXPARAMS];
+ int pTempIndexes[MAXPARAMS];
+ int nTempIndexes = 0;
- sal_Int32 nTempIndizes = 0;
+ // Type descriptions for reconversions
+ typelib_TypeDescription *pTempParamTypeDescr[MAXPARAMS];
- for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ for ( int nPos = 0; nPos < nParams; ++nPos )
{
const typelib_MethodParameter & rParam = pParams[nPos];
typelib_TypeDescription * pParamTypeDescr = 0;
@@ -169,19 +160,9 @@ static void cpp_call(
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
{
::uno_copyAndConvertData(
- pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
+ aCppParams[nCppParamIndex++].p, pUnoArgs[nPos], pParamTypeDescr,
pThis->getBridge()->getUno2Cpp() );
- switch (pParamTypeDescr->eTypeClass)
- {
- case typelib_TypeClass_HYPER:
- case typelib_TypeClass_UNSIGNED_HYPER:
- case typelib_TypeClass_DOUBLE:
- pCppStack += sizeof(sal_Int64); // extra qword
- break;
- default:
- break;
- }
// no longer needed
TYPELIB_DANGER_RELEASE( pParamTypeDescr );
}
@@ -191,44 +172,77 @@ static void cpp_call(
{
// cpp out is constructed mem, uno out is not!
::uno_constructData(
- *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ aCppParams[nCppParamIndex].p = alloca( pParamTypeDescr->nSize ),
pParamTypeDescr );
- pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+ pTempIndexes[nTempIndexes] = nPos;
+
// will be released at reconversion
- ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
+ pTempParamTypeDescr[nTempIndexes++] = pParamTypeDescr;
+
+ nCppParamIndex++;
}
// is in/inout
else if (bridges::cpp_uno::shared::relatesToInterfaceType(
pParamTypeDescr ))
{
::uno_copyAndConvertData(
- *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ aCppParams[nCppParamIndex].p = alloca( pParamTypeDescr->nSize ),
pUnoArgs[nPos], pParamTypeDescr,
pThis->getBridge()->getUno2Cpp() );
- pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+ pTempIndexes[nTempIndexes] = nPos;
+
// will be released at reconversion
- ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
+ pTempParamTypeDescr[nTempIndexes++] = pParamTypeDescr;
+
+ nCppParamIndex++;
}
else // direct way
{
- *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ aCppParams[nCppParamIndex++].p = pUnoArgs[nPos];
// no longer needed
TYPELIB_DANGER_RELEASE( pParamTypeDescr );
}
}
- pCppStack += sizeof(sal_Int64); // standard parameter length
}
__try
{
- // pCppI is mscx this pointer
- callVirtualMethod(
- reinterpret_cast< void ** >(pThis->getCppI()) + aVtableSlot.offset,
- aVtableSlot.index,
- pCppReturn, pReturnTypeDescr->eTypeClass,
- (sal_Int64 *)pCppStackStart,
- (pCppStack - pCppStackStart) / sizeof(sal_Int64) );
+ // The first real parameter is always a pointer: either the
+ // address of where to store a complex return value or "this".
+
+ // The Windows x64 calling convention is very regular and
+ // elegant (even if perhaps then slightly slower than the
+ // Linux x64 one): The first four parameters, never more, are
+ // passed in registers, as long as they are a qword ins size
+ // or less. (If larger, a pointer to a temp copy is passed, so
+ // it's equivalent anyway.) Floating point values are passed
+ // in XMM0..3 register, others in RCX, RDX, R8, R9. Now, the
+ // nice thing for us is that for varargs functions,
+ // floating-point parameters among the four first ones are
+ // always passed *both* in XMM and integer registers. So we
+ // don't need to bother here calling the method different ways
+ // depending on what types of parameters it actually expects,
+ // just pretend parameters 3..4 are doubles and they will be
+ // passed both in XMM and integer registers, callee will find
+ // them where it expects. (The callee is not actually varargs,
+ // of course.)
+
+ sal_Int64 (*pMethod)(sal_Int64, ...) =
+ (sal_Int64 (*)(sal_Int64, ...))
+ (((sal_Int64 *)pCppThis) + aVtableSlot.index);
+
+ // Pass parameters 2..4 as double so that it gets put in both XMM and integer
+ // registers per the
+ uRetVal.i =
+ pMethod (aCppParams[0].i, aCppParams[1].d, aCppParams[2].d, aCppParams[3].d,
+ aCppParams[4].i, aCppParams[5].i, aCppParams[6].i, aCppParams[7].i,
+ aCppParams[8].i, aCppParams[9].i, aCppParams[10].i, aCppParams[11].i,
+ aCppParams[12].i, aCppParams[13].i, aCppParams[14].i, aCppParams[15].i,
+ aCppParams[16].i, aCppParams[17].i, aCppParams[18].i, aCppParams[19].i );
}
__except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException(
GetExceptionInformation(),
@@ -236,14 +250,14 @@ static void cpp_call(
{
// *ppUnoExc was constructed by filter function
// temporary params
- while (nTempIndizes--)
+ while (nTempIndexes--)
{
- sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
// destroy temp cpp param => cpp: every param was constructed
::uno_destructData(
- pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes],
+ aCppParams[nCppIndex].p, pTempParamTypeDescr[nTempIndexes],
cpp_release );
- TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
+ TYPELIB_DANGER_RELEASE( pTempParamTypeDescr[nTempIndexes] );
}
// return type
if (pReturnTypeDescr)
@@ -257,12 +271,13 @@ static void cpp_call(
// NO exception occurred
*ppUnoExc = 0;
- // reconvert temporary params
- while (nTempIndizes--)
+ // Reconvert temporary params
+ while (nTempIndexes--)
{
- sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ int nIndex = pTempIndexes[nTempIndexes];
typelib_TypeDescription * pParamTypeDescr =
- ppTempParamTypeDescr[nTempIndizes];
+ pTempParamTypeDescr[nTempIndexes];
if (pParams[nIndex].bIn)
{
@@ -271,30 +286,30 @@ static void cpp_call(
::uno_destructData(
pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
::uno_copyAndConvertData(
- pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTypeDescr,
pThis->getBridge()->getCpp2Uno() );
}
}
else // pure out
{
::uno_copyAndConvertData(
- pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTypeDescr,
pThis->getBridge()->getCpp2Uno() );
}
// destroy temp cpp param => cpp: every param was constructed
::uno_destructData(
- pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ aCppParams[nCppIndex].p, pParamTypeDescr, cpp_release );
TYPELIB_DANGER_RELEASE( pParamTypeDescr );
}
// return value
- if (pCppReturn && pUnoReturn != pCppReturn)
+ if (!bSimpleReturn)
{
::uno_copyAndConvertData(
- pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pUnoReturn, uRetVal.p, pReturnTypeDescr,
pThis->getBridge()->getCpp2Uno() );
::uno_destructData(
- pCppReturn, pReturnTypeDescr, cpp_release );
+ aCppParams[0].p, pReturnTypeDescr, cpp_release );
}
// return type
if (pReturnTypeDescr)