1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
28 #include <com/sun/star/uno/XInterface.hpp>
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <sal/alloca.h>
31 #include <sal/types.h>
32 #include <typelib/typeclass.h>
33 #include <typelib/typedescription.h>
34 #include <typelib/typedescription.hxx>
37 #include <cppinterfaceproxy.hxx>
39 #include <vtablefactory.hxx>
41 #include <msvc/arm64.hxx>
45 extern "C" void vtableSlotCall();
47 using namespace ::com::sun::star
;
51 void call(bridges::cpp_uno::shared::CppInterfaceProxy
* proxy
,
52 uno::TypeDescription
const& description
, typelib_TypeDescriptionReference
* returnType
,
53 sal_Int32 count
, typelib_MethodParameter
* parameters
, sal_uInt64
* gpr
, sal_uInt64
* fpr
,
54 sal_uInt64
* stack
, void* indirectRet
)
56 typelib_TypeDescription
* rtd
= 0;
58 TYPELIB_DANGER_GET(&rtd
, returnType
);
60 ReturnKind retKind
= rtd
== 0 ? RETURN_KIND_REG
: getReturnKind(rtd
);
61 bool retConv
= rtd
!= 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd
);
63 void* retin
= retKind
== RETURN_KIND_INDIRECT
&& !retConv
? indirectRet
64 : rtd
== 0 ? 0 : alloca(rtd
->nSize
);
65 void** args
= static_cast<void**>(alloca(count
* sizeof(void*)));
66 void** cppArgs
= static_cast<void**>(alloca(count
* sizeof(void*)));
67 typelib_TypeDescription
** argtds
68 = static_cast<typelib_TypeDescription
**>(alloca(count
* sizeof(typelib_TypeDescription
*)));
73 for (sal_Int32 i
= 0; i
!= count
; ++i
)
75 if (!parameters
[i
].bOut
&& bridges::cpp_uno::shared::isSimpleType(parameters
[i
].pTypeRef
))
77 switch (parameters
[i
].pTypeRef
->eTypeClass
)
79 case typelib_TypeClass_BOOLEAN
:
80 case typelib_TypeClass_BYTE
:
81 case typelib_TypeClass_SHORT
:
82 case typelib_TypeClass_UNSIGNED_SHORT
:
83 case typelib_TypeClass_LONG
:
84 case typelib_TypeClass_UNSIGNED_LONG
:
85 case typelib_TypeClass_HYPER
:
86 case typelib_TypeClass_UNSIGNED_HYPER
:
87 case typelib_TypeClass_CHAR
:
88 case typelib_TypeClass_ENUM
:
89 args
[i
] = ngpr
== 8 ? stack
+ sp
++ : gpr
+ ngpr
++;
91 case typelib_TypeClass_FLOAT
:
92 case typelib_TypeClass_DOUBLE
:
93 args
[i
] = nfpr
== 8 ? stack
+ sp
++ : fpr
+ nfpr
++;
102 cppArgs
[i
] = reinterpret_cast<void*>(ngpr
== 8 ? stack
[sp
++] : gpr
[ngpr
++]);
103 typelib_TypeDescription
* ptd
= 0;
104 TYPELIB_DANGER_GET(&ptd
, parameters
[i
].pTypeRef
);
105 if (!parameters
[i
].bIn
)
107 args
[i
] = alloca(ptd
->nSize
);
110 else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd
))
112 args
[i
] = alloca(ptd
->nSize
);
113 uno_copyAndConvertData(args
[i
], cppArgs
[i
], ptd
, proxy
->getBridge()->getCpp2Uno());
118 args
[i
] = cppArgs
[i
];
120 TYPELIB_DANGER_RELEASE(ptd
);
126 uno_Any
* pexc
= &exc
;
127 proxy
->getUnoI()->pDispatcher(proxy
->getUnoI(), description
.get(), retin
, args
, &pexc
);
130 for (sal_Int32 i
= 0; i
!= count
; ++i
)
134 if (parameters
[i
].bIn
)
135 uno_destructData(args
[i
], argtds
[i
], 0);
136 TYPELIB_DANGER_RELEASE(argtds
[i
]);
139 TYPELIB_DANGER_RELEASE(rtd
);
140 assert(pexc
== &exc
);
141 msvc_raiseException(&exc
, proxy
->getBridge()->getUno2Cpp());
144 for (sal_Int32 i
= 0; i
!= count
; ++i
)
148 if (parameters
[i
].bOut
)
150 uno_destructData(cppArgs
[i
], argtds
[i
],
151 reinterpret_cast<uno_ReleaseFunc
>(uno::cpp_release
));
152 uno_copyAndConvertData(cppArgs
[i
], args
[i
], argtds
[i
],
153 proxy
->getBridge()->getUno2Cpp());
155 uno_destructData(args
[i
], argtds
[i
], 0);
156 TYPELIB_DANGER_RELEASE(argtds
[i
]);
160 void* retout
= 0; // avoid false -Werror=maybe-uninitialized
163 case RETURN_KIND_REG
:
164 switch (rtd
== 0 ? typelib_TypeClass_VOID
: rtd
->eTypeClass
)
166 case typelib_TypeClass_VOID
:
168 case typelib_TypeClass_BOOLEAN
:
169 case typelib_TypeClass_BYTE
:
170 case typelib_TypeClass_SHORT
:
171 case typelib_TypeClass_UNSIGNED_SHORT
:
172 case typelib_TypeClass_LONG
:
173 case typelib_TypeClass_UNSIGNED_LONG
:
174 case typelib_TypeClass_HYPER
:
175 case typelib_TypeClass_UNSIGNED_HYPER
:
176 case typelib_TypeClass_CHAR
:
177 case typelib_TypeClass_ENUM
:
178 std::memcpy(gpr
, retin
, rtd
->nSize
);
181 case typelib_TypeClass_FLOAT
:
182 case typelib_TypeClass_DOUBLE
:
183 std::memcpy(fpr
, retin
, rtd
->nSize
);
186 case typelib_TypeClass_STRUCT
:
193 std::memcpy(gpr
, retin
, rtd
->nSize
);
200 case RETURN_KIND_HFA_FLOAT
:
205 std::memcpy(fpr
+ 3, static_cast<char*>(retin
) + 12, 4);
208 std::memcpy(fpr
+ 2, static_cast<char*>(retin
) + 8, 4);
211 std::memcpy(fpr
+ 1, static_cast<char*>(retin
) + 4, 4);
214 std::memcpy(fpr
, retin
, 4);
221 case RETURN_KIND_HFA_DOUBLE
:
223 std::memcpy(fpr
, retin
, rtd
->nSize
);
226 case RETURN_KIND_INDIRECT
:
227 retout
= indirectRet
;
233 uno_copyAndConvertData(retout
, retin
, rtd
, proxy
->getBridge()->getUno2Cpp());
234 uno_destructData(retin
, rtd
, 0);
238 TYPELIB_DANGER_RELEASE(rtd
);
241 extern "C" void vtableCall(sal_Int32 functionIndex
, sal_Int32 vtableOffset
, sal_uInt64
* gpr
,
242 sal_uInt64
* fpr
, sal_uInt64
* stack
, void* indirectRet
)
244 bridges::cpp_uno::shared::CppInterfaceProxy
* proxy
245 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
246 reinterpret_cast<char*>(gpr
[0]) - vtableOffset
);
247 typelib_InterfaceTypeDescription
* pInterfaceTD
= proxy
->getTypeDescr();
248 assert(functionIndex
< pInterfaceTD
->nMapFunctionIndexToMemberIndex
);
249 sal_Int32 nMemberPos
= pInterfaceTD
->pMapFunctionIndexToMemberIndex
[functionIndex
];
250 assert(nMemberPos
< pInterfaceTD
->nAllMembers
);
251 uno::TypeDescription
aMemberDescr(pInterfaceTD
->ppAllMembers
[nMemberPos
]);
253 switch (aMemberDescr
.get()->eTypeClass
)
255 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
257 typelib_TypeDescriptionReference
* pAttrTypeRef
258 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(aMemberDescr
.get())
261 if (pInterfaceTD
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == functionIndex
)
264 call(proxy
, aMemberDescr
, pAttrTypeRef
, 0, 0, gpr
, fpr
, stack
, indirectRet
);
269 typelib_MethodParameter param
= { 0, pAttrTypeRef
, true, false };
270 call(proxy
, aMemberDescr
, 0, 1, ¶m
, gpr
, fpr
, stack
, indirectRet
);
274 case typelib_TypeClass_INTERFACE_METHOD
:
275 switch (functionIndex
)
278 proxy
->acquireProxy();
281 proxy
->releaseProxy();
285 typelib_TypeDescription
* td
= nullptr;
286 TYPELIB_DANGER_GET(&td
,
287 (reinterpret_cast<uno::Type
*>(gpr
[1])->getTypeLibType()));
288 if (td
!= 0 && td
->eTypeClass
== typelib_TypeClass_INTERFACE
)
290 uno::XInterface
* ifc
= nullptr;
291 proxy
->getBridge()->getCppEnv()->getRegisteredInterface(
292 proxy
->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc
),
293 proxy
->getOid().pData
,
294 reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
));
297 uno_any_construct(reinterpret_cast<uno_Any
*>(indirectRet
), &ifc
, td
,
298 reinterpret_cast<uno_AcquireFunc
>(uno::cpp_acquire
));
300 TYPELIB_DANGER_RELEASE(td
);
303 TYPELIB_DANGER_RELEASE(td
);
308 typelib_InterfaceMethodTypeDescription
* pMethodTD
309 = reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(
311 call(proxy
, aMemberDescr
, pMethodTD
->pReturnTypeRef
, pMethodTD
->nParams
,
312 pMethodTD
->pParams
, gpr
, fpr
, stack
, indirectRet
);
320 std::size_t const codeSnippetSize
= 8 * 4;
322 unsigned char* GenerateVTableSlotTrampoline(unsigned char* code
, sal_Int32 functionIndex
,
323 sal_Int32 vtableOffset
)
325 // movz x9, <low functionIndex>
326 reinterpret_cast<unsigned int*>(code
)[0] = 0xD2800009 | ((functionIndex
& 0xFFFF) << 5);
327 // movk x9, <high functionIndex>, LSL #16
328 reinterpret_cast<unsigned int*>(code
)[1] = 0xF2A00009 | ((functionIndex
>> 16) << 5);
329 // movz x10, <low vtableOffset>
330 reinterpret_cast<unsigned int*>(code
)[2] = 0xD280000A | ((vtableOffset
& 0xFFFF) << 5);
331 // movk x10, <high vtableOffset>, LSL #16
332 reinterpret_cast<unsigned int*>(code
)[3] = 0xF2A0000A | ((vtableOffset
>> 16) << 5);
334 reinterpret_cast<unsigned int*>(code
)[4] = 0x5800004B;
336 reinterpret_cast<unsigned int*>(code
)[5] = 0xD61F0160;
337 reinterpret_cast<void**>(code
)[3] = reinterpret_cast<void*>(&vtableSlotCall
);
338 return code
+ codeSnippetSize
;
342 namespace bridges::cpp_uno::shared
344 struct bridges::cpp_uno::shared::VtableFactory::Slot
349 bridges::cpp_uno::shared::VtableFactory::Slot
*
350 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block
)
352 return static_cast<Slot
*>(block
) + 1;
355 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount
)
357 return (slotCount
+ 1) * sizeof(Slot
) + slotCount
* codeSnippetSize
;
360 bridges::cpp_uno::shared::VtableFactory::Slot
*
361 bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block
, sal_Int32 slotCount
,
363 typelib_InterfaceTypeDescription
*)
367 sal_Int32 n0
, n1
, n2
;
373 , rtti(RTTInfos::get("com.sun.star.uno.XInterface"))
379 Slot
* slots
= mapBlockToVtable(block
);
380 slots
[-1].fn
= &rtti
;
381 return slots
+ slotCount
;
384 unsigned char* VtableFactory::addLocalFunctions(VtableFactory::Slot
** slots
, unsigned char* code
,
385 typelib_InterfaceTypeDescription
const* type
,
386 sal_Int32 functionOffset
, sal_Int32 functionCount
,
387 sal_Int32 vtableOffset
)
389 (*slots
) -= functionCount
;
390 VtableFactory::Slot
* s
= *slots
;
391 for (sal_Int32 i
= 0; i
!= type
->nMembers
; ++i
)
393 typelib_TypeDescription
* td
= nullptr;
394 TYPELIB_DANGER_GET(&td
, type
->ppMembers
[i
]);
396 switch (td
->eTypeClass
)
398 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
400 typelib_InterfaceAttributeTypeDescription
* atd
401 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(td
);
404 code
= GenerateVTableSlotTrampoline(code
, functionOffset
++, vtableOffset
);
409 code
= GenerateVTableSlotTrampoline(code
, functionOffset
++, vtableOffset
);
413 case typelib_TypeClass_INTERFACE_METHOD
:
415 code
= GenerateVTableSlotTrampoline(code
, functionOffset
++, vtableOffset
);
420 TYPELIB_DANGER_RELEASE(td
);
425 void VtableFactory::flushCode(unsigned char const* begin
, unsigned char const* end
)
427 FlushInstructionCache(GetCurrentProcess(), begin
, end
- begin
);
430 } // namespace bridges::cpp_uno::shared
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */