1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 21 // MARKER(update_precomp.py): autogen include statement, do not remove 22 #include "precompiled_bridges.hxx" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <hash_map> 27 28 #include <rtl/alloc.h> 29 #include <osl/mutex.hxx> 30 31 #include <com/sun/star/uno/genfunc.hxx> 32 #include "com/sun/star/uno/RuntimeException.hpp" 33 #include <uno/data.h> 34 #include <typelib/typedescription.hxx> 35 36 #include "bridges/cpp_uno/shared/bridge.hxx" 37 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" 38 #include "bridges/cpp_uno/shared/types.hxx" 39 #include "bridges/cpp_uno/shared/vtablefactory.hxx" 40 41 #include "abi.hxx" 42 #include "share.hxx" 43 44 using namespace ::osl; 45 using namespace ::rtl; 46 using namespace ::com::sun::star::uno; 47 48 //================================================================================================== 49 50 // Perform the UNO call 51 // 52 // We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO 53 // arguments and call pThis->getUnoI()->pDispatcher. 54 // 55 // gpreg: this, [gpr params x0..x7] (the indirect-result ptr is x8, separate) 56 // fpreg: [fpr params d0..d7] 57 // ovrflw: [gpr or fpr params (properly aligned)] 58 // 59 // On AArch64 a structure bigger than 16 bytes is returned via the buffer 60 // addressed by x8 (pIndirectReturn); 'this' is always x0 = gpreg[0]. 61 // Simple types are returned in x0,x1 (int) or d0,d1 (fp); HFAs in d0..d3; 62 // non-HFA structures <= 16 bytes in x0,x1. 63 static typelib_TypeClass cpp2uno_call( 64 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 65 const typelib_TypeDescription * pMemberTypeDescr, 66 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 67 sal_Int32 nParams, typelib_MethodParameter * pParams, 68 void ** gpreg, void ** fpreg, unsigned char * ovrflw, 69 void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none) 70 sal_uInt64 * pRegisterReturn /* space for register return */ ) 71 { 72 unsigned int nr_gpr = 0; //number of gpr registers used 73 unsigned int nr_fpr = 0; //number of fpr registers used 74 sal_uInt32 stackOffset = 0; 75 76 // return 77 typelib_TypeDescription * pReturnTypeDescr = 0; 78 if (pReturnTypeRef) 79 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 80 81 void * pUnoReturn = 0; 82 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 83 84 if ( pReturnTypeDescr ) 85 { 86 if ( aarch64::return_in_hidden_param( pReturnTypeRef ) ) 87 { 88 // AArch64: the indirect-result pointer arrives in x8, NOT in the 89 // first general-purpose argument register (unlike x86-64 SysV). 90 // So we take it from pIndirectReturn and do NOT consume a gpreg 91 // slot here; 'this' still occupies gpreg[0] below. 92 pCppReturn = pIndirectReturn; 93 94 pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 95 ? alloca( pReturnTypeDescr->nSize ) 96 : pCppReturn ); // direct way 97 } 98 else 99 pUnoReturn = pRegisterReturn; // direct way for simple types 100 } 101 102 // pop this (x0) 103 gpreg++; 104 nr_gpr++; 105 106 // stack space 107 // parameters 108 void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) * nParams )); 109 void ** pCppArgs = pUnoArgs + nParams; 110 // indices of values this have to be converted (interface conversion cpp<=>uno) 111 sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams)); 112 // type descriptions for reconversions 113 typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams)); 114 115 sal_Int32 nTempIndizes = 0; 116 117 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 118 { 119 const typelib_MethodParameter & rParam = pParams[nPos]; 120 121 int nUsedGPR = 0; 122 int nUsedFPR = 0; 123 if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value 124 { 125 // A simple UNO type occupies exactly one register, GPR or FPR. 126 if ( rParam.pTypeRef->eTypeClass == typelib_TypeClass_FLOAT || 127 rParam.pTypeRef->eTypeClass == typelib_TypeClass_DOUBLE ) 128 { 129 nUsedFPR = 1; nUsedGPR = 0; 130 } 131 else 132 { 133 nUsedFPR = 0; nUsedGPR = 1; 134 } 135 136 OSL_ASSERT( ( nUsedFPR == 1 && nUsedGPR == 0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) ); 137 138 if ( nUsedFPR == 1 ) 139 { 140 if ( nr_fpr < aarch64::MAX_FPR_REGS ) 141 { 142 pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++; 143 nr_fpr++; 144 } 145 else 146 { 147 stackOffset = aarch64::align_stack_offset( 148 stackOffset, rParam.pTypeRef ); 149 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw + stackOffset; 150 stackOffset += aarch64::stack_size( rParam.pTypeRef ); 151 } 152 } 153 else if ( nUsedGPR == 1 ) 154 { 155 if ( nr_gpr < aarch64::MAX_GPR_REGS ) 156 { 157 pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++; 158 nr_gpr++; 159 } 160 else 161 { 162 stackOffset = aarch64::align_stack_offset( 163 stackOffset, rParam.pTypeRef ); 164 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw + stackOffset; 165 stackOffset += aarch64::stack_size( rParam.pTypeRef ); 166 } 167 } 168 } 169 else // struct <= 16 bytes || ptr to complex value || ref 170 { 171 typelib_TypeDescription * pParamTypeDescr = 0; 172 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 173 174 void *pCppStack = 0; 175 if ( nr_gpr < aarch64::MAX_GPR_REGS ) 176 { 177 pCppArgs[nPos] = pCppStack = *gpreg++; 178 nr_gpr++; 179 } 180 else 181 { 182 stackOffset = (stackOffset + sizeof(void *) - 1) & 183 ~(sizeof(void *) - 1); 184 pCppArgs[nPos] = pCppStack = 185 *reinterpret_cast<void **>( ovrflw + stackOffset ); 186 stackOffset += sizeof(void *); 187 } 188 189 if (! rParam.bIn) // is pure out 190 { 191 // uno out is unconstructed mem! 192 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 193 pTempIndizes[nTempIndizes] = nPos; 194 // will be released at reconversion 195 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 196 } 197 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout 198 { 199 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 200 pCppStack, pParamTypeDescr, 201 pThis->getBridge()->getCpp2Uno() ); 202 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 203 // will be released at reconversion 204 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 205 } 206 207 if ( pCppStack ) 208 { 209 if ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT || 210 pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) 211 { 212 // struct in registers/stack: copy it to a temporary if 213 // it needs conversion 214 if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) 215 { 216 // already handled above 217 } 218 else 219 pUnoArgs[nPos] = pCppStack; 220 } 221 } 222 if ( pParamTypeDescr ) 223 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 224 } 225 } 226 227 // ExceptionHolder 228 uno_Any aUnoExc; // Any will be constructed by callee 229 uno_Any * pUnoExc = &aUnoExc; 230 231 // invoke uno dispatch call 232 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 233 234 // in case an exception occurred... 235 if ( pUnoExc ) 236 { 237 // destruct temporary in/inout params 238 for ( ; nTempIndizes--; ) 239 { 240 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 241 242 if (pParams[nIndex].bIn) // is in/inout => was constructed 243 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 244 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 245 } 246 if (pReturnTypeDescr) 247 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 248 249 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any 250 // is here for dummy 251 return typelib_TypeClass_VOID; 252 } 253 else // else no exception occurred... 254 { 255 // temporary params 256 for ( ; nTempIndizes--; ) 257 { 258 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 259 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 260 261 if ( pParams[nIndex].bOut ) // inout/out 262 { 263 // convert and assign 264 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 265 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 266 pThis->getBridge()->getUno2Cpp() ); 267 } 268 // destroy temp uno param 269 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 270 271 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 272 } 273 // return 274 if ( pCppReturn ) // has complex return 275 { 276 if ( pUnoReturn != pCppReturn ) // needs reconversion 277 { 278 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 279 pThis->getBridge()->getUno2Cpp() ); 280 // destroy temp uno return 281 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 282 } 283 // complex return ptr is set to return reg 284 *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn; 285 } 286 if ( pReturnTypeDescr ) 287 { 288 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 289 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 290 return eRet; 291 } 292 else 293 return typelib_TypeClass_VOID; 294 } 295 } 296 297 298 //================================================================================================== 299 extern "C" sal_uInt32 cpp_vtable_call( 300 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 301 void ** gpreg, void ** fpreg, unsigned char * ovrflw, 302 void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none) 303 sal_uInt64 * pRegisterReturn /* space for register return */ ) 304 { 305 // gpreg: this, [other gpr params x0..x7] 306 // fpreg: [fpr params d0..d7] 307 // ovrflw: [gpr or fpr params (properly aligned)] 308 // pIndirectReturn: x8 (the hidden return buffer), when bit 0x80000000 set. 309 // 310 // On AArch64 'this' is ALWAYS x0 = gpreg[0]; the hidden return pointer is 311 // the separate x8 register, not a displaced first GPR (unlike x86-64 SysV 312 // where it occupied gpreg[0] and 'this' moved to gpreg[1]). 313 if ( nFunctionIndex & 0x80000000 ) 314 nFunctionIndex &= 0x7fffffff; 315 316 void * pThis = gpreg[0]; 317 pThis = static_cast<char *>( pThis ) - nVtableOffset; 318 319 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = 320 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); 321 322 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 323 324 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); 325 if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) 326 { 327 throw RuntimeException( OUString::createFromAscii("illegal vtable index!"), 328 reinterpret_cast<XInterface *>( pCppI ) ); 329 } 330 331 // determine called method 332 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 333 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); 334 335 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 336 337 sal_uInt32 eRet; 338 switch ( aMemberDescr.get()->eTypeClass ) 339 { 340 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 341 { 342 typelib_TypeDescriptionReference *pAttrTypeRef = 343 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef; 344 345 if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) 346 { 347 // is GET method 348 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, 349 0, 0, // no params 350 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn ); 351 eRet = aarch64::get_return_kind( pAttrTypeRef ); 352 } 353 else 354 { 355 // is SET method 356 typelib_MethodParameter aParam; 357 aParam.pTypeRef = pAttrTypeRef; 358 aParam.bIn = sal_True; 359 aParam.bOut = sal_False; 360 361 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 362 0, // indicates void return 363 1, &aParam, 364 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn ); 365 } 366 break; 367 } 368 case typelib_TypeClass_INTERFACE_METHOD: 369 { 370 // is METHOD 371 switch ( nFunctionIndex ) 372 { 373 case 1: // acquire() 374 pCppI->acquireProxy(); // non virtual call! 375 eRet = typelib_TypeClass_VOID; 376 break; 377 case 2: // release() 378 pCppI->releaseProxy(); // non virtual call! 379 eRet = typelib_TypeClass_VOID; 380 break; 381 case 0: // queryInterface() opt 382 { 383 // queryInterface([in] type) returns an Any (> 16 bytes), 384 // so on AArch64 the result buffer is x8 (pIndirectReturn), 385 // 'this' is gpreg[0], and the type argument is the first 386 // real parameter, gpreg[1]. 387 typelib_TypeDescription * pTD = 0; 388 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[1] )->getTypeLibType() ); 389 if ( pTD ) 390 { 391 XInterface * pInterface = 0; 392 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) 393 ( pCppI->getBridge()->getCppEnv(), 394 reinterpret_cast<void **>(&pInterface), 395 pCppI->getOid().pData, 396 reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) ); 397 398 if ( pInterface ) 399 { 400 ::uno_any_construct( reinterpret_cast<uno_Any *>( pIndirectReturn ), 401 &pInterface, pTD, cpp_acquire ); 402 403 pInterface->release(); 404 TYPELIB_DANGER_RELEASE( pTD ); 405 406 reinterpret_cast<void **>( pRegisterReturn )[0] = pIndirectReturn; 407 eRet = typelib_TypeClass_ANY; 408 break; 409 } 410 TYPELIB_DANGER_RELEASE( pTD ); 411 } 412 } // else perform queryInterface() 413 default: 414 { 415 typelib_InterfaceMethodTypeDescription *pMethodTD = 416 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() ); 417 418 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 419 pMethodTD->pReturnTypeRef, 420 pMethodTD->nParams, 421 pMethodTD->pParams, 422 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn ); 423 eRet = aarch64::get_return_kind( pMethodTD->pReturnTypeRef ); 424 } 425 } 426 break; 427 } 428 default: 429 { 430 throw RuntimeException( OUString::createFromAscii("no member description found!"), 431 reinterpret_cast<XInterface *>( pCppI ) ); 432 // is here for dummy 433 eRet = typelib_TypeClass_VOID; 434 } 435 } 436 437 return eRet; 438 } 439