summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/msvc_win32_x86-64
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/cpp_uno/msvc_win32_x86-64')
-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.hxx29
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx264
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx465
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx454
5 files changed, 1324 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..393f8fcb4
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx
@@ -0,0 +1,29 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+
+extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void** pStack);
+
+/* 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..159eb99a4
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
@@ -0,0 +1,264 @@
+/* -*- 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 <msvc/cpp2uno.hxx>
+#include <msvc/amd64.hxx>
+
+using namespace ::com::sun::star;
+
+extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void ** pCallStack)
+{
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+ sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF);
+ return cpp_mediate(pCallStack, nFunctionIndex, nVtableOffset, nullptr);
+}
+
+int const codeSnippetSize = 48;
+
+namespace {
+
+typedef enum { REGPARAM_INT, REGPARAM_FLT } RegParamKind;
+
+}
+
+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,
+ 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] == 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] == 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] == 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] == 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(RTTInfos::get("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);
+
+ RegParamKind param_kind[4];
+ int nr = 0;
+
+ for (int i = 0; i < 4; ++i)
+ param_kind[i] = 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++] = 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] = 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..e5836dd11
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
@@ -0,0 +1,465 @@
+/* -*- 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 <com/sun/star/uno/Any.hxx>
+#include <msvc/amd64.hxx>
+#include <except.hxx>
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star;
+
+static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
+ typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
+ return pExcThis;
+}
+
+static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_destructData(pExcThis, pTD, uno::cpp_release);
+ return pExcThis;
+}
+
+const int codeSnippetSize = 40;
+
+static void GenerateConstructorTrampoline(unsigned char* code,
+ typelib_TypeDescription* pTD) noexcept
+{
+ 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) noexcept
+{
+ 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);
+}
+
+ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+ typelib_TypeDescription* pTD) noexcept
+ : _n0(0)
+ , _n1(0)
+ , _n2(-1)
+ , _n3(0)
+ , _n4(pTD->nSize)
+ , exc_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.
+
+ int len;
+ type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);
+
+ memcpy(static_cast<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
+ _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_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);
+}
+
+/* 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) noexcept
+ : _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;
+ RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
+ // 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);
+}
+
+#pragma pack(pop)
+
+/* 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..d5df4a161
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
@@ -0,0 +1,454 @@
+/* -*- 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 <msvc/except.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+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 ) noexcept
+{
+ 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;
+ } aCppArgs[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;
+ aCppArgs[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;
+ aCppArgs[nCppParamIndex++].p = alloca(pReturnTD->nSize);
+ } else {
+ retKind = ReturnKind::Complex;
+ aCppArgs[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 *pTempParamTD[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(
+ &aCppArgs[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(
+ aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pParamTD );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+
+ // default constructed for C++ call
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTD))
+ {
+ ::uno_copyAndConvertData(
+ aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+
+ // has to be reconverted
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ else // direct way
+ {
+ aCppArgs[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 (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
+ aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
+ aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
+ aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
+ aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
+ aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
+ aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
+ aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
+ else
+ uRetVal.i =
+ pIMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
+ aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
+ aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
+ aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
+ aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
+ aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
+ aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
+ aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
+ }
+ __except (msvc_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(
+ aCppArgs[nCppIndex].p, pTempParamTD[nTempIndexes],
+ uno::cpp_release );
+ TYPELIB_DANGER_RELEASE( pTempParamTD[nTempIndexes] );
+ }
+
+ // return type
+ if (pReturnTD)
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return true;
+ }
+
+ // NO exception occurred
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ while (nTempIndexes--)
+ {
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ int nIndex = pTempIndexes[nTempIndexes];
+ typelib_TypeDescription * pParamTD =
+ pTempParamTD[nTempIndexes];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ ::uno_destructData(
+ pUnoArgs[nIndex], pParamTD, nullptr ); // destroy UNO value
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+
+ // destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ aCppArgs[nCppIndex].p, pParamTD, uno::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 == aCppArgs[1].p);
+ ::uno_copyAndConvertData(
+ pUnoReturn, uRetVal.p, pReturnTD,
+ pThis->getBridge()->getCpp2Uno() );
+ ::uno_destructData(
+ uRetVal.p, pReturnTD, uno::cpp_release );
+ break;
+ }
+
+ // return type
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return true;
+}
+
+} // namespace
+
+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)
+ {
+ 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< uno::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:
+ typelib_InterfaceMethodTypeDescription const* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD);
+
+ if (!cpp_call(pThis, aVtableSlot, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
+ pMethodTD->pParams, pReturn, pArgs, ppException))
+ {
+ uno::RuntimeException aExc( "Too many parameters!" );
+
+ uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ uno::RuntimeException aExc("Illegal member type description!", uno::Reference<uno::XInterface>());
+
+ uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */