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 <malloc.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 "msci.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 static inline typelib_TypeClass 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, this, [complex return ptr], params
55 char * pCppStack = (char *)(pCallStack +2);
56
57 // return
58 typelib_TypeDescription * pReturnTypeDescr = 0;
59 if (pReturnTypeRef)
60 {
61 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
62 }
63
64 void * pUnoReturn = 0;
65 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
66
67 if (pReturnTypeDescr)
68 {
69 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
70 {
71 pUnoReturn = pRegisterReturn; // direct way for simple types
72 }
73 else // complex return via ptr (pCppReturn)
74 {
75 pCppReturn = *(void **)pCppStack;
76 pCppStack += sizeof(void *);
77
78 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
79 pReturnTypeDescr )
80 ? alloca( pReturnTypeDescr->nSize )
81 : pCppReturn); // direct way
82 }
83 }
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] = pCppStack;
108 pUnoArgs[nPos] = pCppStack;
109 switch (pParamTypeDescr->eTypeClass)
110 {
111 case typelib_TypeClass_HYPER:
112 case typelib_TypeClass_UNSIGNED_HYPER:
113 case typelib_TypeClass_DOUBLE:
114 pCppStack += sizeof(sal_Int32); // extra long
115 break;
116 default:
117 break;
118 }
119 // no longer needed
120 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
121 }
122 else // ptr to complex value | ref
123 {
124 pCppArgs[nPos] = *(void **)pCppStack;
125
126 if (! rParam.bIn) // is pure out
127 {
128 // uno out is unconstructed mem!
129 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
130 pTempIndizes[nTempIndizes] = nPos;
131 // will be released at reconversion
132 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
133 }
134 // is in/inout
135 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
136 pParamTypeDescr ))
137 {
138 ::uno_copyAndConvertData(
139 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
140 *(void **)pCppStack, pParamTypeDescr,
141 pThis->getBridge()->getCpp2Uno() );
142 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
143 // will be released at reconversion
144 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
145 }
146 else // direct way
147 {
148 pUnoArgs[nPos] = *(void **)pCppStack;
149 // no longer needed
150 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
151 }
152 }
153 pCppStack += sizeof(sal_Int32); // standard parameter length
154 }
155
156 // ExceptionHolder
157 uno_Any aUnoExc; // Any will be constructed by callee
158 uno_Any * pUnoExc = &aUnoExc;
159
160 // invoke uno dispatch call
161 (*pThis->getUnoI()->pDispatcher)(
162 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
163
164 // in case an exception occurred...
165 if (pUnoExc)
166 {
167 // destruct temporary in/inout params
168 while (nTempIndizes--)
169 {
170 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
171
172 if (pParams[nIndex].bIn) // is in/inout => was constructed
173 {
174 ::uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
175 }
176 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
177 }
178 if (pReturnTypeDescr)
179 {
180 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
181 }
182
183 CPPU_CURRENT_NAMESPACE::msci_raiseException(
184 &aUnoExc, pThis->getBridge()->getUno2Cpp() );
185 // has to destruct the any
186 // is here for dummy
187 return typelib_TypeClass_VOID;
188 }
189 else // else no exception occurred...
190 {
191 // temporary params
192 while (nTempIndizes--)
193 {
194 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
195 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
196
197 if (pParams[nIndex].bOut) // inout/out
198 {
199 // convert and assign
200 ::uno_destructData(
201 pCppArgs[nIndex], pParamTypeDescr, cpp_release );
202 ::uno_copyAndConvertData(
203 pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
204 pThis->getBridge()->getUno2Cpp() );
205 }
206 // destroy temp uno param
207 ::uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
208
209 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
210 }
211 // return
212 if (pCppReturn) // has complex return
213 {
214 if (pUnoReturn != pCppReturn) // needs reconversion
215 {
216 ::uno_copyAndConvertData(
217 pCppReturn, pUnoReturn, pReturnTypeDescr,
218 pThis->getBridge()->getUno2Cpp() );
219 // destroy temp uno return
220 ::uno_destructData(
221 pUnoReturn, pReturnTypeDescr, 0 );
222 }
223 // complex return ptr is set to eax
224 *(void **)pRegisterReturn = pCppReturn;
225 }
226 if (pReturnTypeDescr)
227 {
228 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
229 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
230 return eRet;
231 }
232 else
233 return typelib_TypeClass_VOID;
234 }
235 }
236
237 //==================================================================================================
cpp_mediate(void ** pCallStack,sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,sal_Int64 * pRegisterReturn)238 static typelib_TypeClass __cdecl cpp_mediate(
239 void ** pCallStack, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
240 sal_Int64 * pRegisterReturn /* space for register return */ )
241 {
242 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
243
244 // pCallStack: ret adr, this, [ret *], params
245 void * pThis = static_cast< char * >(pCallStack[1]) - 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 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
252 "### illegal vtable index!" );
253 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
254 {
255 throw RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("illegal vtable index!") ),
256 (XInterface *)pThis );
257 }
258
259 // determine called method
260 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
261 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
262
263 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
264
265 typelib_TypeClass eRet;
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 eRet = cpp2uno_call(
274 pCppI, aMemberDescr.get(),
275 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
276 0, 0, // no params
277 pCallStack, pRegisterReturn );
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 eRet = cpp2uno_call(
289 pCppI, aMemberDescr.get(),
290 0, // indicates void return
291 1, &aParam,
292 pCallStack, pRegisterReturn );
293 }
294 break;
295 }
296 case typelib_TypeClass_INTERFACE_METHOD:
297 {
298 // is METHOD
299 switch (nFunctionIndex)
300 {
301 // standard XInterface vtable calls
302 case 1: // acquire()
303 pCppI->acquireProxy(); // non virtual call!
304 eRet = typelib_TypeClass_VOID;
305 break;
306 case 2: // release()
307 pCppI->releaseProxy(); // non virtual call!
308 eRet = typelib_TypeClass_VOID;
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[2] ),
326 &pInterface, pTD, cpp_acquire );
327 pInterface->release();
328 TYPELIB_DANGER_RELEASE( pTD );
329 *(void **)pRegisterReturn = pCallStack[2];
330 eRet = typelib_TypeClass_ANY;
331 break;
332 }
333 TYPELIB_DANGER_RELEASE( pTD );
334 }
335 } // else perform queryInterface()
336 default:
337 eRet = cpp2uno_call(
338 pCppI, aMemberDescr.get(),
339 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
340 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
341 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
342 pCallStack, pRegisterReturn );
343 }
344 break;
345 }
346 default:
347 {
348 throw RuntimeException(
349 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("no member description found!") ),
350 (XInterface *)pThis );
351 // is here for dummy
352 eRet = typelib_TypeClass_VOID;
353 }
354 }
355
356 return eRet;
357 }
358
359 //==================================================================================================
360 /**
361 * is called on incoming vtable calls
362 * (called by asm snippets)
363 */
cpp_vtable_call(void)364 static __declspec(naked) void __cdecl cpp_vtable_call(void)
365 {
366 __asm
367 {
368 sub esp, 8 // space for immediate return type
369 push esp
370 push edx // vtable offset
371 push eax // function index
372 mov eax, esp
373 add eax, 20
374 push eax // original stack ptr
375
376 call cpp_mediate
377 add esp, 16
378
379 cmp eax, typelib_TypeClass_FLOAT
380 je Lfloat
381 cmp eax, typelib_TypeClass_DOUBLE
382 je Ldouble
383 cmp eax, typelib_TypeClass_HYPER
384 je Lhyper
385 cmp eax, typelib_TypeClass_UNSIGNED_HYPER
386 je Lhyper
387 // rest is eax
388 pop eax
389 add esp, 4
390 ret
391 Lhyper:
392 pop eax
393 pop edx
394 ret
395 Lfloat:
396 fld dword ptr [esp]
397 add esp, 8
398 ret
399 Ldouble:
400 fld qword ptr [esp]
401 add esp, 8
402 ret
403 }
404 }
405
406 //==================================================================================================
407 int const codeSnippetSize = 16;
408
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset)409 unsigned char * codeSnippet(
410 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
411 {
412 unsigned char * p = code;
413 OSL_ASSERT(sizeof (sal_Int32) == 4);
414 // mov eax, functionIndex:
415 *p++ = 0xB8;
416 *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
417 p += sizeof (sal_Int32);
418 // mov edx, vtableOffset:
419 *p++ = 0xBA;
420 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
421 p += sizeof (sal_Int32);
422 // jmp rel32 cpp_vtable_call:
423 *p++ = 0xE9;
424 *reinterpret_cast< sal_Int32 * >(p)
425 = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32);
426 p += sizeof (sal_Int32);
427 OSL_ASSERT(p - code <= codeSnippetSize);
428 return code + codeSnippetSize;
429 }
430
431 }
432
433 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
434
435 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)436 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
437 {
438 return static_cast< Slot * >(block) + 1;
439 }
440
getBlockSize(sal_Int32 slotCount)441 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
442 sal_Int32 slotCount)
443 {
444 return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
445 }
446
447 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)448 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
449 void * block, sal_Int32 slotCount)
450 {
451 struct Rtti {
452 sal_Int32 n0, n1, n2;
453 type_info * rtti;
454 Rtti():
455 n0(0), n1(0), n2(0),
456 rtti(CPPU_CURRENT_NAMESPACE::msci_getRTTI(
457 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
458 "com.sun.star.uno.XInterface"))))
459 {}
460 };
461 static Rtti rtti;
462
463 Slot * slots = mapBlockToVtable(block);
464 slots[-1].fn = &rtti;
465 return slots + slotCount;
466 }
467
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const *,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)468 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
469 Slot ** slots, unsigned char * code,
470 typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset,
471 sal_Int32 functionCount, sal_Int32 vtableOffset)
472 {
473 (*slots) -= functionCount;
474 Slot * s = *slots;
475 for (sal_Int32 i = 0; i < functionCount; ++i) {
476 (s++)->fn = code;
477 code = codeSnippet(code, functionOffset++, vtableOffset);
478 }
479 return code;
480 }
481
flushCode(unsigned char const *,unsigned char const *)482 void bridges::cpp_uno::shared::VtableFactory::flushCode(
483 unsigned char const *, unsigned char const *)
484 {}
485