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