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_intel.hxx"
39
40 using namespace com::sun::star::uno;
41
42 namespace
43 {
44
45 //==================================================================================================
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)46 void cpp2uno_call(
47 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
48 const typelib_TypeDescription * pMemberTypeDescr,
49 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
50 sal_Int32 nParams, typelib_MethodParameter * pParams,
51 void ** pCallStack,
52 sal_Int64 * pRegisterReturn /* space for register return */ )
53 {
54 // pCallStack: ret, [return ptr], this, params
55 char * pCppStack = (char *)(pCallStack +1);
56
57 // return
58 typelib_TypeDescription * pReturnTypeDescr = 0;
59 if (pReturnTypeRef)
60 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
61
62 void * pUnoReturn = 0;
63 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
64
65 if (pReturnTypeDescr)
66 {
67 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
68 {
69 pUnoReturn = pRegisterReturn; // direct way for simple types
70 }
71 else // complex return via ptr (pCppReturn)
72 {
73 pCppReturn = *(void**)pCppStack;
74 pCppStack += sizeof( void* );
75 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
76 pReturnTypeDescr )
77 ? alloca( pReturnTypeDescr->nSize )
78 : pCppReturn); // direct way
79 }
80 }
81 // pop this
82 pCppStack += sizeof( void* );
83
84 // stack space
85 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
86 // parameters
87 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
88 void ** pCppArgs = pUnoArgs + nParams;
89 // indizes of values this have to be converted (interface conversion cpp<=>uno)
90 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
91 // type descriptions for reconversions
92 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
93
94 sal_Int32 nTempIndizes = 0;
95
96 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
97 {
98 const typelib_MethodParameter & rParam = pParams[nPos];
99 typelib_TypeDescription * pParamTypeDescr = 0;
100 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
101
102 if (!rParam.bOut
103 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
104 // value
105 {
106 pCppArgs[ nPos ] = pUnoArgs[ nPos ] = pCppStack;
107 switch (pParamTypeDescr->eTypeClass)
108 {
109 case typelib_TypeClass_HYPER:
110 case typelib_TypeClass_UNSIGNED_HYPER:
111 case typelib_TypeClass_DOUBLE:
112 pCppStack += sizeof(sal_Int32); // extra long
113 }
114 // no longer needed
115 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
116 }
117 else // ptr to complex value | ref
118 {
119 pCppArgs[nPos] = *(void **)pCppStack;
120
121 if (! rParam.bIn) // is pure out
122 {
123 // uno out is unconstructed mem!
124 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
125 pTempIndizes[nTempIndizes] = nPos;
126 // will be released at reconversion
127 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
128 }
129 // is in/inout
130 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
131 pParamTypeDescr ))
132 {
133 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
134 *(void **)pCppStack, pParamTypeDescr,
135 pThis->getBridge()->getCpp2Uno() );
136 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
137 // will be released at reconversion
138 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
139 }
140 else // direct way
141 {
142 pUnoArgs[nPos] = *(void **)pCppStack;
143 // no longer needed
144 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
145 }
146 }
147 pCppStack += sizeof(sal_Int32); // standard parameter length
148 }
149
150 // ExceptionHolder
151 uno_Any aUnoExc; // Any will be constructed by callee
152 uno_Any * pUnoExc = &aUnoExc;
153
154 // invoke uno dispatch call
155 (*pThis->getUnoI()->pDispatcher)(
156 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
157
158 // in case no exception occured...
159 if (pUnoExc)
160 {
161 // destruct temporary in/inout params
162 for ( ; nTempIndizes--; )
163 {
164 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
165
166 if (pParams[nIndex].bIn) // is in/inout => was constructed
167 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
168 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
169 }
170 if (pReturnTypeDescr)
171 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
172
173 CPPU_CURRENT_NAMESPACE::cc50_solaris_intel_raiseException(
174 &aUnoExc, pThis->getBridge()->getUno2Cpp() );
175 // has to destruct the any
176 }
177 else // else no exception occured...
178 {
179 // temporary params
180 for ( ; nTempIndizes--; )
181 {
182 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
183 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
184
185 if (pParams[nIndex].bOut) // inout/out
186 {
187 // convert and assign
188 uno_destructData(
189 pCppArgs[nIndex], pParamTypeDescr,
190 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
191 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
192 pThis->getBridge()->getUno2Cpp() );
193 }
194 // destroy temp uno param
195 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
196
197 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
198 }
199 // return
200 if (pCppReturn) // has complex return
201 {
202 if (pUnoReturn != pCppReturn) // needs reconversion
203 {
204 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
205 pThis->getBridge()->getUno2Cpp() );
206 // destroy temp uno return
207 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
208 }
209 // complex return ptr is set to eax
210 *(void **)pRegisterReturn = pCppReturn;
211 }
212 if (pReturnTypeDescr)
213 {
214 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
215 }
216 }
217 }
218
219
220 //==================================================================================================
cpp_vtable_call(int nFunctionIndex,int nVtableOffset,void ** pCallStack,sal_Int64 nRegReturn)221 extern "C" void cpp_vtable_call(
222 int nFunctionIndex, int nVtableOffset, void** pCallStack,
223 sal_Int64 nRegReturn )
224 {
225 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
226
227 // pCallStack: ret adr, [ret *], this, params
228 void * pThis;
229 if( nFunctionIndex & 0x80000000 )
230 {
231 nFunctionIndex &= 0x7fffffff;
232 pThis = pCallStack[2];
233 }
234 else
235 {
236 pThis = pCallStack[1];
237 }
238 pThis = static_cast< char * >(pThis) - nVtableOffset;
239 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
240 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
241 pThis);
242
243 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
244
245 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
246 "### illegal vtable index!" );
247 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
248 {
249 throw RuntimeException( rtl::OUString::createFromAscii("illegal vtable index!"), (XInterface *)pThis );
250 }
251
252 // determine called method
253 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
254 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
255
256 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
257
258 switch (aMemberDescr.get()->eTypeClass)
259 {
260 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
261 {
262 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
263 {
264 // is GET method
265 cpp2uno_call(
266 pCppI, aMemberDescr.get(),
267 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
268 0, 0, // no params
269 pCallStack, &nRegReturn );
270 }
271 else
272 {
273 // is SET method
274 typelib_MethodParameter aParam;
275 aParam.pTypeRef =
276 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
277 aParam.bIn = sal_True;
278 aParam.bOut = sal_False;
279
280 cpp2uno_call(
281 pCppI, aMemberDescr.get(),
282 0, // indicates void return
283 1, &aParam,
284 pCallStack, &nRegReturn );
285 }
286 break;
287 }
288 case typelib_TypeClass_INTERFACE_METHOD:
289 {
290 // is METHOD
291 switch (nFunctionIndex)
292 {
293 // standard XInterface vtable calls
294 case 1: // acquire()
295 pCppI->acquireProxy(); // non virtual call!
296 break;
297 case 2: // release()
298 pCppI->releaseProxy(); // non virtual call!
299 break;
300 case 0: // queryInterface() opt
301 {
302 typelib_TypeDescription * pTD = 0;
303 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
304 if (pTD)
305 {
306 XInterface * pInterface = 0;
307 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
308 pCppI->getBridge()->getCppEnv(),
309 (void **)&pInterface, pCppI->getOid().pData,
310 (typelib_InterfaceTypeDescription *)pTD );
311
312 if (pInterface)
313 {
314 ::uno_any_construct(
315 reinterpret_cast< uno_Any * >( pCallStack[1] ),
316 &pInterface, pTD,
317 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
318 pInterface->release();
319 TYPELIB_DANGER_RELEASE( pTD );
320 *(void **)&nRegReturn = pCallStack[1];
321 break;
322 }
323 TYPELIB_DANGER_RELEASE( pTD );
324 }
325 } // else perform queryInterface()
326 default:
327 cpp2uno_call(
328 pCppI, aMemberDescr.get(),
329 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
330 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
331 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
332 pCallStack, &nRegReturn );
333 }
334 break;
335 }
336 default:
337 {
338 throw RuntimeException( rtl::OUString::createFromAscii("no member description found!"), (XInterface *)pThis );
339 }
340 }
341 }
342
343 //==================================================================================================
isSimpleStruct(typelib_TypeDescriptionReference * type)344 bool isSimpleStruct(typelib_TypeDescriptionReference * type) {
345 typelib_TypeDescription * td = 0;
346 TYPELIB_DANGER_GET(&td, type);
347 OSL_ASSERT(td != 0);
348 for (typelib_CompoundTypeDescription * ctd
349 = reinterpret_cast< typelib_CompoundTypeDescription * >(td);
350 ctd != 0; ctd = ctd->pBaseTypeDescription)
351 {
352 OSL_ASSERT(ctd->aBase.eTypeClass == typelib_TypeClass_STRUCT);
353 for (sal_Int32 i = 0; i < ctd->nMembers; ++i) {
354 typelib_TypeClass c = ctd->ppTypeRefs[i]->eTypeClass;
355 switch (c) {
356 case typelib_TypeClass_STRING:
357 case typelib_TypeClass_TYPE:
358 case typelib_TypeClass_ANY:
359 case typelib_TypeClass_SEQUENCE:
360 case typelib_TypeClass_INTERFACE:
361 return false;
362 case typelib_TypeClass_STRUCT:
363 if (!isSimpleStruct(ctd->ppTypeRefs[i])) {
364 return false;
365 }
366 break;
367 default:
368 OSL_ASSERT(
369 c <= typelib_TypeClass_DOUBLE
370 || c == typelib_TypeClass_ENUM);
371 break;
372 }
373 }
374 }
375 TYPELIB_DANGER_RELEASE(td);
376 return true;
377 }
378
379 extern "C" void privateSnippetExecutorGeneral();
380 extern "C" void privateSnippetExecutorVoid();
381 extern "C" void privateSnippetExecutorHyper();
382 extern "C" void privateSnippetExecutorFloat();
383 extern "C" void privateSnippetExecutorDouble();
384 extern "C" void privateSnippetExecutorStruct();
385 extern "C" typedef void (*PrivateSnippetExecutor)();
386
387 int const codeSnippetSize = 16;
388
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,typelib_TypeDescriptionReference * returnType)389 unsigned char * codeSnippet(
390 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
391 typelib_TypeDescriptionReference * returnType)
392 {
393 typelib_TypeClass c = returnType == 0
394 ? typelib_TypeClass_VOID : returnType->eTypeClass;
395 if (returnType != 0 && !bridges::cpp_uno::shared::isSimpleType(c)) {
396 functionIndex |= 0x80000000;
397 }
398 PrivateSnippetExecutor exec;
399 switch (c) {
400 case typelib_TypeClass_VOID:
401 exec = privateSnippetExecutorVoid;
402 break;
403 case typelib_TypeClass_HYPER:
404 case typelib_TypeClass_UNSIGNED_HYPER:
405 exec = privateSnippetExecutorHyper;
406 break;
407 case typelib_TypeClass_FLOAT:
408 exec = privateSnippetExecutorFloat;
409 break;
410 case typelib_TypeClass_DOUBLE:
411 exec = privateSnippetExecutorDouble;
412 break;
413 case typelib_TypeClass_STRUCT:
414 OSL_ASSERT(returnType != 0);
415 // For "simple" (more-or-less POD, but not exactly) structs, the caller
416 // pops the pointer to the return value off the stack, as documented in
417 // the Intel SYSV ABI; for other structs (which includes STRING, TYPE,
418 // ANY, sequences, and interfaces, btw.), the callee pops the pointer to
419 // the return value off the stack:
420 exec = isSimpleStruct(returnType)
421 ? privateSnippetExecutorStruct : privateSnippetExecutorGeneral;
422 break;
423 default:
424 exec = privateSnippetExecutorGeneral;
425 break;
426 }
427 unsigned char * p = code;
428 OSL_ASSERT(sizeof (sal_Int32) == 4);
429 // mov function_index, %eax:
430 *p++ = 0xB8;
431 *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
432 p += sizeof (sal_Int32);
433 // mov vtable_offset, %edx:
434 *p++ = 0xBA;
435 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
436 p += sizeof (sal_Int32);
437 // jmp privateSnippetExecutor:
438 *p++ = 0xE9;
439 #pragma disable_warn
440 void * e = reinterpret_cast< void * >(exec);
441 #pragma enable_warn
442 *reinterpret_cast< sal_Int32 * >(p)
443 = static_cast< unsigned char * >(e) - p - sizeof (sal_Int32);
444 p += sizeof (sal_Int32);
445 OSL_ASSERT(p - code <= codeSnippetSize);
446 return code + codeSnippetSize;
447 }
448
449 }
450
451 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
452
453 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)454 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
455 return static_cast< Slot * >(block) + 1;
456 }
457
getBlockSize(sal_Int32 slotCount)458 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
459 sal_Int32 slotCount)
460 {
461 return (slotCount + 3) * sizeof (Slot) + slotCount * codeSnippetSize;
462 }
463
464 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)465 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
466 void * block, sal_Int32 slotCount)
467 {
468 Slot * slots = mapBlockToVtable(block) + 2;
469 slots[-3].fn = 0; // RTTI
470 slots[-2].fn = 0; // null
471 slots[-1].fn = 0; // destructor
472 return slots + slotCount;
473 }
474
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)475 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
476 Slot ** slots, unsigned char * code,
477 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
478 sal_Int32 functionCount, sal_Int32 vtableOffset)
479 {
480 (*slots) -= functionCount;
481 Slot * s = *slots;
482 for (sal_Int32 i = 0; i < type->nMembers; ++i) {
483 typelib_TypeDescription * member = 0;
484 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
485 OSL_ASSERT(member != 0);
486 switch (member->eTypeClass) {
487 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
488 // Getter:
489 (s++)->fn = code;
490 code = codeSnippet(
491 code, functionOffset++, vtableOffset,
492 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
493 member)->pAttributeTypeRef);
494 // Setter:
495 if (!reinterpret_cast<
496 typelib_InterfaceAttributeTypeDescription * >(
497 member)->bReadOnly)
498 {
499 (s++)->fn = code;
500 code = codeSnippet(code, functionOffset++, vtableOffset, 0);
501 }
502 break;
503
504 case typelib_TypeClass_INTERFACE_METHOD:
505 (s++)->fn = code;
506 code = codeSnippet(
507 code, functionOffset++, vtableOffset,
508 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
509 member)->pReturnTypeRef);
510 break;
511
512 default:
513 OSL_ASSERT(false);
514 break;
515 }
516 TYPELIB_DANGER_RELEASE(member);
517 }
518 return code;
519 }
520
flushCode(unsigned char const *,unsigned char const *)521 void bridges::cpp_uno::shared::VtableFactory::flushCode(
522 unsigned char const *, unsigned char const *)
523 {}
524