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