xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx (revision 66b843ff8f1eedd2e69941f1ea52fa080f01ec28)
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 "abi.hxx"
39 #include "mscx.hxx"
40 
41 using namespace ::rtl;
42 using namespace ::com::sun::star::uno;
43 
44 namespace
45 {
46 
47 //==================================================================================================
48 
49 // Perform the UNO call
50 //
51 // We must convert the parameters stored in pCallStack to UNO
52 // arguments and call pThis->getUnoI()->pDispatcher.
53 //
54 // pCallStack:  ret addr, this, [ret *], [params]
55 //
56 // [ret *] is present when we are returning a structure bigger than 8 bytes
57 // Simple types are returned in rax, or xmm0 (fp).
58 // Similarly structures <= 8 bytes are in rax, xmm0 as necessary.
59 static inline 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 ** pCallStack,
65     sal_uInt64 * pRegisterReturn /* space for register return */ )
66 {
67     // return
68     typelib_TypeDescription * pReturnTypeDescr = 0;
69     if (pReturnTypeRef)
70         TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
71 
72     void * pUnoReturn = 0;
73     void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
74 
75     if ( pReturnTypeDescr )
76     {
77         if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
78         {
79             // complex return via ptr (pCppReturn)
80             pCppReturn = pCallStack[2];
81             ++pCallStack;
82 
83             pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
84                            ? alloca( pReturnTypeDescr->nSize )
85                            : pCppReturn ); // direct way
86         }
87         else
88             pUnoReturn = pRegisterReturn; // direct way for simple types
89     }
90 
91     // skip to first argument
92     pCallStack += 2;
93 
94     // stack space
95     // parameters
96     void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
97     void ** pCppArgs = pUnoArgs + nParams;
98     // indices of values this have to be converted (interface conversion cpp<=>uno)
99     sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
100     // type descriptions for reconversions
101     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
102 
103     sal_Int32 nTempIndizes = 0;
104 
105     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
106     {
107         const typelib_MethodParameter & rParam = pParams[nPos];
108         typelib_TypeDescription * pParamTypeDescr = 0;
109         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
110 
111         if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
112         {
113             pCppArgs[nPos] = pUnoArgs[nPos] = pCallStack++;
114             // no longer needed
115             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
116         }
117         else // ptr to complex value || ref
118         {
119             void *pCppStack;
120             pCppArgs[nPos] = pCppStack = *pCallStack++;
121 
122             if (! rParam.bIn) // is pure out
123             {
124                 // uno out is unconstructed mem!
125                 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
126                 pTempIndizes[nTempIndizes] = nPos;
127                 // will be released at reconversion
128                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
129             }
130             else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
131             {
132                 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
133                                         pCppStack, pParamTypeDescr,
134                                         pThis->getBridge()->getCpp2Uno() );
135                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
136                 // will be released at reconversion
137                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
138             }
139             else // direct way
140             {
141                 pUnoArgs[nPos] = pCppStack;
142                 // no longer needed
143                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
144             }
145         }
146     }
147 
148     // ExceptionHolder
149     uno_Any aUnoExc; // Any will be constructed by callee
150     uno_Any * pUnoExc = &aUnoExc;
151 
152     // invoke uno dispatch call
153     (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
154 
155     // in case an exception occurred...
156     if ( pUnoExc )
157     {
158         // destruct temporary in/inout params
159         for ( ; nTempIndizes--; )
160         {
161             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
162 
163             if (pParams[nIndex].bIn) // is in/inout => was constructed
164                 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
165             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
166         }
167         if (pReturnTypeDescr)
168             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
169 
170         CPPU_CURRENT_NAMESPACE::mscx_raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
171         // is here for dummy
172         return typelib_TypeClass_VOID;
173     }
174     else // else no exception occurred...
175     {
176         // temporary params
177         for ( ; nTempIndizes--; )
178         {
179             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
180             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
181 
182             if ( pParams[nIndex].bOut ) // inout/out
183             {
184                 // convert and assign
185                 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
186                 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
187                                         pThis->getBridge()->getUno2Cpp() );
188             }
189             // destroy temp uno param
190             uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
191 
192             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
193         }
194         // return
195         if ( pCppReturn ) // has complex return
196         {
197             if ( pUnoReturn != pCppReturn ) // needs reconversion
198             {
199                 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
200                                         pThis->getBridge()->getUno2Cpp() );
201                 // destroy temp uno return
202                 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
203             }
204             // complex return ptr is set to rax
205             *(void **)pRegisterReturn = pCppReturn;
206         }
207         if ( pReturnTypeDescr )
208         {
209             typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
210             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
211             return eRet;
212         }
213         else
214             return typelib_TypeClass_VOID;
215     }
216 }
217 
218 
219 //==================================================================================================
220 extern "C" typelib_TypeClass cpp_vtable_call(
221     void ** pCallStack, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
222     sal_uInt64 * pRegisterReturn /* space for register return */ )
223 {
224     // pCallStack: ret adr, this, [ret *], params
225     void * pThis = static_cast< char * >(pCallStack[1]) - nVtableOffset;
226 
227     bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
228         bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
229 
230     typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
231 
232     OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
233     if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
234     {
235         throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
236                                 reinterpret_cast<XInterface *>( pCppI ) );
237     }
238 
239     // determine called method
240     sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
241     OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
242 
243     TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
244 
245     typelib_TypeClass eRet;
246     switch ( aMemberDescr.get()->eTypeClass )
247     {
248         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
249         {
250             typelib_TypeDescriptionReference *pAttrTypeRef =
251                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
252 
253             if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
254             {
255                 // is GET method
256                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
257                         0, 0, // no params
258                         pCallStack, pRegisterReturn );
259             }
260             else
261             {
262                 // is SET method
263                 typelib_MethodParameter aParam;
264                 aParam.pTypeRef = pAttrTypeRef;
265                 aParam.bIn      = sal_True;
266                 aParam.bOut     = sal_False;
267 
268                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
269                         0, // indicates void return
270                         1, &aParam,
271                         pCallStack, pRegisterReturn );
272             }
273             break;
274         }
275         case typelib_TypeClass_INTERFACE_METHOD:
276         {
277             // is METHOD
278             switch ( nFunctionIndex )
279             {
280                 // standard XInterface vtable calls
281                 case 1: // acquire()
282                     pCppI->acquireProxy(); // non virtual call!
283                     eRet = typelib_TypeClass_VOID;
284                     break;
285                 case 2: // release()
286                     pCppI->releaseProxy(); // non virtual call!
287                     eRet = typelib_TypeClass_VOID;
288                     break;
289                 case 0: // queryInterface() opt
290                 {
291                     typelib_TypeDescription * pTD = 0;
292                     TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( pCallStack[3] )->getTypeLibType() );
293                     if ( pTD )
294                     {
295                         XInterface * pInterface = 0;
296                         (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
297                             ( pCppI->getBridge()->getCppEnv(),
298                               (void **)&pInterface,
299                               pCppI->getOid().pData,
300                               reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
301 
302                         if ( pInterface )
303                         {
304                             ::uno_any_construct( reinterpret_cast<uno_Any *>( pCallStack[1] ),
305                                                  &pInterface, pTD, cpp_acquire );
306 
307                             pInterface->release();
308                             TYPELIB_DANGER_RELEASE( pTD );
309 
310                             reinterpret_cast<void **>( pRegisterReturn )[0] = pCallStack[1];
311                             eRet = typelib_TypeClass_ANY;
312                             break;
313                         }
314                         TYPELIB_DANGER_RELEASE( pTD );
315                     }
316                 } // else perform queryInterface()
317                 default:
318                 {
319                     typelib_InterfaceMethodTypeDescription *pMethodTD =
320                         reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
321 
322                     eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
323                                          pMethodTD->pReturnTypeRef,
324                                          pMethodTD->nParams,
325                                          pMethodTD->pParams,
326                                          pCallStack, pRegisterReturn );
327                 }
328             }
329             break;
330         }
331         default:
332         {
333             throw RuntimeException( OUString::createFromAscii("no member description found!"),
334                                     reinterpret_cast<XInterface *>( pCppI ) );
335             // is here for dummy
336             eRet = typelib_TypeClass_VOID;
337         }
338     }
339 
340     return eRet;
341 }
342 
343 //==================================================================================================
344 extern "C" void privateSnippetExecutor( ... );
345 
346 int const codeSnippetSize = 44;
347 
348 unsigned char * codeSnippet(
349     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, bool isArgFloat[4])
350 {
351     unsigned char * p = code;
352 
353 
354     //
355     //         | ...                        |
356     //         +----------------------------+
357     //         | argument 4                 |
358     //  rsp+40 +----------------------------+ -------
359     //         | argument 3, r9/xmm3 home   | ^ shadow
360     //  rsp+32 +----------------------------+ | space,
361     //         | argument 2, r8/xmm2 home   | | guaranteed to be present but uninitialized,
362     //  rsp+24 +----------------------------+ | we have to copy
363     //         | argument 1, rdx/xmm1 home  | | the first 4 parameters there from the registers,
364     //  rsp+16 +----------------------------+ | to form the continuous array of arguments.
365     //         | argument 0, rcx/xmm0 home  | v
366     //  rsp+08 +----------------------------+ -------
367     //         | return address             |
368     //  rsp--> +----------------------------+
369     //
370     //
371 
372     if (isArgFloat[0])
373     {
374         // movsd QWORD[rsp+8], XMM0
375         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08;
376     }
377     else
378     {
379         // mov QWORD[rsp+8], rcx
380         *p++ = 0x48; *p++ = 0x49; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x08;
381     }
382 
383     if (isArgFloat[1])
384     {
385         // movsd QWORD[rsp+16], XMM1
386         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x10;
387     }
388     else
389     {
390         // mov QWORD[rsp+16], rdx
391         *p++ = 0x48; *p++ = 0x49; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
392     }
393 
394     if (isArgFloat[2])
395     {
396         // movsd QWORD[rsp+24], XMM2
397         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
398     }
399     else
400     {
401         // mov QWORD[rsp+24], r8
402         *p++ = 0x4c; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18;
403     }
404 
405     if (isArgFloat[3])
406     {
407         // movsd QWORD[rsp+32], XMM3
408         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x5c; *p++ = 0x24; *p++ = 0x20;
409     }
410     else
411     {
412         // mov QWORD[rsp+32], r9
413         *p++ = 0x4c; *p++ = 0x89; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x20;
414     }
415 
416     // mov rax, functionIndex
417     *p++ = 0xb8;
418     *p++ = functionIndex & 0xff;
419     *p++ = (functionIndex >> 8) & 0xff;
420     *p++ = (functionIndex >> 16) & 0xff;
421     *p++ = (functionIndex >> 24) & 0xff;
422 
423     // mov r10, vtableOffset
424     *p++ = 0x41;
425     *p++ = 0xba;
426     *p++ = vtableOffset & 0xff;
427     *p++ = (vtableOffset >> 8) & 0xff;
428     *p++ = (vtableOffset >> 16) & 0xff;
429     *p++ = (vtableOffset >> 24) & 0xff;
430 
431     // mov r11, privateSnippetExecutor
432     *p++ = 0x49;
433     *p++ = 0xbb;
434     *p++ = ((sal_uIntPtr)(&privateSnippetExecutor)) & 0xff;
435     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 8) & 0xff;
436     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 16) & 0xff;
437     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 24) & 0xff;
438     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 32) & 0xff;
439     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 40) & 0xff;
440     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 48) & 0xff;
441     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 56) & 0xff;
442 
443     // jmp r11
444     *p++ = 0x49;
445     *p++ = 0xff;
446     *p++ = 0xe3;
447 
448     OSL_ASSERT(p - code <= codeSnippetSize);
449     return code + codeSnippetSize;
450 }
451 
452 }
453 
454 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
455 
456 bridges::cpp_uno::shared::VtableFactory::Slot *
457 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
458 {
459     return static_cast< Slot * >(block) + 1;
460 }
461 
462 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
463     sal_Int32 slotCount)
464 {
465     return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
466 }
467 
468 bridges::cpp_uno::shared::VtableFactory::Slot *
469 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
470     void * block, sal_Int32 slotCount)
471 {
472     struct RttiCompleteObjectLocator {
473         sal_uInt32 signature;
474         sal_uInt32 offset;    // offset of vtable in objects of the class
475         sal_uInt32 cdOffset;  // constructor displacement offset
476         // On AMD64, these 2 are offsets from the module's base address (when signature == 0):
477         sal_uInt32 typeDescriptorAddress;
478         sal_uInt32 classDescriptorAddress;
479         sal_uInt32 objectBase; // ignored when signature == 0
480 
481         RttiCompleteObjectLocator(): signature(0), offset(0), cdOffset(0)
482         {
483             type_info *typeInfo = CPPU_CURRENT_NAMESPACE::mscx_getRTTI(
484                      rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
485                                        "com.sun.star.uno.XInterface")));
486             HMODULE thisDLLBase;
487             GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&bridges::cpp_uno::shared::VtableFactory::initializeBlock, &thisDLLBase);
488             typeDescriptorAddress = (sal_uInt32) (((char*)typeInfo) - (char*)thisDLLBase);
489             classDescriptorAddress = 0;
490             objectBase = 0;
491         }
492     };
493     static RttiCompleteObjectLocator rtti;
494 
495     Slot * slots = mapBlockToVtable(block);
496     slots[-1].fn = &rtti;
497     return slots + slotCount;
498 }
499 
500 static void findFirst4Win64ArgumentTypes(
501     typelib_MethodParameter *pParams, sal_Int32 nParams,
502     typelib_TypeDescriptionReference *pReturnType, bool isArgFloat[4])
503 {
504     sal_uInt32 index = 0;
505 
506     isArgFloat[0] = isArgFloat[1] = isArgFloat[2] = isArgFloat[3] = false;
507 
508     // C++ "this" pointer:
509     ++index;
510 
511     // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
512     // "Otherwise the caller assumes the responsibility of allocating memory
513     // and passing a pointer for the return value as the first argument.
514     // Subsequent arguments are then shifted one argument to the right.
515     // The same pointer must be returned by the callee in RAX."
516     if ( pReturnType && x86_64::return_in_hidden_param( pReturnType ) )
517         ++index;
518 
519     for (int param = 0; param < nParams; param++)
520     {
521         if (index >= 4)
522             break;
523 
524         typelib_TypeDescription *pParamTypeDescr = 0;
525 
526         TYPELIB_DANGER_GET( &pParamTypeDescr, pParams[param].pTypeRef );
527         OSL_ASSERT( pParamTypeDescr );
528 
529         isArgFloat[index++] = !pParams[param].bOut &&
530             (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT ||
531             pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE);
532 
533         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
534     }
535 }
536 
537 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
538     Slot ** slots, unsigned char * code,
539     typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset,
540     sal_Int32 functionCount, sal_Int32 vtableOffset)
541 {
542     (*slots) -= functionCount;
543     Slot * s = *slots;
544     for (sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos) {
545         typelib_TypeDescription * pTD = 0;
546 
547         TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
548         OSL_ASSERT( pTD );
549 
550         bool isArgFloat[4];
551         if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
552         {
553             typelib_InterfaceAttributeTypeDescription *pAttrTD =
554                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
555 
556             // get method
557             findFirst4Win64ArgumentTypes(0, 0, pAttrTD->pAttributeTypeRef, isArgFloat);
558             (s++)->fn = code;
559             code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
560 
561             if ( ! pAttrTD->bReadOnly )
562             {
563                 // set method
564                 typelib_MethodParameter aParam;
565                 aParam.pTypeRef = pAttrTD->pAttributeTypeRef;
566                 aParam.bIn      = sal_True;
567                 aParam.bOut     = sal_False;
568                 findFirst4Win64ArgumentTypes(&aParam, 1, 0, isArgFloat);
569                 (s++)->fn = code;
570                 code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
571             }
572         }
573         else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
574         {
575             typelib_InterfaceMethodTypeDescription *pMethodTD =
576                 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
577             findFirst4Win64ArgumentTypes(pMethodTD->pParams, pMethodTD->nParams,
578                 pMethodTD->pReturnTypeRef, isArgFloat);
579             (s++)->fn = code;
580             code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
581         }
582         else
583             OSL_ASSERT( false );
584 
585         TYPELIB_DANGER_RELEASE( pTD );
586     }
587     return code;
588 }
589 
590 void bridges::cpp_uno::shared::VtableFactory::flushCode(
591     unsigned char const *, unsigned char const *)
592 {}
593