/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_bridges.hxx" #include "sal/config.h" #include #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 "com/sun/star/uno/genfunc.hxx" #include "osl/diagnose.h" #include "sal/alloca.h" #include "sal/types.h" #include "typelib/typeclass.h" #include "typelib/typedescription.h" #include "typelib/typedescription.hxx" #include "uno/any2.h" #include "uno/data.h" #include "exceptions.hxx" #include "flushcode.hxx" #include "fp.hxx" #include "isdirectreturntype.hxx" #include "vtableslotcall.hxx" namespace { namespace css = com::sun::star; void loadFpRegsFromStruct(typelib_TypeDescription * type, void * data) { for (typelib_CompoundTypeDescription * t = reinterpret_cast< typelib_CompoundTypeDescription * >(type); t != NULL; t = t->pBaseTypeDescription) { for (sal_Int32 i = 0; i < t->nMembers; ++i) { switch (t->ppTypeRefs[i]->eTypeClass) { case typelib_TypeClass_FLOAT: switch (t->pMemberOffsets[i]) { case 0: fp_loadf0(reinterpret_cast< float * >(data)); break; case 4: fp_loadf1(reinterpret_cast< float * >(data) + 1); break; case 8: fp_loadf2(reinterpret_cast< float * >(data) + 2); break; case 12: fp_loadf3(reinterpret_cast< float * >(data) + 3); break; case 16: fp_loadf4(reinterpret_cast< float * >(data) + 4); break; case 20: fp_loadf5(reinterpret_cast< float * >(data) + 5); break; case 24: fp_loadf6(reinterpret_cast< float * >(data) + 6); break; case 28: fp_loadf7(reinterpret_cast< float * >(data) + 7); break; default: OSL_ASSERT(false); break; } break; case typelib_TypeClass_DOUBLE: switch (t->pMemberOffsets[i]) { case 0: fp_loadd0(reinterpret_cast< double * >(data)); break; case 8: fp_loadd2(reinterpret_cast< double * >(data) + 1); break; case 16: fp_loadd4(reinterpret_cast< double * >(data) + 2); break; case 24: fp_loadd6(reinterpret_cast< double * >(data) + 3); break; default: OSL_ASSERT(false); break; } break; case typelib_TypeClass_STRUCT: { typelib_TypeDescription * td = NULL; TYPELIB_DANGER_GET(&td, t->ppTypeRefs[i]); loadFpRegsFromStruct(td, data); TYPELIB_DANGER_RELEASE(td); break; } } } } } void call( bridges::cpp_uno::shared::CppInterfaceProxy * proxy, css::uno::TypeDescription const & description, bool directReturn, typelib_TypeDescriptionReference * returnType, sal_Int32 count, typelib_MethodParameter * parameters, unsigned long * callStack) { typelib_TypeDescription * rtd = NULL; if (returnType != NULL) { TYPELIB_DANGER_GET(&rtd, returnType); } bool retconv = rtd != NULL && bridges::cpp_uno::shared::relatesToInterfaceType(rtd); OSL_ASSERT(!(directReturn && retconv)); void * retin; void * retout; char retbuf[32]; if (directReturn) { retin = returnType == NULL ? NULL : retbuf; } else { retout = reinterpret_cast< void * >(callStack[0]); retin = retconv ? alloca(rtd->nSize) : retout; } void ** args = static_cast< void ** >(alloca(count * sizeof (void *))); void ** cppArgs = static_cast< void ** >(alloca(count * sizeof (void *))); typelib_TypeDescription ** argtds = static_cast< typelib_TypeDescription ** >( alloca(count * sizeof (typelib_TypeDescription *))); union fp { float f; double d; }; fp copies[15]; sal_Int32 stackPos = directReturn ? 1 : 2; // skip return ptr and this ptr for (sal_Int32 i = 0; i < count; ++i) { typelib_TypeDescription * ptd = NULL; TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef); if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(ptd)) { switch (ptd->eTypeClass) { case typelib_TypeClass_FLOAT: if (stackPos <= 15) { switch (stackPos) { case 1: fp_storef3(&copies[0].f); break; case 2: fp_storef5(&copies[1].f); break; case 3: fp_storef7(&copies[2].f); break; case 4: fp_storef9(&copies[3].f); break; case 5: fp_storef11(&copies[4].f); break; case 6: fp_storef13(&copies[5].f); break; case 7: fp_storef15(&copies[6].f); break; case 8: fp_storef17(&copies[7].f); break; case 9: fp_storef19(&copies[8].f); break; case 10: fp_storef21(&copies[9].f); break; case 11: fp_storef23(&copies[10].f); break; case 12: fp_storef25(&copies[11].f); break; case 13: fp_storef27(&copies[12].f); break; case 14: fp_storef29(&copies[13].f); break; case 15: fp_storef31(&copies[14].f); break; default: OSL_ASSERT(false); break; } args[i] = &copies[stackPos - 1].f; } else { args[i] = reinterpret_cast< char * >(callStack + stackPos) + (sizeof (unsigned long) - sizeof (float)); } break; case typelib_TypeClass_DOUBLE: if (stackPos <= 15) { switch (stackPos) { case 1: fp_stored2(&copies[0].d); break; case 2: fp_stored4(&copies[1].d); break; case 3: fp_stored6(&copies[2].d); break; case 4: fp_stored8(&copies[3].d); break; case 5: fp_stored10(&copies[4].d); break; case 6: fp_stored12(&copies[5].d); break; case 7: fp_stored14(&copies[6].d); break; case 8: fp_stored16(&copies[7].d); break; case 9: fp_stored18(&copies[8].d); break; case 10: fp_stored20(&copies[9].d); break; case 11: fp_stored22(&copies[10].d); break; case 12: fp_stored24(&copies[11].d); break; case 13: fp_stored26(&copies[12].d); break; case 14: fp_stored28(&copies[13].d); break; case 15: fp_stored30(&copies[14].d); break; default: OSL_ASSERT(false); break; } args[i] = &copies[stackPos - 1].d; } else { args[i] = reinterpret_cast< char * >(callStack + stackPos) + (sizeof (unsigned long) - sizeof (double)); } break; default: OSL_ASSERT(ptd->nSize <= 8); args[i] = reinterpret_cast< char * >(callStack + stackPos) + (sizeof (unsigned long) - ptd->nSize); break; } argtds[i] = NULL; TYPELIB_DANGER_RELEASE(ptd); } else { cppArgs[i] = reinterpret_cast< void * >(callStack[stackPos]); if (!parameters[i].bIn) { args[i] = alloca(ptd->nSize); argtds[i] = ptd; } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) { args[i] = alloca(ptd->nSize); uno_copyAndConvertData( args[i], reinterpret_cast< void * >(callStack[stackPos]), ptd, proxy->getBridge()->getCpp2Uno()); argtds[i] = ptd; } else { args[i] = reinterpret_cast< void * >(callStack[stackPos]); argtds[i] = NULL; TYPELIB_DANGER_RELEASE(ptd); } } ++stackPos; } uno_Any exc; uno_Any * pexc = &exc; proxy->getUnoI()->pDispatcher( proxy->getUnoI(), description.get(), retin, args, &pexc); if (pexc != NULL) { for (sal_Int32 i = 0; i < count; ++i) { if (argtds[i] != NULL) { if (parameters[i].bIn) { uno_destructData(args[i], argtds[i], NULL); } TYPELIB_DANGER_RELEASE(argtds[i]); } } if (rtd != NULL) { TYPELIB_DANGER_RELEASE(rtd); } bridges::cpp_uno::cc5_solaris_sparc64::raiseException( &exc, proxy->getBridge()->getUno2Cpp()); std::abort(); // just in case } for (sal_Int32 i = 0; i < count; ++i) { if (argtds[i] != NULL) { if (parameters[i].bOut) { uno_destructData( cppArgs[i], argtds[i], reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release)); uno_copyAndConvertData( cppArgs[i], args[i], argtds[i], proxy->getBridge()->getUno2Cpp()); } uno_destructData(args[i], argtds[i], NULL); TYPELIB_DANGER_RELEASE(argtds[i]); } } if (directReturn) { if (rtd != NULL) { switch (rtd->eTypeClass) { case typelib_TypeClass_VOID: break; case typelib_TypeClass_BOOLEAN: callStack[0] = *reinterpret_cast< sal_Bool * >(retbuf); break; case typelib_TypeClass_BYTE: callStack[0] = *reinterpret_cast< sal_Int8 * >(retbuf); break; case typelib_TypeClass_SHORT: callStack[0] = *reinterpret_cast< sal_Int16 * >(retbuf); break; case typelib_TypeClass_UNSIGNED_SHORT: callStack[0] = *reinterpret_cast< sal_uInt16 * >(retbuf); break; case typelib_TypeClass_LONG: case typelib_TypeClass_ENUM: callStack[0] = *reinterpret_cast< sal_Int32 * >(retbuf); break; case typelib_TypeClass_UNSIGNED_LONG: callStack[0] = *reinterpret_cast< sal_uInt32 * >(retbuf); break; case typelib_TypeClass_HYPER: callStack[0] = *reinterpret_cast< sal_Int64 * >(retbuf); break; case typelib_TypeClass_UNSIGNED_HYPER: callStack[0] = *reinterpret_cast< sal_uInt64 * >(retbuf); break; case typelib_TypeClass_FLOAT: fp_loadf0(reinterpret_cast< float * >(retbuf)); break; case typelib_TypeClass_DOUBLE: fp_loadd0(reinterpret_cast< double * >(retbuf)); break; case typelib_TypeClass_CHAR: callStack[0] = *reinterpret_cast< sal_Unicode * >(retbuf); break; case typelib_TypeClass_STRING: case typelib_TypeClass_TYPE: case typelib_TypeClass_SEQUENCE: case typelib_TypeClass_INTERFACE: callStack[0] = reinterpret_cast< unsigned long >( *reinterpret_cast< void ** >(retbuf)); break; case typelib_TypeClass_STRUCT: loadFpRegsFromStruct(rtd, retbuf); // fall through case typelib_TypeClass_ANY: std::memcpy(callStack, retbuf, rtd->nSize); break; default: OSL_ASSERT(false); break; } } } else if (retconv) { uno_copyAndConvertData( retout, retin, rtd, proxy->getBridge()->getUno2Cpp()); uno_destructData(retin, rtd, NULL); } if (rtd != NULL) { TYPELIB_DANGER_RELEASE(rtd); } } extern "C" void vtableCall( sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long * callStack) { bool direct = static_cast< sal_uInt32 >((functionIndex) & 0x80000000) == 0; functionIndex = static_cast< sal_uInt32 >(functionIndex) & 0x7FFFFFFF; bridges::cpp_uno::shared::CppInterfaceProxy * proxy = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( reinterpret_cast< char * >(callStack[direct ? 0 : 1]) - vtableOffset); typelib_InterfaceTypeDescription * type = proxy->getTypeDescr(); OSL_ASSERT(functionIndex < type->nMapFunctionIndexToMemberIndex); sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex]; css::uno::TypeDescription desc(type->ppAllMembers[pos]); switch (desc.get()->eTypeClass) { case typelib_TypeClass_INTERFACE_ATTRIBUTE: if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) { // Getter: call( proxy, desc, direct, reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( desc.get())->pAttributeTypeRef, 0, NULL, callStack); } else { // Setter: typelib_MethodParameter param = { NULL, reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( desc.get())->pAttributeTypeRef, true, false }; call(proxy, desc, true, NULL, 1, ¶m, callStack); } break; case typelib_TypeClass_INTERFACE_METHOD: switch (functionIndex) { case 1: proxy->acquireProxy(); break; case 2: proxy->releaseProxy(); break; case 0: { typelib_TypeDescription * td = NULL; TYPELIB_DANGER_GET( &td, reinterpret_cast< css::uno::Type * >( callStack[2])->getTypeLibType()); if (td != NULL) { css::uno::XInterface * ifc = NULL; proxy->getBridge()->getCppEnv()->getRegisteredInterface( proxy->getBridge()->getCppEnv(), reinterpret_cast< void ** >(&ifc), proxy->getOid().pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( td)); if (ifc != NULL) { uno_any_construct( reinterpret_cast< uno_Any * >(callStack[0]), &ifc, td, reinterpret_cast< uno_AcquireFunc >( css::uno::cpp_acquire)); ifc->release(); TYPELIB_DANGER_RELEASE(td); break; } TYPELIB_DANGER_RELEASE(td); } } // fall through default: call( proxy, desc, direct, reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( desc.get())->pReturnTypeRef, reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( desc.get())->nParams, reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( desc.get())->pParams, callStack); } break; default: OSL_ASSERT(false); break; } } int const codeSnippetSize = 10 * 4; unsigned char * generateCodeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, bool directReturn) { sal_uInt32 index = functionIndex; if (!directReturn) { index |= 0x80000000; } unsigned int * p = reinterpret_cast< unsigned int * >(code); OSL_ASSERT(sizeof (unsigned int) == 4); // 0*4: save %sp, -176, %sp ! minimal stack frame: *p++ = 0x9DE3BF50; // 1*4: rd %pc, %l0: *p++ = 0xA1414000; // 2*4: ldx %l0, (8-1)*4, %l0: *p++ = 0xE05C201C; // 3*4: sethi %hi(index), %o0: *p++ = 0x11000000 | (index >> 10); // 4*4: or %o0, %lo(index), %o0: *p++ = 0x90122000 | (index & 0x3FF); // 5*4: sethi %hi(vtableOffset), %o1: *p++ = 0x13000000 | (vtableOffset >> 10); // 6*4: jmpl %l0, %g0, %g0: *p++ = 0x81C40000; // 7*4: or %o1, %lo(vtableOffset), %o1: *p++ = 0x92126000 | (vtableOffset & 0x3FF); // 8*4: .xword privateSnippetExecutor: *reinterpret_cast< unsigned long * >(p) = reinterpret_cast< unsigned long >(vtableSlotCall); return code + codeSnippetSize; } } 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) + 1; } sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( sal_Int32 slotCount) { return (slotCount + 3) * 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) + 2; slots[-3].fn = NULL; // RTTI slots[-2].fn = NULL; // null slots[-1].fn = NULL; // destructor return slots + slotCount; } unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( Slot ** slots, unsigned char * code, typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, sal_Int32 functionCount, sal_Int32 vtableOffset) { (*slots) -= functionCount; Slot * s = *slots; 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; code = generateCodeSnippet( code, functionOffset++, vtableOffset, bridges::cpp_uno::cc5_solaris_sparc64::isDirectReturnType( reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( member)->pAttributeTypeRef)); // Setter: if (!reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( member)->bReadOnly) { (s++)->fn = code; code = generateCodeSnippet( code, functionOffset++, vtableOffset, true); } break; case typelib_TypeClass_INTERFACE_METHOD: (s++)->fn = code; code = generateCodeSnippet( code, functionOffset++, vtableOffset, bridges::cpp_uno::cc5_solaris_sparc64::isDirectReturnType( reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( member)->pReturnTypeRef)); break; default: OSL_ASSERT(false); break; } TYPELIB_DANGER_RELEASE(member); } return code; } void bridges::cpp_uno::shared::VtableFactory::flushCode( unsigned char const * begin, unsigned char const * end) { bridges::cpp_uno::cc5_solaris_sparc64::flushCode(begin, end); }