| /************************************************************** |
| * |
| * 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 <cstddef> |
| #include <cstdlib> |
| #include <cstring> |
| |
| #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); |
| } |