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