1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26
27 #include <sal/alloca.h>
28
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <uno/data.h>
31 #include <typelib/typedescription.hxx>
32
33 #include "bridges/cpp_uno/shared/bridge.hxx"
34 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
35 #include "bridges/cpp_uno/shared/types.hxx"
36 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
37
38 #include "cc50_solaris_sparc.hxx"
39 #include "flushcode.hxx"
40
41 using namespace com::sun::star::uno;
42
43 namespace
44 {
45
46 //==================================================================================================
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** pCallStack,sal_Int64 * pRegisterReturn)47 static typelib_TypeClass cpp2uno_call(
48 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
49 const typelib_TypeDescription * pMemberTypeDescr,
50 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
51 sal_Int32 nParams, typelib_MethodParameter * pParams,
52 void ** pCallStack,
53 sal_Int64 * pRegisterReturn /* space for register return */ )
54 {
55 // pCallStack: [return ptr], this, params
56 char * pCppStack = (char *)pCallStack;
57
58 // return
59 typelib_TypeDescription * pReturnTypeDescr = 0;
60 if (pReturnTypeRef)
61 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
62
63 void * pUnoReturn = 0;
64 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
65
66 if (pReturnTypeDescr)
67 {
68 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
69 {
70 pUnoReturn = pRegisterReturn; // direct way for simple types
71 }
72 else // complex return via ptr (pCppReturn)
73 {
74 pCppReturn = *pCallStack;
75 pCppStack += sizeof( void* );
76 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
77 pReturnTypeDescr )
78 ? alloca( pReturnTypeDescr->nSize )
79 : pCppReturn); // direct way
80 }
81 }
82 // pop this
83 pCppStack += sizeof( void* );
84
85 // stack space
86 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
87 // parameters
88 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
89 void ** pCppArgs = pUnoArgs + nParams;
90 // indizes of values this have to be converted (interface conversion cpp<=>uno)
91 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
92 // type descriptions for reconversions
93 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
94
95 sal_Int32 nTempIndizes = 0;
96
97 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
98 {
99 const typelib_MethodParameter & rParam = pParams[nPos];
100 typelib_TypeDescription * pParamTypeDescr = 0;
101 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
102
103 if (!rParam.bOut
104 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
105 // value
106 {
107 pCppArgs[ nPos ] = pUnoArgs[ nPos ] =
108 CPPU_CURRENT_NAMESPACE::adjustPointer(
109 pCppStack, pParamTypeDescr );
110 switch (pParamTypeDescr->eTypeClass)
111 {
112 case typelib_TypeClass_HYPER:
113 case typelib_TypeClass_UNSIGNED_HYPER:
114 case typelib_TypeClass_DOUBLE:
115 pCppStack += sizeof(sal_Int32); // extra long
116 }
117 // no longer needed
118 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
119 }
120 else // ptr to complex value | ref
121 {
122 pCppArgs[nPos] = *(void **)pCppStack;
123
124 if (! rParam.bIn) // is pure out
125 {
126 // uno out is unconstructed mem!
127 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
128 pTempIndizes[nTempIndizes] = nPos;
129 // will be released at reconversion
130 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
131 }
132 // is in/inout
133 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
134 pParamTypeDescr ))
135 {
136 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
137 *(void **)pCppStack, pParamTypeDescr,
138 pThis->getBridge()->getCpp2Uno() );
139 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
140 // will be released at reconversion
141 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
142 }
143 else // direct way
144 {
145 pUnoArgs[nPos] = *(void **)pCppStack;
146 // no longer needed
147 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
148 }
149 }
150 pCppStack += sizeof(sal_Int32); // standard parameter length
151 }
152
153 // ExceptionHolder
154 uno_Any aUnoExc; // Any will be constructed by callee
155 uno_Any * pUnoExc = &aUnoExc;
156
157 // invoke uno dispatch call
158 (*pThis->getUnoI()->pDispatcher)(
159 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
160
161 // in case no exception occured...
162 if (pUnoExc)
163 {
164 // destruct temporary in/inout params
165 for ( ; nTempIndizes--; )
166 {
167 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
168
169 if (pParams[nIndex].bIn) // is in/inout => was constructed
170 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
171 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
172 }
173 if (pReturnTypeDescr)
174 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
175
176 CPPU_CURRENT_NAMESPACE::cc50_solaris_sparc_raiseException(
177 &aUnoExc, pThis->getBridge()->getUno2Cpp() );
178 // has to destruct the any
179 // is here for dummy
180 return typelib_TypeClass_VOID;
181 }
182 else // else no exception occured...
183 {
184 // temporary params
185 for ( ; nTempIndizes--; )
186 {
187 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
188 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
189
190 if (pParams[nIndex].bOut) // inout/out
191 {
192 // convert and assign
193 uno_destructData(
194 pCppArgs[nIndex], pParamTypeDescr,
195 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
196 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
197 pThis->getBridge()->getUno2Cpp() );
198 }
199 // destroy temp uno param
200 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
201
202 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
203 }
204 // return
205 if (pCppReturn) // has complex return
206 {
207 if (pUnoReturn != pCppReturn) // needs reconversion
208 {
209 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
210 pThis->getBridge()->getUno2Cpp() );
211 // destroy temp uno return
212 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
213 }
214 // complex return ptr is set to eax
215 *(void **)pRegisterReturn = pCppReturn;
216 }
217 if (pReturnTypeDescr)
218 {
219 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
220 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
221 return eRet;
222 }
223 else
224 return typelib_TypeClass_VOID;
225 }
226 }
227
228
229 //==================================================================================================
cpp_mediate(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** pCallStack,sal_Int64 * pRegisterReturn)230 static typelib_TypeClass cpp_mediate(
231 sal_Int32 nFunctionIndex,
232 sal_Int32 nVtableOffset,
233 void ** pCallStack,
234 sal_Int64 * pRegisterReturn /* space for register return */ )
235 {
236 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
237
238 // pCallStack: this, params
239 void * pThis;
240 if( nFunctionIndex & 0x80000000 )
241 {
242 nFunctionIndex &= 0x7fffffff;
243 pThis = pCallStack[1];
244 }
245 else
246 {
247 pThis = pCallStack[0];
248 }
249 pThis = static_cast< char * >(pThis) - nVtableOffset;
250 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
251 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
252 pThis);
253
254 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
255
256 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
257 "### illegal vtable index!" );
258 // if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
259 // {
260 // RuntimeException aExc;
261 // aExc.Message = OUString::createFromAscii("illegal vtable index!");
262 // aExc.Context = (XInterface *)pThis;
263 // throw aExc;
264 // }
265
266 // determine called method
267 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
268 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
269
270 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
271
272 typelib_TypeClass eRet;
273 switch (aMemberDescr.get()->eTypeClass)
274 {
275 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
276 {
277 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
278 {
279 // is GET method
280 eRet = cpp2uno_call(
281 pCppI, aMemberDescr.get(),
282 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
283 0, 0, // no params
284 pCallStack, pRegisterReturn );
285 }
286 else
287 {
288 // is SET method
289 typelib_MethodParameter aParam;
290 aParam.pTypeRef =
291 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
292 aParam.bIn = sal_True;
293 aParam.bOut = sal_False;
294
295 eRet = cpp2uno_call(
296 pCppI, aMemberDescr.get(),
297 0, // indicates void return
298 1, &aParam,
299 pCallStack, pRegisterReturn );
300 }
301 break;
302 }
303 case typelib_TypeClass_INTERFACE_METHOD:
304 {
305 // is METHOD
306 switch (nFunctionIndex)
307 {
308 // standard XInterface vtable calls
309 case 1: // acquire()
310 pCppI->acquireProxy(); // non virtual call!
311 eRet = typelib_TypeClass_VOID;
312 break;
313 case 2: // release()
314 pCppI->releaseProxy(); // non virtual call!
315 eRet = typelib_TypeClass_VOID;
316 break;
317 case 0: // queryInterface() opt
318 {
319 typelib_TypeDescription * pTD = 0;
320 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[2] )->getTypeLibType() );
321 if (pTD)
322 {
323 XInterface * pInterface = 0;
324 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
325 pCppI->getBridge()->getCppEnv(),
326 (void **)&pInterface, pCppI->getOid().pData,
327 (typelib_InterfaceTypeDescription *)pTD );
328
329 if (pInterface)
330 {
331 ::uno_any_construct(
332 reinterpret_cast< uno_Any * >( pCallStack[0] ),
333 &pInterface, pTD,
334 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
335 pInterface->release();
336 TYPELIB_DANGER_RELEASE( pTD );
337 *(void **)pRegisterReturn = pCallStack[0];
338 eRet = typelib_TypeClass_ANY;
339 break;
340 }
341 TYPELIB_DANGER_RELEASE( pTD );
342 }
343 } // else perform queryInterface()
344 default:
345 eRet = cpp2uno_call(
346 pCppI, aMemberDescr.get(),
347 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
348 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
349 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
350 pCallStack, pRegisterReturn );
351 }
352 break;
353 }
354 // default:
355 // {
356 // RuntimeException aExc;
357 // aExc.Message = OUString::createFromAscii("no member description found!");
358 // aExc.Context = (XInterface *)pThis;
359 // throw aExc;
360 // // is here for dummy
361 // eRet = typelib_TypeClass_VOID;
362 // }
363 }
364
365 return eRet;
366 }
367
368 }
369
370 //==================================================================================================
cpp_vtable_call(int nFunctionIndex,int nVtableOffset,void ** pCallStack)371 extern "C" int cpp_vtable_call(
372 int nFunctionIndex, int nVtableOffset, void** pCallStack )
373 {
374 sal_Int64 nRegReturn;
375 typelib_TypeClass aType = cpp_mediate(
376 nFunctionIndex, nVtableOffset, pCallStack, &nRegReturn );
377 OSL_ASSERT( sizeof(void *) == sizeof(sal_Int32) );
378 switch( aType )
379 {
380 // move return value into register space
381 // (will be loaded by machine code snippet)
382 // Use pCallStack[1/2] instead of pCallStack[0/1], because the former is
383 // properly dword aligned:
384 case typelib_TypeClass_BOOLEAN:
385 case typelib_TypeClass_BYTE:
386 pCallStack[1] = (void*)*(char*)&nRegReturn;
387 break;
388 case typelib_TypeClass_CHAR:
389 case typelib_TypeClass_SHORT:
390 case typelib_TypeClass_UNSIGNED_SHORT:
391 pCallStack[1] = (void*)*(short*)&nRegReturn;
392 break;
393 case typelib_TypeClass_DOUBLE:
394 case typelib_TypeClass_HYPER:
395 case typelib_TypeClass_UNSIGNED_HYPER:
396 // move long to %i1
397 pCallStack[2] = ((void **)&nRegReturn)[ 1 ];
398 case typelib_TypeClass_FLOAT:
399 default:
400 // move long to %i0
401 pCallStack[1] = ((void **)&nRegReturn)[ 0 ];
402 break;
403 }
404 return aType;
405 }
406
407 //==================================================================================================
408 namespace {
409
410 extern "C" void privateSnippetExecutor();
411
412 int const codeSnippetSize = 7 * 4;
413
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,bool simpleRetType)414 unsigned char * codeSnippet(
415 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
416 bool simpleRetType)
417 {
418 sal_uInt32 index = functionIndex;
419 if (!simpleRetType) {
420 index |= 0x80000000;
421 }
422 unsigned int * p = reinterpret_cast< unsigned int * >(code);
423 OSL_ASSERT(sizeof (unsigned int) == 4);
424 // save %sp, -96, %sp ! 92 byte minimal stack frame, + 4 byte dword align:
425 *p++ = 0x9DE3BFA0;
426 // sethi %hi(privateSnippetExecutor), %l0:
427 *p++ = 0x21000000
428 | (reinterpret_cast< unsigned int >(privateSnippetExecutor) >> 10);
429 // sethi %hi(index), %o0:
430 *p++ = 0x11000000 | (index >> 10);
431 // or %o0, %lo(index), %o0:
432 *p++ = 0x90122000 | (index & 0x3FF);
433 // sethi %hi(vtableOffset), %o1:
434 *p++ = 0x13000000 | (vtableOffset >> 10);
435 // jmpl %l0, %lo(privateSnippetExecutor), %g0:
436 *p++ = 0x81C42000
437 | (reinterpret_cast< unsigned int >(privateSnippetExecutor) & 0x3FF);
438 // or %o1, %lo(vtableOffset), %o1:
439 *p++ = 0x92126000 | (vtableOffset & 0x3FF);
440 OSL_ASSERT(
441 reinterpret_cast< unsigned char * >(p) - code <= codeSnippetSize);
442 return code + codeSnippetSize;
443 }
444
445 }
446
447 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
448
449 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)450 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
451 {
452 return static_cast< Slot * >(block) + 1;
453 }
454
getBlockSize(sal_Int32 slotCount)455 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
456 sal_Int32 slotCount)
457 {
458 return (slotCount + 3) * sizeof (Slot) + slotCount * codeSnippetSize;
459 }
460
461 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)462 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
463 void * block, sal_Int32 slotCount)
464 {
465 Slot * slots = mapBlockToVtable(block) + 2;
466 slots[-3].fn = 0; // RTTI
467 slots[-2].fn = 0; // null
468 slots[-1].fn = 0; // destructor
469 return slots + slotCount;
470 }
471
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)472 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
473 Slot ** slots, unsigned char * code,
474 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
475 sal_Int32 functionCount, sal_Int32 vtableOffset)
476 {
477 (*slots) -= functionCount;
478 Slot * s = *slots;
479 for (sal_Int32 i = 0; i < type->nMembers; ++i) {
480 typelib_TypeDescription * member = 0;
481 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
482 OSL_ASSERT(member != 0);
483 switch (member->eTypeClass) {
484 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
485 // Getter:
486 (s++)->fn = code;
487 code = codeSnippet(
488 code, functionOffset++, vtableOffset,
489 bridges::cpp_uno::shared::isSimpleType(
490 reinterpret_cast<
491 typelib_InterfaceAttributeTypeDescription * >(
492 member)->pAttributeTypeRef));
493 // Setter:
494 if (!reinterpret_cast<
495 typelib_InterfaceAttributeTypeDescription * >(
496 member)->bReadOnly)
497 {
498 (s++)->fn = code;
499 code = codeSnippet(code, functionOffset++, vtableOffset, true);
500 }
501 break;
502
503 case typelib_TypeClass_INTERFACE_METHOD:
504 (s++)->fn = code;
505 code = codeSnippet(
506 code, functionOffset++, vtableOffset,
507 bridges::cpp_uno::shared::isSimpleType(
508 reinterpret_cast<
509 typelib_InterfaceMethodTypeDescription * >(
510 member)->pReturnTypeRef));
511 break;
512
513 default:
514 OSL_ASSERT(false);
515 break;
516 }
517 TYPELIB_DANGER_RELEASE(member);
518 }
519 return code;
520 }
521
flushCode(unsigned char const * begin,unsigned char const * end)522 void bridges::cpp_uno::shared::VtableFactory::flushCode(
523 unsigned char const * begin, unsigned char const * end)
524 {
525 bridges::cpp_uno::cc50_solaris_sparc::flushCode(begin, end);
526 }
527