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 <stdio.h>
22 : #include <stdlib.h>
23 :
24 : #include <rtl/alloc.h>
25 : #include <sal/log.hxx>
26 : #include <osl/mutex.hxx>
27 :
28 : #include <com/sun/star/uno/genfunc.hxx>
29 : #include "com/sun/star/uno/RuntimeException.hpp"
30 : #include <config_options.h>
31 : #include <uno/data.h>
32 : #include <typelib/typedescription.hxx>
33 :
34 : #include "bridges/cpp_uno/shared/bridge.hxx"
35 : #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
36 : #include "bridges/cpp_uno/shared/types.hxx"
37 : #include "bridges/cpp_uno/shared/vtablefactory.hxx"
38 :
39 : #include "abi.hxx"
40 : #include "call.hxx"
41 : #include "rtti.hxx"
42 : #include "share.hxx"
43 :
44 : using namespace ::osl;
45 : using namespace ::com::sun::star::uno;
46 :
47 : // Perform the UNO call
48 : //
49 : // We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
50 : // arguments and call pThis->getUnoI()->pDispatcher.
51 : //
52 : // gpreg: [ret *], this, [gpr params]
53 : // fpreg: [fpr params]
54 : // ovrflw: [gpr or fpr params (properly aligned)]
55 : //
56 : // [ret *] is present when we are returning a structure bigger than 16 bytes
57 : // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
58 : // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
59 380246 : static typelib_TypeClass cpp2uno_call(
60 : bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
61 : const typelib_TypeDescription * pMemberTypeDescr,
62 : typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
63 : sal_Int32 nParams, typelib_MethodParameter * pParams,
64 : void ** gpreg, void ** fpreg, void ** ovrflw,
65 : sal_uInt64 * pRegisterReturn /* space for register return */ )
66 : {
67 380246 : unsigned int nr_gpr = 0; //number of gpr registers used
68 380246 : unsigned int nr_fpr = 0; //number of fpr registers used
69 :
70 : // return
71 380246 : typelib_TypeDescription * pReturnTypeDescr = 0;
72 380246 : if (pReturnTypeRef)
73 380223 : TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
74 :
75 380246 : void * pUnoReturn = 0;
76 380246 : void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
77 :
78 380246 : if ( pReturnTypeDescr )
79 : {
80 380223 : if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
81 : {
82 185351 : pCppReturn = *gpreg++;
83 185351 : nr_gpr++;
84 :
85 185351 : pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
86 134354 : ? alloca( pReturnTypeDescr->nSize )
87 319705 : : pCppReturn ); // direct way
88 : }
89 : else
90 194872 : pUnoReturn = pRegisterReturn; // direct way for simple types
91 : }
92 :
93 : // pop this
94 380246 : gpreg++;
95 380246 : nr_gpr++;
96 :
97 : // stack space
98 : // parameters
99 380246 : void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
100 380246 : void ** pCppArgs = pUnoArgs + nParams;
101 : // indices of values this have to be converted (interface conversion cpp<=>uno)
102 380246 : sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
103 : // type descriptions for reconversions
104 380246 : typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
105 :
106 380246 : sal_Int32 nTempIndices = 0;
107 :
108 663217 : for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
109 : {
110 282971 : const typelib_MethodParameter & rParam = pParams[nPos];
111 :
112 282971 : int nUsedGPR = 0;
113 282971 : int nUsedSSE = 0;
114 282971 : bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE );
115 282971 : if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
116 : {
117 : // Simple types must fit exactly one register on x86_64
118 : assert( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); (void)bFitsRegisters;
119 :
120 136850 : if ( nUsedSSE == 1 )
121 : {
122 18 : if ( nr_fpr < x86_64::MAX_SSE_REGS )
123 : {
124 16 : pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
125 16 : nr_fpr++;
126 : }
127 : else
128 2 : pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
129 : }
130 136832 : else if ( nUsedGPR == 1 )
131 : {
132 136832 : if ( nr_gpr < x86_64::MAX_GPR_REGS )
133 : {
134 136818 : pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
135 136818 : nr_gpr++;
136 : }
137 : else
138 14 : pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
139 : }
140 : }
141 : else // struct <= 16 bytes || ptr to complex value || ref
142 : {
143 146121 : typelib_TypeDescription * pParamTypeDescr = 0;
144 146121 : TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
145 :
146 : void *pCppStack;
147 146121 : if ( nr_gpr < x86_64::MAX_GPR_REGS )
148 : {
149 146053 : pCppArgs[nPos] = pCppStack = *gpreg++;
150 146053 : nr_gpr++;
151 : }
152 : else
153 68 : pCppArgs[nPos] = pCppStack = *ovrflw++;
154 :
155 146121 : if (! rParam.bIn) // is pure out
156 : {
157 : // uno out is unconstructed mem!
158 59 : pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
159 59 : pTempIndices[nTempIndices] = nPos;
160 : // will be released at reconversion
161 59 : ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
162 : }
163 146062 : else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
164 : {
165 57514 : uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
166 : pCppStack, pParamTypeDescr,
167 86271 : pThis->getBridge()->getCpp2Uno() );
168 28757 : pTempIndices[nTempIndices] = nPos; // has to be reconverted
169 : // will be released at reconversion
170 28757 : ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
171 : }
172 : else // direct way
173 : {
174 117305 : pUnoArgs[nPos] = pCppStack;
175 : // no longer needed
176 117305 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
177 : }
178 : }
179 : }
180 :
181 : // ExceptionHolder
182 : uno_Any aUnoExc; // Any will be constructed by callee
183 380246 : uno_Any * pUnoExc = &aUnoExc;
184 :
185 : // invoke uno dispatch call
186 380246 : (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
187 :
188 : // in case an exception occurred...
189 380246 : if ( pUnoExc )
190 : {
191 : // destruct temporary in/inout params
192 68711 : for ( ; nTempIndices--; )
193 : {
194 22783 : sal_Int32 nIndex = pTempIndices[nTempIndices];
195 :
196 22783 : if (pParams[nIndex].bIn) // is in/inout => was constructed
197 22783 : uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
198 22783 : TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
199 : }
200 22964 : if (pReturnTypeDescr)
201 22962 : TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
202 :
203 22964 : CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
204 : // is here for dummy
205 0 : return typelib_TypeClass_VOID;
206 : }
207 : else // else no exception occurred...
208 : {
209 : // temporary params
210 720597 : for ( ; nTempIndices--; )
211 : {
212 6033 : sal_Int32 nIndex = pTempIndices[nTempIndices];
213 6033 : typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
214 :
215 6033 : if ( pParams[nIndex].bOut ) // inout/out
216 : {
217 : // convert and assign
218 65 : uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
219 130 : uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
220 195 : pThis->getBridge()->getUno2Cpp() );
221 : }
222 : // destroy temp uno param
223 6033 : uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
224 :
225 6033 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
226 : }
227 : // return
228 357282 : if ( pCppReturn ) // has complex return
229 : {
230 185350 : if ( pUnoReturn != pCppReturn ) // needs reconversion
231 : {
232 : uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
233 134353 : pThis->getBridge()->getUno2Cpp() );
234 : // destroy temp uno return
235 134353 : uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
236 : }
237 : // complex return ptr is set to return reg
238 185350 : *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
239 : }
240 357282 : if ( pReturnTypeDescr )
241 : {
242 357261 : typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
243 357261 : TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
244 357261 : return eRet;
245 : }
246 : else
247 21 : return typelib_TypeClass_VOID;
248 : }
249 : }
250 :
251 :
252 929346 : typelib_TypeClass cpp_vtable_call(
253 : sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
254 : void ** gpreg, void ** fpreg, void ** ovrflw,
255 : sal_uInt64 * pRegisterReturn /* space for register return */ )
256 : {
257 : // gpreg: [ret *], this, [other gpr params]
258 : // fpreg: [fpr params]
259 : // ovrflw: [gpr or fpr params (properly aligned)]
260 : void * pThis;
261 929346 : if ( nFunctionIndex & 0x80000000 )
262 : {
263 235671 : nFunctionIndex &= 0x7fffffff;
264 235671 : pThis = gpreg[1];
265 : }
266 : else
267 : {
268 693675 : pThis = gpreg[0];
269 : }
270 929346 : pThis = static_cast<char *>( pThis ) - nVtableOffset;
271 :
272 : bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
273 929346 : bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
274 :
275 929346 : typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
276 :
277 929346 : if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
278 : {
279 : SAL_WARN(
280 : "bridges",
281 : "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
282 : << " vtable index " << nFunctionIndex << "/"
283 : << pTypeDescr->nMapFunctionIndexToMemberIndex);
284 : throw RuntimeException(
285 0 : ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
286 0 : + " vtable index " + OUString::number(nFunctionIndex) + "/"
287 0 : + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
288 0 : reinterpret_cast<XInterface *>( pCppI ) );
289 : }
290 :
291 : // determine called method
292 929346 : sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
293 : assert(nMemberPos < pTypeDescr->nAllMembers);
294 :
295 929346 : TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
296 :
297 : typelib_TypeClass eRet;
298 929346 : switch ( aMemberDescr.get()->eTypeClass )
299 : {
300 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
301 : {
302 : typelib_TypeDescriptionReference *pAttrTypeRef =
303 1827 : reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
304 :
305 1827 : if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
306 : {
307 : // is GET method
308 1804 : eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
309 : 0, 0, // no params
310 1804 : gpreg, fpreg, ovrflw, pRegisterReturn );
311 : }
312 : else
313 : {
314 : // is SET method
315 : typelib_MethodParameter aParam;
316 23 : aParam.pTypeRef = pAttrTypeRef;
317 23 : aParam.bIn = sal_True;
318 23 : aParam.bOut = sal_False;
319 :
320 23 : eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
321 : 0, // indicates void return
322 : 1, &aParam,
323 23 : gpreg, fpreg, ovrflw, pRegisterReturn );
324 : }
325 1822 : break;
326 : }
327 : case typelib_TypeClass_INTERFACE_METHOD:
328 : {
329 : // is METHOD
330 927519 : switch ( nFunctionIndex )
331 : {
332 : case 1: // acquire()
333 185392 : pCppI->acquireProxy(); // non virtual call!
334 185392 : eRet = typelib_TypeClass_VOID;
335 185392 : break;
336 : case 2: // release()
337 313388 : pCppI->releaseProxy(); // non virtual call!
338 313388 : eRet = typelib_TypeClass_VOID;
339 313388 : break;
340 : case 0: // queryInterface() opt
341 : {
342 138223 : typelib_TypeDescription * pTD = 0;
343 138223 : TYPELIB_DANGER_GET( &pTD, static_cast<Type *>( gpreg[2] )->getTypeLibType() );
344 138223 : if ( pTD )
345 : {
346 138223 : XInterface * pInterface = 0;
347 138223 : (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
348 : ( pCppI->getBridge()->getCppEnv(),
349 : reinterpret_cast<void **>(&pInterface),
350 : pCppI->getOid().pData,
351 138223 : reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
352 :
353 138223 : if ( pInterface )
354 : {
355 : ::uno_any_construct( static_cast<uno_Any *>( gpreg[0] ),
356 50320 : &pInterface, pTD, cpp_acquire );
357 :
358 50320 : pInterface->release();
359 50320 : TYPELIB_DANGER_RELEASE( pTD );
360 :
361 50320 : reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
362 50320 : eRet = typelib_TypeClass_ANY;
363 50320 : break;
364 : }
365 87903 : TYPELIB_DANGER_RELEASE( pTD );
366 : }
367 : } // else perform queryInterface()
368 : default:
369 : {
370 : typelib_InterfaceMethodTypeDescription *pMethodTD =
371 378419 : reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
372 :
373 378419 : eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
374 : pMethodTD->pReturnTypeRef,
375 : pMethodTD->nParams,
376 : pMethodTD->pParams,
377 756838 : gpreg, fpreg, ovrflw, pRegisterReturn );
378 : }
379 : }
380 904560 : break;
381 : }
382 : default:
383 : {
384 : throw RuntimeException("no member description found!",
385 0 : reinterpret_cast<XInterface *>( pCppI ) );
386 : }
387 : }
388 :
389 929346 : return eRet;
390 : }
391 :
392 : const int codeSnippetSize = 24;
393 :
394 : // Generate a trampoline that redirects method calls to
395 : // privateSnippetExecutor().
396 : //
397 : // privateSnippetExecutor() saves all the registers that are used for
398 : // parameter passing on x86_64, and calls the cpp_vtable_call().
399 : // When it returns, privateSnippetExecutor() sets the return value.
400 : //
401 : // Note: The code snippet we build here must not create a stack frame,
402 : // otherwise the UNO exceptions stop working thanks to non-existing
403 : // unwinding info.
404 5566 : unsigned char * codeSnippet( unsigned char * code,
405 : sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
406 : bool bHasHiddenParam )
407 : {
408 5566 : sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
409 :
410 5566 : if ( bHasHiddenParam )
411 1747 : nOffsetAndIndex |= 0x80000000;
412 :
413 : // movq $<nOffsetAndIndex>, %r10
414 5566 : *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
415 5566 : *reinterpret_cast<sal_uInt16 *>( code + 2 ) = nOffsetAndIndex & 0xFFFF;
416 5566 : *reinterpret_cast<sal_uInt32 *>( code + 4 ) = nOffsetAndIndex >> 16;
417 5566 : *reinterpret_cast<sal_uInt16 *>( code + 8 ) = nOffsetAndIndex >> 48;
418 :
419 : // movq $<address of the privateSnippetExecutor>, %r11
420 5566 : *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
421 : *reinterpret_cast<sal_uInt32 *>( code + 12 )
422 5566 : = reinterpret_cast<sal_uInt64>(privateSnippetExecutor);
423 : *reinterpret_cast<sal_uInt32 *>( code + 16 )
424 5566 : = reinterpret_cast<sal_uInt64>(privateSnippetExecutor) >> 32;
425 :
426 : // jmpq *%r11
427 5566 : *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
428 :
429 : #if OSL_DEBUG_LEVEL > 1
430 : fprintf(stderr,
431 : "==> codeSnippet, functionIndex=%d%s, vtableOffset=%d\n",
432 : nFunctionIndex, (bHasHiddenParam ? "|0x80000000":""), nVtableOffset);
433 : #endif
434 :
435 5566 : return code + codeSnippetSize;
436 : }
437 :
438 : struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
439 :
440 : bridges::cpp_uno::shared::VtableFactory::Slot *
441 134151 : bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
442 : {
443 134151 : return static_cast< Slot * >(block) + 2;
444 : }
445 :
446 676 : sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
447 : sal_Int32 slotCount)
448 : {
449 676 : return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
450 : }
451 :
452 : bridges::cpp_uno::shared::VtableFactory::Slot *
453 676 : bridges::cpp_uno::shared::VtableFactory::initializeBlock(
454 : void * block, sal_Int32 slotCount, sal_Int32 vtableNumber,
455 : typelib_InterfaceTypeDescription * type)
456 : {
457 676 : Slot * slots = mapBlockToVtable(block);
458 676 : slots[-2].fn = reinterpret_cast<void *>(-(vtableNumber * sizeof (void *)));
459 : #if ENABLE_RUNTIME_OPTIMIZATIONS
460 676 : slots[-1].fn = 0;
461 : (void)type;
462 : #else
463 : slots[-1].fn = x86_64::getRtti(type->aBase);
464 : #endif
465 676 : return slots + slotCount;
466 : }
467 :
468 :
469 :
470 1489 : unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
471 : Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
472 : typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
473 : sal_Int32 functionCount, sal_Int32 nVtableOffset )
474 : {
475 1489 : (*slots) -= functionCount;
476 1489 : Slot * s = *slots;
477 6991 : for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
478 : {
479 5502 : typelib_TypeDescription * pTD = 0;
480 :
481 5502 : TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
482 : assert(pTD);
483 :
484 5502 : if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
485 : {
486 : typelib_InterfaceAttributeTypeDescription *pAttrTD =
487 95 : reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
488 :
489 : // get method
490 95 : (s++)->fn = code + writetoexecdiff;
491 : code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
492 95 : x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
493 :
494 95 : if ( ! pAttrTD->bReadOnly )
495 : {
496 : // set method
497 64 : (s++)->fn = code + writetoexecdiff;
498 64 : code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
499 : }
500 : }
501 5407 : else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
502 : {
503 : typelib_InterfaceMethodTypeDescription *pMethodTD =
504 5407 : reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
505 :
506 5407 : (s++)->fn = code + writetoexecdiff;
507 : code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
508 5407 : x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
509 : }
510 : else
511 : assert(false);
512 :
513 5502 : TYPELIB_DANGER_RELEASE( pTD );
514 : }
515 1489 : return code;
516 : }
517 :
518 676 : void bridges::cpp_uno::shared::VtableFactory::flushCode(
519 : SAL_UNUSED_PARAMETER unsigned char const *,
520 : SAL_UNUSED_PARAMETER unsigned char const * )
521 676 : {}
522 :
523 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|