1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <com/sun/star/uno/genfunc.hxx>
21 #include <sal/log.hxx>
22 #include <typelib/typedescription.hxx>
24 #include <osl/endian.h>
26 #include "cppinterfaceproxy.hxx"
28 #include "vtablefactory.hxx"
37 using namespace com::sun::star::uno
;
39 namespace CPPU_CURRENT_NAMESPACE
41 bool is_complex_struct(const typelib_TypeDescription
* type
)
43 const typelib_CompoundTypeDescription
* p
44 = reinterpret_cast<const typelib_CompoundTypeDescription
*>(type
);
45 for (sal_Int32 i
= 0; i
< p
->nMembers
; ++i
)
47 if (p
->ppTypeRefs
[i
]->eTypeClass
== typelib_TypeClass_STRUCT
48 || p
->ppTypeRefs
[i
]->eTypeClass
== typelib_TypeClass_EXCEPTION
)
50 typelib_TypeDescription
* t
= 0;
51 TYPELIB_DANGER_GET(&t
, p
->ppTypeRefs
[i
]);
52 bool b
= is_complex_struct(t
);
53 TYPELIB_DANGER_RELEASE(t
);
59 else if (!bridges::cpp_uno::shared::isSimpleType(p
->ppTypeRefs
[i
]->eTypeClass
))
62 if (p
->pBaseTypeDescription
!= 0)
63 return is_complex_struct(&p
->pBaseTypeDescription
->aBase
);
67 bool return_in_hidden_param(typelib_TypeDescriptionReference
* pTypeRef
)
69 if (bridges::cpp_uno::shared::isSimpleType(pTypeRef
))
71 else if (pTypeRef
->eTypeClass
== typelib_TypeClass_STRUCT
72 || pTypeRef
->eTypeClass
== typelib_TypeClass_EXCEPTION
)
74 typelib_TypeDescription
* pTypeDescr
= 0;
75 TYPELIB_DANGER_GET(&pTypeDescr
, pTypeRef
);
77 //A Composite Type not larger than 16 bytes is returned in up to two GPRs
78 bool bRet
= pTypeDescr
->nSize
> 16 || is_complex_struct(pTypeDescr
);
80 TYPELIB_DANGER_RELEASE(pTypeDescr
);
89 static int cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
90 const typelib_TypeDescription
* pMemberTypeDescr
,
91 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
92 sal_Int32 nParams
, typelib_MethodParameter
* pParams
, void** gpreg
,
93 void** fpreg
, void** ovrflw
,
94 sal_uInt64
* pRegisterReturn
/* space for register return */)
101 typelib_TypeDescription
* pReturnTypeDescr
= 0;
103 TYPELIB_DANGER_GET(&pReturnTypeDescr
, pReturnTypeRef
);
104 loongarch64::ReturnKind returnKind
105 = (pReturnTypeRef
== nullptr || pReturnTypeRef
->eTypeClass
== typelib_TypeClass_VOID
)
106 ? loongarch64::ReturnKind::RegistersInt
107 : loongarch64::getReturnKind(pReturnTypeRef
);
109 void* pUnoReturn
= 0;
110 void* pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
112 if (pReturnTypeDescr
)
114 if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param(pReturnTypeRef
))
116 pCppReturn
= gpreg
[gCount
++]; // complex return via ptr (pCppReturn)
117 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr
)
118 ? alloca(pReturnTypeDescr
->nSize
)
119 : pCppReturn
); // direct way
123 pUnoReturn
= pRegisterReturn
; // direct way for simple types
131 static_assert(sizeof(void*) == sizeof(sal_Int64
), "### unexpected size!");
133 void** pUnoArgs
= (void**)alloca(4 * sizeof(void*) * nParams
);
134 void** pCppArgs
= pUnoArgs
+ nParams
;
135 // indices of values this have to be converted (interface conversion cpp<=>uno)
136 sal_Int32
* pTempIndices
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
137 // type descriptions for reconversions
138 typelib_TypeDescription
** ppTempParamTypeDescr
139 = (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
141 sal_Int32 nTempIndices
= 0;
143 for (sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
145 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
147 typelib_TypeDescription
* pParamTypeDescr
= 0;
148 TYPELIB_DANGER_GET(&pParamTypeDescr
, rParam
.pTypeRef
);
150 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType(pParamTypeDescr
)) // value
152 switch (pParamTypeDescr
->eTypeClass
)
154 case typelib_TypeClass_FLOAT
:
155 case typelib_TypeClass_DOUBLE
:
157 = fCount
!= MAX_FP_REGS
159 : (gCount
!= MAX_GP_REGS
? &(gpreg
[gCount
++]) : &(ovrflw
[sp
++]));
160 pUnoArgs
[nPos
] = pCppArgs
[nPos
];
163 pCppArgs
[nPos
] = gCount
== MAX_GP_REGS
? &(ovrflw
[sp
++]) : &(gpreg
[gCount
++]);
164 pUnoArgs
[nPos
] = pCppArgs
[nPos
];
168 TYPELIB_DANGER_RELEASE(pParamTypeDescr
);
170 else // ptr to complex value | ref
173 pCppStack
= gCount
== MAX_GP_REGS
? ovrflw
[sp
++] : gpreg
[gCount
++];
174 pCppArgs
[nPos
] = pCppStack
;
175 if (!rParam
.bIn
) // is pure out
177 // uno out is unconstructed mem!
178 pUnoArgs
[nPos
] = alloca(pParamTypeDescr
->nSize
);
179 pTempIndices
[nTempIndices
] = nPos
;
180 // will be released at reconversion
181 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
184 else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTypeDescr
))
186 uno_copyAndConvertData(pUnoArgs
[nPos
] = alloca(pParamTypeDescr
->nSize
), pCppStack
,
187 pParamTypeDescr
, pThis
->getBridge()->getCpp2Uno());
188 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
189 // will be released at reconversion
190 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
194 pUnoArgs
[nPos
] = pCppStack
;
196 TYPELIB_DANGER_RELEASE(pParamTypeDescr
);
201 uno_Any aUnoExc
; // Any will be constructed by callee
202 uno_Any
* pUnoExc
= &aUnoExc
;
204 // invoke uno dispatch call
205 (*pThis
->getUnoI()->pDispatcher
)(pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
,
207 // in case an exception occurred...
210 // destruct temporary in/inout params
211 for (; nTempIndices
--;)
213 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
215 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
216 uno_destructData(pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], 0);
217 TYPELIB_DANGER_RELEASE(ppTempParamTypeDescr
[nTempIndices
]);
219 if (pReturnTypeDescr
)
220 TYPELIB_DANGER_RELEASE(pReturnTypeDescr
);
222 CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc
, pThis
->getBridge()->getUno2Cpp());
223 // has to destruct the any
227 else // else no exception occurred...
230 for (; nTempIndices
--;)
232 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
233 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
235 if (pParams
[nIndex
].bOut
) // inout/out
237 // convert and assign
238 uno_destructData(pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
239 uno_copyAndConvertData(pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
240 pThis
->getBridge()->getUno2Cpp());
242 // destroy temp uno param
243 uno_destructData(pUnoArgs
[nIndex
], pParamTypeDescr
, 0);
245 TYPELIB_DANGER_RELEASE(pParamTypeDescr
);
248 if (pCppReturn
) // has complex return
250 if (pUnoReturn
!= pCppReturn
) // needs reconversion
252 uno_copyAndConvertData(pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
253 pThis
->getBridge()->getUno2Cpp());
254 // destroy temp uno return
255 uno_destructData(pUnoReturn
, pReturnTypeDescr
, 0);
257 // complex return ptr is set to return reg
258 *(void**)pRegisterReturn
= pCppReturn
;
260 if (pReturnTypeDescr
)
262 TYPELIB_DANGER_RELEASE(pReturnTypeDescr
);
266 case loongarch64::ReturnKind::RegistersIntFloat
:
267 memcpy(pRegisterReturn
+ 1, static_cast<char*>(pUnoReturn
) + 4, 4);
269 case loongarch64::ReturnKind::RegistersIntFp
:
271 case loongarch64::ReturnKind::RegistersFloatInt
:
272 memcpy(pRegisterReturn
+ 1, static_cast<char*>(pUnoReturn
) + 4, 4);
274 case loongarch64::ReturnKind::RegistersFpInt
:
276 case loongarch64::ReturnKind::RegistersTwoFloat
:
277 memcpy(pRegisterReturn
+ 1, static_cast<char*>(pUnoReturn
) + 4, 4);
286 * is called on incoming vtable calls
287 * (called by asm snippets)
289 int cpp_vtable_call(sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
, void** gpreg
, void** fpreg
,
290 void** ovrflw
, sal_uInt64
* pRegisterReturn
/* space for register return */)
292 static_assert(sizeof(sal_Int64
) == sizeof(void*), "### unexpected!");
294 // gpreg: [ret *], this, [other gpr params]
295 // fpreg: [fpr params]
296 // ovrflw: [gpr or fpr params (properly aligned)]
298 if (nFunctionIndex
& 0x80000000)
300 nFunctionIndex
&= 0x7fffffff;
307 pThis
= static_cast<char*>(pThis
) - nVtableOffset
;
308 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
309 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis
);
310 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
312 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
314 SAL_WARN("bridges", "illegal " << OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
315 << " vtable index " << nFunctionIndex
<< "/"
316 << pTypeDescr
->nMapFunctionIndexToMemberIndex
);
317 throw RuntimeException(("illegal " + OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
318 + " vtable index " + OUString::number(nFunctionIndex
) + "/"
319 + OUString::number(pTypeDescr
->nMapFunctionIndexToMemberIndex
)),
323 // determine called method
324 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
325 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
327 TypeDescription
aMemberDescr(pTypeDescr
->ppAllMembers
[nMemberPos
]);
330 switch (aMemberDescr
.get()->eTypeClass
)
332 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
334 typelib_TypeDescriptionReference
* pAttrTypeRef
335 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(aMemberDescr
.get())
338 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
341 eRet
= cpp2uno_call(pCppI
, aMemberDescr
.get(), pAttrTypeRef
, 0, 0, // no params
342 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
347 typelib_MethodParameter aParam
;
348 aParam
.pTypeRef
= pAttrTypeRef
;
349 aParam
.bIn
= sal_True
;
350 aParam
.bOut
= sal_False
;
352 eRet
= cpp2uno_call(pCppI
, aMemberDescr
.get(),
353 0, // indicates void return
354 1, &aParam
, gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
358 case typelib_TypeClass_INTERFACE_METHOD
:
361 switch (nFunctionIndex
)
364 pCppI
->acquireProxy(); // non virtual call!
368 pCppI
->releaseProxy(); // non virtual call!
371 case 0: // queryInterface() opt
373 typelib_TypeDescription
* pTD
= 0;
374 TYPELIB_DANGER_GET(&pTD
, reinterpret_cast<Type
*>(gpreg
[2])->getTypeLibType());
377 XInterface
* pInterface
= 0;
378 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
379 pCppI
->getBridge()->getCppEnv(), (void**)&pInterface
,
380 pCppI
->getOid().pData
,
381 reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
));
385 ::uno_any_construct(reinterpret_cast<uno_Any
*>(gpreg
[0]), &pInterface
,
388 pInterface
->release();
389 TYPELIB_DANGER_RELEASE(pTD
);
391 reinterpret_cast<void**>(pRegisterReturn
)[0] = gpreg
[0];
395 TYPELIB_DANGER_RELEASE(pTD
);
397 } // else perform queryInterface()
400 typelib_InterfaceMethodTypeDescription
* pMethodTD
401 = reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(
404 eRet
= cpp2uno_call(pCppI
, aMemberDescr
.get(), pMethodTD
->pReturnTypeRef
,
405 pMethodTD
->nParams
, pMethodTD
->pParams
, gpreg
, fpreg
,
406 ovrflw
, pRegisterReturn
);
412 throw RuntimeException("no member description found!", (XInterface
*)pThis
);
419 extern "C" void privateSnippetExecutor(...);
421 int const codeSnippetSize
= 0x34;
423 unsigned char* codeSnippet(unsigned char* code
, sal_Int32 functionIndex
, sal_Int32 vtableOffset
,
424 bool bHasHiddenParam
)
427 functionIndex
|= 0x80000000;
429 unsigned int* p
= (unsigned int*)code
;
431 assert((((unsigned long)code
) & 0x3) == 0); //aligned to 4 otherwise a mistake
433 /* generate this code */
436 0: 14000012 lu12i.w $t6,0x0
437 4: 34420000 ori $t6,$t6,0x0
438 # privateSnippetExecutor
439 8: 14000014 lu12i.w $t8,0x0
440 c: 03800294 ori $t8,$t8,0x0
441 10: 16000014 lu32i.d $t8,0x0
442 14: 03000294 lu52i.d $t8,$t8,0x0
444 18: 14000011 lu12i.w $t5,0x0
445 1c: 03800231 ori $t5,$t5,0x0
446 20: 16000011 lu32i.d $t5,0x0
447 24: 03000231 lu52i.d $t5,$t5,0x0
449 28: 14000013 lu12i.w $t7,0x0
450 2c: 03800273 ori $t7,$t7,0x0
454 *p
++ = 0x14000012 | (((functionIndex
>> 12) & 0x000fffff) << 5);
455 *p
++ = 0x03800252 | ((functionIndex
& 0x00000fff) << 10);
456 *p
++ = 0x14000014 | (((((unsigned long)privateSnippetExecutor
) >> 12) & 0x000fffff) << 5);
457 *p
++ = 0x03800294 | ((((unsigned long)privateSnippetExecutor
) & 0x00000fff) << 10);
458 *p
++ = 0x16000014 | (((((unsigned long)privateSnippetExecutor
) >> 32) & 0x000fffff) << 5);
459 *p
++ = 0x03000294 | (((((unsigned long)privateSnippetExecutor
) >> 52) & 0x00000fff) << 10);
460 *p
++ = 0x14000011 | (((((unsigned long)cpp_vtable_call
) >> 12) & 0x000fffff) << 5);
461 *p
++ = 0x03800231 | ((((unsigned long)cpp_vtable_call
) & 0x00000fff) << 10);
462 *p
++ = 0x16000011 | (((((unsigned long)cpp_vtable_call
) >> 32) & 0x000fffff) << 5);
463 *p
++ = 0x03000231 | (((((unsigned long)cpp_vtable_call
) >> 52) & 0x00000fff) << 10);
464 *p
++ = 0x14000013 | (((vtableOffset
>> 12) & 0x000fffff) << 5);
465 *p
++ = 0x03800273 | ((vtableOffset
& 0x00000fff) << 10);
467 return (code
+ codeSnippetSize
);
471 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const* bptr
,
472 unsigned char const* eptr
)
474 asm volatile("ibar 0" :::);
477 struct bridges::cpp_uno::shared::VtableFactory::Slot
482 bridges::cpp_uno::shared::VtableFactory::Slot
*
483 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block
)
485 return static_cast<Slot
*>(block
) + 2;
488 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount
)
490 return (slotCount
+ 2) * sizeof(Slot
) + slotCount
* codeSnippetSize
;
495 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
496 // on such proxy objects not crash:
502 bridges::cpp_uno::shared::VtableFactory::Slot
*
503 bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block
, sal_Int32 slotCount
,
505 typelib_InterfaceTypeDescription
*)
507 Slot
* slots
= mapBlockToVtable(block
);
508 slots
[-2].fn
= 0; //null
509 slots
[-1].fn
= &typeid(ProxyRtti
);
510 return slots
+ slotCount
;
513 unsigned char* bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
514 Slot
** slots
, unsigned char* code
, sal_PtrDiff writetoexecdiff
,
515 typelib_InterfaceTypeDescription
const* type
, sal_Int32 functionOffset
, sal_Int32 functionCount
,
516 sal_Int32 vtableOffset
)
518 (*slots
) -= functionCount
;
521 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
523 typelib_TypeDescription
* member
= 0;
524 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
526 switch (member
->eTypeClass
)
528 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
530 (s
++)->fn
= code
+ writetoexecdiff
;
532 code
, functionOffset
++, vtableOffset
,
533 CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
534 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(member
)
535 ->pAttributeTypeRef
));
538 if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(member
)
541 (s
++)->fn
= code
+ writetoexecdiff
;
542 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, false);
546 case typelib_TypeClass_INTERFACE_METHOD
:
547 (s
++)->fn
= code
+ writetoexecdiff
;
549 code
, functionOffset
++, vtableOffset
,
550 CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
551 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(member
)
559 TYPELIB_DANGER_RELEASE(member
);
564 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */