--- bridges/prj/build.lst 8 Mar 2006 08:49:22 -0000 1.34 +++ bridges/prj/build.lst 8 May 2006 21:26:08 -0000 @@ -9,6 +9,7 @@ br bridges\source\cpp_uno\gcc3_linux_intel nmake - u br_gcc3li br_cppuno_shared br_unotypes NULL br bridges\source\cpp_uno\gcc3_freebsd_intel nmake - u br_gcc3fi br_cppuno_shared br_unotypes NULL br bridges\source\cpp_uno\gcc3_linux_x86-64 nmake - u br_gcc3lx br_cppuno_shared br_unotypes NULL +br bridges\source\cpp_uno\gcc3_freebsd_x86-64 nmake - u br_gcc3fx br_cppuno_shared br_unotypes NULL br bridges\source\cpp_uno\gcc3_linux_powerpc nmake - u br_gcclp3 br_cppuno_shared br_unotypes NULL br bridges\source\cpp_uno\gcc3_linux_s390 nmake - u br_gccl33 br_unotypes NULL br bridges\source\cpp_uno\gcc3_linux_sparc nmake - u br_gccl3s br_unotypes br_cppuno_shared NULL --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/abi.cxx Wed Mar 8 03:49:32 2006 @@ -0,0 +1,808 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// This is an implementation of the x86-64 ABI as described in 'System V +// Application Binary Interface, AMD64 Architecture Processor Supplement' +// (http://www.x86-64.org/documentation/abi-0.95.pdf) +// +// The code in this file is a modification of src/x86/ffi64.c from libffi +// (http://sources.redhat.com/libffi/) which is under the following license: + +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002 Bo Thorsen + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include + +#include + +using namespace x86_64; + +typedef struct +{ + /* Registers for argument passing. */ + long gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; + + /* Stack space for arguments. */ + char argspace[0]; +} stackLayout; + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). + */ +enum x86_64_reg_class +{ + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_MEMORY_CLASS +}; + +#define MAX_CLASSES 4 + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int &rByteOffset ) +{ + /* First, align to the right place. */ + rByteOffset = ALIGN( rByteOffset, pTypeRef->pType->nAlignment ); + + switch ( pTypeRef->eTypeClass ) + { + case typelib_TypeClass_VOID: + classes[0] = X86_64_NO_CLASS; + return 1; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_ENUM: + if ( ( rByteOffset % 8 + pTypeRef->pType->nSize ) <= 4 ) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + return 1; + case typelib_TypeClass_FLOAT: + if ( ( rByteOffset % 8 ) == 0 ) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case typelib_TypeClass_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + /*case LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2;*/ + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_UNION: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_ARRAY: + case typelib_TypeClass_INTERFACE: + return 0; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + + const int UNITS_PER_WORD = 8; + int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 16 bytes, pass it on the stack. */ + if ( pTypeDescr->nSize > 16 ) + { + TYPELIB_DANGER_RELEASE( pTypeDescr ); + return 0; + } + + for ( int i = 0; i < words; i++ ) + classes[i] = X86_64_NO_CLASS; + + const typelib_CompoundTypeDescription *pStruct = reinterpret_cast( pTypeDescr ); + + /* Merge the fields of structure. */ + for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember ) + { + typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ]; + + int num = classify_argument( pTypeInStruct, subclasses, rByteOffset ); + + if ( num == 0 ) + { + TYPELIB_DANGER_RELEASE( pTypeDescr ); + return 0; + } + + for ( int i = 0; i < num; i++ ) + { + int pos = rByteOffset / 8; + classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] ); + } + + if ( pTypeInStruct->eTypeClass != typelib_TypeClass_STRUCT ) + rByteOffset = pStruct->pMemberOffsets[ nMember ]; + } + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + + /* Final merger cleanup. */ + for ( int i = 0; i < words; i++ ) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if ( classes[i] == X86_64_MEMORY_CLASS ) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if ( classes[i] == X86_64_SSEUP_CLASS + && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) ) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if ( classes[i] == X86_64_X87UP_CLASS + && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) ) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + default: +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "Unhandled case: pType->eTypeClass == %d\n", pTypeRef->eTypeClass ); +#endif + OSL_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return 0 iff parameter should be passed in memory. */ +bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int offset = 0; + int n; + + n = classify_argument( pTypeRef, classes, offset ); + + if ( n == 0 ) + return false; + + nUsedGPR = 0; + nUsedSSE = 0; + for ( n--; n >= 0; n-- ) + switch ( classes[n] ) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + nUsedGPR++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + nUsedSSE++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + if ( !bInReturn ) + return false; + break; + default: +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "Unhandled case: classes[n] == %d\n", classes[n] ); +#endif + OSL_ASSERT(0); + } + return true; +} + +bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) +{ + int g, s; + + return examine_argument( pTypeRef, true, g, s ) == 0; +} + +void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, void * const *pGPR, void * const *pSSE, void *pStruct ) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int offset = 0; + int n; + + n = classify_argument( pTypeRef, classes, offset ); + + sal_uInt64 *pStructAlign = reinterpret_cast( pStruct ); + for ( n--; n >= 0; n-- ) + switch ( classes[n] ) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + *pStructAlign++ = *reinterpret_cast( *pGPR++ ); + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + *pStructAlign++ = *reinterpret_cast( *pSSE++ ); + break; + } +} + +#if 0 + +/* Functions to load floats and double to an SSE register placeholder. */ +extern void float2sse (float, __int128_t *); +extern void double2sse (double, __int128_t *); +extern void floatfloat2sse (void *, __int128_t *); + +/* Functions to put the floats and doubles back. */ +extern float sse2float (__int128_t *); +extern double sse2double (__int128_t *); +extern void sse2floatfloat(__int128_t *, void *); + +/*@-exportheader@*/ +void +ffi_prep_args (stackLayout *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + int gprcount, ssecount, i, g, s; + void **p_argv; + void *argp = &stack->argspace; + ffi_type **p_arg; + + /* First check if the return value should be passed in memory. If so, + pass the pointer as the first argument. */ + gprcount = ssecount = 0; + if (ecif->cif->rtype->type != FFI_TYPE_VOID + && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0) + (void *)stack->gpr[gprcount++] = ecif->rvalue; + + for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue; + i!=0; i--, p_arg++, p_argv++) + { + int in_register = 0; + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + if (gprcount < MAX_GPR_REGS) + { + stack->gpr[gprcount] = 0; + stack->gpr[gprcount++] = *(long long *)(*p_argv); + in_register = 1; + } + break; + + case FFI_TYPE_FLOAT: + if (ssecount < MAX_SSE_REGS) + { + float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + + case FFI_TYPE_DOUBLE: + if (ssecount < MAX_SSE_REGS) + { + double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]); + in_register = 1; + } + break; + } + + if (in_register) + continue; + + /* Either all places in registers where filled, or this is a + type that potentially goes into a memory slot. */ + if (examine_argument (*p_arg, 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* Pass this argument in memory. */ + argp = (void *)ALIGN(argp, (*p_arg)->alignment); + memcpy (argp, *p_argv, (*p_arg)->size); + argp += (*p_arg)->size; + } + else + { + /* All easy cases are eliminated. Now fire the big guns. */ + + enum x86_64_reg_class classes[MAX_CLASSES]; + int offset = 0, j, num; + void *a; + + num = classify_argument (*p_arg, classes, &offset); + for (j=0, a=*p_argv; jgpr[gprcount++] = *(long long *)a; + break; + case X86_64_SSE_CLASS: + floatfloat2sse (a, &stack->sse[ssecount++]); + break; + case X86_64_SSESF_CLASS: + float2sse (*(float *)a, &stack->sse[ssecount++]); + break; + case X86_64_SSEDF_CLASS: + double2sse (*(double *)a, &stack->sse[ssecount++]); + break; + default: + abort(); + } + } + } + } +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, g, s; + + gprcount = ssecount = 0; + + /* Reset the byte count. We handle this size estimation here. */ + cif->bytes = 0; + + /* If the return value should be passed in memory, pass the pointer + as the first argument. The actual memory isn't allocated here. */ + if (cif->rtype->type != FFI_TYPE_VOID + && examine_argument (cif->rtype, 1, &g, &s) == 0) + gprcount = 1; + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (i=0; inargs; i++) + { + if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0 + || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) + { + /* This is passed in memory. First align to the basic type. */ + cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment); + + /* Stack arguments are *always* at least 8 byte aligned. */ + cif->bytes = ALIGN(cif->bytes, 8); + + /* Now add the size of this argument. */ + cif->bytes += cif->arg_types[i]->size; + } + else + { + gprcount += g; + ssecount += s; + } + } + + /* Set the flag for the closures return. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +typedef struct +{ + long gpr[2]; + __int128_t sse[2]; + long double st0; +} return_value; + +//#endif + +void +ffi_fill_return_value (return_value *rv, extended_cif *ecif) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int i = 0, num; + long *gpr = rv->gpr; + __int128_t *sse = rv->sse; + signed char sc; + signed short ss; + + /* This is needed because of the way x86-64 handles signed short + integers. */ + switch (ecif->cif->rtype->type) + { + case FFI_TYPE_SINT8: + sc = *(signed char *)gpr; + *(long long *)ecif->rvalue = (long long)sc; + return; + case FFI_TYPE_SINT16: + ss = *(signed short *)gpr; + *(long long *)ecif->rvalue = (long long)ss; + return; + default: + /* Just continue. */ + ; + } + + num = classify_argument (ecif->cif->rtype, classes, &i); + + if (num == 0) + /* Return in memory. */ + ecif->rvalue = (void *) rv->gpr[0]; + else if (num == 2 && classes[0] == X86_64_X87_CLASS && + classes[1] == X86_64_X87UP_CLASS) + /* This is a long double (this is easiest to handle this way instead + of an eightbyte at a time as in the loop below. */ + *((long double *)ecif->rvalue) = rv->st0; + else + { + void *a; + + for (i=0, a=ecif->rvalue; irtype, 1, &dummy, &dummy) == 0)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + /* Stack must always be 16byte aligned. Make it so. */ + cif->bytes = ALIGN(cif->bytes, 16); + + switch (cif->abi) + { + case FFI_SYSV: + /* Calling 32bit code from 64bit is not possible */ + FFI_ASSERT(0); + break; + + case FFI_UNIX64: + /*@-usedef@*/ + ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif, + cif->bytes, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} + +extern void ffi_closure_UNIX64(void); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + volatile unsigned short *tramp; + + /* FFI_ASSERT (cif->abi == FFI_OSF); */ + + tramp = (volatile unsigned short *) &closure->tramp[0]; + tramp[0] = 0xbb49; /* mov , %r11 */ + tramp[5] = 0xba49; /* mov , %r10 */ + tramp[10] = 0xff49; /* jmp *%r11 */ + tramp[11] = 0x00e3; + *(void * volatile *) &tramp[1] = ffi_closure_UNIX64; + *(void * volatile *) &tramp[6] = closure; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn, argn; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + argn = 0; + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + { + if (l->gp_offset > 48-8) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->gp_offset; + l->gp_offset += 8; + } + } + break; + + case FFI_TYPE_STRUCT: + /* FIXME */ + FFI_ASSERT(0); + break; + + case FFI_TYPE_DOUBLE: + { + if (l->fp_offset > 176-16) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->fp_offset; + l->fp_offset += 16; + } + } +#if DEBUG_FFI + fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]); +#endif + break; + + case FFI_TYPE_FLOAT: + { + if (l->fp_offset > 176-16) + { + avalue[i] = l->overflow_arg_area; + l->overflow_arg_area = (char *)l->overflow_arg_area + 8; + } + else + { + avalue[i] = (char *)l->reg_save_area + l->fp_offset; + l->fp_offset += 16; + } + } +#if DEBUG_FFI + fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]); +#endif + break; + + default: + FFI_ASSERT(0); + } + + argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rp, avalue, closure->user_data); + + /* FIXME: Structs not supported. */ + FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT); + + /* Tell ffi_closure_UNIX64 how to perform return type promotions. */ + + return cif->rtype->type; +} + +#endif --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/abi.hxx Wed Mar 8 03:49:42 2006 @@ -0,0 +1,75 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ +#define _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ + +// This is an implementation of the x86-64 ABI as described in 'System V +// Application Binary Interface, AMD64 Architecture Processor Supplement' +// (http://www.x86-64.org/documentation/abi-0.95.pdf) + +#include + +namespace x86_64 +{ + +/* 6 general purpose registers are used for parameter passing */ +const sal_uInt32 MAX_GPR_REGS = 6; + +/* 8 SSE registers are used for parameter passing */ +const sal_uInt32 MAX_SSE_REGS = 8; + +/* Count number of required registers. + + Examine the argument and return set number of register required in each + class. + + Return false iff parameter should be passed in memory. +*/ +bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ); + +/** Does function that returns this type use a hidden parameter, or registers? + + The value can be returned either in a hidden 1st parameter (which is a + pointer to a structure allocated by the caller), or in registers (rax, rdx + for the integers, xmm0, xmm1 for the floating point numbers). +*/ +bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ); + +void fill_struct( typelib_TypeDescriptionReference *pTypeRef, void * const *pGPR, void * const *pSSE, void *pStruct ); + +} // namespace x86_64 + +#endif // _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/call.s Mon May 15 13:21:10 2006 @@ -0,0 +1,93 @@ + .text + .align 2 +.globl privateSnippetExecutor + .type privateSnippetExecutor, @function +privateSnippetExecutor: +.LFB3: + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $160, %rsp +.LCFI2: + movq %r10, -152(%rbp) # Save (nVtableOffset << 32) + nFunctionIndex + + movq %rdi, -112(%rbp) # Save GP registers + movq %rsi, -104(%rbp) + movq %rdx, -96(%rbp) + movq %rcx, -88(%rbp) + movq %r8 , -80(%rbp) + movq %r9 , -72(%rbp) + + movsd %xmm0, -64(%rbp) # Save FP registers + movsd %xmm1, -56(%rbp) + movsd %xmm2, -48(%rbp) + movsd %xmm3, -40(%rbp) + movsd %xmm4, -32(%rbp) + movsd %xmm5, -24(%rbp) + movsd %xmm6, -16(%rbp) + movsd %xmm7, -8(%rbp) + + leaq -144(%rbp), %r9 # 6th param: sal_uInt64 * pRegisterReturn + leaq 16(%rbp), %r8 # 5rd param: void ** ovrflw + leaq -64(%rbp), %rcx # 4th param: void ** fpreg + leaq -112(%rbp), %rdx # 3rd param: void ** gpreg + movl -148(%rbp), %esi # 2nd param: sal_int32 nVtableOffset + movl -152(%rbp), %edi # 1st param: sal_int32 nFunctionIndex + + call cpp_vtable_call + + cmp $10, %rax # typelib_TypeClass_FLOAT + je .Lfloat + cmp $11, %rax # typelib_TypeClass_DOUBLE + je .Lfloat + + movq -144(%rbp), %rax # Return value (int case) + jmp .Lfinish +.Lfloat: + movlpd -144(%rbp), %xmm0 # Return value (float/double case) + +.Lfinish: + leave + ret +.LFE3: + .size privateSnippetExecutor, .-privateSnippetExecutor + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x1b + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB3-. + .long .LFE3-.LFB3 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB3 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .section .note.GNU-stack,"",@progbits --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/cpp2uno.cxx Tue May 9 12:49:06 2006 @@ -0,0 +1,539 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include +#include +#include + +#include +#include + +#include +#include "com/sun/star/uno/RuntimeException.hpp" +#include +#include + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" +#include "bridges/cpp_uno/shared/types.hxx" +#include "bridges/cpp_uno/shared/vtablefactory.hxx" + +#include "abi.hxx" +#include "share.hxx" + +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +//================================================================================================== + +// Perform the UNO call +// +// We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO +// arguments and call pThis->getUnoI()->pDispatcher. +// +// gpreg: [ret *], this, [gpr params] +// fpreg: [fpr params] +// ovrflw: [gpr or fpr params (properly aligned)] +// +// [ret *] is present when we are returning a structure bigger than 16 bytes +// Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp). +// Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary. +static typelib_TypeClass cpp2uno_call( + bridges::cpp_uno::shared::CppInterfaceProxy * pThis, + const typelib_TypeDescription * pMemberTypeDescr, + typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return + sal_Int32 nParams, typelib_MethodParameter * pParams, + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_uInt64 * pRegisterReturn /* space for register return */ ) +{ + int nr_gpr = 0; //number of gpr registers used + int nr_fpr = 0; //number of fpr regsiters used + + // return + typelib_TypeDescription * pReturnTypeDescr = 0; + if (pReturnTypeRef) + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + + void * pUnoReturn = 0; + void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need + + if ( pReturnTypeDescr ) + { + if ( x86_64::return_in_hidden_param( pReturnTypeRef ) ) + { + pCppReturn = *gpreg++; + nr_gpr++; + + pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) + ? alloca( pReturnTypeDescr->nSize ) + : pCppReturn ); // direct way + } + else + pUnoReturn = pRegisterReturn; // direct way for simple types + } + + // pop this + gpreg++; + nr_gpr++; + + // stack space + // parameters + void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); + void ** pCppArgs = pUnoArgs + nParams; + // indizes of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); + // type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); + + sal_Int32 nTempIndizes = 0; + + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + typelib_TypeDescription * pParamTypeDescr = 0; + TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); + + int nUsedGPR = 0; + int nUsedSSE = 0; + bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE ); + if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value + { + // Simple types must fit exactly one register on x86_64 + OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); + + if ( nUsedSSE == 1 ) + { + if ( nr_fpr < x86_64::MAX_SSE_REGS ) + { + pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++; + nr_fpr++; + } + else + pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; + } + else if ( nUsedGPR == 1 ) + { + if ( nr_gpr < x86_64::MAX_GPR_REGS ) + { + pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++; + nr_gpr++; + } + else + pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; + } + + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + else // struct <= 16 bytes || ptr to complex value || ref + { + void *pCppStack; + char pTmpStruct[16]; + + if ( bFitsRegisters && !rParam.bOut && + ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT || + pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) ) + { + if ( ( nr_gpr + nUsedGPR <= x86_64::MAX_GPR_REGS ) && ( nr_fpr + nUsedSSE <= x86_64::MAX_SSE_REGS ) ) + { + x86_64::fill_struct( rParam.pTypeRef, gpreg, fpreg, pTmpStruct ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "nUsedGPR == %d, nUsedSSE == %d, pTmpStruct[0] == 0x%x, pTmpStruct[1] == 0x%x, **gpreg == 0x%lx\n", + nUsedGPR, nUsedSSE, pTmpStruct[0], pTmpStruct[1], *(sal_uInt64*)*gpreg ); +#endif + + pCppArgs[nPos] = pCppStack = reinterpret_cast( pTmpStruct ); + gpreg += nUsedGPR; + fpreg += nUsedSSE; + } + else + pCppArgs[nPos] = pCppStack = *ovrflw++; + } + else if ( nr_gpr < x86_64::MAX_GPR_REGS ) + { + pCppArgs[nPos] = pCppStack = *gpreg++; + nr_gpr++; + } + else + pCppArgs[nPos] = pCppStack = *ovrflw++; + + if (! rParam.bIn) // is pure out + { + // uno out is unconstructed mem! + pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); + pTempIndizes[nTempIndizes] = nPos; + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout + { + uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pCppStack, pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + pTempIndizes[nTempIndizes] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else // direct way + { + pUnoArgs[nPos] = pCppStack; + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + } + } + + // ExceptionHolder + uno_Any aUnoExc; // Any will be constructed by callee + uno_Any * pUnoExc = &aUnoExc; + + // invoke uno dispatch call + (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); + + // in case an exception occured... + if ( pUnoExc ) + { + // destruct temporary in/inout params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + + if (pParams[nIndex].bIn) // is in/inout => was constructed + uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + + CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any + // is here for dummy + return typelib_TypeClass_VOID; + } + else // else no exception occured... + { + // temporary params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; + + if ( pParams[nIndex].bOut ) // inout/out + { + // convert and assign + uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); + uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, + pThis->getBridge()->getUno2Cpp() ); + } + // destroy temp uno param + uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); + + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + // return + if ( pCppReturn ) // has complex return + { + if ( pUnoReturn != pCppReturn ) // needs reconversion + { + uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, + pThis->getBridge()->getUno2Cpp() ); + // destroy temp uno return + uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); + } + // complex return ptr is set to return reg + *(void **)pRegisterReturn = pCppReturn; + } + if ( pReturnTypeDescr ) + { + typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + return eRet; + } + else + return typelib_TypeClass_VOID; + } +} + + +//================================================================================================== +extern "C" typelib_TypeClass cpp_vtable_call( + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_uInt64 * pRegisterReturn /* space for register return */ ) +{ + // gpreg: [ret *], this, [other gpr params] + // fpreg: [fpr params] + // ovrflw: [gpr or fpr params (properly aligned)] + void * pThis; + if ( nFunctionIndex & 0x80000000 ) + { + nFunctionIndex &= 0x7fffffff; + pThis = gpreg[1]; + } + else + { + pThis = gpreg[0]; + } + pThis = static_cast( pThis ) - nVtableOffset; + + bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = + bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); + + typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); + + OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); + if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) + { + throw RuntimeException( OUString::createFromAscii("illegal vtable index!"), + reinterpret_cast( pCppI ) ); + } + + // determine called method + sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); + + TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); + + typelib_TypeClass eRet; + switch ( aMemberDescr.get()->eTypeClass ) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_TypeDescriptionReference *pAttrTypeRef = + reinterpret_cast( aMemberDescr.get() )->pAttributeTypeRef; + + if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) + { + // is GET method + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, + 0, 0, // no params + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + else + { + // is SET method + typelib_MethodParameter aParam; + aParam.pTypeRef = pAttrTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + 0, // indicates void return + 1, &aParam, + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + // is METHOD + switch ( nFunctionIndex ) + { + case 1: // acquire() + pCppI->acquireProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 2: // release() + pCppI->releaseProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 0: // queryInterface() opt + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast( gpreg[2] )->getTypeLibType() ); + if ( pTD ) + { + XInterface * pInterface = 0; + (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) + ( pCppI->getBridge()->getCppEnv(), + (void **)&pInterface, + pCppI->getOid().pData, + reinterpret_cast( pTD ) ); + + if ( pInterface ) + { + ::uno_any_construct( reinterpret_cast( gpreg[0] ), + &pInterface, pTD, cpp_acquire ); + + pInterface->release(); + TYPELIB_DANGER_RELEASE( pTD ); + + reinterpret_cast( pRegisterReturn )[0] = gpreg[0]; + eRet = typelib_TypeClass_ANY; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } // else perform queryInterface() + default: + { + typelib_InterfaceMethodTypeDescription *pMethodTD = + reinterpret_cast( aMemberDescr.get() ); + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + pMethodTD->pReturnTypeRef, + pMethodTD->nParams, + pMethodTD->pParams, + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + } + break; + } + default: + { + throw RuntimeException( OUString::createFromAscii("no member description found!"), + reinterpret_cast( pCppI ) ); + // is here for dummy + eRet = typelib_TypeClass_VOID; + } + } + + return eRet; +} + +//================================================================================================== +extern "C" void privateSnippetExecutor( ... ); + +const int codeSnippetSize = 24; + +// Generate a trampoline that redirects method calls to +// privateSnippetExecutor(). +// +// privateSnippetExecutor() saves all the registers that are used for +// parameter passing on x86_64, and calls the cpp_vtable_call(). +// When it returns, privateSnippetExecutor() sets the return value. +// +// Note: The code snippet we build here must not create a stack frame, +// otherwise the UNO exceptions stop working thanks to non-existing +// unwinding info. +unsigned char * codeSnippet( unsigned char * code, + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, + bool bHasHiddenParam ) SAL_THROW( () ) +{ + sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); + + if ( bHasHiddenParam ) + nOffsetAndIndex |= 0x80000000; + + // movq $, %r10 + *reinterpret_cast( code ) = 0xba49; + *reinterpret_cast( code + 2 ) = nOffsetAndIndex; + + // movq $
, %r11 + *reinterpret_cast( code + 10 ) = 0xbb49; + *reinterpret_cast( code + 12 ) = reinterpret_cast( privateSnippetExecutor ); + + // jmpq *%r11 + *reinterpret_cast( code + 20 ) = 0x00e3ff49; + + return code + codeSnippetSize; +} + +//================================================================================================== +void ** bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable( void * block ) +{ + return static_cast( block ) + 2; +} + +//================================================================================================== +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( + sal_Int32 slotCount) +{ + return ( slotCount + 2 ) * sizeof( void * ) + slotCount * codeSnippetSize; +} + +//================================================================================================== +void ** bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block ) +{ + void ** slots = mapBlockToVtable( block ); + slots[-2] = 0; + slots[-1] = 0; + + return slots; +} + +//================================================================================================== + +unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( + void ** slots, unsigned char * code, + typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset, + sal_Int32 functionCount, sal_Int32 nVtableOffset ) +{ + for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos ) + { + typelib_TypeDescription * pTD = 0; + + TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); + OSL_ASSERT( pTD ); + + if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass ) + { + typelib_InterfaceAttributeTypeDescription *pAttrTD = + reinterpret_cast( pTD ); + + // get method + *slots++ = code; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); + + if ( ! pAttrTD->bReadOnly ) + { + // set method + *slots++ = code; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false ); + } + } + else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass ) + { + typelib_InterfaceMethodTypeDescription *pMethodTD = + reinterpret_cast( pTD ); + + *slots++ = code; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); + } + else + OSL_ASSERT( false ); + + TYPELIB_DANGER_RELEASE( pTD ); + } + return code; +} + +//================================================================================================== +void bridges::cpp_uno::shared::VtableFactory::flushCode( + unsigned char const *, unsigned char const * ) +{ +} --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/except.cxx Mon May 8 17:19:14 2006 @@ -0,0 +1,334 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "com/sun/star/uno/RuntimeException.hpp" +#include +#include + +#include "share.hxx" + + +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::__cxxabiv1; + + +namespace CPPU_CURRENT_NAMESPACE +{ + +void dummy_can_throw_anything( char const * ) +{ +} + +//================================================================================================== +static OUString toUNOname( char const * p ) SAL_THROW( () ) +{ +#if OSL_DEBUG_LEVEL > 1 + char const * start = p; +#endif + + // example: N3com3sun4star4lang24IllegalArgumentExceptionE + + OUStringBuffer buf( 64 ); + OSL_ASSERT( 'N' == *p ); + ++p; // skip N + + while ('E' != *p) + { + // read chars count + long n = (*p++ - '0'); + while ('0' <= *p && '9' >= *p) + { + n *= 10; + n += (*p++ - '0'); + } + buf.appendAscii( p, n ); + p += n; + if ('E' != *p) + buf.append( (sal_Unicode)'.' ); + } + +#if OSL_DEBUG_LEVEL > 1 + OUString ret( buf.makeStringAndClear() ); + OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() ); + return ret; +#else + return buf.makeStringAndClear(); +#endif +} + +//================================================================================================== +class RTTI +{ + typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map; + + Mutex m_mutex; + t_rtti_map m_rttis; + t_rtti_map m_generatedRttis; + + void * m_hApp; + +public: + RTTI() SAL_THROW( () ); + ~RTTI() SAL_THROW( () ); + + type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () ); +}; +//__________________________________________________________________________________________________ +RTTI::RTTI() SAL_THROW( () ) + : m_hApp( dlopen( 0, RTLD_NOW | RTLD_GLOBAL ) ) +{ +} +//__________________________________________________________________________________________________ +RTTI::~RTTI() SAL_THROW( () ) +{ + dlclose( m_hApp ); +} + +//__________________________________________________________________________________________________ +type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () ) +{ + type_info * rtti; + + OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName; + + MutexGuard guard( m_mutex ); + t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) ); + if (iFind == m_rttis.end()) + { + // RTTI symbol + OStringBuffer buf( 64 ); + buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") ); + sal_Int32 index = 0; + do + { + OUString token( unoName.getToken( 0, '.', index ) ); + buf.append( token.getLength() ); + OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( c_token ); + } + while (index >= 0); + buf.append( 'E' ); + + OString symName( buf.makeStringAndClear() ); + rtti = (type_info *)dlsym( RTLD_DEFAULT, symName.getStr() ); + + if (rtti) + { + pair< t_rtti_map::iterator, bool > insertion( + m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) ); + OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" ); + } + else + { + // try to lookup the symbol in the generated rtti map + t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) ); + if (iFind == m_generatedRttis.end()) + { + // we must generate it ! + // symbol and rtti-name is nearly identical, + // the symbol is prefixed with _ZTI + char const * rttiName = symName.getStr() +4; +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr,"generated rtti for %s\n", rttiName ); +#endif + if (pTypeDescr->pBaseTypeDescription) + { + // ensure availability of base + type_info * base_rtti = getRTTI( + (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription ); + rtti = new __si_class_type_info( + strdup( rttiName ), (__class_type_info *)base_rtti ); + } + else + { + // this class has no base class + rtti = new __class_type_info( strdup( rttiName ) ); + } + + pair< t_rtti_map::iterator, bool > insertion( + m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) ); + OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" ); + } + else // taking already generated rtti + { + rtti = iFind->second; + } + } + } + else + { + rtti = iFind->second; + } + + return rtti; +} + +//-------------------------------------------------------------------------------------------------- +static void deleteException( void * pExc ) +{ + __cxa_exception const * header = ((__cxa_exception const *)pExc - 1); + typelib_TypeDescription * pTD = 0; + OUString unoName( toUNOname( header->exceptionType->name() ) ); + ::typelib_typedescription_getByName( &pTD, unoName.pData ); + OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" ); + if (pTD) + { + ::uno_destructData( pExc, pTD, cpp_release ); + ::typelib_typedescription_release( pTD ); + } +} + +//================================================================================================== +void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) +{ +#if OSL_DEBUG_LEVEL > 1 + OString cstr( + OUStringToOString( + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() ); +#endif + void * pCppExc; + type_info * rtti; + + { + // construct cpp exception object + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType ); + OSL_ASSERT( pTypeDescr ); + if (! pTypeDescr) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) + + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + Reference< XInterface >() ); + } + + pCppExc = __cxa_allocate_exception( pTypeDescr->nSize ); + ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp ); + + // destruct uno exception + ::uno_any_destruct( pUnoExc, 0 ); + // avoiding locked counts + static RTTI * s_rtti = 0; + if (! s_rtti) + { + MutexGuard guard( Mutex::getGlobalMutex() ); + if (! s_rtti) + { +#ifdef LEAK_STATIC_DATA + s_rtti = new RTTI(); +#else + static RTTI rtti_data; + s_rtti = &rtti_data; +#endif + } + } + rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); + if (! rtti) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + Reference< XInterface >() ); + } + } + + __cxa_throw( pCppExc, rtti, deleteException ); +} + +//================================================================================================== +void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno ) +{ + if (! header) + { + RuntimeException aRE( + OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ), + Reference< XInterface >() ); + Type const & rType = ::getCppuType( &aRE ); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr.getStr() ); +#endif + return; + } + + typelib_TypeDescription * pExcTypeDescr = 0; + OUString unoName( toUNOname( header->exceptionType->name() ) ); +#if OSL_DEBUG_LEVEL > 1 + OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "> c++ exception occured: %s\n", cstr_unoName.getStr() ); +#endif + typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); + if (0 == pExcTypeDescr) + { + RuntimeException aRE( + OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName, + Reference< XInterface >() ); + Type const & rType = ::getCppuType( &aRE ); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE( 0, cstr.getStr() ); +#endif + } + else + { + // construct uno exception any + uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno ); + typelib_typedescription_release( pExcTypeDescr ); + } +} + +} + --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/makefile.mk Mon May 8 17:17:43 2006 @@ -0,0 +1,92 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile$ +# +# $Revision$ +# +# last change: $Author$ $Date$ +# +# The Contents of this file are made available subject to +# the terms of GNU Lesser General Public License Version 2.1. +# +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2005 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=bridges +TARGET=gcc3_uno +LIBTARGET=no +ENABLE_EXCEPTIONS=TRUE +NO_BSYMBOLIC=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +.IF "$(COM)$(OS)$(CPU)$(COMNAME)" == "GCCFREEBSDXgcc3" + +.IF "$(cppu_no_leak)" == "" +CFLAGS += -DLEAK_STATIC_DATA +.ENDIF + +NOOPTFILES= \ + $(SLO)$/uno2cpp.obj + + +CFLAGSNOOPT=-O0 + +SLOFILES= \ + $(SLO)$/abi.obj \ + $(SLO)$/except.obj \ + $(SLO)$/cpp2uno.obj \ + $(SLO)$/uno2cpp.obj \ + $(SLO)$/call.obj + +SHL1TARGET= $(TARGET) + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +SHL1IMPLIB=i$(TARGET) +SHL1VERSIONMAP=..$/..$/bridge_exports.map + +SHL1OBJS = $(SLOFILES) +SHL1LIBS = $(SLB)$/cpp_uno_shared.lib + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(SALLIB) + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +$(SLO)$/%.obj: %.s + $(CC) -c -o $(SLO)$/$(@:b).o $< + touch $@ --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/share.hxx Wed Mar 8 03:51:06 2006 @@ -0,0 +1,98 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include "uno/mapping.h" + +#include +#include +#include + +namespace CPPU_CURRENT_NAMESPACE +{ + +void dummy_can_throw_anything( char const * ); + +// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h + +struct _Unwind_Exception +{ + unsigned exception_class __attribute__((__mode__(__DI__))); + void * exception_cleanup; + unsigned private_1 __attribute__((__mode__(__word__))); + unsigned private_2 __attribute__((__mode__(__word__))); +} __attribute__((__aligned__)); + +struct __cxa_exception +{ + ::std::type_info *exceptionType; + void (*exceptionDestructor)(void *); + + ::std::unexpected_handler unexpectedHandler; + ::std::terminate_handler terminateHandler; + + __cxa_exception *nextException; + + int handlerCount; + + int handlerSwitchValue; + const unsigned char *actionRecord; + const unsigned char *languageSpecificData; + void *catchTemp; + void *adjustedPtr; + + _Unwind_Exception unwindHeader; +}; + +extern "C" void *__cxa_allocate_exception( + std::size_t thrown_size ) throw(); +extern "C" void __cxa_throw ( + void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn)); + +struct __cxa_eh_globals +{ + __cxa_exception *caughtExceptions; + unsigned int uncaughtExceptions; +}; +extern "C" __cxa_eh_globals *__cxa_get_globals () throw(); + +// ----- + +//================================================================================================== +void raiseException( + uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ); +//================================================================================================== +void fillUnoException( + __cxa_exception * header, uno_Any *, uno_Mapping * pCpp2Uno ); +} --- /dev/null Wed Dec 31 19:00:00 1969 +++ bridges/source/cpp_uno/gcc3_freebsd_x86-64/uno2cpp.cxx Wed Mar 8 03:51:19 2006 @@ -0,0 +1,645 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include +#include +#include + +#include +#include "com/sun/star/uno/RuntimeException.hpp" +#include + +#include +#include +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "share.hxx" + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +void dummy_can_throw_anything( char const * ); + +// 6 integral parameters are passed in registers +const sal_uInt32 GPR_COUNT = 6; + +// 8 floating point parameters are passed in SSE registers +const sal_uInt32 FPR_COUNT = 8; + +static inline void +invoke_count_words(char * pPT, // Parameter Types + sal_uInt32 & nr_gpr, // Number of arguments in GPRs + sal_uInt32 & nr_fpr, // Number of arguments in FPRs + sal_uInt32 & nr_stack) // Number of arguments in stack +{ + nr_gpr = 0; + nr_fpr = 0; + nr_stack = 0; + char c; + + while ((c = *pPT++) != 'X') + { + if (c == 'F' || c == 'D') + { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else + { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(sal_uInt64 * pDS, // Stack Storage + char * pPT, // Parameter Types + sal_uInt64 * pSV, // Source Values + sal_uInt64 * pGPR, // General Purpose Registers + double * pFPR) // Floating-Point Registers +{ + sal_uInt32 nr_gpr = 0; + sal_uInt32 nr_fpr = 0; + sal_uInt64 value; + char c; + + while ((c = *pPT++) != 'X') + { + switch (c) + { + case 'D': // Double + if (nr_fpr < FPR_COUNT) + pFPR[nr_fpr++] = *reinterpret_cast( pSV++ ); + else + *pDS++ = *pSV++; + break; + + case 'F': // Float + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + pFPR[nr_fpr++] = *reinterpret_cast( pSV++ ); + else + *pDS++ = *reinterpret_cast( pSV++ ); + break; + + case 'H': // 64-bit Word + if (nr_gpr < GPR_COUNT) + pGPR[nr_gpr++] = *pSV++; + else + *pDS++ = *pSV++; + break; + + case 'I': // 32-bit Word + if (nr_gpr < GPR_COUNT) + pGPR[nr_gpr++] = *reinterpret_cast( pSV++ ); + else + *pDS++ = *reinterpret_cast( pSV++ ); + break; + + case 'S': // 16-bit Word + if (nr_gpr < GPR_COUNT) + pGPR[nr_gpr++] = *reinterpret_cast( pSV++ ); + else + *pDS++ = *reinterpret_cast( pSV++ ); + break; + + case 'B': // Byte + if (nr_gpr < GPR_COUNT) + pGPR[nr_gpr++] = *reinterpret_cast( pSV++ ); + else + *pDS++ = *reinterpret_cast( pSV++ ); + break; + + default: // Default, assume 64-bit values + if (nr_gpr < GPR_COUNT) + pGPR[nr_gpr++] = *pSV++; + else + *pDS++ = *pSV++; + break; + } + } +} + +//================================================================================================== +static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, + void * pRegisterReturn, typelib_TypeClass eReturnType, + char * pPT, sal_uInt64 * pStackLongs, sal_uInt32 nStackLongs) +{ + sal_uInt32 nr_gpr, nr_fpr, nr_stack; + invoke_count_words(pPT, nr_gpr, nr_fpr, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + + bool bReturnsSimpleType = bridges::cpp_uno::shared::isSimpleType( eReturnType ); + +#if OSL_DEBUG_LEVEL > 1 + // Let's figure out what is really going on here + fprintf(stderr,"callVirtualMethod() parameters string is %s\n", pPT); + { + sal_uInt32 k = nStackLongs; + sal_uInt64 *q = pStackLongs; + while (k > 0) + { + fprintf(stderr, "uno stack is: %lx\n", *q); + k--; + q++; + } + } +#endif + + // Load parameters to stack, if necessary + sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca(nr_stack * 8); + sal_uInt64 gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; + invoke_copy_to_stack(stack, pPT, pStackLongs, gpregs, fpregs); + + // Load FPR registers from fpregs[] + register double d0 asm("xmm0"); + register double d1 asm("xmm1"); + register double d2 asm("xmm2"); + register double d3 asm("xmm3"); + register double d4 asm("xmm4"); + register double d5 asm("xmm5"); + register double d6 asm("xmm6"); + register double d7 asm("xmm7"); + + switch (nr_fpr) { +#define ARG_FPR(N) \ + case N+1: d##N = fpregs[N]; + ARG_FPR(7); + ARG_FPR(6); + ARG_FPR(5); + ARG_FPR(4); + ARG_FPR(3); + ARG_FPR(2); + ARG_FPR(1); + ARG_FPR(0); + case 0:; +#undef ARG_FPR + } + + // Load GPR registers from gpregs[] + register sal_uInt64 a0 asm("rdi"); + register sal_uInt64 a1 asm("rsi"); + register sal_uInt64 a2 asm("rdx"); + register sal_uInt64 a3 asm("rcx"); + register sal_uInt64 a4 asm("r8"); + register sal_uInt64 a5 asm("r9"); + + switch (nr_gpr) { +#define ARG_GPR(N) \ + case N+1: a##N = gpregs[N]; + ARG_GPR(5); + ARG_GPR(4); + ARG_GPR(3); + ARG_GPR(2); + ARG_GPR(1); + ARG_GPR(0); + case 0:; +#undef ARG_GPR + } + + if ( bReturnsSimpleType ) + a0 = (sal_uInt64) pThis; + else + a1 = (sal_uInt64) pThis; + + // Ensure that assignments to SSE registers won't be optimized away + asm("" :: + "x" (d0), "x" (d1), "x" (d2), "x" (d3), + "x" (d4), "x" (d5), "x" (d6), "x" (d7)); + + // Get pointer to method + sal_uInt64 pMethod = *((sal_uInt64 *)pThis); + pMethod += 8 * nVtableIndex; + pMethod = *((sal_uInt64 *)pMethod); + + union ReturnValue { + struct { + sal_uInt64 rax; + sal_uInt64 rdx; + } i; + struct { + double xmm0; + double xmm1; + } f; + }; + + typedef ReturnValue (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 ); + + // Perform the call + ReturnValue aRet = ( ( FunctionCall ) pMethod )( a0, a1, a2, a3, a4, a5 ); + + switch (eReturnType) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *reinterpret_cast( pRegisterReturn ) = aRet.i.rax; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + *reinterpret_cast( pRegisterReturn ) = *reinterpret_cast( &aRet.i.rax ); + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *reinterpret_cast( pRegisterReturn ) = *reinterpret_cast( &aRet.i.rax ); + break; + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + *reinterpret_cast( pRegisterReturn ) = *reinterpret_cast( &aRet.i.rax ); + break; + case typelib_TypeClass_FLOAT: + *reinterpret_cast( pRegisterReturn ) = *reinterpret_cast( &aRet.f.xmm0 ); + break; + case typelib_TypeClass_DOUBLE: + *reinterpret_cast( pRegisterReturn ) = *reinterpret_cast( &aRet.f.xmm0 ); + break; + } +} + + +//================================================================================================== +static void cpp_call( + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, + bridges::cpp_uno::shared::VtableSlot aVtableSlot, + typelib_TypeDescriptionReference * pReturnTypeRef, + sal_Int32 nParams, typelib_MethodParameter * pParams, + void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) +{ + // Maxium space for [complex ret ptr], values | ptr ... + char * pCppStack = (char *)__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ); + char * pCppStackStart = pCppStack; + + // We need to know parameter types for callVirtualMethod() so generate a signature string + char * pParamType = (char *)__builtin_alloca( nParams + 3 ); + char * pPT = pParamType; + + // Return + typelib_TypeDescription * pReturnTypeDescr = 0; + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); + + void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion + + if (pReturnTypeDescr) + { + if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) + { + pCppReturn = pUnoReturn; // direct way for simple types + } + else + { + // complex return via ptr + pCppReturn = *(void **)pCppStack = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) + ? __builtin_alloca( pReturnTypeDescr->nSize ) + : pUnoReturn); // direct way + *pPT++ = 'H'; + pCppStack += sizeof(void *); + } + } + + // Push "this" pointer + void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset; + *(void **)pCppStack = pAdjustedThisPtr; + *pPT++ = 'H'; + pCppStack += sizeof(void *); + + // stack space + // Args + void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); + // Indizes of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); + // Type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); + + sal_Int32 nTempIndizes = 0; + + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + typelib_TypeDescription * pParamTypeDescr = 0; + TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); + + if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) + { + uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, + pThis->getBridge()->getUno2Cpp() ); + + switch (pParamTypeDescr->eTypeClass) + { + + // we need to know type of each param so that we know whether to use + // gpr or fpr to pass in parameters: + // Key: I - 32-bit value passed in gpr + // B - byte value passed in gpr + // S - short value passed in gpr + // F - float value pass in fpr + // D - double value pass in fpr + // H - long value passed in gpr + // X - indicates end of parameter description string + + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + *pPT++ = 'I'; + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_CHAR: + case typelib_TypeClass_UNSIGNED_SHORT: + *pPT++ = 'S'; + break; + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + *pPT++ = 'B'; + break; + case typelib_TypeClass_FLOAT: + *pPT++ = 'F'; + break; + case typelib_TypeClass_DOUBLE: + *pPT++ = 'D'; + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *pPT++ = 'H'; + break; + } + + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + else // ptr to complex value | ref + { + if (! rParam.bIn) // is pure out + { + // cpp out is constructed mem, uno out is not! + uno_constructData( + *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pParamTypeDescr ); + pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + // is in/inout + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) + { + uno_copyAndConvertData( + *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); + + pTempIndizes[nTempIndizes] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else // direct way + { + *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + // FIXME: is this the right way to pass these? + *pPT++='H'; + } + pCppStack += sizeof(sal_uInt64); // standard parameter length + } + + // terminate the signature string + *pPT++ = 'X'; + *pPT = 0; + + try + { + OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 7), "UNALIGNED STACK !!! (Please DO panic)" ); + callVirtualMethod( + pAdjustedThisPtr, aVtableSlot.index, + pCppReturn, pReturnTypeDescr->eTypeClass, pParamType, + (sal_uInt64 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_uInt64) ); + // NO exception occured... + *ppUnoExc = 0; + + // reconvert temporary params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; + + if (pParams[nIndex].bIn) + { + if (pParams[nIndex].bOut) // inout + { + uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value + uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + } + } + else // pure out + { + uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + } + // destroy temp cpp param => cpp: every param was constructed + uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); + + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + // return value + if (pCppReturn && pUnoReturn != pCppReturn) + { + uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); + } + } + catch (...) + { + // fill uno exception + fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); + + // temporary params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + // destroy temp cpp param => cpp: every param was constructed + uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + // return type + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + } +} + + +//================================================================================================== +void bridges::cpp_uno::shared::UnoInterfaceProxy::dispatch( + uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, + void * pReturn, void * pArgs[], uno_Any ** ppException ) SAL_THROW(()) +{ + // is my surrogate + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis + = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); + typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; + + switch (pMemberDescr->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + // determine vtable call index + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); + + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + pMemberDescr))); + + if (pReturn) + { + // dependent dispatch + cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, + 0, 0, // no params + pReturn, pArgs, ppException ); + } + else + { + // is SET + typelib_MethodParameter aParam; + aParam.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + typelib_TypeDescriptionReference * pReturnTypeRef = 0; + OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); + typelib_typedescriptionreference_new( + &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); + + // dependent dispatch + aVtableSlot.index += 1; // get, then set method + cpp_call( + pThis, aVtableSlot, // get, then set method + pReturnTypeRef, + 1, &aParam, + pReturn, pArgs, ppException ); + + typelib_typedescriptionreference_release( pReturnTypeRef ); + } + + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + // determine vtable call index + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); + + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >( + pMemberDescr))); + + switch (aVtableSlot.index) + { + // standard calls + case 1: // acquire uno interface + (*pUnoI->acquire)( pUnoI ); + *ppException = 0; + break; + case 2: // release uno interface + (*pUnoI->release)( pUnoI ); + *ppException = 0; + break; + case 0: // queryInterface() opt + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); + if (pTD) + { + uno_Interface * pInterface = 0; + (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( + pThis->getBridge()->getUnoEnv(), + (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); + + if (pInterface) + { + ::uno_any_construct( + reinterpret_cast< uno_Any * >( pReturn ), + &pInterface, pTD, 0 ); + (*pInterface->release)( pInterface ); + TYPELIB_DANGER_RELEASE( pTD ); + *ppException = 0; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } // else perform queryInterface() + default: + // dependent dispatch + cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, + pReturn, pArgs, ppException ); + } + break; + } + default: + { + ::com::sun::star::uno::RuntimeException aExc( + OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); + + Type const & rExcType = ::getCppuType( &aExc ); + // binary identical null reference + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } +}