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