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