xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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                             // pCallStack is "ret addr, this, [ret *], params", so the
305                             // hidden return buffer is [2]; [1] is `this`.  Writing the
306                             // Any to [1] overwrote the proxy object and left the
307                             // caller's return buffer untouched, so the caller then
308                             // destructed an uninitialised Any.
309                             ::uno_any_construct( reinterpret_cast<uno_Any *>( pCallStack[2] ),
310                                                  &pInterface, pTD, cpp_acquire );
311 
312                             pInterface->release();
313                             TYPELIB_DANGER_RELEASE( pTD );
314 
315                             reinterpret_cast<void **>( pRegisterReturn )[0] = pCallStack[2];
316                             eRet = typelib_TypeClass_ANY;
317                             break;
318                         }
319                         TYPELIB_DANGER_RELEASE( pTD );
320                     }
321                 } // else perform queryInterface()
322                 default:
323                 {
324                     typelib_InterfaceMethodTypeDescription *pMethodTD =
325                         reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
326 
327                     eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
328                                          pMethodTD->pReturnTypeRef,
329                                          pMethodTD->nParams,
330                                          pMethodTD->pParams,
331                                          pCallStack, pRegisterReturn );
332                 }
333             }
334             break;
335         }
336         default:
337         {
338             throw RuntimeException( OUString::createFromAscii("no member description found!"),
339                                     reinterpret_cast<XInterface *>( pCppI ) );
340             // is here for dummy
341             eRet = typelib_TypeClass_VOID;
342         }
343     }
344 
345     return eRet;
346 }
347 
348 //==================================================================================================
349 extern "C" void privateSnippetExecutor( ... );
350 
351 int const codeSnippetSize = 48;
352 
353 unsigned char * codeSnippet(
354     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, bool isArgFloat[4])
355 {
356     unsigned char * p = code;
357 
358 
359     //
360     //         | ...                        |
361     //         +----------------------------+
362     //         | argument 4                 |
363     //  rsp+40 +----------------------------+ -------
364     //         | argument 3, r9/xmm3 home   | ^ shadow
365     //  rsp+32 +----------------------------+ | space,
366     //         | argument 2, r8/xmm2 home   | | guaranteed to be present but uninitialized,
367     //  rsp+24 +----------------------------+ | we have to copy
368     //         | argument 1, rdx/xmm1 home  | | the first 4 parameters there from the registers,
369     //  rsp+16 +----------------------------+ | to form the continuous array of arguments.
370     //         | argument 0, rcx/xmm0 home  | v
371     //  rsp+08 +----------------------------+ -------
372     //         | return address             |
373     //  rsp--> +----------------------------+
374     //
375     //
376 
377     // When it doubt about correctness,
378     // uncomment this and disassemble at runtime:
379     // INT 0x3
380     //*p++ = 0xcc;
381 
382     if (isArgFloat[0])
383     {
384         // movsd QWORD[rsp+8], XMM0
385         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08;
386     }
387     else
388     {
389         // mov QWORD[rsp+8], rcx
390         *p++ = 0x48; *p++ = 0x89; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x08;
391     }
392 
393     if (isArgFloat[1])
394     {
395         // movsd QWORD[rsp+16], XMM1
396         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x10;
397     }
398     else
399     {
400         // mov QWORD[rsp+16], rdx
401         *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
402     }
403 
404     if (isArgFloat[2])
405     {
406         // movsd QWORD[rsp+24], XMM2
407         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
408     }
409     else
410     {
411         // mov QWORD[rsp+24], r8
412         *p++ = 0x4c; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18;
413     }
414 
415     if (isArgFloat[3])
416     {
417         // movsd QWORD[rsp+32], XMM3
418         *p++ = 0xf2; *p++ = 0x0f; *p++ = 0x11; *p++ = 0x5c; *p++ = 0x24; *p++ = 0x20;
419     }
420     else
421     {
422         // mov QWORD[rsp+32], r9
423         *p++ = 0x4c; *p++ = 0x89; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x20;
424     }
425 
426     // mov rax, functionIndex
427     *p++ = 0xb8;
428     *p++ = functionIndex & 0xff;
429     *p++ = (functionIndex >> 8) & 0xff;
430     *p++ = (functionIndex >> 16) & 0xff;
431     *p++ = (functionIndex >> 24) & 0xff;
432 
433     // mov r10, vtableOffset
434     *p++ = 0x41;
435     *p++ = 0xba;
436     *p++ = vtableOffset & 0xff;
437     *p++ = (vtableOffset >> 8) & 0xff;
438     *p++ = (vtableOffset >> 16) & 0xff;
439     *p++ = (vtableOffset >> 24) & 0xff;
440 
441     // mov r11, privateSnippetExecutor
442     *p++ = 0x49;
443     *p++ = 0xbb;
444     *p++ = ((sal_uIntPtr)(&privateSnippetExecutor)) & 0xff;
445     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 8) & 0xff;
446     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 16) & 0xff;
447     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 24) & 0xff;
448     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 32) & 0xff;
449     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 40) & 0xff;
450     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 48) & 0xff;
451     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 56) & 0xff;
452 
453     // jmp r11
454     *p++ = 0x41;
455     *p++ = 0xff;
456     *p++ = 0xe3;
457 
458     OSL_ASSERT(p - code <= codeSnippetSize);
459     return code + codeSnippetSize;
460 }
461 
462 }
463 
464 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
465 
466 bridges::cpp_uno::shared::VtableFactory::Slot *
467 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
468 {
469     return static_cast< Slot * >(block) + 1;
470 }
471 
472 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
473     sal_Int32 slotCount)
474 {
475     return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
476 }
477 
478 bridges::cpp_uno::shared::VtableFactory::Slot *
479 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
480     void * block, sal_Int32 slotCount)
481 {
482     struct RttiCompleteObjectLocator {
483         sal_uInt32 signature;
484         sal_uInt32 offset;    // offset of vtable in objects of the class
485         sal_uInt32 cdOffset;  // constructor displacement offset
486         // On AMD64, these 2 are offsets from the module's base address (when signature == 0):
487         sal_uInt32 typeDescriptorAddress;
488         sal_uInt32 classDescriptorAddress;
489         sal_uInt32 objectBase; // ignored when signature == 0
490 
491         RttiCompleteObjectLocator(): signature(0), offset(0), cdOffset(0)
492         {
493             type_info *typeInfo = CPPU_CURRENT_NAMESPACE::mscx_getRTTI(
494                      rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
495                                        "com.sun.star.uno.XInterface")));
496             HMODULE thisDLLBase;
497             GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&bridges::cpp_uno::shared::VtableFactory::initializeBlock, &thisDLLBase);
498             typeDescriptorAddress = (sal_uInt32) (((char*)typeInfo) - (char*)thisDLLBase);
499             classDescriptorAddress = 0;
500             objectBase = 0;
501         }
502     };
503     static RttiCompleteObjectLocator rtti;
504 
505     Slot * slots = mapBlockToVtable(block);
506     slots[-1].fn = &rtti;
507     return slots + slotCount;
508 }
509 
510 static void findFirst4Win64ArgumentTypes(
511     typelib_MethodParameter *pParams, sal_Int32 nParams,
512     typelib_TypeDescriptionReference *pReturnType, bool isArgFloat[4])
513 {
514     sal_uInt32 index = 0;
515 
516     isArgFloat[0] = isArgFloat[1] = isArgFloat[2] = isArgFloat[3] = false;
517 
518     // C++ "this" pointer:
519     ++index;
520 
521     // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
522     // "Otherwise the caller assumes the responsibility of allocating memory
523     // and passing a pointer for the return value as the first argument.
524     // Subsequent arguments are then shifted one argument to the right.
525     // The same pointer must be returned by the callee in RAX."
526     if ( pReturnType && x86_64::return_in_hidden_param( pReturnType ) )
527         ++index;
528 
529     for (int param = 0; param < nParams; param++)
530     {
531         if (index >= 4)
532             break;
533 
534         typelib_TypeDescription *pParamTypeDescr = 0;
535 
536         TYPELIB_DANGER_GET( &pParamTypeDescr, pParams[param].pTypeRef );
537         OSL_ASSERT( pParamTypeDescr );
538 
539         isArgFloat[index++] = !pParams[param].bOut &&
540             (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT ||
541             pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE);
542 
543         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
544     }
545 }
546 
547 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
548     Slot ** slots, unsigned char * code,
549     typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset,
550     sal_Int32 functionCount, sal_Int32 vtableOffset)
551 {
552     (*slots) -= functionCount;
553     Slot * s = *slots;
554     for (sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos) {
555         typelib_TypeDescription * pTD = 0;
556 
557         TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
558         OSL_ASSERT( pTD );
559 
560         bool isArgFloat[4];
561         if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
562         {
563             typelib_InterfaceAttributeTypeDescription *pAttrTD =
564                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
565 
566             // get method
567             findFirst4Win64ArgumentTypes(0, 0, pAttrTD->pAttributeTypeRef, isArgFloat);
568             (s++)->fn = code;
569             code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
570 
571             if ( ! pAttrTD->bReadOnly )
572             {
573                 // set method
574                 typelib_MethodParameter aParam;
575                 aParam.pTypeRef = pAttrTD->pAttributeTypeRef;
576                 aParam.bIn      = sal_True;
577                 aParam.bOut     = sal_False;
578                 findFirst4Win64ArgumentTypes(&aParam, 1, 0, isArgFloat);
579                 (s++)->fn = code;
580                 code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
581             }
582         }
583         else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
584         {
585             typelib_InterfaceMethodTypeDescription *pMethodTD =
586                 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
587             findFirst4Win64ArgumentTypes(pMethodTD->pParams, pMethodTD->nParams,
588                 pMethodTD->pReturnTypeRef, isArgFloat);
589             (s++)->fn = code;
590             code = codeSnippet(code, functionOffset++, vtableOffset, isArgFloat);
591         }
592         else
593             OSL_ASSERT( false );
594 
595         TYPELIB_DANGER_RELEASE( pTD );
596     }
597     return code;
598 }
599 
600 void bridges::cpp_uno::shared::VtableFactory::flushCode(
601     unsigned char const *, unsigned char const *)
602 {}
603