summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/msvc_win32_x86-64
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/call.asm112
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx32
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx589
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx935
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx51
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx457
6 files changed, 2176 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
new file mode 100644
index 000000000..fc12d6873
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
@@ -0,0 +1,112 @@
+; -*- Mode: text; tab-width: 8; indent-tabs-mode: nil comment-column: 44; comment-start: ";; " comment-start-skip: ";; *" -*-
+
+;;
+;; This file is part of the LibreOffice project.
+;;
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+
+;; This is the function jumped to from the trampoline generated by
+;; codeSnippet() in cpp2uno.cxx. Here we call cpp_vtable_call() which
+;; then calls the actual UNO function.
+
+;; The code snippet generated is called from "normal" C++ code which
+;; has no idea that it is calling dynamically generated code.
+
+;; The generated short code snippet is not covered by any function
+;; table and unwind info, but that doesn't matter, as the instructions
+;; in it are not really going to cause any exception. Once it jumps
+;; here it is covered by a function table, and the calls further down
+;; through cpp_vtable_call() can be unwound cleanly.
+
+;; This is in a separate file for x86-64 as MSVC doesn't have in-line
+;; assembly for x64.
+
+;; Random web links and other documentation about low-level
+;; implementation details for the C++/UNO bridge on x64 Windows kept
+;; here:
+
+;; Caolan's "Lazy Hackers Guide To Porting" is useful:
+;; http://wiki.openoffice.org/wiki/Lazy_Hackers_Guide_To_Porting
+
+;; As for details about the x64 Windows calling convention, register
+;; usage, stack usage, exception handling etc, the official
+;; documentation (?) on MSDN is a bit fragmented and split up into a
+;; needlessly large number of short pages. But still:
+;; http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=VS.90%29.aspx
+
+;; Also see Raymond Chen's blog post:
+;; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/14/58579.aspx
+
+;; This one is actually more readable: "Improving Automated Analysis
+;; of Windows x64 Binaries": http://www.uninformed.org/?v=4&a=1
+
+;; This one has a mass of information about different architectures
+;; and compilers, and contains some details about the x64 Windows
+;; calling convention in particular that Microsoft doesn't mention
+;; above:
+;; http://www.agner.org/optimize/calling_conventions.pdf
+
+;; Random interesting discussion threads:
+;; http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/300bd6d3-9381-4d2d-8129-e48b392c05d8
+
+;; Ken Johnson's blog http://www.nynaeve.net/ has much interesting
+;; information, for instance:
+;; http://www.nynaeve.net/?p=11
+
+typelib_TypeClass_FLOAT equ 10
+typelib_TypeClass_DOUBLE equ 11
+
+extern cpp_vtable_call: proc
+
+.code
+
+privateSnippetExecutor proc frame
+
+ ;; Make stack frame. Re-align RSP at 16 bytes. We need just one
+ ;; qword of stack for our own purposes: Where cpp_vtable_call()
+ ;; will store the return value of the UNO callee. But we of course
+ ;; must also allocate space for the functions we call (i.e., just
+ ;; cpp_vtable_call()) to spill their register parameters.
+
+ sub rsp, 40
+ .allocstack (40)
+ .endprolog
+
+ ;; Call cpp_vtable_call() with 2 parameters:
+
+ ;; 1 (rcx): nOffsetAndIndex (already put there in code generated by codeSnippet)
+ ;; 2 (rdx): pointer to where to store return value, followed by our
+ ;; return address (uninteresting to cpp_vtable_call()), followed
+ ;; by our spilled register parameters, as stored above, followed
+ ;; by the rest of our parameters, if any.
+
+ lea rdx, 32[rsp]
+
+ call cpp_vtable_call
+
+ ;; cpp_vtable_call() returns the typelib_TypeClass type of the
+ ;; return value of the called UNO function
+
+ cmp rax, typelib_TypeClass_FLOAT
+ je Lfloat
+
+ cmp rax, typelib_TypeClass_DOUBLE
+ je Lfloat
+
+ mov rax, qword ptr 32[rsp]
+ jmp Lepilogue
+
+Lfloat:
+ movsd xmm0, qword ptr 32[rsp]
+
+Lepilogue:
+ add rsp, 40
+ ret
+privateSnippetExecutor endp
+
+end
+
+; vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx b/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx
new file mode 100644
index 000000000..668fb523e
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_MSVC_WIN32_X86_64_CALL_HXX
+#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_MSVC_WIN32_X86_64_CALL_HXX
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+
+extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void** pStack);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
new file mode 100644
index 000000000..d8b2220fc
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
@@ -0,0 +1,589 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "call.hxx"
+#include "mscx.hxx"
+
+using namespace ::com::sun::star::uno;
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTD,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // NULL indicates void return
+ sal_Int32 nParams,
+ typelib_MethodParameter * pParams,
+ void ** pStack )
+{
+ // Return type
+ typelib_TypeDescription * pReturnTD = nullptr;
+ if ( pReturnTypeRef )
+ TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
+
+ int nFirstRealParam = 3; // Index into pStack, past return
+ // value, return address and 'this'
+ // pointer.
+
+ void * pUnoReturn = nullptr;
+ void * pCppReturn = nullptr; // Complex return ptr: if != NULL && != pUnoReturn, reconversion need
+
+ if ( pReturnTD )
+ {
+ if ( bridges::cpp_uno::shared::isSimpleType( pReturnTD ) )
+ {
+ pUnoReturn = pStack;
+ }
+ else
+ {
+ pCppReturn = pStack[nFirstRealParam++];
+
+ pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTD )
+ ? alloca( pReturnTD->nSize )
+ : pCppReturn ); // direct way
+ }
+ }
+
+ void ** pCppIncomingParams = pStack + nFirstRealParam;
+
+ // Unlike this method for other archs, prefer clarity to
+ // micro-optimization, and allocate these array separately
+
+ // Parameters passed to the UNO function
+ void ** pUnoArgs = static_cast<void **>(alloca( sizeof(void *) * nParams ));
+
+ // Parameters received from C++
+ void ** pCppArgs = static_cast<void **>(alloca( sizeof(void *) * nParams ));
+
+ // Indexes of values this have to be converted (interface conversion C++<=>UNO)
+ int * pTempIndexes =
+ static_cast<int *>(alloca( sizeof(int) * nParams ));
+
+ // Type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTD =
+ static_cast<typelib_TypeDescription **>(alloca( sizeof(void *) * nParams ));
+
+ int nTempIndexes = 0;
+
+ for ( int nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+
+ typelib_TypeDescription * pParamTD = nullptr;
+ TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
+
+ if ( !rParam.bOut &&
+ bridges::cpp_uno::shared::isSimpleType( pParamTD ) )
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = pCppIncomingParams++;
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ else // ptr to complex value | ref
+ {
+ void * pCppStack;
+
+ pCppArgs[nPos] = pCppStack = *pCppIncomingParams++;
+
+ if ( !rParam.bIn ) // Pure out
+ {
+ // UNO out is unconstructed mem
+ pUnoArgs[nPos] = alloca( pParamTD->nSize );
+ pTempIndexes[nTempIndexes] = nPos;
+ // pParamTD will be released at reconversion
+ ppTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD ) )
+ {
+ ::uno_copyAndConvertData(
+ pUnoArgs[nPos] = alloca( pParamTD->nSize ),
+ pCppStack, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndexes[nTempIndexes] = nPos; // Has to be reconverted
+ // pParamTD will be released at reconversion
+ ppTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // No longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke UNO dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTD, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if ( pUnoExc )
+ {
+ // Destruct temporary in/inout params
+ while ( nTempIndexes-- )
+ {
+ int nIndex = pTempIndexes[nTempIndexes];
+
+ if ( pParams[nIndex].bIn ) // Is in/inout => was constructed
+ {
+ ::uno_destructData( pUnoArgs[nIndex], ppTempParamTD[nTempIndexes], nullptr );
+ }
+ TYPELIB_DANGER_RELEASE( ppTempParamTD[nTempIndexes] );
+ }
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ CPPU_CURRENT_NAMESPACE::mscx_raiseException(
+ &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // Has to destruct the any
+
+ // Is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // Else, no exception occurred...
+ {
+ // Temporary params
+ while (nTempIndexes--)
+ {
+ int nIndex = pTempIndexes[nTempIndexes];
+ typelib_TypeDescription * pParamTD = ppTempParamTD[nTempIndexes];
+
+ if ( pParams[nIndex].bOut ) // inout/out
+ {
+ // Convert and assign
+ ::uno_destructData(
+ pCppArgs[nIndex], pParamTD, cpp_release );
+ ::uno_copyAndConvertData(
+ pCppArgs[nIndex], pUnoArgs[nIndex], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // Destroy temp UNO param
+ ::uno_destructData( pUnoArgs[nIndex], pParamTD, nullptr );
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ // Return
+ if ( pCppReturn ) // Has complex return
+ {
+ if ( pUnoReturn != pCppReturn ) // Needs reconversion
+ {
+ ::uno_copyAndConvertData(
+ pCppReturn, pUnoReturn, pReturnTD,
+ pThis->getBridge()->getUno2Cpp() );
+ // Destroy temp UNO return
+ ::uno_destructData( pUnoReturn, pReturnTD, nullptr );
+ }
+ // Complex return ptr is set to eax
+ pStack[0] = pCppReturn;
+ }
+ if ( pReturnTD )
+ {
+ typelib_TypeClass eRet = pReturnTD->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+extern "C" typelib_TypeClass cpp_vtable_call(
+ sal_Int64 nOffsetAndIndex,
+ void ** pStack )
+{
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+ sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF);
+
+ // pStack points to space for return value allocated by
+ // privateSnippetExecutor() in call.asm, after which follows our
+ // return address (uninteresting), then the integer or
+ // floating-point register parameters (spilled by
+ // privateSnippetExecutor()) from the call to the trampoline,
+ // followed by stacked parameters. The first parameter is the
+ // 'this' pointer. If the callee returns a large value, the
+ // parameter after that is actually a pointer to where the callee
+ // should store its return value.
+
+ void * pThis = static_cast<char *>( pStack[2] ) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+
+ typelib_InterfaceTypeDescription * pTD = pCppI->getTypeDescr();
+
+ SAL_INFO( "bridges", "cpp_vtable_call: pCallStack=[" <<
+ std::hex << pStack[0] << "," << pStack[1] << "," << pStack[2] << ",...], pThis=" <<
+ pThis << ", pCppI=" << pCppI <<
+ std::dec << ", nFunctionIndex=" << nFunctionIndex << ", nVtableOffset=" << nVtableOffset );
+ SAL_INFO( "bridges", "name=" << OUString::unacquired(&pTD->aBase.pTypeName) );
+
+ if ( nFunctionIndex >= pTD->nMapFunctionIndexToMemberIndex )
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTD->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTD->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTD->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTD->nMapFunctionIndexToMemberIndex)),
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+
+ // Determine called method
+ int nMemberPos = pTD->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTD->nAllMembers);
+
+ TypeDescription aMemberDescr( pTD->ppAllMembers[nMemberPos] );
+
+ SAL_INFO( "bridges", "Calling " << OUString::unacquired(&aMemberDescr.get()->pTypeName) );
+
+ typelib_TypeClass eRet;
+ switch ( aMemberDescr.get()->eTypeClass )
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference *pAttrTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
+
+ if ( pTD->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
+ {
+ // is GET method
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
+ 0, nullptr, // No params
+ pStack );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ nullptr, // Indicates void return
+ 1, &aParam,
+ pStack );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch ( nFunctionIndex )
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // Non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD2 = nullptr;
+
+ // the incoming C++ parameters are: The this
+ // pointer, the hidden return value pointer, and
+ // then the actual queryInterface() only
+ // parameter. Thus pStack[4]..
+
+ TYPELIB_DANGER_GET( &pTD2, static_cast<Type *>( pStack[4] )->getTypeLibType() );
+
+ if ( pTD2 )
+ {
+ XInterface * pInterface = nullptr;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
+ ( pCppI->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&pInterface),
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD2 ) );
+
+ if ( pInterface )
+ {
+ // pStack[3] = hidden return value pointer
+ ::uno_any_construct( static_cast<uno_Any *>( pStack[3] ),
+ &pInterface, pTD2, cpp_acquire );
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD2 );
+
+ pStack[0] = pStack[3];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD2 );
+ }
+ [[fallthrough]];
+ }
+ default:
+ {
+ typelib_InterfaceMethodTypeDescription * pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams,
+ pMethodTD->pParams,
+ pStack );
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException("No member description found!",
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+ }
+
+ return eRet;
+}
+
+int const codeSnippetSize = 48;
+
+extern "C" char privateSnippetExecutor;
+
+// This function generates the code that acts as a proxy for the UNO function to be called.
+// The generated code does the following:
+// - Spills register parameters on stack
+// - Loads functionIndex and vtableOffset into scratch registers
+// - Jumps to privateSnippetExecutor
+
+static unsigned char * codeSnippet(
+ unsigned char * code,
+ CPPU_CURRENT_NAMESPACE::RegParamKind param_kind[4],
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset )
+{
+ sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>(nVtableOffset) << 32 ) | static_cast<sal_uInt64>(nFunctionIndex);
+ unsigned char *p = code;
+
+ // Spill parameters
+ if ( param_kind[0] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 8[rsp], rcx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x08;
+ }
+ else
+ {
+ // movsd qword ptr 8[rsp], xmm0
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08;
+ }
+ if ( param_kind[1] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 16[rsp], rdx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
+ }
+ else
+ {
+ // movsd qword ptr 16[rsp], xmm1
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x10;
+ }
+ if ( param_kind[2] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 24[rsp], r8
+ *p++ = 0x4C; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18;
+ }
+ else
+ {
+ // movsd qword ptr 24[rsp], xmm2
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
+ }
+ if ( param_kind[3] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 32[rsp], r9
+ *p++ = 0x4C;*p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x20;
+ }
+ else
+ {
+ // movsd qword ptr 32[rsp], xmm3
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x5C; *p++ = 0x24; *p++ = 0x20;
+ }
+
+ // mov rcx, nOffsetAndIndex
+ *p++ = 0x48; *p++ = 0xB9;
+ *reinterpret_cast<sal_uInt64 *>(p) = nOffsetAndIndex; p += 8;
+
+ // mov r11, privateSnippetExecutor
+ *p++ = 0x49; *p++ = 0xBB;
+ *reinterpret_cast<void **>(p) = &privateSnippetExecutor; p += 8;
+
+ // jmp r11
+ *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
+
+ assert(p < code + codeSnippetSize);
+
+ return code + codeSnippetSize;
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(
+ void * block )
+{
+ return static_cast< Slot * >(block) + 1;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount )
+{
+ return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block,
+ sal_Int32 slotCount,
+ sal_Int32, typelib_InterfaceTypeDescription * )
+{
+ struct Rtti {
+ sal_Int32 n0, n1, n2;
+ type_info * rtti;
+ Rtti():
+ n0(0), n1(0), n2(0),
+ rtti(CPPU_CURRENT_NAMESPACE::mscx_getRTTI(
+ "com.sun.star.uno.XInterface"))
+ {}
+ };
+ static Rtti rtti;
+
+ Slot * slots = mapBlockToVtable(block);
+ slots[-1].fn = &rtti;
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots,
+ unsigned char * code,
+ typelib_InterfaceTypeDescription const * type,
+ sal_Int32 nFunctionOffset,
+ sal_Int32 functionCount,
+ sal_Int32 nVtableOffset )
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+
+ for (int member = 0; member < type->nMembers; ++member) {
+ typelib_TypeDescription * pTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pTD, type->ppMembers[ member ] );
+ assert(pTD);
+
+ CPPU_CURRENT_NAMESPACE::RegParamKind param_kind[4];
+ int nr = 0;
+
+ for (int i = 0; i < 4; ++i)
+ param_kind[i] = CPPU_CURRENT_NAMESPACE::REGPARAM_INT;
+
+ // 'this'
+ ++nr;
+
+ if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
+ {
+ typelib_InterfaceAttributeTypeDescription * pIfaceAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
+
+ // Getter
+
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+ if ( ! pIfaceAttrTD->bReadOnly )
+ {
+ typelib_TypeDescription * pAttrTD = nullptr;
+ TYPELIB_DANGER_GET( &pAttrTD, pIfaceAttrTD->pAttributeTypeRef );
+ assert(pAttrTD);
+
+ // Setter
+ if ( pAttrTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pAttrTD->eTypeClass == typelib_TypeClass_DOUBLE )
+ param_kind[nr++] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT;
+
+ TYPELIB_DANGER_RELEASE( pAttrTD );
+
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+ }
+ }
+ else if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
+ {
+ typelib_InterfaceMethodTypeDescription * pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
+
+ typelib_TypeDescription * pReturnTD = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTD, pMethodTD->pReturnTypeRef );
+ assert(pReturnTD);
+
+ if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD ) )
+ {
+ // Return value
+ ++nr;
+ }
+
+ for (int param = 0; nr < 4 && param < pMethodTD->nParams; ++param, ++nr)
+ {
+ typelib_TypeDescription * pParamTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pParamTD, pMethodTD->pParams[param].pTypeRef );
+ assert(pParamTD);
+
+ if ( pParamTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pParamTD->eTypeClass == typelib_TypeClass_DOUBLE )
+ param_kind[nr] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT;
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+ }
+ else
+ assert(false);
+
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *,
+ unsigned char const * )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
new file mode 100644
index 000000000..daa0426a2
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
@@ -0,0 +1,935 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// Interesting info can be found in:
+
+// MSDN, obviously
+
+// http://www.osronline.com/article.cfm?article=469
+
+// ONTL, "Open NT Native Template Library", a C++ STL-like library
+// that can be used even when writing Windows drivers. This is some
+// quite badass code. The author has done impressive heavy spelunking
+// of MSVCR structures. http://code.google.com/p/ontl/
+
+// Geoff Chappell's pages:
+// http://www.geoffchappell.com/studies/msvc/language/index.htm
+
+// The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts:
+
+#if 0
+
+/* This information until the corresponding '#endif // 0' is covered
+ * by ONTL's license, which is said to be the "zlib/libpng license"
+ * below, which as far as I see is permissive enough to allow this
+ * information to be included here in this source file. Note that no
+ * actual code from ONTL below gets compiled into the object file.
+ */
+
+/*
+ * Copyright (c) 2011 <copyright holders> (The ONTL main
+ * developer(s) don't tell their real name(s) on the ONTL site.)
+ *
+ * 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.
+ *
+ */
+
+typedef uint32_t rva_t;
+
+///\note the calling convention should not matter since this has no arguments
+typedef void generic_function_t();
+
+struct ptrtomember // _PMD
+{
+ typedef __w64 int32_t mdiff_t;
+ mdiff_t member_offset;
+ mdiff_t vbtable_offset; // -1 if not a virtual base
+ mdiff_t vdisp_offset; // offset to the displacement value inside the vbtable
+
+ template<typename T>
+ T * operator()(T * const thisptr) const
+ {
+ uintptr_t tp = reinterpret_cast<uintptr_t>(thisptr);
+ uintptr_t ptr = tp + member_offset;
+ if ( vbtable_offset != -1 ) // !(vbtable_offset < 0)
+ {
+ ptr += *reinterpret_cast<mdiff_t*>( static_cast<intptr_t>(vdisp_offset + *reinterpret_cast<mdiff_t*>(tp + vbtable_offset)) )
+ + vbtable_offset;
+ }
+ return reinterpret_cast<T*>(ptr);
+ }
+};
+
+struct eobject
+{
+ typedef void (* dtor_ptr )(eobject*);
+ typedef void (* ctor_ptr )(eobject*, eobject*);
+ typedef void (* ctor_ptr2)(eobject*, eobject*, int);
+};
+
+struct catchabletype
+{
+ /** is simple type */
+ uint32_t memmoveable : 1;
+ /** catchable as reference only */
+ uint32_t refonly : 1;
+ /** class with virtual base */
+ uint32_t hasvirtbase : 1;
+ /** offset to the type descriptor */
+ rva_t typeinfo;
+
+ /** catch type instance location within a thrown object */
+ ptrtomember thiscast;
+ /** size of the simple type or offset into buffer of \c this pointer for catch object */
+ uint32_t object_size;
+
+ union
+ {
+ rva_t copyctor;
+ rva_t copyctor2;
+ };
+};
+
+#pragma pack(push, 4)
+struct catchabletypearray
+{
+ uint32_t size;
+ rva_t type[1];
+};
+#pragma pack(pop)
+
+#pragma pack(push, 4)
+struct throwinfo
+{
+ typedef exception_disposition __cdecl forwardcompathandler_t(...);
+
+ /* 0x00 */ uint32_t econst : 1;
+ /* 0x00 */ uint32_t evolatile : 1;
+ /* 0x00 */ uint32_t : 1;
+ /* 0x00 */ uint32_t e8 : 1;
+ /* 0x04 */ rva_t exception_dtor;
+ /* 0x08 */ rva_t forwardcompathandler;
+ /* 0x0C */ rva_t catchabletypearray; ///< types able to catch the exception.
+};
+#pragma pack(pop)
+
+/// This type represents the catch clause
+struct ehandler
+{
+ // union { uint32_t adjectives; void * ptr; };
+ uint32_t isconst : 1;
+ uint32_t isvolatile : 1;
+ uint32_t isunaligned : 1;// guess it is not used on x86
+ uint32_t isreference : 1;
+
+ uint32_t :27;
+ uint32_t ishz : 1;
+
+ /** offset to the type descriptor of this catch object */
+ /*0x04*/ rva_t typeinfo; // dispType
+ /*0x08*/ int eobject_bpoffset; // dispCatchObj
+ /** offset to the catch clause funclet */
+ /*0x0C*/ rva_t handler; // dispOfHandler
+ /*0x10*/ uint32_t frame; // dispFrame
+}
+
+// ___BuildCatchObject
+/// 15.3/16 When the exception-declaration specifies a class type, a copy
+/// constructor is used to initialize either the object declared
+/// in the exception-declaration or,
+/// if the exception-declaration does not specify a name,
+/// a temporary object of that type.
+///\note This is the question may we optimize out the last case.
+///\warning If the copy constructor throws an exception, std::unexpected would be called
+void
+ constructcatchobject(
+ cxxregistration * cxxreg,
+ const ehandler * const catchblock,
+ catchabletype * const convertible,
+ const dispatcher_context* const dispatch
+ )
+ const
+{
+ _EH_TRACE_ENTER();
+ // build helper
+ __try {
+ struct typeinfo_t { void* vtbl; void* spare; char name[1]; };
+ enum catchable_info { cidefault, cicomplex, civirtual } cinfo = cidefault;
+
+ const typeinfo_t* ti = catchblock->typeinfo ? dispatch->va<typeinfo_t*>(catchblock->typeinfo) : NULL;
+ if(ti && *ti->name && (catchblock->eobject_bpoffset || catchblock->ishz)){
+ eobject** objplace = catchblock->ishz
+ ? reinterpret_cast<eobject**>(cxxreg)
+ : reinterpret_cast<eobject**>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers);
+ if(catchblock->isreference){
+ // just ref/pointer
+ *objplace = adjust_pointer(get_object(), convertible);
+ }else if(convertible->memmoveable){
+ // POD
+ std::memcpy(objplace, get_object(), convertible->object_size);
+ if(convertible->object_size == sizeof(void*) && *objplace)
+ *objplace = adjust_pointer((void*)*objplace, convertible);
+ }else{
+ // if copy ctor exists, call it; binary copy otherwise
+ if(convertible->copyctor){
+ cinfo = convertible->hasvirtbase ? civirtual : cicomplex;
+ }else{
+ std::memcpy(objplace, (const void*)adjust_pointer(get_object(), convertible), convertible->object_size);
+ }
+ }
+ }
+ // end of build helper
+ if(cinfo != cidefault){
+ eobject* objthis = catchblock->ishz
+ ? reinterpret_cast<eobject*>(cxxreg)
+ : reinterpret_cast<eobject*>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers);
+ void* copyctor = thrown_va(convertible->copyctor);
+ eobject* copyarg = adjust_pointer(get_object(), convertible);
+ if(cinfo == cicomplex)
+ (eobject::ctor_ptr (copyctor))(objthis, copyarg);
+ else
+ (eobject::ctor_ptr2(copyctor))(objthis, copyarg, 1);
+ }
+ }
+ __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus>(_exception_code())))
+ {
+ nt::exception::inconsistency();
+ }
+ _EH_TRACE_LEAVE();
+}
+
+#endif // 0
+
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <malloc.h>
+#include <new.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <unordered_map>
+#include "mscx.hxx"
+#include <except.hxx>
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star::uno;
+using namespace ::std;
+using namespace ::osl;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ static int mscx_getRTTI_len(OUString const & rUNOname);
+
+
+static OUString toUNOname(
+ OUString const & rRTTIname )
+ throw ()
+{
+ OUStringBuffer aRet( 64 );
+ OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
+ sal_Int32 nPos = aStr.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = aStr.lastIndexOf( '@', nPos );
+ aRet.append( aStr.copy( n +1, nPos -n -1 ) );
+ if (n >= 0)
+ {
+ aRet.append( '.' );
+ }
+ nPos = n;
+ }
+ return aRet.makeStringAndClear();
+}
+
+static OUString toRTTIname(
+ OUString const & rUNOname )
+ throw ()
+{
+ OUStringBuffer aRet( 64 );
+ aRet.append( ".?AV" ); // class ".?AV"; struct ".?AU"
+ sal_Int32 nPos = rUNOname.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
+ aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
+ aRet.append( '@' );
+ nPos = n;
+ }
+ aRet.append( '@' );
+ return aRet.makeStringAndClear();
+}
+
+//RTTI simulation
+
+typedef std::unordered_map< OUString, void * > t_string2PtrMap;
+
+namespace {
+
+class type_info_descriptor;
+
+class RTTInfos
+{
+ Mutex _aMutex;
+ t_string2PtrMap _allRTTI;
+
+public:
+ type_info * getRTTI( OUString const & rUNOname ) throw ();
+ int getRTTI_len(OUString const & rUNOname) throw ();
+ type_info_descriptor * insert_new_type_info_descriptor(OUString const & rUNOname);
+
+ RTTInfos() throw ();
+};
+class type_info_
+{
+ friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
+ friend int mscx::mscx_filterCppException(
+ EXCEPTION_POINTERS *, uno_Any *, uno_Mapping * );
+
+public:
+ virtual ~type_info_() throw ();
+
+ type_info_( void * m_data, const char * m_d_name ) throw ()
+ : _m_data( m_data )
+ { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
+
+private:
+ void * _m_data;
+ char _m_d_name[1];
+};
+
+}
+
+type_info_::~type_info_() throw ()
+{
+ (void)_m_data;
+}
+
+namespace {
+
+class type_info_descriptor
+{
+private:
+ int type_info_size;
+ type_info_ info;
+
+public:
+
+ type_info_descriptor(void * m_data, const char * m_d_name) throw ()
+ : info(m_data, m_d_name)
+ {
+ type_info_size = sizeof(type_info_) + strlen(m_d_name);
+ }
+
+ type_info * get_type_info()
+ {
+ return reinterpret_cast<type_info *>(&info);
+ }
+ int get_type_info_size()
+ {
+ return type_info_size;
+ }
+};
+
+}
+
+type_info_descriptor * RTTInfos::insert_new_type_info_descriptor(OUString const & rUNOname) {
+
+ // insert new type_info
+ OString aRawName(OUStringToOString(toRTTIname(rUNOname), RTL_TEXTENCODING_ASCII_US));
+ type_info_descriptor * pRTTI = new(std::malloc(sizeof(type_info_descriptor) + aRawName.getLength()))
+ type_info_descriptor(nullptr, aRawName.getStr());
+
+ // put into map
+ pair< t_string2PtrMap::iterator, bool > insertion(
+ _allRTTI.insert(t_string2PtrMap::value_type(rUNOname, pRTTI)));
+ assert(insertion.second && "### rtti insertion failed?!");
+
+ return pRTTI;
+}
+type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
+{
+ // a must be
+ static_assert(sizeof(type_info_) == sizeof(type_info), "### type info structure size differ!");
+
+ MutexGuard aGuard( _aMutex );
+ t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) );
+
+ // check if type is already available
+ if (iFind == _allRTTI.end())
+ {
+ // Wrap new type_info_ in type_info_descriptor to preserve length info
+ type_info_descriptor * pRTTI = insert_new_type_info_descriptor(rUNOname);
+ return pRTTI->get_type_info();
+ }
+ else
+ {
+ return static_cast<type_info_descriptor *>(iFind->second)->get_type_info();
+ }
+}
+
+int RTTInfos::getRTTI_len(OUString const & rUNOname) throw ()
+{
+ MutexGuard aGuard(_aMutex);
+ t_string2PtrMap::const_iterator const iFind(_allRTTI.find(rUNOname));
+
+ // Wrap new type_info_ in type_info_descriptor to preserve length info
+ // check if type is already available
+ if (iFind == _allRTTI.end())
+ {
+ // Wrap new type_info_ in type_info_descriptor to preserve length info
+ type_info_descriptor * pRTTI = insert_new_type_info_descriptor(rUNOname);
+ return pRTTI->get_type_info_size();
+ }
+ else
+ {
+ return static_cast<type_info_descriptor *>(iFind->second)->get_type_info_size();
+ }
+}
+
+RTTInfos::RTTInfos() throw ()
+{
+}
+
+static void * __cdecl copyConstruct(
+ void * pExcThis,
+ void * pSource,
+ typelib_TypeDescription * pTD ) throw ()
+{
+ ::uno_copyData( pExcThis, pSource, pTD, cpp_acquire );
+ return pExcThis;
+}
+
+static void * __cdecl destruct(
+ void * pExcThis,
+ typelib_TypeDescription * pTD ) throw ()
+{
+ ::uno_destructData( pExcThis, pTD, cpp_release );
+ return pExcThis;
+}
+
+const int codeSnippetSize = 40;
+
+static void GenerateConstructorTrampoline(
+ unsigned char * code,
+ typelib_TypeDescription * pTD ) throw ()
+{
+ unsigned char *p = code;
+
+ // mov r8, pTD
+ *p++ = 0x49; *p++ = 0xB8;
+ *reinterpret_cast<void **>(p) = pTD; p += 8;
+
+ // mov r11, copyConstruct
+ *p++ = 0x49; *p++ = 0xBB;
+ *reinterpret_cast<void **>(p) = reinterpret_cast<void *>(&copyConstruct); p += 8;
+
+ // jmp r11
+ *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
+
+ assert( p < code + codeSnippetSize );
+}
+
+static void GenerateDestructorTrampoline(
+ unsigned char * code,
+ typelib_TypeDescription * pTD ) throw ()
+{
+ unsigned char *p = code;
+
+ // mov rdx, pTD
+ *p++ = 0x48; *p++ = 0xBA;
+ *reinterpret_cast<void **>(p) = pTD; p += 8;
+
+ // mov r11, destruct
+ *p++ = 0x49; *p++ = 0xBB;
+ *reinterpret_cast<void **>(p) = reinterpret_cast<void *>(&destruct); p += 8;
+
+ // jmp r11
+ *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
+
+ assert( p < code + codeSnippetSize );
+}
+
+namespace {
+
+// This looks like it is the struct catchabletype above
+
+struct ExceptionType
+{
+ sal_Int32 _n0; // flags
+ sal_uInt32 _pTypeInfo; // typeinfo
+ sal_Int32 _n1, _n2, _n3; // thiscast
+ sal_Int32 _n4; // object_size
+ sal_uInt32 _pCopyCtor; // copyctor
+ type_info_ type_info;
+
+
+ ExceptionType(
+ unsigned char * pCode,
+ sal_uInt64 pCodeBase,
+ typelib_TypeDescription * pTD ) throw ()
+ : _n0( 0 )
+ , _n1( 0 )
+ , _n2( -1 )
+ , _n3( 0 )
+ , _n4( pTD->nSize)
+ , type_info(nullptr, "")
+ {
+ // As _n0 is always initialized to zero, that means the
+ // hasvirtbase flag (see the ONTL catchabletype struct) is
+ // off, and thus the copyctor is of the ctor_ptr kind.
+ memcpy(static_cast<void *>(&type_info), static_cast<void *>(mscx_getRTTI(pTD->pTypeName)), mscx_getRTTI_len(pTD->pTypeName));
+ _pTypeInfo = static_cast<sal_uInt32>(
+ reinterpret_cast<sal_uInt64>(&type_info) - pCodeBase);
+ GenerateConstructorTrampoline( pCode, pTD );
+ assert(
+ pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
+ && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase
+ < 0x100000000));
+ _pCopyCtor = static_cast<sal_uInt32>(
+ reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
+ }
+};
+
+struct RaiseInfo;
+
+class ExceptionInfos
+{
+ Mutex _aMutex;
+ t_string2PtrMap _allRaiseInfos;
+
+public:
+ static RaiseInfo * getRaiseInfo( typelib_TypeDescription * pTD ) throw ();
+
+ static DWORD allocationGranularity;
+
+ ExceptionInfos() throw ();
+};
+
+}
+
+DWORD ExceptionInfos::allocationGranularity = 0;
+
+// This corresponds to the struct throwinfo described above.
+
+namespace {
+
+struct RaiseInfo
+{
+ sal_Int32 _n0;
+ sal_uInt32 _pDtor;
+ sal_Int32 _n2;
+ sal_uInt32 _types;
+
+ // Additional fields
+ typelib_TypeDescription * _pTD;
+ unsigned char * _code;
+ sal_uInt64 _codeBase;
+
+ explicit RaiseInfo(typelib_TypeDescription * pTD) throw ();
+};
+
+}
+
+/* Rewrite of 32-Bit-Code to work under 64 Bit:
+* To use the 32 Bit offset values in the ExceptionType we have to
+* allocate a single allocation block and use it for all code and date
+* all offsets inside this area are guaranteed to be in 32 bit address range.
+* So we have to calc total memory allocation size for D-tor, C-Tors,
+* ExceptionType and type_info. ExceptionType is allocated via placement new
+* to locate everything inside our mem block.
+* There is one caveat: Struct type_info is kept in
+* a map and was referenced from class ExceptionType. Therefore type_info now
+* is also member of ExceptionType and can be referenced via 32 bit offset.
+*/
+
+RaiseInfo::RaiseInfo(typelib_TypeDescription * pTD)throw ()
+ : _n0(0)
+ , _n2(0)
+ , _pTD(pTD)
+{
+ typelib_CompoundTypeDescription * pCompTD;
+
+ // Count how many trampolines we need
+ int codeSize = codeSnippetSize;
+ // Info count
+ int nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD);
+ pCompTD; pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ ++nLen;
+ codeSize += codeSnippetSize;
+ }
+
+ // Array with size (4) and all _pTypeInfo (4*nLen)
+ int typeInfoArraySize = 4 + 4 * nLen;
+
+ // 2.Pass: Get the total needed memory for class ExceptionType
+ // (with embedded type_info) and keep the sizes for each instance
+ // is stored in allocated int array
+ auto exceptionTypeSizeArray = std::make_unique<int[]>(nLen);
+
+ nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD);
+ pCompTD; pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ int typeInfoLen = mscx_getRTTI_len(pCompTD->aBase.pTypeName);
+ // Mem has to be on 4-byte Boundary
+ if (typeInfoLen % 4 != 0)
+ {
+ int n = typeInfoLen / 4;
+ n++;
+ typeInfoLen = n*4;
+ }
+ exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
+ }
+
+ // Total ExceptionType related mem
+ int excTypeAddLen = 0;
+ for (int i = 0; i < nLen; i++)
+ {
+ excTypeAddLen += exceptionTypeSizeArray[i];
+ }
+
+ // Allocate mem for code and all dynamic data in one chunk to guarantee
+ // 32 bit offsets
+ const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
+ unsigned char * pCode = _code =
+ static_cast<unsigned char *>(std::malloc(totalSize));
+ int pCodeOffset = 0;
+
+ // New base of types array, starts after Trampoline D-Tor / C-Tors
+ DWORD * types = reinterpret_cast<DWORD *>(pCode + codeSize);
+
+ // New base of ExceptionType array, starts after types array
+ unsigned char *etMem = pCode + codeSize + typeInfoArraySize;
+ int etMemOffset = 0;
+
+ _codeBase = reinterpret_cast<sal_uInt64>(pCode)
+ & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
+
+ DWORD old_protect;
+ bool success =
+ VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
+ (void) success;
+ assert(success && "VirtualProtect() failed!");
+
+ ::typelib_typedescription_acquire(pTD);
+
+ // Fill pCode with D-Tor code
+ GenerateDestructorTrampoline(pCode, pTD);
+ _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
+ pCodeOffset += codeSnippetSize;
+
+ // Info count accompanied by type info ptrs: type, base type, base base type, ...
+ // Keep offset of types_array
+ _types = static_cast<sal_Int32>(
+ reinterpret_cast<sal_uInt64>(types)-_codeBase);
+ // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
+ types[0] = nLen;
+
+ int nPos = 1;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD);
+ pCompTD; pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ // Create instance in mem block with placement new
+ ExceptionType * et = new(etMem + etMemOffset)ExceptionType(
+ pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription *>(pCompTD));
+
+ // Next trampoline entry offset
+ pCodeOffset += codeSnippetSize;
+ // Next ExceptionType placement offset
+ etMemOffset += exceptionTypeSizeArray[nPos - 1];
+
+ // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
+ types[nPos++]
+ = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et)-_codeBase);
+ }
+ // Final check: end of address calculation must be end of mem
+ assert(etMem + etMemOffset == pCode + totalSize);
+}
+
+ExceptionInfos::ExceptionInfos() throw ()
+{
+}
+
+RaiseInfo * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTD ) throw ()
+{
+ static ExceptionInfos* s_pInfos = []() {
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ allocationGranularity = systemInfo.dwAllocationGranularity;
+
+ return new ExceptionInfos();
+ }();
+
+ assert( pTD &&
+ (pTD->eTypeClass == typelib_TypeClass_STRUCT ||
+ pTD->eTypeClass == typelib_TypeClass_EXCEPTION) );
+
+ RaiseInfo * pRaiseInfo;
+
+ OUString const & rTypeName = OUString::unacquired( &pTD->pTypeName );
+ MutexGuard aGuard( s_pInfos->_aMutex );
+ t_string2PtrMap::const_iterator const iFind(
+ s_pInfos->_allRaiseInfos.find( rTypeName ) );
+ if (iFind == s_pInfos->_allRaiseInfos.end())
+ {
+ pRaiseInfo = new RaiseInfo( pTD );
+
+ // Put into map
+ pair< t_string2PtrMap::iterator, bool > insertion(
+ s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, static_cast<void *>(pRaiseInfo) ) ) );
+ assert(insertion.second && "### raise info insertion failed?!");
+ }
+ else
+ {
+ // Reuse existing info
+ pRaiseInfo = static_cast<RaiseInfo *>(iFind->second);
+ }
+
+ return pRaiseInfo;
+}
+
+type_info * mscx_getRTTI(
+ OUString const & rUNOname )
+{
+ static RTTInfos* s_pRTTIs = new RTTInfos();
+ return s_pRTTIs->getRTTI( rUNOname );
+}
+int mscx_getRTTI_len(
+ OUString const & rUNOname)
+{
+ static RTTInfos* s_pRTTIs = new RTTInfos();
+ return s_pRTTIs->getRTTI_len(rUNOname);
+}
+
+
+void mscx_raiseException(
+ uno_Any * pUnoExc,
+ uno_Mapping * pUno2Cpp )
+{
+ // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
+ // thus this obj file will be compiled without opt, so no inlining of
+ // ExceptionInfos::getRaiseInfo()
+
+ // construct cpp exception object
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pUnoExc->pType );
+
+ void * pCppExc = alloca( pTD->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTD, pUno2Cpp );
+
+ ULONG_PTR arFilterArgs[4];
+ arFilterArgs[0] = MSVC_magic_number;
+ arFilterArgs[1] = reinterpret_cast<ULONG_PTR>(pCppExc);
+ arFilterArgs[2] = reinterpret_cast<ULONG_PTR>(ExceptionInfos::getRaiseInfo( pTD ));
+ arFilterArgs[3] = reinterpret_cast<RaiseInfo *>(arFilterArgs[2])->_codeBase;
+
+ // Destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ // last point to release anything not affected by stack unwinding
+ RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 4, arFilterArgs);
+}
+
+namespace
+{
+// This function does the same check as __CxxDetectRethrow from msvcrt (see its
+// crt/src/vcruntime/mgdframe.cpp). But it does not alter the global state, i.e. it does not
+// increment __ProcessingThrow, and so does not break following exception handling. We rely on the
+// definition of EHExceptionRecord, PER_IS_MSVC_EH and PER_PTHROW, that are current as of msvcrt
+// 2017 (14.14.26428).
+bool DetectRethrow(void* ppExcept)
+{
+ struct EHExceptionRecord
+ {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD* ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+ struct alignas(8)
+ {
+ DWORD magicNumber;
+ PVOID pExceptionObject;
+ PVOID pThrowInfo;
+ PVOID pThrowImageBase;
+ } params;
+ };
+
+ constexpr auto PER_IS_MSVC_EH = [](EHExceptionRecord* p) {
+ constexpr DWORD EH_EXCEPTION_NUMBER = 0xE06D7363; // The NT Exception # that msvcrt uses ('msc' | 0xE0000000)
+ constexpr DWORD EH_MAGIC_NUMBER1 = 0x19930520; // latest magic # in thrown object
+ constexpr DWORD EH_MAGIC_NUMBER2 = 0x19930521; // latest magic # in func info for exception specs
+ constexpr DWORD EH_MAGIC_NUMBER3 = 0x19930522; // latest magic #
+ constexpr DWORD EH_EXCEPTION_PARAMETERS = 4; // Number of parameters in exception record for AMD64
+
+ return p->ExceptionCode == EH_EXCEPTION_NUMBER
+ && p->NumberParameters == EH_EXCEPTION_PARAMETERS
+ && (p->params.magicNumber == EH_MAGIC_NUMBER1
+ || p->params.magicNumber == EH_MAGIC_NUMBER2
+ || p->params.magicNumber == EH_MAGIC_NUMBER3);
+ };
+
+ constexpr auto PER_PTHROW = [](EHExceptionRecord* p) {
+ return p->params.pThrowInfo;
+ };
+
+ EHExceptionRecord* pExcept;
+ if (!ppExcept)
+ return false;
+ pExcept = *static_cast<EHExceptionRecord**>(ppExcept);
+ if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr)
+ {
+ return true;
+ }
+ return false;
+}
+}
+
+int mscx_filterCppException(
+ EXCEPTION_POINTERS * pPointers,
+ uno_Any * pUnoExc,
+ uno_Mapping * pCpp2Uno )
+{
+ if (pPointers == nullptr)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord;
+
+ // Handle only C++ exceptions:
+ if (pRecord == nullptr || pRecord->ExceptionCode != MSVC_ExceptionCode)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ const bool rethrow = DetectRethrow(&pRecord);
+ assert(pRecord == pPointers->ExceptionRecord);
+
+ if (rethrow && pRecord == pPointers->ExceptionRecord)
+ {
+ pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(__current_exception());
+ }
+
+ // Rethrow: handle only C++ exceptions:
+ if (pRecord == nullptr || pRecord->ExceptionCode != MSVC_ExceptionCode)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if (pRecord->NumberParameters == 4 &&
+ pRecord->ExceptionInformation[0] == MSVC_magic_number &&
+ pRecord->ExceptionInformation[1] != 0 &&
+ pRecord->ExceptionInformation[2] != 0 &&
+ pRecord->ExceptionInformation[3] != 0)
+ {
+ // ExceptionInformation[1] is the address of the thrown object
+ // (or the address of a pointer to it, in most cases when it
+ // is a C++ class, obviously).
+
+ // [2] is the throwinfo pointer
+
+ // [3] is the image base address which is added the 32-bit
+ // rva_t fields in throwinfo to get actual 64-bit addresses
+ ULONG_PTR base = pRecord->ExceptionInformation[3];
+ DWORD * types = reinterpret_cast<DWORD *>(
+ base
+ + (reinterpret_cast<RaiseInfo *>(pRecord->ExceptionInformation[2])
+ ->_types));
+ if (types != nullptr && types[0] != 0)
+ {
+ DWORD pType = types[1];
+ ExceptionType * et
+ = reinterpret_cast<ExceptionType *>(base + pType);
+ if (pType != 0 && et->_pTypeInfo != 0)
+ {
+ OUString aRTTIname(
+ OStringToOUString(
+ (reinterpret_cast<type_info_ *>(base + et->_pTypeInfo)
+ ->_m_d_name),
+ RTL_TEXTENCODING_ASCII_US));
+ OUString aUNOname( toUNOname( aRTTIname ) );
+
+ typelib_TypeDescription * pExcTD = nullptr;
+ typelib_typedescription_getByName(
+ &pExcTD, aUNOname.pData );
+ if (pExcTD == nullptr)
+ {
+ OUString sMsg = "[mscx_uno bridge error] UNO type of "
+ "C++ exception unknown: \""
+ + aUNOname + "\", RTTI-name=\""
+ + aRTTIname + "\"!";
+
+ RuntimeException exc( sMsg );
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc,
+ cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno );
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert(
+ pUnoExc, reinterpret_cast<void *>(pRecord->ExceptionInformation[1]),
+ pExcTD, pCpp2Uno );
+ typelib_typedescription_release( pExcTD );
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ }
+ }
+ // though this unknown exception leaks now, no user-defined exception
+ // is ever thrown through the binary C-UNO dispatcher call stack.
+ RuntimeException exc( "[mscx_uno bridge error] unexpected "
+ "C++ exception occurred!" );
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno );
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+}
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx b/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx
new file mode 100644
index 000000000..078fd23fd
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_MSVC_WIN32_X86_64_MSCX_HXX
+#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_MSVC_WIN32_X86_64_MSCX_HXX
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <rtl/ustring.hxx>
+
+
+class type_info;
+typedef struct _uno_Any uno_Any;
+typedef struct _uno_Mapping uno_Mapping;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+const DWORD MSVC_ExceptionCode = 0xe06d7363;
+const long MSVC_magic_number = 0x19930520L;
+
+typedef enum { REGPARAM_INT, REGPARAM_FLT } RegParamKind;
+
+type_info * mscx_getRTTI( OUString const & rUNOname );
+
+int mscx_filterCppException(
+ EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno );
+
+void mscx_raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
new file mode 100644
index 000000000..99f87e23d
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
@@ -0,0 +1,457 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "mscx.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+bool cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams,
+ typelib_MethodParameter * pParams,
+ void * pUnoReturn,
+ void * pUnoArgs[],
+ uno_Any ** ppUnoExc ) throw ()
+{
+ const int MAXPARAMS = 32;
+
+ if ( nParams > MAXPARAMS )
+ {
+ // We have a hard limit on the number of parameters so that we
+ // don't need any assembler code here but can call the
+ // function using normal C++.
+
+ return false;
+ }
+
+ // Table with this pointer, optional complex return value ptr, and the parameters
+ union {
+ sal_Int64 i;
+ void *p;
+ double d;
+ } aCppParams[MAXPARAMS+2], uRetVal;
+ int nCppParamIndex = 0;
+
+ // Return type
+ typelib_TypeDescription * pReturnTD = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
+ assert(pReturnTD);
+
+ // 'this'
+ void * pAdjustedThisPtr = reinterpret_cast<void **>( pThis->getCppI() ) + aVtableSlot.offset;
+ aCppParams[nCppParamIndex++].p = pAdjustedThisPtr;
+
+ enum class ReturnKind { Void, Simple, Complex, ComplexConvert };
+ ReturnKind retKind;
+ if (pUnoReturn == nullptr) {
+ retKind = ReturnKind::Void;
+ } else {
+ assert(pReturnTD != nullptr);
+ if (bridges::cpp_uno::shared::isSimpleType(pReturnTD)) {
+ retKind = ReturnKind::Simple;
+ } else if (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTD))
+ {
+ retKind = ReturnKind::ComplexConvert;
+ aCppParams[nCppParamIndex++].p = alloca(pReturnTD->nSize);
+ } else {
+ retKind = ReturnKind::Complex;
+ aCppParams[nCppParamIndex++].p = pUnoReturn;
+ }
+ }
+
+ // Indexes of values this have to be converted (interface conversion C++<=>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, ++nCppParamIndex )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+
+ typelib_TypeDescription * pParamTD = nullptr;
+ TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
+
+ if ( !rParam.bOut &&
+ bridges::cpp_uno::shared::isSimpleType( pParamTD ) )
+ {
+ ::uno_copyAndConvertData(
+ &aCppParams[nCppParamIndex], pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ // No longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ else // Ptr to complex value | ref
+ {
+ if ( !rParam.bIn ) // Is pure out
+ {
+ // C++ out is constructed mem, UNO out is not!
+ ::uno_constructData(
+ aCppParams[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pParamTD );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // Will be released at reconversion
+ pTempParamTypeDescr[nTempIndexes++] = pParamTD;
+
+ }
+ // Is in/inout
+ else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD ) )
+ {
+ ::uno_copyAndConvertData(
+ aCppParams[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // Will be released at reconversion
+ pTempParamTypeDescr[nTempIndexes++] = pParamTD;
+ }
+ else // direct way
+ {
+ aCppParams[nCppParamIndex].p = pUnoArgs[nPos];
+
+ // No longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ }
+ }
+
+ __try
+ {
+ // The first real parameter is always '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 in 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 registers, others in RCX, RDX, R8, R9.
+
+ // Now, the nice thing for us is that when calling varargs
+ // functions, floating-point parameters among the four first
+ // ones are always passed *both* in an XMM and integer
+ // register. So we don't need to bother here calling the
+ // method different ways depending on what types of parameters
+ // it actually expects. We just pretend parameters 3..4 are
+ // doubles, and they will be passed both in XMM and integer
+ // registers, and the callee will find them where it
+ // expects. (The callee is not actually varargs, of course.)
+
+ sal_Int64 (*pIMethod)(sal_Int64, ...) =
+ reinterpret_cast<sal_Int64 (*)(sal_Int64, ...)>(
+ (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
+
+ double (*pFMethod)(sal_Int64, ...) =
+ reinterpret_cast<double (*)(sal_Int64, ...)>(
+ (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
+
+ // Pass parameters 2..4 as if it was a floating-point value so
+ // that it gets put in both XMM and integer registers per the
+ // calling convention. It doesn't matter if it actually is a
+ // fp or not.
+
+ if ( pReturnTD &&
+ (pReturnTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pReturnTD->eTypeClass == typelib_TypeClass_DOUBLE) )
+ uRetVal.d =
+ pFMethod (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,
+ aCppParams[20].i, aCppParams[21].i, aCppParams[22].i, aCppParams[23].i,
+ aCppParams[24].i, aCppParams[25].i, aCppParams[26].i, aCppParams[27].i,
+ aCppParams[28].i, aCppParams[29].i, aCppParams[30].i, aCppParams[31].i );
+ else
+ uRetVal.i =
+ pIMethod (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,
+ aCppParams[20].i, aCppParams[21].i, aCppParams[22].i, aCppParams[23].i,
+ aCppParams[24].i, aCppParams[25].i, aCppParams[26].i, aCppParams[27].i,
+ aCppParams[28].i, aCppParams[29].i, aCppParams[30].i, aCppParams[31].i );
+ }
+ __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException(
+ GetExceptionInformation(),
+ *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
+ {
+ // *ppUnoExc was constructed by filter function.
+ // Temporary params
+ while ( nTempIndexes-- )
+ {
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ // Destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ aCppParams[nCppIndex].p, pTempParamTypeDescr[nTempIndexes],
+ cpp_release );
+ TYPELIB_DANGER_RELEASE( pTempParamTypeDescr[nTempIndexes] );
+ }
+ // Return type
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ // End here
+ return true;
+ }
+
+ // No exception occurred
+ *ppUnoExc = nullptr;
+
+ // Reconvert temporary params
+ while ( nTempIndexes-- )
+ {
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ int nIndex = pTempIndexes[nTempIndexes];
+ typelib_TypeDescription * pParamTD =
+ pTempParamTypeDescr[nTempIndexes];
+
+ if ( pParams[nIndex].bIn )
+ {
+ if ( pParams[nIndex].bOut ) // Inout
+ {
+ ::uno_destructData(
+ pUnoArgs[nIndex], pParamTD, nullptr ); // Destroy UNO value
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // Pure out
+ {
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+
+ // Destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ aCppParams[nCppIndex].p, pParamTD, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+
+ // Return value
+ switch (retKind) {
+ case ReturnKind::Void:
+ break;
+ case ReturnKind::Simple:
+ *static_cast<sal_Int64*>(pUnoReturn) = uRetVal.i;
+ break;
+ case ReturnKind::Complex:
+ assert(uRetVal.p == pUnoReturn);
+ break;
+ case ReturnKind::ComplexConvert:
+ assert(uRetVal.p == aCppParams[1].p);
+ ::uno_copyAndConvertData(
+ pUnoReturn, uRetVal.p, pReturnTD,
+ pThis->getBridge()->getCpp2Uno() );
+ ::uno_destructData(
+ uRetVal.p, pReturnTD, cpp_release );
+ break;
+ }
+
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return true;
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI,
+ const typelib_TypeDescription * pMemberTD,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberTD->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberTD)));
+ if ( pReturn )
+ {
+ // Is GET
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // Is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberTD)));
+
+ switch (aVtableSlot.index)
+ {
+ // Standard calls
+ case 1: // Acquire UNO interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // Release UNO interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
+
+ if ( pTD )
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if ( pInterface )
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ if ( ! cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD)->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD)->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD)->pParams,
+ pReturn, pArgs, ppException ) )
+ {
+ RuntimeException aExc( "Too many parameters!" );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+ break;
+ }
+ default:
+ {
+ RuntimeException aExc( "Illegal member type description!" );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // Binary identical null reference (whatever that comment means...)
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */