/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { void pushArgument( unsigned long value, unsigned long * stack, sal_Int32 * sp, unsigned long * regs, sal_Int32 * nregs) { (*nregs != 8 ? regs[(*nregs)++] : stack[(*sp)++]) = value; } void call( bridges::cpp_uno::shared::UnoInterfaceProxy * proxy, bridges::cpp_uno::shared::VtableSlot slot, typelib_TypeDescriptionReference * returnType, sal_Int32 count, typelib_MethodParameter * parameters, void * returnValue, void ** arguments, uno_Any ** exception) { typelib_TypeDescription * rtd = 0; TYPELIB_DANGER_GET(&rtd, returnType); abi_aarch64::ReturnKind retKind = abi_aarch64::getReturnKind(rtd); bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(rtd); void * ret = retConv ? alloca(rtd->nSize) : returnValue; unsigned long ** thisPtr = reinterpret_cast(proxy->getCppI()) + slot.offset; unsigned long * stack = static_cast( alloca(count * sizeof (unsigned long))); sal_Int32 sp = 0; unsigned long gpr[8]; sal_Int32 ngpr = 0; unsigned long fpr[8]; sal_Int32 nfpr = 0; gpr[ngpr++] = reinterpret_cast(thisPtr); void ** cppArgs = static_cast(alloca(count * sizeof (void *))); typelib_TypeDescription ** ptds = static_cast( alloca(count * sizeof (typelib_TypeDescription *))); for (sal_Int32 i = 0; i != count; ++i) { if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef)) { cppArgs[i] = 0; switch (parameters[i].pTypeRef->eTypeClass) { case typelib_TypeClass_BOOLEAN: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_BYTE: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_SHORT: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_UNSIGNED_SHORT: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_LONG: case typelib_TypeClass_ENUM: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_UNSIGNED_LONG: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_HYPER: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_UNSIGNED_HYPER: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; case typelib_TypeClass_FLOAT: pushArgument( *static_cast(arguments[i]), stack, &sp, fpr, &nfpr); break; case typelib_TypeClass_DOUBLE: pushArgument( *static_cast(arguments[i]), stack, &sp, fpr, &nfpr); break; case typelib_TypeClass_CHAR: pushArgument( *static_cast(arguments[i]), stack, &sp, gpr, &ngpr); break; default: assert(false); } } else { typelib_TypeDescription * ptd = 0; TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef); if (!parameters[i].bIn) { cppArgs[i] = alloca(ptd->nSize); uno_constructData(cppArgs[i], ptd); ptds[i] = ptd; pushArgument( reinterpret_cast(cppArgs[i]), stack, &sp, gpr, &ngpr); } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) { cppArgs[i] = alloca(ptd->nSize); uno_copyAndConvertData( cppArgs[i], arguments[i], ptd, proxy->getBridge()->getUno2Cpp()); ptds[i] = ptd; pushArgument( reinterpret_cast(cppArgs[i]), stack, &sp, gpr, &ngpr); } else { cppArgs[i] = 0; pushArgument( reinterpret_cast(arguments[i]), stack, &sp, gpr, &ngpr); TYPELIB_DANGER_RELEASE(ptd); } } } try { try { callVirtualFunction( (*thisPtr)[slot.index], gpr, fpr, stack, sp, ret); } catch (css::uno::Exception &) { throw; } catch (std::exception & e) { throw css::uno::RuntimeException( "C++ code threw " + OStringToOUString(typeid(e).name(), RTL_TEXTENCODING_UTF8) + ": " + OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8)); } catch (...) { throw css::uno::RuntimeException( "C++ code threw unknown exception"); } } catch (css::uno::Exception &) { abi_aarch64::mapException( reinterpret_cast( __cxxabiv1::__cxa_get_globals())->caughtExceptions, *exception, proxy->getBridge()->getCpp2Uno()); for (sal_Int32 i = 0; i != count; ++i) { if (cppArgs[i] != 0) { uno_destructData( cppArgs[i], ptds[i], reinterpret_cast(css::uno::cpp_release)); TYPELIB_DANGER_RELEASE(ptds[i]); } } TYPELIB_DANGER_RELEASE(rtd); return; } *exception = 0; for (sal_Int32 i = 0; i != count; ++i) { if (cppArgs[i] != 0) { if (parameters[i].bOut) { if (parameters[i].bIn) { uno_destructData(arguments[i], ptds[i], 0); } uno_copyAndConvertData( arguments[i], cppArgs[i], ptds[i], proxy->getBridge()->getCpp2Uno()); } uno_destructData( cppArgs[i], ptds[i], reinterpret_cast(css::uno::cpp_release)); TYPELIB_DANGER_RELEASE(ptds[i]); } } switch (retKind) { case abi_aarch64::RETURN_KIND_REG: switch (rtd->eTypeClass) { case typelib_TypeClass_VOID: break; 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_CHAR: case typelib_TypeClass_ENUM: case typelib_TypeClass_STRUCT: std::memcpy(ret, gpr, rtd->nSize); break; case typelib_TypeClass_FLOAT: case typelib_TypeClass_DOUBLE: std::memcpy(ret, fpr, rtd->nSize); break; default: assert(false); } break; case abi_aarch64::RETURN_KIND_HFA_FLOAT: switch (rtd->nSize) { case 16: std::memcpy(static_cast(ret) + 12, fpr + 3, 4); // fall through case 12: std::memcpy(static_cast(ret) + 8, fpr + 2, 4); // fall through case 8: std::memcpy(static_cast(ret) + 4, fpr + 1, 4); // fall through case 4: std::memcpy(ret, fpr, 4); break; default: assert(false); } break; case abi_aarch64::RETURN_KIND_HFA_DOUBLE: std::memcpy(ret, fpr, rtd->nSize); break; case abi_aarch64::RETURN_KIND_INDIRECT: break; } if (retConv) { uno_copyAndConvertData( returnValue, ret, rtd, proxy->getBridge()->getCpp2Uno()); uno_destructData( ret, rtd, reinterpret_cast(css::uno::cpp_release)); } TYPELIB_DANGER_RELEASE(rtd); } } namespace bridges { namespace cpp_uno { namespace shared { void unoInterfaceProxyDispatch( uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr, void * pReturn, void ** pArgs, uno_Any ** ppException) { UnoInterfaceProxy * proxy = static_cast(pUnoI); switch (pMemberDescr->eTypeClass) { case typelib_TypeClass_INTERFACE_ATTRIBUTE: { typelib_InterfaceAttributeTypeDescription const * atd = reinterpret_cast< typelib_InterfaceAttributeTypeDescription const *>( pMemberDescr); VtableSlot slot(getVtableSlot(atd)); if (pReturn != 0) { // getter call( proxy, slot, atd->pAttributeTypeRef, 0, 0, pReturn, pArgs, ppException); } else { // setter typelib_MethodParameter param = { 0, atd->pAttributeTypeRef, true, false }; typelib_TypeDescriptionReference * rtd = 0; typelib_typedescriptionreference_new( &rtd, typelib_TypeClass_VOID, OUString("void").pData); slot.index += 1; call(proxy, slot, rtd, 1, ¶m, pReturn, pArgs, ppException); typelib_typedescriptionreference_release(rtd); } break; } case typelib_TypeClass_INTERFACE_METHOD: { typelib_InterfaceMethodTypeDescription const * mtd = reinterpret_cast< typelib_InterfaceMethodTypeDescription const *>( pMemberDescr); VtableSlot slot(getVtableSlot(mtd)); switch (slot.index) { case 1: pUnoI->acquire(pUnoI); *ppException = 0; break; case 2: pUnoI->release(pUnoI); *ppException = 0; break; case 0: { typelib_TypeDescription * td = 0; TYPELIB_DANGER_GET( &td, (reinterpret_cast(pArgs[0]) ->getTypeLibType())); if (td != 0) { uno_Interface * ifc = 0; proxy->pBridge->getUnoEnv()->getRegisteredInterface( proxy->pBridge->getUnoEnv(), reinterpret_cast(&ifc), proxy->oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription *>(td)); if (ifc != 0) { uno_any_construct( reinterpret_cast(pReturn), &ifc, td, 0); ifc->release(ifc); TYPELIB_DANGER_RELEASE(td); *ppException = 0; break; } TYPELIB_DANGER_RELEASE(td); } } // fall through default: call( proxy, slot, mtd->pReturnTypeRef, mtd->nParams, mtd->pParams, pReturn, pArgs, ppException); break; } break; } default: assert(false); } } } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */