diff options
Diffstat (limited to 'bridges/source/cpp_uno/gcc3_linux_mips')
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx | 806 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_mips/except.cxx | 328 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_mips/makefile.mk | 85 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_mips/share.hxx | 94 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx | 600 |
5 files changed, 1913 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx new file mode 100644 index 000000000000..ec4055ca74c4 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx @@ -0,0 +1,806 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: cpp2uno.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <com/sun/star/uno/genfunc.hxx> +#include <typelib/typedescription.hxx> +#include <uno/data.h> +#include <osl/endian.h> +#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 "share.hxx" + +#include <stdio.h> +#include <string.h> + +using namespace com::sun::star::uno; + +//#define BRDEBUG + +#ifdef BRDEBUG +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; +#endif +#include <sys/sysmips.h> + +#ifdef OSL_BIGENDIAN +#define IS_BIG_ENDIAN 1 +#else +#define IS_BIG_ENDIAN 0 +#endif + +using namespace ::com::sun::star::uno; + +namespace +{ + + //================================================================================================== + 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_Int64 * pRegisterReturn /* space for register return */ ) + { + /* Most MIPS ABIs view the arguments as a struct, of which the + first N words go in registers and the rest go on the stack. If I < N, the + Ith word might go in Ith integer argument register or the Ith + floating-point one. For these ABIs, we only need to remember the number + of words passed so far. We are interested only in o32 ABI,so it is the + case. + */ + int nw = 0; // number of words used by arguments + +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call1\n"); +#endif + + /* C++ has [ret *] or this as the first arguments, so no arguments will + * be passed in floating-point registers? + */ + //int int_seen = 0; // have we seen integer arguments? + + void ** pCppStack; //temporary stack pointer + + // gpreg: [ret *], this, [gpr params] + // fpreg: [fpr params] + // ovrflw: [gpr or fpr params (properly aligned)] + + // 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 (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) + { + pUnoReturn = pRegisterReturn; // direct way for simple types +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:simplereturn\n"); +#endif + } + else // complex return via ptr (pCppReturn) + { + pCppReturn = *(void **)gpreg; + gpreg++; + nw++; + + pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) + ? alloca( pReturnTypeDescr->nSize ) + : pCppReturn); // direct way +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:complexreturn\n"); +#endif + } + } + + // pop this + gpreg++; + nw++; + + // stack space + OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); + // 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; + +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:nParams=%d\n",nParams); +#endif + + 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 )) + // value + { + + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_DOUBLE: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:hyper=%d,%p\n",pParamTypeDescr->eTypeClass,gpreg[0]); +#endif + if (nw < 3) { + if (nw & 1) { + nw++; + gpreg++; + } +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:gpreg=%p,%p\n",gpreg[0],gpreg[1]); +#endif + pCppArgs[nPos] = gpreg; + pUnoArgs[nPos] = gpreg; + nw += 2; + gpreg += 2; + } else { + if (((long)ovrflw) & 4) ovrflw++; +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:overflw=%p,%p\n",ovrflw[0],ovrflw[1]); +#endif + pCppArgs[nPos] = ovrflw; + pUnoArgs[nPos] = ovrflw; + ovrflw += 2; + } + break; + + case typelib_TypeClass_BYTE: + case typelib_TypeClass_BOOLEAN: +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:byte=%p,%p\n",gpreg[0],ovrflw[0]); +#endif + if (nw < 4) { + pCppArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN); + pUnoArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN); + nw++; + gpreg++; + } else { + pCppArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN); + pUnoArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN); + ovrflw++; + } + break; + + + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:char=%p,%p\n",gpreg[0],ovrflw[0]); +#endif + if (nw < 4) { + pCppArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN); + pUnoArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN); + nw++; + gpreg++; + } else { + pCppArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN); + pUnoArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN); + ovrflw++; + } + break; + + + default: +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:def=%p,%p\n",gpreg[0],ovrflw[0]); +#endif + if (nw < 4) { + pCppArgs[nPos] = gpreg; + pUnoArgs[nPos] = gpreg; + nw++; + gpreg++; + } else { + pCppArgs[nPos] = ovrflw; + pUnoArgs[nPos] = ovrflw; + ovrflw++; + } + break; + + } + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + else // ptr to complex value | ref + { + +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:ptr|ref\n"); +#endif + if (nw < 4) { + pCppArgs[nPos] = *(void **)gpreg; + pCppStack = gpreg; + nw++; + gpreg++; + } else { + pCppArgs[nPos] = *(void **)ovrflw; + pCppStack = ovrflw; + ovrflw++; + } +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:pCppStack=%p\n",pCppStack); +#endif + + 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; + } + // is in/inout + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) + { + uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), + *(void **)pCppStack, pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + pTempIndizes[nTempIndizes] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",*(void**)pCppStack,pParamTypeDescr->nSize,nPos,pUnoArgs[nPos]); +#endif + } + else // direct way + { + pUnoArgs[nPos] = *(void **)pCppStack; +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call:direct,pUnoArgs[%d]=%p\n",nPos,pUnoArgs[nPos]); +#endif + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + } + } +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call2,%p,unoargs=%p\n",pThis->getUnoI()->pDispatcher,pUnoArgs); +#endif + + // 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 ); +#ifdef BRDEBUG + fprintf(stderr,"cpp2uno_call2,after dispatch\n"); +#endif + + // 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; + } + } + + + //================================================================================================== + static typelib_TypeClass cpp_mediate( + sal_Int32 nFunctionIndex, + sal_Int32 nVtableOffset, + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_Int64 * pRegisterReturn /* space for register return */ ) + { + OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); + +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate1 gp=%p,fp=%p,ov=%p\n",gpreg,fpreg,ovrflw); + fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]); +#endif + + // 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]; + } +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate12,pThis=%p, nFunctionIndex=%d,nVtableOffset=%d\n",pThis,nFunctionIndex,nVtableOffset); +#endif + + pThis = static_cast< char * >(pThis) - nVtableOffset; + bridges::cpp_uno::shared::CppInterfaceProxy * pCppI + = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( + pThis); +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate13,pCppI=%p\n",pCppI); +#endif + + typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); + +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate2\n"); +#endif + OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); + if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) + { + throw RuntimeException( + rtl::OUString::createFromAscii("illegal vtable index!"), + (XInterface *)pThis ); + } + + // determine called method + sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); + + TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); + +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate3\n"); + OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex ); +#endif + typelib_TypeClass eRet; + switch (aMemberDescr.get()->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate4\n"); +#endif + if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) + { + // is GET method + eRet = cpp2uno_call( + pCppI, aMemberDescr.get(), + ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, + 0, 0, // no params + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + else + { + // is SET method + typelib_MethodParameter aParam; + aParam.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; + 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: + { +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate5\n"); +#endif + // is METHOD + switch (nFunctionIndex) + { + case 1: // acquire() + pCppI->acquireProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 2: // release() +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate51\n"); +#endif + pCppI->releaseProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate52\n"); +#endif + break; + case 0: // queryInterface() opt + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() ); + if (pTD) + { + XInterface * pInterface = 0; + (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( + pCppI->getBridge()->getCppEnv(), + (void **)&pInterface, pCppI->getOid().pData, + (typelib_InterfaceTypeDescription *)pTD ); + + if (pInterface) + { + ::uno_any_construct( + reinterpret_cast< uno_Any * >( gpreg[0] ), + &pInterface, pTD, cpp_acquire ); + pInterface->release(); + TYPELIB_DANGER_RELEASE( pTD ); + *(void **)pRegisterReturn = gpreg[0]; + eRet = typelib_TypeClass_ANY; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } // else perform queryInterface() + default: + eRet = cpp2uno_call( + pCppI, aMemberDescr.get(), + ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, + ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, + ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + break; + } + default: + { +#ifdef BRDEBUG + fprintf(stderr,"cpp_mediate6\n"); +#endif + throw RuntimeException( + rtl::OUString::createFromAscii("no member description found!"), + (XInterface *)pThis ); + // is here for dummy + eRet = typelib_TypeClass_VOID; + } + } + + return eRet; + } + + //================================================================================================== + /** + * is called on incoming vtable calls + * (called by asm snippets) + */ +// static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw) +// static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** ovrflw) + static void cpp_vtable_call(void) + { + int nFunctionIndex; + int vTableOffset; + void** pCallStack; + void** ovrflw; + + sal_Int32 gpreg[4]; + double fpreg[2]; + + //memcpy( fpreg, fpregptr, 16); + + volatile long nRegReturn[2]; + + __asm__( "sw $4, %0\n\t" + "sw $5, %1\n\t" + "sw $6, %2\n\t" + "sw $7, %3\n\t" + ::"m"(nFunctionIndex), "m"(vTableOffset), "m"(pCallStack), "m"(ovrflw) ); + + memcpy( gpreg, pCallStack, 16); + +#ifdef BRDEBUG + fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %d\n",nFunctionIndex); + fprintf(stderr,"in cpp_vtable_call nVtableOffset is %d\n",vTableOffset); + fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]); +#endif + + //sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False; + + typelib_TypeClass aType = + cpp_mediate( nFunctionIndex, vTableOffset, (void**)gpreg, (void**)fpreg, ovrflw, (sal_Int64*)nRegReturn ); + + switch( aType ) + { + + // move return value into register space + // (will be loaded by machine code snippet) + + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + __asm__( "lbu $2,%0\n\t" : : + "m"(nRegReturn[0]) ); + break; + + case typelib_TypeClass_CHAR: + case typelib_TypeClass_UNSIGNED_SHORT: + __asm__( "lhu $2,%0\n\t" : : + "m"(nRegReturn[0]) ); + break; + + case typelib_TypeClass_SHORT: + __asm__( "lh $2,%0\n\t" : : + "m"(nRegReturn[0]) ); + break; + + + case typelib_TypeClass_FLOAT: + __asm__( "lwc1 $f0,%0\n\t" : : + "m" (*((float*)nRegReturn)) ); + break; + + case typelib_TypeClass_DOUBLE: + { register double dret asm("$f0"); + dret = (*((double*)nRegReturn)); } + break; + + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + __asm__( "lw $3,%0\n\t" : : + "m"(nRegReturn[1]) ); // fall through + + default: + __asm__( "lw $2,%0\n\t" : : + "m"(nRegReturn[0]) ); + break; + } + } + + + int const codeSnippetSize = 56; + + unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, + bool simpleRetType) + { + +#ifdef BRDEBUG + fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex); + fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset); + fflush(stderr); +#endif + + if (! simpleRetType ) + functionIndex |= 0x80000000; + + unsigned long * p = (unsigned long *) code; + + // OSL_ASSERT( sizeof (long) == 4 ); + OSL_ASSERT((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake + + /* generate this code */ + /* + #save regs into argument space required by mips abi + c: afa40000 sw a0,0(sp) + 10: afa50004 sw a1,4(sp) + 14: afa60008 sw a2,8(sp) + 18: afa7000c sw a3,12(sp) + #a0=index + 1c: 3c040000 lui a0,0x0 + 20: 34840000 ori a0,a0,0x0 + #a1=offset + 24: 3c050000 lui a1,0x0 + 28: 34a50000 ori a1,a1,0x0 + #a2=gpregptr + 2c: 27a60000 addiu a2,sp,0 + #a3=ovrflw + 30: 27a70010 addiu a3,sp,16 + #load cpp_vtable_call addr + 34: 3c190000 lui t9,0x0 + 38: 37390000 ori t9,t9,0 + #jmp to the function,note: we don't use jalr, that will destroy $ra + #but be sure to use t9! gp calculation depends on it + 3c: 03200008 jr t9 + 40: 00000000 nop + + be careful, we use the argument space reserved by the caller to + write down regs. This can avoid the need to make use of arbitary far away + stack space or to allocate a function frame for this code snippet itself. + Since only functions with variable arguments will overwrite the space, + cpp_vtable_call should be safe. + ??? gcc seems change this behavior! cpp_vtable_call overwrite the space! + */ + + * p++ = 0xafa40000; + * p++ = 0xafa50004; + * p++ = 0xafa60008; + * p++ = 0xafa7000c; + * p++ = 0x3c040000 | ((functionIndex>>16) & 0x0000ffff); + * p++ = 0x34840000 | (functionIndex & 0x0000ffff); + * p++ = 0x3c050000 | ((vtableOffset>>16) & 0x0000ffff); + * p++ = 0x34a50000 | (vtableOffset & 0x0000ffff); + * p++ = 0x27a60000; + * p++ = 0x27a70010; + * p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff); + * p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF); + * p++ = 0x03200008; + * p++ = 0x00000000; + return (code + codeSnippetSize); + + } + + +} + + +#define MIN_LINE_SIZE 32 + +void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * /*bptr*/, unsigned char const * /*eptr*/) +{ + sysmips(FLUSH_CACHE,0,0,0); +} + +struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; + +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) +{ + return static_cast< Slot * >(block) + 2; +} + + +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( + sal_Int32 slotCount) +{ + return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; +} + +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::initializeBlock( + void * block, sal_Int32 slotCount) +{ + Slot * slots = mapBlockToVtable(block); + slots[-2].fn = 0; //null + slots[-1].fn = 0; //destructor + return slots + slotCount; +} + +unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( + Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff, + typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, + sal_Int32 functionCount, sal_Int32 vtableOffset) +{ + (*slots) -= functionCount; + Slot * s = *slots; +#ifdef BRDEBUG + fprintf(stderr, "in addLocalFunctions functionOffset is %d\n",functionOffset); + fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n",vtableOffset); + fprintf(stderr, "nMembers=%d\n",type->nMembers); + fflush(stderr); +#endif + + for (sal_Int32 i = 0; i < type->nMembers; ++i) { + typelib_TypeDescription * member = 0; + TYPELIB_DANGER_GET(&member, type->ppMembers[i]); + OSL_ASSERT(member != 0); + switch (member->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + // Getter: + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( + code, functionOffset++, vtableOffset, + bridges::cpp_uno::shared::isSimpleType( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member)->pAttributeTypeRef)); + + // Setter: + if (!reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member)->bReadOnly) + { + (s++)->fn = code + writetoexecdiff; + code = codeSnippet(code, functionOffset++, vtableOffset, true); + } + break; + + case typelib_TypeClass_INTERFACE_METHOD: + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( + code, functionOffset++, vtableOffset, + bridges::cpp_uno::shared::isSimpleType( + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member)->pReturnTypeRef)); + break; + + default: + OSL_ASSERT(false); + break; + } + TYPELIB_DANGER_RELEASE(member); + } + return code; +} + diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx new file mode 100644 index 000000000000..88dd91e4e47a --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx @@ -0,0 +1,328 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: except.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <cxxabi.h> +#include <hash_map> + +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +#include <com/sun/star/uno/genfunc.hxx> +#include <typelib/typedescription.hxx> +#include <uno/any2.h> + +#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 defined BRIDGES_DEBUG + 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 defined BRIDGES_DEBUG + 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_LAZY ) ) +{ +} +//__________________________________________________________________________________________________ +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 iRttiFind( m_rttis.find( unoName ) ); + if (iRttiFind == 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( m_hApp, 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 defined BRIDGES_DEBUG + 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 = iRttiFind->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 defined BRIDGES_DEBUG + 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 defined _DEBUG + 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 defined BRIDGES_DEBUG + 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 defined _DEBUG + 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 ); + } +} + +} + diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/makefile.mk b/bridges/source/cpp_uno/gcc3_linux_mips/makefile.mk new file mode 100644 index 000000000000..73bc2768869b --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_mips/makefile.mk @@ -0,0 +1,85 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/..$/.. + +PRJNAME=bridges +TARGET=gcc3_uno +LIBTARGET=no +ENABLE_EXCEPTIONS=TRUE +NO_BSYMBOLIC=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +.IF "$(COM)$(OS)$(CPU)" == "GCCLINUXM" + +.IF "$(cppu_no_leak)" == "" +CFLAGS += -DLEAK_STATIC_DATA +.ENDIF + +# In case someone enabled the non-standard -fomit-frame-pointer which does not +# work with the .cxx sources in this directory: +CFLAGSCXX += -fno-omit-frame-pointer + +CFLAGSNOOPT=-O0 + +NOOPTFILES = \ + $(SLO)$/uno2cpp.obj \ + $(SLO)$/cpp2uno.obj + +SLOFILES= \ + $(SLO)$/except.obj \ + $(SLO)$/cpp2uno.obj \ + $(SLO)$/uno2cpp.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 + diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx b/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx new file mode 100644 index 000000000000..64224956fa40 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: share.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "uno/mapping.h" + +#include <typeinfo> +#include <exception> +#include <cstddef> + +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 ); +} diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx new file mode 100644 index 000000000000..19026bbdd01c --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx @@ -0,0 +1,600 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: uno2cpp.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <malloc.h> + +#include <com/sun/star/uno/genfunc.hxx> +#include <uno/data.h> + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/types.hxx" +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "share.hxx" + +//#define BRDEBUG +#ifdef BRDEBUG +#include <stdio.h> +#endif + + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +namespace +{ + + + //================================================================================================== + static void callVirtualMethod( + void * pAdjustedThisPtr, + sal_Int32 nVtableIndex, + void * pRegisterReturn, + typelib_TypeClass eReturnType, + char * pPT, + sal_Int32 * pStackLongs, + sal_Int32 /*nStackLongs*/) + { + + // parameter list is mixed list of * and values + // reference parameters are pointers + + unsigned long * mfunc; // actual function to be invoked + void (*ptr)(); + int gpr[4]; // storage for gpregisters, map to a0-a3 + int off; // offset used to find function + int nw; // number of words mapped + long *p; // pointer to parameter overflow area + int c; // character of parameter type being decoded + int iret, iret2; // temporary function return values + + // never called + if (! pAdjustedThisPtr ) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something + +#ifdef BRDEBUG + fprintf(stderr,"in CallVirtualMethod\n"); +#endif + + // Because of the MIPS O32 calling conventions we could be passing + // parameters in both register types and on the stack. To create the + // stack parameter area we need we now simply allocate local + // variable storage param[] that is at least the size of the parameter stack + // (more than enough space) which we can overwrite the parameters into. + + /* p = sp - 512; new sp will be p - 16, but we don't change sp + * at this time to avoid breaking ABI--not sure whether changing sp will break + * references to local variables. For the same reason, we use abosulte value. + */ + __asm__ __volatile__ ( + "addiu $2,$29,-512\n\t" + "move %0,$2\n\t" + :"=r"(p): : "$2","$29" ); + +#ifdef BRDEBUG + if (nStackLongs * 4 > 512 ) + fprintf(stderr,"too many arguments"); +#endif + + // now begin to load the C++ function arguments into storage + nw = 0; + + // now we need to parse the entire signature string */ + // until we get the END indicator */ + + // treat complex return pointer like any other parameter // + +#ifdef BRDEBUG + fprintf(stderr,"overflow area pointer p=%p\n",p); + + /* Let's figure out what is really going on here*/ + fprintf(stderr,"callVirtualMethod paramters string is %s\n",pPT); + int k = nStackLongs; + long * q = (long *)pStackLongs; + while (k > 0) { + fprintf(stderr,"uno stack is: %x\n",(unsigned int)*q); + k--; + q++; + } +#endif + + /* parse the argument list up to the ending ) */ + while (*pPT != 'X') { + c = *pPT; + switch (c) { + case 'D': /* type is double */ + /* treat the same as long long */ + case 'H': /* type is long long */ + if (nw & 1) nw++; /* note even elements gpr[] will map to + odd registers*/ + if (nw < 4) { + gpr[nw++] = *pStackLongs; + gpr[nw++] = *(pStackLongs+1); + } else { + if (((long) p) & 4) + p++; + *p++ = *pStackLongs; + *p++ = *(pStackLongs+1); + } + pStackLongs += 2; + break; + + case 'S': + if (nw < 4) { + gpr[nw++] = *((unsigned short*)pStackLongs); + } else { + *p++ = *((unsigned short *)pStackLongs); + } + pStackLongs += 1; + break; + + case 'B': + if (nw < 4) { + gpr[nw++] = *((char *)pStackLongs); + } else { + *p++ = *((char *)pStackLongs); + } + pStackLongs += 1; + break; + + default: + if (nw < 4) { + gpr[nw++] = *pStackLongs; + } else { + *p++ = *pStackLongs; + } + pStackLongs += 1; + break; + } + pPT++; + } + + /* figure out the address of the function we need to invoke */ + off = nVtableIndex; + off = off * 4; // 4 bytes per slot + mfunc = *((unsigned long **)pAdjustedThisPtr); // get the address of the vtable + mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset + mfunc = *((unsigned long **)mfunc); // the function is stored at the address + ptr = (void (*)())mfunc; + +#ifdef BRDEBUG + fprintf(stderr,"calling function %p\n",mfunc); +#endif + + /* Set up the machine registers and invoke the function */ + + __asm__ __volatile__ ( + "lw $4, 0(%0)\n\t" + "lw $5, 4(%0)\n\t" + "lw $6, 8(%0)\n\t" + "lw $7, 12(%0)\n\t" + : : "r" (gpr) + : "$4", "$5", "$6", "$7" + ); + + __asm__ __volatile__ ("addiu $29,$29,-528\r\n":::"$29"); + + (*ptr)(); + + __asm__ __volatile__ ("addiu $29,$29,528\r\n":::"$29"); + + __asm__ __volatile__ ( + "sw $2,%0 \n\t" + "sw $3,%1 \n\t" + : "=m" (iret), "=m" (iret2) : ); + register float fret asm("$f0"); + register double dret asm("$f0"); + + switch( eReturnType ) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + ((long*)pRegisterReturn)[1] = iret2; // fall through + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + ((long*)pRegisterReturn)[0] = iret; + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *(unsigned short*)pRegisterReturn = (unsigned short)iret; + break; + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + *(unsigned char*)pRegisterReturn = (unsigned char)iret; + break; + case typelib_TypeClass_FLOAT: + *(float*)pRegisterReturn = fret; + break; + case typelib_TypeClass_DOUBLE: + *(double*)pRegisterReturn = dret; + break; + default: + 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 ) + { + // max space for: [complex ret ptr], values|ptr ... + char * pCppStack = + (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); + char * pCppStackStart = pCppStack; + + // need to know parameter types for callVirtualMethod so generate a signature string + char * pParamType = (char *) alloca(nParams+2); + char * pPT = pParamType; + +#ifdef BRDEBUG + fprintf(stderr,"in cpp_call\n"); +#endif + + // 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 ) + ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way + *pPT++ = 'I'; //signify that a complex return type on stack + pCppStack += sizeof(void *); + } + } + // push this + void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset; + *(void**)pCppStack = pAdjustedThisPtr; + pCppStack += sizeof( void* ); + *pPT++ = 'I'; + + // stack space + // OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); + // 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 - int, long, pointer, etc means pass 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 long int pass in proper pairs of gpr (3,4) (5,6), etc + // 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'; + pCppStack += sizeof(sal_Int32); // extra long + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *pPT++ = 'H'; + pCppStack += sizeof(sal_Int32); // extra long + break; + default: + 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 ); + } + // KBH: FIXME: is this the right way to pass these + *pPT++='I'; + } + pCppStack += sizeof(sal_Int32); // standard parameter length + } + + // terminate the signature string + *pPT++='X'; + *pPT=0; + + try + { + OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); + callVirtualMethod( + pAdjustedThisPtr, aVtableSlot.index, + pCppReturn, pReturnTypeDescr->eTypeClass, pParamType, + (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); + // 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 ); + } + } + +} + + +namespace bridges { namespace cpp_uno { namespace shared { + +//================================================================================================== +void unoInterfaceProxyDispatch( + uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, + void * pReturn, void * pArgs[], uno_Any ** ppException ) +{ + // is my surrogate + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis + = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI); + //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; + +#ifdef BRDEBUG + fprintf(stderr,"in dispatch\n"); +#endif + + switch (pMemberDescr->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + + 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, + pReturnTypeRef, + 1, &aParam, + pReturn, pArgs, ppException ); + + typelib_typedescriptionreference_release( pReturnTypeRef ); + } + + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + + 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->pBridge->getUnoEnv()->getRegisteredInterface)( + pThis->pBridge->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 ); + } + } +} +}}} + |