[Libreoffice-commits] .: bridges/source

Tor Lillqvist tml at kemper.freedesktop.org
Fri Jan 21 17:26:59 PST 2011


 bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm |    2 
 bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx |   19 +
 bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx  |   24 ++
 bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk |    3 
 bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx |  209 ++++++++++---------
 5 files changed, 157 insertions(+), 100 deletions(-)

New commits:
commit b872b29cbf4d65ab15a871b964e8f1d862a324bf
Author: Tor Lillqvist <tlillqvist at novell.com>
Date:   Sat Jan 22 03:20:19 2011 +0200

    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.

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 29e75ff..09f1177 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 d3a445b..41f46c3 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 a658ed5..81833f5 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 44ea288..6fff82f 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 b22601b..25621e4 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
@@ -101,87 +101,68 @@ 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
-
-    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));
-    
-    sal_Int32 nTempIndizes = 0;
-    
-    for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+    // "this"
+    sal_Int64 * pCppThis = (sal_Int64 *) (pThis->getCppI()) + aVtableSlot.offset;
+    aCppParams[nCppParamIndex++].p = pCppThis;
+
+    // Indexes of values this have to be converted (interface conversion cpp<=>uno)
+    int pTempCppIndexes[MAXPARAMS];
+    int pTempIndexes[MAXPARAMS];
+    int nTempIndexes = 0;
+
+    // Type descriptions for reconversions
+    typelib_TypeDescription *pTempParamTypeDescr[MAXPARAMS];
+
+    for ( int nPos = 0; nPos < nParams; ++nPos )
     {
         const typelib_MethodParameter & rParam = pParams[nPos];
         typelib_TypeDescription * pParamTypeDescr = 0;
         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
-        
+
         if (!rParam.bOut
             && 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)
@@ -253,17 +267,18 @@ static void cpp_call(
         // end here
         return;
     }
-    
+
     // 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)
         {
             if (pParams[nIndex].bOut) // inout
@@ -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)
@@ -314,7 +329,7 @@ void unoInterfaceProxyDispatch(
     // is my surrogate
     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
-    
+
     switch (pMemberDescr->eTypeClass)
     {
     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
@@ -341,12 +356,12 @@ void unoInterfaceProxyDispatch(
                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
             aParam.bIn      = sal_True;
             aParam.bOut     = sal_False;
-            
+
             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
             typelib_typedescriptionreference_new(
                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
-            
+
             // dependent dispatch
             aVtableSlot.index += 1; // get, then set method
             cpp_call(
@@ -354,10 +369,10 @@ void unoInterfaceProxyDispatch(
                 pReturnTypeRef,
                 1, &aParam,
                 pReturn, pArgs, ppException );
-            
+
             typelib_typedescriptionreference_release( pReturnTypeRef );
         }
-        
+
         break;
     }
     case typelib_TypeClass_INTERFACE_METHOD:
@@ -388,7 +403,7 @@ void unoInterfaceProxyDispatch(
                 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
                     pThis->pBridge->getUnoEnv(),
                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
-            
+
                 if (pInterface)
                 {
                     ::uno_any_construct(
@@ -418,7 +433,7 @@ void unoInterfaceProxyDispatch(
         ::com::sun::star::uno::RuntimeException aExc(
             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
-        
+
         Type const & rExcType = ::getCppuType( &aExc );
         // binary identical null reference
         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );


More information about the Libreoffice-commits mailing list