1
0
Fork 0
libreoffice/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

454 lines
16 KiB
C++

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