bridges: add a Windows Arm64 UNO bridge

Since Microsoft follows the general ARM64 ABI calling conventions,
and the SEH exception handling is the same, this result is a mixed
port of the gcc3_linux_aarch64 bridge and the refactored x86-64
exception handling.

I have no idea, if the complicated 32-bit handling in RaiseInfo()
is needed, as the ARM64 trampolines definitly use 64-bit code.
But since this is the first working version, I currently don't
mind much ;-)

There is definitly more potential for refactoring in the whole
bridges directory...

Change-Id: I9782a2e99c0231cdd1286af156ad312229eccf39
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103642
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
This commit is contained in:
Jan-Marek Glogowski 2020-07-17 22:59:07 +02:00
parent f11dc8335c
commit 03aacdb73d
13 changed files with 1433 additions and 6 deletions

View File

@ -557,7 +557,9 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \
) \
log_uno_uno \
unsafe_uno_uno \
$(if $(filter MSC,$(COM)),$(if $(filter INTEL,$(CPUNAME)),msci,mscx),gcc3)_uno \
$(if $(filter MSC,$(COM)), \
$(if $(filter INTEL,$(CPUNAME)),msci, \
$(if $(filter ARM64,$(CPUNAME)),msca,mscx)),gcc3)_uno \
))
$(eval $(call gb_Helper_register_libraries_for_install,PRIVATELIBS_URE,ure, \

View File

@ -21,6 +21,13 @@ $(call gb_LinkTarget_get_target,$(call gb_Library_get_linktarget,gcc3_uno)) : \
EXTRAOBJECTLISTS += $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist
endif
else ifeq ($(CPUNAME),ARM64)
bridges_SELECTED_BRIDGE := msvc_win32_arm64
bridge_exception_objects := cpp2uno uno2cpp abi
bridge_noopt_objects := except
bridge_asm_objects := callvirtualfunction vtableslotcall
else ifeq ($(CPUNAME),AARCH64)
ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX MACOSX NETBSD OPENBSD,$(OS)),)

View File

@ -0,0 +1,59 @@
/* -*- 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 .
*/
#pragma once
#include <msvc/except.hxx>
#pragma pack(push, 8)
struct ExceptionType final
{
sal_Int32 _n0; // flags
sal_uInt32 _pTypeInfo; // typeinfo
sal_Int32 _n1, _n2, _n3; // thiscast
sal_Int32 _n4; // object_size
sal_uInt32 _pCopyCtor; // copyctor
ExceptionTypeInfo exc_type_info;
explicit ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
typelib_TypeDescription* pTD) throw();
ExceptionType(const ExceptionType&) = delete;
ExceptionType& operator=(const ExceptionType&) = delete;
};
struct RaiseInfo final
{
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();
};
#pragma pack(pop)
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -38,15 +38,13 @@ constexpr DWORD MSVC_EH_MAGIC_PARAM = 0x19930520;
// The NT Exception code that msvcrt uses ('msc' | 0xE0000000)
constexpr DWORD MSVC_EH_MAGIC_CODE = 0xE06D7363;
#ifdef _M_IX86
#if defined(_M_IX86)
#define MSVC_EH_PARAMETERS 3 // Number of parameters in exception record for x86
#else
#ifdef _M_AMD64
#elif defined(_M_AMD64) || defined(_M_ARM64)
#define MSVC_EH_PARAMETERS 4 // Number of parameters in exception record for AMD64
#else
#error "Unsupported machine type"
#endif
#endif
class type_info;
struct RaiseInfo;

View File

@ -41,6 +41,8 @@
#include <msvc/x86.hxx>
#elif defined(_M_AMD64)
#include <msvc/amd64.hxx>
#elif defined(_M_ARM64)
#include <msvc/arm64.hxx>
#else
#error "Unsupported machine type"
#endif
@ -137,7 +139,7 @@ ExceptionInfos::~ExceptionInfos() throw()
RaiseInfo* ExceptionInfos::getRaiseInfo(typelib_TypeDescription* pTD) throw()
{
static ExceptionInfos* s_pInfos = []() {
#ifdef _M_AMD64
#if defined _M_AMD64 || defined _M_ARM64
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
allocationGranularity = systemInfo.dwAllocationGranularity;

View File

@ -0,0 +1,158 @@
/* -*- 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 <sal/types.h>
#include <cassert>
#include "abi.hxx"
enum StructKind
{
STRUCT_KIND_EMPTY,
STRUCT_KIND_FLOAT,
STRUCT_KIND_DOUBLE,
STRUCT_KIND_POD,
STRUCT_KIND_DTOR
};
static StructKind getStructKind(typelib_CompoundTypeDescription const* type)
{
StructKind k = type->pBaseTypeDescription == 0 ? STRUCT_KIND_EMPTY
: getStructKind(type->pBaseTypeDescription);
for (sal_Int32 i = 0; i != type->nMembers; ++i)
{
StructKind k2 = StructKind();
switch (type->ppTypeRefs[i]->eTypeClass)
{
case typelib_TypeClass_BOOLEAN:
case typelib_TypeClass_BYTE:
case typelib_TypeClass_SHORT:
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_LONG:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_CHAR:
case typelib_TypeClass_ENUM:
k2 = STRUCT_KIND_POD;
break;
case typelib_TypeClass_FLOAT:
k2 = STRUCT_KIND_FLOAT;
break;
case typelib_TypeClass_DOUBLE:
k2 = STRUCT_KIND_DOUBLE;
break;
case typelib_TypeClass_STRING:
case typelib_TypeClass_TYPE:
case typelib_TypeClass_ANY:
case typelib_TypeClass_SEQUENCE:
case typelib_TypeClass_INTERFACE:
k2 = STRUCT_KIND_DTOR;
break;
case typelib_TypeClass_STRUCT:
{
typelib_TypeDescription* td = 0;
TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
k2 = getStructKind(reinterpret_cast<typelib_CompoundTypeDescription const*>(td));
TYPELIB_DANGER_RELEASE(td);
break;
}
default:
assert(false);
}
switch (k2)
{
case STRUCT_KIND_EMPTY:
// this means an empty sub-object, which nevertheless obtains a byte
// of storage (TODO: does it?), so the full object cannot be a
// homogeneous collection of float or double
case STRUCT_KIND_POD:
assert(k != STRUCT_KIND_DTOR);
k = STRUCT_KIND_POD;
break;
case STRUCT_KIND_FLOAT:
case STRUCT_KIND_DOUBLE:
if (k == STRUCT_KIND_EMPTY)
{
k = k2;
}
else if (k != k2)
{
assert(k != STRUCT_KIND_DTOR);
k = STRUCT_KIND_POD;
}
break;
case STRUCT_KIND_DTOR:
return STRUCT_KIND_DTOR;
}
}
return k;
}
ReturnKind getReturnKind(typelib_TypeDescription const* type)
{
switch (type->eTypeClass)
{
default:
assert(false);
[[fallthrough]];
case typelib_TypeClass_VOID:
case typelib_TypeClass_BOOLEAN:
case typelib_TypeClass_BYTE:
case typelib_TypeClass_SHORT:
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_LONG:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_FLOAT:
case typelib_TypeClass_DOUBLE:
case typelib_TypeClass_CHAR:
case typelib_TypeClass_ENUM:
assert(type->nSize <= 16);
return RETURN_KIND_REG;
case typelib_TypeClass_STRING:
case typelib_TypeClass_TYPE:
case typelib_TypeClass_ANY:
case typelib_TypeClass_SEQUENCE:
case typelib_TypeClass_INTERFACE:
return RETURN_KIND_INDIRECT;
case typelib_TypeClass_STRUCT:
if (type->nSize > 16)
{
return RETURN_KIND_INDIRECT;
}
switch (getStructKind(reinterpret_cast<typelib_CompoundTypeDescription const*>(type)))
{
case STRUCT_KIND_FLOAT:
return RETURN_KIND_HFA_FLOAT;
case STRUCT_KIND_DOUBLE:
return RETURN_KIND_HFA_DOUBLE;
case STRUCT_KIND_DTOR:
return RETURN_KIND_INDIRECT;
default:
return RETURN_KIND_REG;
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -0,0 +1,34 @@
/* -*- 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 .
*/
#pragma once
#include <typelib/typedescription.h>
enum ReturnKind
{
RETURN_KIND_REG,
RETURN_KIND_HFA_FLOAT,
RETURN_KIND_HFA_DOUBLE,
RETURN_KIND_INDIRECT
};
ReturnKind getReturnKind(typelib_TypeDescription const* type);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -0,0 +1,72 @@
/* -*- tab-width: 4; indent-tabs-mode: nil; 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/.
*/
OPT 2 // disable listing
// macros to add unwind information
#include "ksarm64.h"
OPT 1 // re-enable listing
EXPORT callVirtualFunction
TEXTAREA, ALIGN=8
/*
extern void callVirtualFunction
x0 stack
x1 frame
x2 function
x3 return
*/
NESTED_ENTRY callVirtualFunction_fake
// for unwind information, Windows has to store fp and lr
PROLOG_SAVE_REG_PAIR x29, x30, #-32!
ALTERNATE_ENTRY callVirtualFunction
// use a stack frame allocated by our caller
stp x29, x30, [x1]
mov x29, x1
mov sp, x0
mov x9, x2 // function
mov x8, x3 // complex return
str x3, [x29, #16] // save rvalue
// load the core argument passing registers
ldp x0, x1, [sp, #0]
ldp x2, x3, [sp, #16]
ldp x4, x5, [sp, #32]
ldp x6, x7, [sp, #48]
ldp d0, d1, [sp, #64]
ldp d2, d3, [sp, #80]
ldp d4, d5, [sp, #96]
ldp d6, d7, [sp, #112]
blr x9 // call
ldr x3, [x29, #16] // reload rvalue
// partially deconstruct the stack frame
mov sp, x29
ldp x29, x30, [x29]
// save the simple return values
stp x0, x1, [sp, #0]
stp d0, d1, [sp, #64]
stp d2, d3, [sp, #80]
NESTED_END callVirtualFunction_fake
END
/* vim:set shiftwidth=4 softtabstop=4 expandtab */

View File

@ -0,0 +1,432 @@
/* -*- 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 <cstdarg>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <com/sun/star/uno/XInterface.hpp>
#include <com/sun/star/uno/genfunc.hxx>
#include <sal/alloca.h>
#include <sal/types.h>
#include <typelib/typeclass.h>
#include <typelib/typedescription.h>
#include <typelib/typedescription.hxx>
#include <bridge.hxx>
#include <cppinterfaceproxy.hxx>
#include <types.hxx>
#include <vtablefactory.hxx>
#include <msvc/arm64.hxx>
#include "abi.hxx"
extern "C" void vtableSlotCall();
using namespace ::com::sun::star;
namespace
{
void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
uno::TypeDescription const& description, typelib_TypeDescriptionReference* returnType,
sal_Int32 count, typelib_MethodParameter* parameters, sal_uInt64* gpr, sal_uInt64* fpr,
sal_uInt64* stack, void* indirectRet)
{
typelib_TypeDescription* rtd = 0;
if (returnType != 0)
TYPELIB_DANGER_GET(&rtd, returnType);
ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd);
bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
void* retin = retKind == RETURN_KIND_INDIRECT && !retConv ? indirectRet
: rtd == 0 ? 0 : alloca(rtd->nSize);
void** args = static_cast<void**>(alloca(count * sizeof(void*)));
void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
typelib_TypeDescription** argtds
= static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
sal_Int32 ngpr = 1;
sal_Int32 nfpr = 0;
sal_Int32 sp = 0;
for (sal_Int32 i = 0; i != count; ++i)
{
if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
{
switch (parameters[i].pTypeRef->eTypeClass)
{
case typelib_TypeClass_BOOLEAN:
case typelib_TypeClass_BYTE:
case typelib_TypeClass_SHORT:
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_LONG:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_CHAR:
case typelib_TypeClass_ENUM:
args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
break;
case typelib_TypeClass_FLOAT:
case typelib_TypeClass_DOUBLE:
args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
break;
default:
assert(false);
}
argtds[i] = 0;
}
else
{
cppArgs[i] = reinterpret_cast<void*>(ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
typelib_TypeDescription* ptd = 0;
TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
if (!parameters[i].bIn)
{
args[i] = alloca(ptd->nSize);
argtds[i] = ptd;
}
else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd))
{
args[i] = alloca(ptd->nSize);
uno_copyAndConvertData(args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
argtds[i] = ptd;
}
else
{
args[i] = cppArgs[i];
argtds[i] = 0;
TYPELIB_DANGER_RELEASE(ptd);
}
}
}
uno_Any exc;
uno_Any* pexc = &exc;
proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
if (pexc != 0)
{
for (sal_Int32 i = 0; i != count; ++i)
{
if (argtds[i] == 0)
continue;
if (parameters[i].bIn)
uno_destructData(args[i], argtds[i], 0);
TYPELIB_DANGER_RELEASE(argtds[i]);
}
if (rtd != 0)
TYPELIB_DANGER_RELEASE(rtd);
assert(pexc == &exc);
msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp());
}
for (sal_Int32 i = 0; i != count; ++i)
{
if (argtds[i] != 0)
{
if (parameters[i].bOut)
{
uno_destructData(cppArgs[i], argtds[i],
reinterpret_cast<uno_ReleaseFunc>(uno::cpp_release));
uno_copyAndConvertData(cppArgs[i], args[i], argtds[i],
proxy->getBridge()->getUno2Cpp());
}
uno_destructData(args[i], argtds[i], 0);
TYPELIB_DANGER_RELEASE(argtds[i]);
}
}
void* retout = 0; // avoid false -Werror=maybe-uninitialized
switch (retKind)
{
case RETURN_KIND_REG:
switch (rtd == 0 ? typelib_TypeClass_VOID : rtd->eTypeClass)
{
case typelib_TypeClass_VOID:
break;
case typelib_TypeClass_BOOLEAN:
case typelib_TypeClass_BYTE:
case typelib_TypeClass_SHORT:
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_LONG:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_CHAR:
case typelib_TypeClass_ENUM:
std::memcpy(gpr, retin, rtd->nSize);
assert(!retConv);
break;
case typelib_TypeClass_FLOAT:
case typelib_TypeClass_DOUBLE:
std::memcpy(fpr, retin, rtd->nSize);
assert(!retConv);
break;
case typelib_TypeClass_STRUCT:
if (retConv)
{
retout = gpr;
}
else
{
std::memcpy(gpr, retin, rtd->nSize);
}
break;
default:
assert(false);
}
break;
case RETURN_KIND_HFA_FLOAT:
assert(rtd != 0);
switch (rtd->nSize)
{
case 16:
std::memcpy(fpr + 3, static_cast<char*>(retin) + 12, 4);
[[fallthrough]];
case 12:
std::memcpy(fpr + 2, static_cast<char*>(retin) + 8, 4);
[[fallthrough]];
case 8:
std::memcpy(fpr + 1, static_cast<char*>(retin) + 4, 4);
[[fallthrough]];
case 4:
std::memcpy(fpr, retin, 4);
break;
default:
assert(false);
}
assert(!retConv);
break;
case RETURN_KIND_HFA_DOUBLE:
assert(rtd != 0);
std::memcpy(fpr, retin, rtd->nSize);
assert(!retConv);
break;
case RETURN_KIND_INDIRECT:
retout = indirectRet;
break;
}
if (retConv)
{
uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
uno_destructData(retin, rtd, 0);
}
if (rtd != 0)
TYPELIB_DANGER_RELEASE(rtd);
}
extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr,
sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet)
{
bridges::cpp_uno::shared::CppInterfaceProxy* proxy
= bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
reinterpret_cast<char*>(gpr[0]) - vtableOffset);
typelib_InterfaceTypeDescription* pInterfaceTD = proxy->getTypeDescr();
assert(functionIndex < pInterfaceTD->nMapFunctionIndexToMemberIndex);
sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[functionIndex];
assert(nMemberPos < pInterfaceTD->nAllMembers);
uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
switch (aMemberDescr.get()->eTypeClass)
{
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
{
typelib_TypeDescriptionReference* pAttrTypeRef
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
->pAttributeTypeRef;
if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex)
{
// Getter:
call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet);
}
else
{
// Setter:
typelib_MethodParameter param = { 0, pAttrTypeRef, true, false };
call(proxy, aMemberDescr, 0, 1, &param, gpr, fpr, stack, indirectRet);
}
}
break;
case typelib_TypeClass_INTERFACE_METHOD:
switch (functionIndex)
{
case 1:
proxy->acquireProxy();
break;
case 2:
proxy->releaseProxy();
break;
case 0:
{
typelib_TypeDescription* td = nullptr;
TYPELIB_DANGER_GET(&td,
(reinterpret_cast<uno::Type*>(gpr[1])->getTypeLibType()));
if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE)
{
uno::XInterface* ifc = nullptr;
proxy->getBridge()->getCppEnv()->getRegisteredInterface(
proxy->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc),
proxy->getOid().pData,
reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
if (ifc != 0)
{
uno_any_construct(reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
reinterpret_cast<uno_AcquireFunc>(uno::cpp_acquire));
ifc->release();
TYPELIB_DANGER_RELEASE(td);
break;
}
TYPELIB_DANGER_RELEASE(td);
}
}
[[fallthrough]];
default:
typelib_InterfaceMethodTypeDescription* pMethodTD
= reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
aMemberDescr.get());
call(proxy, aMemberDescr, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
pMethodTD->pParams, gpr, fpr, stack, indirectRet);
}
break;
default:
assert(false);
}
}
std::size_t const codeSnippetSize = 8 * 4;
unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex,
sal_Int32 vtableOffset)
{
// movz x9, <low functionIndex>
reinterpret_cast<unsigned int*>(code)[0] = 0xD2800009 | ((functionIndex & 0xFFFF) << 5);
// movk x9, <high functionIndex>, LSL #16
reinterpret_cast<unsigned int*>(code)[1] = 0xF2A00009 | ((functionIndex >> 16) << 5);
// movz x10, <low vtableOffset>
reinterpret_cast<unsigned int*>(code)[2] = 0xD280000A | ((vtableOffset & 0xFFFF) << 5);
// movk x10, <high vtableOffset>, LSL #16
reinterpret_cast<unsigned int*>(code)[3] = 0xF2A0000A | ((vtableOffset >> 16) << 5);
// ldr x11, +2*4
reinterpret_cast<unsigned int*>(code)[4] = 0x5800004B;
// br x11
reinterpret_cast<unsigned int*>(code)[5] = 0xD61F0160;
reinterpret_cast<void**>(code)[3] = reinterpret_cast<void*>(&vtableSlotCall);
return code + codeSnippetSize;
}
}
namespace bridges::cpp_uno::shared
{
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* VtableFactory::addLocalFunctions(VtableFactory::Slot** slots, unsigned char* code,
typelib_InterfaceTypeDescription const* type,
sal_Int32 functionOffset, sal_Int32 functionCount,
sal_Int32 vtableOffset)
{
(*slots) -= functionCount;
VtableFactory::Slot* s = *slots;
for (sal_Int32 i = 0; i != type->nMembers; ++i)
{
typelib_TypeDescription* td = nullptr;
TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
assert(td != 0);
switch (td->eTypeClass)
{
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
{
typelib_InterfaceAttributeTypeDescription* atd
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(td);
// Getter:
(s++)->fn = code;
code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
// Setter:
if (!atd->bReadOnly)
{
(s++)->fn = code;
code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
}
break;
}
case typelib_TypeClass_INTERFACE_METHOD:
(s++)->fn = code;
code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
break;
default:
assert(false);
}
TYPELIB_DANGER_RELEASE(td);
}
return code;
}
void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end)
{
FlushInstructionCache(GetCurrentProcess(), begin, end - begin);
}
} // namespace bridges::cpp_uno::shared
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -0,0 +1,234 @@
/* -*- 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 <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/arm64.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 nCodeSnippetSize = 28;
static void GenerateCopyConstructorTrampoline(unsigned char* target,
typelib_TypeDescription* pTD) noexcept
{
// ldr x2, #12
// ldr x3, #20
// br x3
// pTD
// &copyConstruct
static const char code[] = "\x62\x00\x00\x58\x83\x00\x00\x58\x60\x00\x1f\xd6";
static_assert(sizeof(code) == 13);
static const unsigned int code_size = sizeof(code) - 1;
memcpy(target, code, code_size);
*reinterpret_cast<void**>(target + code_size) = pTD;
*reinterpret_cast<void**>(target + code_size + 8) = &copyConstruct;
}
static void GenerateDestructorTrampoline(unsigned char* target,
typelib_TypeDescription* pTD) noexcept
{
// ldr x1, #12
// ldr x2, #20
// br x2
// pTD
// &destruct
static const char code[] = "\x61\x00\x00\x58\x82\x00\x00\x58\x40\x00\x1f\xd6";
static_assert(sizeof(code) == 13);
static const unsigned int code_size = sizeof(code) - 1;
memcpy(target, code, code_size);
*reinterpret_cast<void**>(target + code_size) = pTD;
*reinterpret_cast<void**>(target + code_size + 8) = &destruct;
}
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);
GenerateCopyConstructorTrampoline(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 = nCodeSnippetSize;
// Info count
int nLen = 0;
for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
pCompTD = pCompTD->pBaseTypeDescription)
{
++nLen;
codeSize += nCodeSnippetSize;
}
// 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 += nCodeSnippetSize;
// 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 += nCodeSnippetSize;
// 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: */

View File

@ -0,0 +1,341 @@
/* -*- 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 <cstring>
#include <exception>
#include <typeinfo>
#include <bridge.hxx>
#include <types.hxx>
#include <unointerfaceproxy.hxx>
#include <vtables.hxx>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/genfunc.hxx>
#include <rtl/textenc.h>
#include <rtl/ustring.hxx>
#include <sal/alloca.h>
#include <sal/types.h>
#include <typelib/typeclass.h>
#include <typelib/typedescription.h>
#include <uno/any2.h>
#include <uno/data.h>
#include "abi.hxx"
#include <msvc/arm64.hxx>
namespace
{
extern "C" void callVirtualFunction(sal_uInt64* stack, sal_uInt64* frame, sal_uInt64 function,
void* ret);
void pushArgument(sal_uInt64 value, sal_uInt64* stack, sal_Int32& sp, sal_uInt64* regs,
sal_Int32& nregs)
{
(nregs != 8 ? regs[nregs++] : stack[sp++]) = value;
}
void call(bridges::cpp_uno::shared::UnoInterfaceProxy* pProxy,
bridges::cpp_uno::shared::VtableSlot slot, typelib_TypeDescriptionReference* returnType,
const sal_Int32 count, typelib_MethodParameter* parameters, void* returnValue,
void** arguments, uno_Any** exception)
{
static_assert(sizeof(sal_uInt64) == sizeof(void*));
typelib_TypeDescription* aReturnTD = nullptr;
TYPELIB_DANGER_GET(&aReturnTD, returnType);
const ReturnKind eRetKind = getReturnKind(aReturnTD);
const bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(aReturnTD);
void* ret = retConv ? alloca(aReturnTD->nSize) : returnValue;
sal_uInt64** thisPtr = reinterpret_cast<sal_uInt64**>(pProxy->getCppI()) + slot.offset;
sal_uInt64* gpr = static_cast<sal_uInt64*>(alloca((count + 16) * sizeof(sal_uInt64) + 32));
sal_uInt64* fpr = &gpr[8];
sal_uInt64* stack = &gpr[16];
sal_uInt64* frame = &gpr[16 + count];
void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
typelib_TypeDescription** ptds
= static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
sal_Int32 sp = 0;
sal_Int32 nGPR = 0;
sal_Int32 nFPR = 0;
gpr[nGPR++] = reinterpret_cast<sal_uInt64>(thisPtr);
for (sal_Int32 i = 0; i != count; ++i)
{
if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
{
cppArgs[i] = 0;
switch (parameters[i].pTypeRef->eTypeClass)
{
case typelib_TypeClass_BOOLEAN:
pushArgument(*static_cast<sal_Bool*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_BYTE:
pushArgument(*static_cast<sal_Int8*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_SHORT:
pushArgument(*static_cast<sal_Int16*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_UNSIGNED_SHORT:
pushArgument(*static_cast<sal_uInt16*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_LONG:
case typelib_TypeClass_ENUM:
pushArgument(*static_cast<sal_Int32*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_UNSIGNED_LONG:
pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_HYPER:
pushArgument(*static_cast<sal_Int64*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_UNSIGNED_HYPER:
pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, gpr, nGPR);
break;
case typelib_TypeClass_FLOAT:
pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, fpr, nFPR);
break;
case typelib_TypeClass_DOUBLE:
pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, fpr, nFPR);
break;
case typelib_TypeClass_CHAR:
pushArgument(*static_cast<sal_Unicode*>(arguments[i]), stack, sp, gpr, nGPR);
break;
default:
assert(false);
}
}
else
{
typelib_TypeDescription* ptd = 0;
TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
if (!parameters[i].bIn)
{
cppArgs[i] = alloca(ptd->nSize);
uno_constructData(cppArgs[i], ptd);
ptds[i] = ptd;
pushArgument(reinterpret_cast<sal_uInt64>(cppArgs[i]), stack, sp, gpr, nGPR);
}
else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd))
{
cppArgs[i] = alloca(ptd->nSize);
uno_copyAndConvertData(cppArgs[i], arguments[i], ptd,
pProxy->getBridge()->getUno2Cpp());
ptds[i] = ptd;
pushArgument(reinterpret_cast<sal_uInt64>(cppArgs[i]), stack, sp, gpr, nGPR);
}
else
{
cppArgs[i] = 0;
pushArgument(reinterpret_cast<sal_uInt64>(arguments[i]), stack, sp, gpr, nGPR);
TYPELIB_DANGER_RELEASE(ptd);
}
}
}
__try
{
callVirtualFunction(stack, frame, (*thisPtr)[slot.index], ret);
}
__except (msvc_filterCppException(GetExceptionInformation(), *exception,
pProxy->getBridge()->getCpp2Uno()))
{
for (sal_Int32 i = 0; i != count; ++i)
{
if (cppArgs[i] != 0)
{
uno_destructData(cppArgs[i], ptds[i],
reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
TYPELIB_DANGER_RELEASE(ptds[i]);
}
}
TYPELIB_DANGER_RELEASE(aReturnTD);
return;
}
*exception = 0;
for (sal_Int32 i = 0; i != count; ++i)
{
if (cppArgs[i] != 0)
{
if (parameters[i].bOut)
{
if (parameters[i].bIn)
{
uno_destructData(arguments[i], ptds[i], 0);
}
uno_copyAndConvertData(arguments[i], cppArgs[i], ptds[i],
pProxy->getBridge()->getCpp2Uno());
}
uno_destructData(cppArgs[i], ptds[i],
reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
TYPELIB_DANGER_RELEASE(ptds[i]);
}
}
switch (eRetKind)
{
case RETURN_KIND_REG:
switch (aReturnTD->eTypeClass)
{
case typelib_TypeClass_VOID:
break;
case typelib_TypeClass_BOOLEAN:
case typelib_TypeClass_BYTE:
case typelib_TypeClass_SHORT:
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_LONG:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_CHAR:
case typelib_TypeClass_ENUM:
case typelib_TypeClass_STRUCT:
std::memcpy(ret, gpr, aReturnTD->nSize);
break;
case typelib_TypeClass_FLOAT:
case typelib_TypeClass_DOUBLE:
std::memcpy(ret, fpr, aReturnTD->nSize);
break;
default:
assert(false);
}
break;
case RETURN_KIND_HFA_FLOAT:
switch (aReturnTD->nSize)
{
case 16:
std::memcpy(static_cast<char*>(ret) + 12, fpr + 3, 4);
[[fallthrough]];
case 12:
std::memcpy(static_cast<char*>(ret) + 8, fpr + 2, 4);
[[fallthrough]];
case 8:
std::memcpy(static_cast<char*>(ret) + 4, fpr + 1, 4);
[[fallthrough]];
case 4:
std::memcpy(ret, fpr, 4);
break;
default:
assert(false);
}
break;
case RETURN_KIND_HFA_DOUBLE:
std::memcpy(ret, fpr, aReturnTD->nSize);
break;
case RETURN_KIND_INDIRECT:
break;
}
if (retConv)
{
uno_copyAndConvertData(returnValue, ret, aReturnTD, pProxy->getBridge()->getCpp2Uno());
uno_destructData(ret, aReturnTD, reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
}
TYPELIB_DANGER_RELEASE(aReturnTD);
}
}
namespace bridges::cpp_uno::shared
{
void unoInterfaceProxyDispatch(uno_Interface* pUnoI, typelib_TypeDescription const* pMemberDescr,
void* pReturn, void** pArgs, uno_Any** ppException)
{
UnoInterfaceProxy* pProxy = static_cast<UnoInterfaceProxy*>(pUnoI);
switch (pMemberDescr->eTypeClass)
{
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
{
typelib_InterfaceAttributeTypeDescription const* atd
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription const*>(pMemberDescr);
VtableSlot slot(getVtableSlot(atd));
if (pReturn != 0)
{ // getter
call(pProxy, slot, atd->pAttributeTypeRef, 0, 0, pReturn, pArgs, ppException);
}
else
{ // setter
typelib_MethodParameter param = { 0, atd->pAttributeTypeRef, true, false };
typelib_TypeDescriptionReference* pReturnTD = nullptr;
typelib_typedescriptionreference_new(&pReturnTD, typelib_TypeClass_VOID,
OUString("void").pData);
slot.index += 1;
call(pProxy, slot, pReturnTD, 1, &param, pReturn, pArgs, ppException);
typelib_typedescriptionreference_release(pReturnTD);
}
break;
}
case typelib_TypeClass_INTERFACE_METHOD:
{
typelib_InterfaceMethodTypeDescription const* mtd
= reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(pMemberDescr);
VtableSlot slot(getVtableSlot(mtd));
switch (slot.index)
{
case 1:
pUnoI->acquire(pUnoI);
*ppException = 0;
break;
case 2:
pUnoI->release(pUnoI);
*ppException = 0;
break;
case 0:
{
typelib_TypeDescription* td = 0;
TYPELIB_DANGER_GET(
&td, (reinterpret_cast<css::uno::Type*>(pArgs[0])->getTypeLibType()));
if (td != 0)
{
uno_Interface* ifc = 0;
pProxy->pBridge->getUnoEnv()->getRegisteredInterface(
pProxy->pBridge->getUnoEnv(), reinterpret_cast<void**>(&ifc),
pProxy->oid.pData,
reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
if (ifc != 0)
{
uno_any_construct(reinterpret_cast<uno_Any*>(pReturn), &ifc, td, 0);
ifc->release(ifc);
TYPELIB_DANGER_RELEASE(td);
*ppException = 0;
break;
}
TYPELIB_DANGER_RELEASE(td);
}
}
[[fallthrough]];
default:
call(pProxy, slot, mtd->pReturnTypeRef, mtd->nParams, mtd->pParams, pReturn,
pArgs, ppException);
break;
}
break;
}
default:
assert(false);
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -0,0 +1,72 @@
/* -*- tab-width: 4; indent-tabs-mode: nil; 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 .
*/
OPT 2 // disable listing
// macros to add unwind information
#include "ksarm64.h"
OPT 1 // re-enable listing
EXPORT vtableSlotCall
IMPORT vtableCall
TEXTAREA, ALIGN=2
NESTED_ENTRY vtableSlotCall
PROLOG_SAVE_REG_PAIR fp, lr, #-192!
PROLOG_SAVE_REG_PAIR x19, x20, #16
add x11, sp, 192
add x20, sp, 128
add x19, sp, 64
stp x11, x11, [sp, 32]
str x11, [sp, 48]
stp wzr, wzr, [sp, 56]
stp x0, x1, [sp, 64]
mov w0, w9
mov w1, w10
stp x2, x3, [sp, 80]
mov x3, x20
mov x2, x19
stp x4, x5, [sp, 96]
mov x5, x8
mov x4, x11
stp x6, x7, [sp, 112]
stp d0, d1, [sp, 128]
stp d2, d3, [sp, 144]
stp d4, d5, [sp, 160]
stp d6, d7, [sp, 176]
bl vtableCall
ldp x0, x1, [x19]
ldp d0, d1, [x20]
ldp d2, d3, [x20, #16]
EPILOG_STACK_RESTORE
EPILOG_RESTORE_REG_PAIR x19, x20, #16
EPILOG_RESTORE_REG_PAIR fp, lr, #192!
EPILOG_RETURN
NESTED_END vtableSlotCall
END
/* vim:set shiftwidth=4 softtabstop=4 expandtab */

View File

@ -134,6 +134,21 @@ fi
endef
# AsmObject class
ifeq ($(CPUNAME),ARM64)
gb_AsmObject_get_source = $(1)/$(2).S
# Code needs a preprozessor step .S -> .asm -> .o
define gb_AsmObject__command
$(call gb_Output_announce,$(2),$(true),ASM,3)
$(call gb_Helper_abbreviate_dirs,\
mkdir -p $(dir $(1)) $(dir $(4)) && \
"$(CC)" -nologo -EP -D_M_ARM64 $(SOLARINC) $(3) > $(subst .o,.asm,$(1)) && \
"$(ML_EXE)" $(gb_AFLAGS) -g -errorReport:prompt -o $(1) $(subst .o,.asm,$(1)), \
) && \
echo "$(1) : $(3)" > $(4)
endef
else # !ARM64
gb_AsmObject_get_source = $(1)/$(2).asm
define gb_AsmObject__command
@ -146,6 +161,7 @@ $(call gb_Helper_abbreviate_dirs,\
echo "$(1) : $(3)" > $(4)
endef
endif
# LinkTarget class