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