From 1ac60e8b6acb07698eb8765718e8d093b519dc86 Mon Sep 17 00:00:00 2001 From: Sakura286 Date: Tue, 26 Jul 2022 02:18:23 +0000 Subject: [PATCH] Add riscv64 support 1. Configure gbuild to compile on riscv64 2. Add UNO Bridge for riscv64 Now the welcome page could be established and files could be saved with Writer on riscv64. Test on Debian sid. Credits: - Heiher and Stephan Bergmann contributes the code of UNO bridge for MIPS64 and AArch64, which I refer to. - Bo Yu configures gbuild for riscv64. - WANG Xuerui gives lots of guiding tips. - wjh-la contributes the code of UNO- bridge for Loongarch64, which inspired me. Change-Id: Ifad3b0de8b2c9e7328627ed03396bbd45a9c71e4 --- bridges/Library_cpp_uno.mk | 9 + .../cpp_uno/gcc3_linux_riscv64/call.hxx | 35 + .../source/cpp_uno/gcc3_linux_riscv64/call.s | 72 ++ .../cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx | 723 ++++++++++++++++++ .../cpp_uno/gcc3_linux_riscv64/except.cxx | 297 +++++++ .../cpp_uno/gcc3_linux_riscv64/share.hxx | 89 +++ .../cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx | 595 ++++++++++++++ configure.ac | 10 +- jvmfwk/inc/vendorbase.hxx | 2 + solenv/gbuild/platform/LINUX_RISCV64_GCC.mk | 15 + 10 files changed, 1845 insertions(+), 2 deletions(-) create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/call.s create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx create mode 100644 bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx create mode 100644 solenv/gbuild/platform/LINUX_RISCV64_GCC.mk diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk index e2de3c1678b45..27e1249f31a35 100644 --- a/bridges/Library_cpp_uno.mk +++ b/bridges/Library_cpp_uno.mk @@ -114,6 +114,15 @@ bridge_noopt_objects := cpp2uno uno2cpp bridge_exception_objects := except endif +else ifeq ($(CPUNAME),RISCV64) + +ifneq ($(filter LINUX,$(OS)),) +bridges_SELECTED_BRIDGE := gcc3_linux_riscv64 +bridge_asm_objects := call +bridge_noopt_objects := cpp2uno uno2cpp +bridge_exception_objects := except +endif + else ifeq ($(CPUNAME),POWERPC) ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),) diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx new file mode 100644 index 0000000000000..dc84d56b88aec --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include + +namespace { + + extern "C" typelib_TypeClass cpp_vtable_call( + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_uInt64 * pRegisterReturn /* space for register return */ ); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s new file mode 100644 index 0000000000000..2bddfc1dcbf4a --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s @@ -0,0 +1,72 @@ +/* + * 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 . + */ +// https://cgit.freedesktop.org/libreoffice/core/tree/bridges/source/cpp_uno/gcc3_linux_mips64/call.s + + .text + .align 2 + .global privateSnippetExecutor + .hidden privateSnippetExecutor + .type privateSnippetExecutor, %function +privateSnippetExecutor: + .cfi_startproc + addi sp,sp,-160 + .cfi_def_cfa_offset 160 + sd ra,152(sp) + .cfi_offset 1, -8 + fsd fa0,80(sp) + fsd fa1,88(sp) + fsd fa2,96(sp) + fsd fa3,104(sp) + fsd fa4,112(sp) + fsd fa5,120(sp) + fsd fa6,128(sp) + fsd fa7,136(sp) + sd a0,16(sp) + sd a1,24(sp) + sd a2,32(sp) + sd a3,40(sp) + sd a4,48(sp) + sd a5,56(sp) + sd a6,64(sp) + sd a7,72(sp) + // a0 = functionIndex + // a1 = vtableOffset + // a2 = gpreg + // a3 = fpreg + // a4 = overflw + // a5 = pRegisterReturn + add a0,t4,zero + add a1,t5,zero + addi a2,sp,16 + addi a3,sp,80 + addi a4,sp,160 + add a5,sp,zero + // jump to cpp_vtable_call + jalr ra,t6,0 + ld a0,0(sp) + ld a1,8(sp) + fld fa0,0(sp) + fld fa1,8(sp) + ld ra,152(sp) + .cfi_restore 1 + addi sp,sp,160 + .cfi_def_cfa_offset 0 + jalr zero,ra,0 + .cfi_endproc + .size privateSnippetExecutor, .-privateSnippetExecutor + .section .note.GNU-stack, "", @progbits \ No newline at end of file diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx new file mode 100644 index 0000000000000..4ee41ab486a80 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx @@ -0,0 +1,723 @@ +/* -*- 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 "bridge.hxx" +#include "cppinterfaceproxy.hxx" +#include "types.hxx" +#include "vtablefactory.hxx" +#include "call.hxx" +#include "share.hxx" + +#include +#include + +using namespace com::sun::star::uno; + +//#define BRDEBUG + +#ifdef BRDEBUG +#include +#include +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; +#endif + +namespace CPPU_CURRENT_NAMESPACE +{ + bool is_complex_struct(const typelib_TypeDescription * type) + { + const typelib_CompoundTypeDescription * p + = reinterpret_cast< const typelib_CompoundTypeDescription * >(type); + for (sal_Int32 i = 0; i < p->nMembers; ++i) + { + if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT || + p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION) + { + typelib_TypeDescription * t = 0; + TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]); + bool b = is_complex_struct(t); + TYPELIB_DANGER_RELEASE(t); + if (b) { + return true; + } + } + else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass)) + return true; + } + if (p->pBaseTypeDescription != 0) + return is_complex_struct(&p->pBaseTypeDescription->aBase); + return false; + } + + bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) + { + if (bridges::cpp_uno::shared::isSimpleType(pTypeRef)) + return false; + else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || + pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION) + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + + //A Composite Type not larger than 16 bytes is returned in up to two GPRs + bool bRet = pTypeDescr->nSize > 16 || is_complex_struct(pTypeDescr); + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + return bRet; + } + return true; + } +} + +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_uInt64 * 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 + With word might go in With integer argument register or the With + floating-point one. For these ABIs, we only need to remember the number + of words passed so far. We are interested only in n64 ABI,so it is the + case. + */ + unsigned int nREG = 0; + +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:begin\n"); +#endif + // 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 (CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) ) + { + pCppReturn = gpreg[nREG]; // complex return via ptr (pCppReturn) + nREG++; + + pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) + ? alloca( pReturnTypeDescr->nSize ) + : pCppReturn); // direct way +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:complexreturn\n"); +#endif + } + else + { + pUnoReturn = pRegisterReturn; // direct way for simple types +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:simplereturn\n"); +#endif + } + } + + // pop this + nREG++; + + // stack space + static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!"); + // parameters + void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); + void ** pCppArgs = pUnoArgs + nParams; + // indices of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams)); + // type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); + + sal_Int32 nTempIndices = 0; + +#ifdef BRDEBUG + fprintf(stdout, "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 + { +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:Param %u, type %u\n", nPos, pParamTypeDescr->eTypeClass); +#endif + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + if (nREG < MAX_FP_REGS) { +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:fpr=%p\n", fpreg[nREG]); +#endif + pCppArgs[nPos] = &(fpreg[nREG]); + pUnoArgs[nPos] = &(fpreg[nREG]); + } else { +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:fpr=%p\n", ovrflw[nREG - MAX_FP_REGS]); +#endif + pCppArgs[nPos] = &(ovrflw[nREG - MAX_FP_REGS]); + pUnoArgs[nPos] = &(ovrflw[nREG - MAX_FP_REGS]); + } + nREG++; + break; + + + default: + if (nREG < MAX_GP_REGS) { +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:gpr=%p\n", gpreg[nREG]); +#endif + pCppArgs[nPos] = &(gpreg[nREG]); + pUnoArgs[nPos] = &(gpreg[nREG]); + } else { +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:gpr=%p\n", ovrflw[nREG - MAX_GP_REGS]); +#endif + pCppArgs[nPos] = &(ovrflw[nREG - MAX_GP_REGS]); + pUnoArgs[nPos] = &(ovrflw[nREG - MAX_GP_REGS]); + } + nREG++; + break; + + } + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + else // ptr to complex value | ref + { +#ifdef BRDEBUG + fprintf(stdout,"cpp2uno_call:ptr|ref\n"); +#endif + void *pCppStack; + if (nREG < MAX_GP_REGS) { + pCppArgs[nPos] = pCppStack = gpreg[nREG]; + } else { + pCppArgs[nPos] = pCppStack = ovrflw[nREG - MAX_GP_REGS]; + } + nREG++; +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:pCppStack=%p\n", pCppStack); +#endif + + if (! rParam.bIn) // is pure out + { + // uno out is unconstructed mem! + pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); + pTempIndices[nTempIndices] = nPos; + // will be released at reconversion + ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr; + } + // is in/inout + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) + { + uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pCppStack, pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + pTempIndices[nTempIndices] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr; +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n", + pCppStack, pParamTypeDescr->nSize, nPos, pUnoArgs[nPos]); +#endif + } + else // direct way + { + pUnoArgs[nPos] = pCppStack; +#ifdef BRDEBUG + fprintf(stdout, "cpp2uno_call:direct,pUnoArgs[%d]=%p\n", nPos, pUnoArgs[nPos]); +#endif + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + } + } +#ifdef BRDEBUG + fprintf(stdout, "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(stdout, "cpp2uno_call2,after dispatch\n"); +#endif + + // in case an exception occurred... + if (pUnoExc) + { + fflush(stdout); + // destruct temporary in/inout params + for ( ; nTempIndices--; ) + { + sal_Int32 nIndex = pTempIndices[nTempIndices]; + + if (pParams[nIndex].bIn) // is in/inout => was constructed + uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] ); + } + 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 occurred... + { + // temporary params + for ( ; nTempIndices--; ) + { + sal_Int32 nIndex = pTempIndices[nTempIndices]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices]; + + 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; + } + } + + + /** + * is called on incoming vtable calls + * (called by asm snippets) + */ + typelib_TypeClass cpp_vtable_call( + sal_Int32 nFunctionIndex, + sal_Int32 nVtableOffset, + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_uInt64 * pRegisterReturn /* space for register return */ ) + { + static_assert( sizeof(sal_Int64)==sizeof(void *), "### unexpected!" ); + +#ifdef BRDEBUG + fprintf(stdout, "in cpp_vtable_call nFunctionIndex is %d\n", nFunctionIndex); + fprintf(stdout, "in cpp_vtable_call nVtableOffset is %d\n", nVtableOffset); + fprintf(stdout, "in cpp_vtable_call gp=%p, fp=%p, ov=%p\n", gpreg, fpreg, ovrflw); +#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(stdout, "cpp_vtable_call, 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(stdout, "cpp_vtable_call, pCppI=%p\n", pCppI); +#endif + + typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); + + if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) + { + SAL_WARN( + "bridges", + "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName) + << " vtable index " << nFunctionIndex << "/" + << pTypeDescr->nMapFunctionIndexToMemberIndex); + throw RuntimeException( + ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName) + + " vtable index " + OUString::number(nFunctionIndex) + "/" + + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)), + (XInterface *)pThis); + } + + // determine called method + sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; + assert(nMemberPos < pTypeDescr->nAllMembers); + + TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); + +#ifdef BRDEBUG + //OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) ); + //fprintf(stdout, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex ); +#endif + typelib_TypeClass eRet; + switch (aMemberDescr.get()->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call interface attribute\n"); +#endif + typelib_TypeDescriptionReference *pAttrTypeRef = + reinterpret_cast( aMemberDescr.get() )->pAttributeTypeRef; + + if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) + { + // is GET method + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, + 0, 0, // no params + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + else + { + // is SET method + typelib_MethodParameter aParam; + aParam.pTypeRef = pAttrTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + 0, // indicates void return + 1, &aParam, + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call interface method\n"); +#endif + // is METHOD + switch (nFunctionIndex) + { + case 1: // acquire() +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call method acquire\n"); +#endif + pCppI->acquireProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 2: // release() +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call method release\n"); +#endif + pCppI->releaseProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 0: // queryInterface() opt + { +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call method query interface opt\n"); +#endif + 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, + reinterpret_cast( pTD ) ); + + if (pInterface) + { + ::uno_any_construct( reinterpret_cast< uno_Any * >( gpreg[0] ), + &pInterface, pTD, cpp_acquire ); + + pInterface->release(); + TYPELIB_DANGER_RELEASE( pTD ); + + reinterpret_cast( pRegisterReturn )[0] = gpreg[0]; + eRet = typelib_TypeClass_ANY; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } // else perform queryInterface() + default: +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call method query interface\n"); +#endif + typelib_InterfaceMethodTypeDescription *pMethodTD = + reinterpret_cast( aMemberDescr.get() ); + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + pMethodTD->pReturnTypeRef, + pMethodTD->nParams, + pMethodTD->pParams, + gpreg, fpreg, ovrflw, pRegisterReturn ); + } + break; + } + default: + { +#ifdef BRDEBUG + fprintf(stdout, "cpp_vtable_call no member\n"); +#endif + throw RuntimeException( "no member description found!", (XInterface *)pThis ); + } + } + + return eRet; + } + + extern "C" void privateSnippetExecutor( ... ); + + int const codeSnippetSize = 0x6c; + + unsigned char * codeSnippet( unsigned char * code, + sal_Int32 functionIndex, sal_Int32 vtableOffset, + bool bHasHiddenParam ) + { +#ifdef BRDEBUG + fprintf(stdout,"in codeSnippet functionIndex is %d\n", functionIndex); + fprintf(stdout,"in codeSnippet vtableOffset is %d\n", vtableOffset); + fprintf(stdout,"in codeSnippet privateSnippetExecutor is %lx\n", (unsigned long)privateSnippetExecutor); + fprintf(stdout,"in codeSnippet cpp_vtable_call is %lx\n", (unsigned long)cpp_vtable_call); + + fflush(stdout); +#endif + + if ( bHasHiddenParam ) + functionIndex |= 0x80000000; + + unsigned int * p = (unsigned int *) code; + + assert((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake + + /* generate this code */ + /* + # load functionIndex to t4 + 00000eb7 lui t4,0x0 + 000eee93 ori t4,t4,0x0 + # load privateSnippetExecutor to t0 + 000002b7 lui t0,0x0 + 02429293 slli t0,t0,36 + 00000337 lui t1,0x0 + 01431313 slli t1,t1,20 + 0062e2b3 or t0,t0,t1 + 00000337 lui t1,0x0 + 00431313 slli t1,t1,4 + 0062e2b3 or t0,t0,t1 + 00000337 lui t1,0x0 + 00c35313 srli t1,t1,12 + 0062e2b3 or t0,t0,t1 + # load cpp_vtable_call to t6 + 00000fb7 lui t6,0x0 + 024f9f93 slli t6,t6,36 + 00000337 lui t1,0x0 + 01431313 slli t1,t1,20 + 006fefb3 or t6,t6,t1 + 00000337 lui t1,0x0 + 00431313 slli t1,t1,4 + 006fefb3 or t6,t6,t1 + 00000337 lui t1,0x0 + 00c35313 srli t1,t1,12 + 006fefb3 or t6,t6,t1 + # load vtableOffset to t5 + 00000f37 lui t5,0x0 + 000f6f13 ori t5,t5,0x0 + # jump to privateSnippetExecutor + 00028067 jalr zero,t0,0x0 + */ + + * p++ = 0x00000eb7 | ((functionIndex) & 0xfffff000); + * p++ = 0x000eee93 | ((functionIndex << 20 ) & 0xfff00000); + + // load privateSnippetExecutor to t0 + unsigned long functionEntry = ((unsigned long)privateSnippetExecutor); + * p++ = 0x000002b7 | ((functionEntry >> 36) & 0x000000000ffff000); + * p++ = 0x02429293; + * p++ = 0x00000337 | ((functionEntry >> 20) & 0x000000000ffff000); + * p++ = 0x01431313; + * p++ = 0x0062e2b3; + * p++ = 0x00000337 | ((functionEntry >> 4) & 0x000000000ffff000); + * p++ = 0x00431313; + * p++ = 0x0062e2b3; + * p++ = 0x00000337 | ((functionEntry << 12) & 0x000000000ffff000); + * p++ = 0x00c35313; + * p++ = 0x0062e2b3; + // load cpp_vtable_call to t6 + functionEntry = (unsigned long) cpp_vtable_call; + * p++ = 0x00000fb7 | ((functionEntry >> 36) & 0x000000000ffff000); + * p++ = 0x024f9f93; + * p++ = 0x00000337 | ((functionEntry >> 20) & 0x000000000ffff000); + * p++ = 0x01431313; + * p++ = 0x006fefb3; + * p++ = 0x00000337 | ((functionEntry >> 4) & 0x000000000ffff000); + * p++ = 0x00431313; + * p++ = 0x006fefb3; + * p++ = 0x00000337 | ((functionEntry << 12) & 0x000000000ffff000); + * p++ = 0x00c35313; + * p++ = 0x006fefb3; + // load vtableOffset to t5 + * p++ = 0x00000f37 | ((vtableOffset) & 0xfffff000); + * p++ = 0x000f6f13 | ((vtableOffset << 20 ) & 0xfff00000); + // jump to privateSnippetExecutor + * p++ = 0x00028067; + return (code + codeSnippetSize); + + } + +} + + +void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *bptr, unsigned char const *eptr) +{ + asm volatile( + "fence"::: + ); +} + +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; +} + + +std::size_t 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, sal_Int32, + typelib_InterfaceTypeDescription *) +{ + 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(stdout, "in addLocalFunctions functionOffset is %d\n", functionOffset); + fprintf(stdout, "in addLocalFunctions vtableOffset is %d\n", vtableOffset); + fprintf(stdout, "nMembers=%d\n", type->nMembers); + fflush(stdout); +#endif + + for (sal_Int32 i = 0; i < type->nMembers; ++i) { + typelib_TypeDescription * member = 0; + TYPELIB_DANGER_GET(&member, type->ppMembers[i]); + assert(member != 0); + switch (member->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + // Getter: + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( + code, functionOffset++, vtableOffset, + CPPU_CURRENT_NAMESPACE::return_in_hidden_param( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member)->pAttributeTypeRef)); + + // Setter: + if (!reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member)->bReadOnly) + { + (s++)->fn = code + writetoexecdiff; + code = codeSnippet(code, functionOffset++, vtableOffset, false); + } + break; + + case typelib_TypeClass_INTERFACE_METHOD: + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( + code, functionOffset++, vtableOffset, + CPPU_CURRENT_NAMESPACE::return_in_hidden_param( + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member)->pReturnTypeRef)); + break; + + default: + assert(false); + break; + } + TYPELIB_DANGER_RELEASE(member); + } + return code; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx new file mode 100644 index 0000000000000..e37e5d8e3a85f --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx @@ -0,0 +1,297 @@ +/* -*- 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 "share.hxx" + +using namespace ::std; +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::__cxxabiv1; + +//#define BRIDGES_DEBUG + +namespace CPPU_CURRENT_NAMESPACE +{ + +void dummy_can_throw_anything( char const * ) +{ +} + +static OUString toUNOname( char const * p ) +{ +#if defined BRIDGES_DEBUG + char const * start = p; +#endif + + // example: N3com3sun4star4lang24IllegalArgumentExceptionE + + OUStringBuffer buf( 64 ); + 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( '.' ); + } + +#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 std::unordered_map< OUString, type_info * > t_rtti_map; + + Mutex m_mutex; + t_rtti_map m_rttis; + t_rtti_map m_generatedRttis; + + void * m_hApp; + +public: + RTTI(); + ~RTTI(); + + type_info * getRTTI( typelib_CompoundTypeDescription * ); +}; + +RTTI::RTTI() + : m_hApp( dlopen( 0, RTLD_LAZY ) ) +{ +} + +RTTI::~RTTI() +{ + dlclose( m_hApp ); +} + + +type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) +{ + 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( "_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 ) ) ); + assert(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 ) ) ); + assert(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 ) +{ + fprintf( stderr, "in deleteException: pExc = %p\n",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 ); + assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!"); + if (pTD) + { + ::uno_destructData( pExc, pTD, cpp_release ); + ::typelib_typedescription_release( pTD ); + } +} + + + +//extern "C" { +// void __cxa_throw(void* ex, void* info, void (*dest)(void*)) { ::abort(); } +//} + + +void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) +{ +#if defined BRIDGES_DEBUG + OString cstr( + OUStringToOString( + OUString::unacquired( &pUnoExc->pType->pTypeName ), + RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() ); +#endif + void * pCppExc; + type_info * rtti; + + { + // construct cpp exception object + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType ); + assert(pTypeDescr); + if (! pTypeDescr) + { + throw RuntimeException( + OUString("cannot get typedescription for type ") + + OUString::unacquired( &pUnoExc->pType->pTypeName ) ); + } + + 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 rtti_data; + rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + assert(rtti && "### no rtti for throwing exception!"); + if (! rtti) + { + throw RuntimeException( + OUString("no rtti for type ") + + OUString::unacquired( &pUnoExc->pType->pTypeName ) ); + } + } + __cxa_throw( pCppExc, rtti, deleteException ); +} + +void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno) +{ + __cxa_exception * header = __cxa_get_globals()->caughtExceptions; + if (! header) + { + RuntimeException aRE( "no exception header!" ); + Type const & rType = cppu::UnoType::get(); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); + SAL_WARN("bridges", aRE.Message); + return; + } + + std::type_info *exceptionType = __cxa_current_exception_type(); + + typelib_TypeDescription * pExcTypeDescr = 0; + OUString unoName( toUNOname( exceptionType->name() ) ); +#if defined BRIDGES_DEBUG + OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() ); +#endif + typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); + if (0 == pExcTypeDescr) + { + RuntimeException aRE( OUString("exception type not found: ") + unoName ); + Type const & rType = cppu::UnoType::get(); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); + SAL_WARN("bridges", aRE.Message); + } + else + { + // construct uno exception any + uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno ); + typelib_typedescription_release( pExcTypeDescr ); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx new file mode 100644 index 0000000000000..ee2235e4fc4b6 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx @@ -0,0 +1,89 @@ +/* -*- 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 . + */ +#pragma once + +#include "uno/mapping.h" + +#include +#include +#include + +#define MAX_GP_REGS (8) +#define MAX_FP_REGS (8) + +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 *); + + void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17 + 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(); +extern "C" std::type_info *__cxa_current_exception_type() throw(); + +void raiseException( + uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ); + +void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno); + +bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx new file mode 100644 index 0000000000000..cae7507669122 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx @@ -0,0 +1,595 @@ +/* -*- 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 "bridge.hxx" +#include "types.hxx" +#include "unointerfaceproxy.hxx" +#include "vtables.hxx" + +#include "share.hxx" + +//#define BRDEBUG +#ifdef BRDEBUG +#include +#endif + +#define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \ + if ( nr < MAX_FP_REGS ) \ + pFPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); // verbatim! + +#define INSERT_INT64( pSV, nr, pGPR, pDS ) \ + if ( nr < MAX_GP_REGS ) \ + pGPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); + +#define INSERT_INT32( pSV, nr, pGPR, pDS ) \ + if ( nr < MAX_GP_REGS ) \ + pGPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); + +#define INSERT_INT16( pSV, nr, pGPR, pDS ) \ + if ( nr < MAX_GP_REGS ) \ + pGPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); + +#define INSERT_UINT16( pSV, nr, pGPR, pDS ) \ + if ( nr < MAX_GP_REGS ) \ + pGPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); + +#define INSERT_INT8( pSV, nr, pGPR, pDS ) \ + if ( nr < MAX_GP_REGS ) \ + pGPR[nr++] = *reinterpret_cast( pSV ); \ + else \ + *pDS++ = *reinterpret_cast( pSV ); + +using namespace ::com::sun::star::uno; + +namespace +{ + + bool isReturnInFPR(const typelib_TypeDescription * pTypeDescr, sal_uInt32 & nSize) + { + const typelib_CompoundTypeDescription *p = + reinterpret_cast( pTypeDescr ); + + for (sal_Int32 i = 0; i < p->nMembers; ++i) + { + typelib_TypeDescriptionReference *pTypeInStruct = p->ppTypeRefs[ i ]; + + switch (pTypeInStruct->eTypeClass) + { + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * t = 0; + TYPELIB_DANGER_GET(&t, pTypeInStruct); + bool isFPR = isReturnInFPR(t, nSize); + TYPELIB_DANGER_RELEASE(t); + if (!isFPR) + return false; + } + break; + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + if (nSize >= 16) + return false; + nSize += 8; + break; + default: + return false; + } + } + return true; + } + + void fillReturn(const typelib_TypeDescription * pTypeDescr, + sal_Int64 * gret, double * fret, void * pRegisterReturn) + { + sal_uInt32 nSize = 0; + if (isReturnInFPR(pTypeDescr, nSize)) + { + reinterpret_cast( pRegisterReturn )[0] = fret[0]; + reinterpret_cast( pRegisterReturn )[1] = fret[1]; + } + else + { + reinterpret_cast( pRegisterReturn )[0] = gret[0]; + reinterpret_cast( pRegisterReturn )[1] = gret[1]; + } + } + + static void callVirtualMethod( + void * pAdjustedThisPtr, + sal_Int32 nVtableIndex, + void * pRegisterReturn, + typelib_TypeDescriptionReference * pReturnTypeRef, + bool bSimpleReturn, + sal_uInt64 *pStack, + sal_uInt32 nStack, + sal_uInt64 *pGPR, + double *pFPR, + sal_uInt32 nREG) + { + // Should not happen, but... + static_assert(MAX_GP_REGS == MAX_FP_REGS, "must be the same size"); + if ( nREG > MAX_GP_REGS ) + nREG = MAX_GP_REGS; + + // Get pointer to method + sal_uInt64 pMethod = *((sal_uInt64 *)pAdjustedThisPtr); + pMethod += 8 * nVtableIndex; + void *mfunc = (void *) *((sal_uInt64 *)pMethod); +#ifdef BRDEBUG + fprintf(stdout, "calling function %p\n", mfunc); +#endif + + // Load parameters to stack, if necessary + sal_uInt64* pCallStack = NULL; + if ( nStack ) + { + // 16-bytes aligned + sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16; + pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes ); + std::memcpy( pCallStack, pStack, nStackBytes ); + } + + sal_Int64 gret[2]; + double fret[2]; + asm volatile ( + //".set push \n\t" + //".set riscv64 \n\t" + // Fill the general purpose registers + "ld a0, 0(%[gpr]) \n\t" + "ld a1, 8(%[gpr]) \n\t" + "ld a2, 16(%[gpr]) \n\t" + "ld a3, 24(%[gpr]) \n\t" + "ld a4, 32(%[gpr]) \n\t" + "ld a5, 40(%[gpr]) \n\t" + "ld a6, 48(%[gpr]) \n\t" + "ld a7, 56(%[gpr]) \n\t" + // Fill the floating pointer registers + "fld fa0, 0(%[fpr]) \n\t" + "fld fa1, 8(%[fpr]) \n\t" + "fld fa2, 16(%[fpr]) \n\t" + "fld fa3, 24(%[fpr]) \n\t" + "fld fa4, 32(%[fpr]) \n\t" + "fld fa5, 40(%[fpr]) \n\t" + "fld fa6, 48(%[fpr]) \n\t" + "fld fa7, 56(%[fpr]) \n\t" + // Perform the call + "jalr ra,%[mfunc],0 \n\t" + // Fill the return values + "add %[gret1], a0,zero \n\t" + "add %[gret2], a1,zero \n\t" + "fcvt.d.l ft7,zero \n\t" + "fadd.d %[fret1], fa0,ft7 \n\t" + "fadd.d %[fret2], fa1,ft7 \n\t" + //".set pop \n\t" + :[gret1]"=r"(gret[0]), [gret2]"=r"(gret[1]), + [fret1]"=f"(fret[0]), [fret2]"=f"(fret[1]) + :[gpr]"r"(pGPR), [fpr]"r"(pFPR), [mfunc]"r"(mfunc), + [stack]"m"(pCallStack) // dummy input to prevent the compiler from optimizing the alloca out + :"a0", "a1", "a2", "a3", "a4", "a5", "a6","a7", + "ra", + "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6","fa7", "memory", + "ft7" + ); + + switch (pReturnTypeRef->eTypeClass) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + *reinterpret_cast( pRegisterReturn ) = gret[0]; + break; + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + *reinterpret_cast( pRegisterReturn ) = fret[0]; + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize; + if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0) + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pReturnTypeRef ); + fillReturn(pTypeDescr, gret, fret, pRegisterReturn); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + } + default: +#ifdef BRDEBUG + fprintf(stdout,"unhandled return type %u\n", pReturnTypeRef->eTypeClass); +#endif + 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 ... + sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( ((nParams+3) * sizeof(sal_Int64)) ); + sal_uInt64 *pStackStart = pStack; + + sal_uInt64 pGPR[MAX_GP_REGS]; + double pFPR[MAX_FP_REGS]; + sal_uInt32 nREG = 0; + +#ifdef BRDEBUG + fprintf(stdout, "in cpp_call\n"); +#endif + + // return + typelib_TypeDescription * pReturnTypeDescr = 0; + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + assert(pReturnTypeDescr); + + void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion + + bool bSimpleReturn = true; + if (pReturnTypeDescr) + { + if ( CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) ) + { + bSimpleReturn = false; + // complex return via ptr + pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )? + __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn; + INSERT_INT64( &pCppReturn, nREG, pGPR, pStack ); + } + else + { + pCppReturn = pUnoReturn; // direct way for simple types + } + } + + // push this + void* pAdjustedThisPtr = reinterpret_cast< void **>( pThis->getCppI() ) + aVtableSlot.offset; + INSERT_INT64( &pAdjustedThisPtr, nREG, pGPR, pStack ); + + // args + void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); + // indices of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams); + // type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); + + sal_Int32 nTempIndices = 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] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr, + pThis->getBridge()->getUno2Cpp() ); + + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + INSERT_INT64( pCppArgs[nPos], nREG, pGPR, pStack ); + break; + case typelib_TypeClass_ENUM: + INSERT_INT32( pCppArgs[nPos], nREG, pGPR, pStack ); + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + INSERT_INT16( pCppArgs[nPos], nREG, pGPR, pStack ); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + INSERT_UINT16( pCppArgs[nPos], nREG, pGPR, pStack ); + break; + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + INSERT_INT8( pCppArgs[nPos], nREG, pGPR, pStack ); + break; + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nREG, pFPR, pStack ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + INSERT_INT64( pCppArgs[nPos], nREG, pGPR, pStack ); + 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( + pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pParamTypeDescr ); + pTempIndices[nTempIndices] = nPos; // default constructed for cpp call + // will be released at reconversion + ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr; + } + // is in/inout + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) + { + uno_copyAndConvertData( + pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); + + pTempIndices[nTempIndices] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr; + } + else // direct way + { + pCppArgs[nPos] = pUnoArgs[nPos]; + // no longer needed + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + INSERT_INT64( &(pCppArgs[nPos]), nREG, pGPR, pStack ); + } + } + + try + { + try { + callVirtualMethod( + pAdjustedThisPtr, aVtableSlot.index, + pCppReturn, pReturnTypeRef, bSimpleReturn, + pStackStart, ( pStack - pStackStart ), + pGPR, pFPR, nREG); + } catch (css::uno::Exception &) { + throw; + } catch (std::exception & e) { + throw css::uno::RuntimeException( + "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": " + + o3tl::runtimeToOUString(e.what())); + } catch (...) { + throw css::uno::RuntimeException("C++ code threw unknown exception"); + } + // NO exception occurred... + *ppUnoExc = 0; + + // reconvert temporary params + for ( ; nTempIndices--; ) + { + sal_Int32 nIndex = pTempIndices[nTempIndices]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices]; + + 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 + CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno()); + + // temporary params + for ( ; nTempIndices--; ) + { + sal_Int32 nIndex = pTempIndices[nTempIndices]; + // destroy temp cpp param => cpp: every param was constructed + uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] ); + } + // return type + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + } + } + +} + + +namespace bridges::cpp_uno::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(stdout, "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("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( + "illegal member type description!", + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); + + Type const & rExcType = cppu::UnoType::get(); + // binary identical null reference + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/configure.ac b/configure.ac index 33dc0fb963162..a6abeb1af9a0c 100644 --- a/configure.ac +++ b/configure.ac @@ -5213,6 +5213,12 @@ linux-gnu*|linux-musl*) EPM_FLAGS="-a mipsel" PLATFORMID=linux_mips_el ;; + riscv64) + CPUNAME=RISCV64 + RTL_ARCH=RISCV64 + EPM_FLAGS="-a riscv64" + PLATFORMID=linux_riscv64 + ;; m68k) CPUNAME=M68K RTL_ARCH=M68K @@ -8608,7 +8614,7 @@ if test "$ENABLE_JAVA" != ""; then JAVAINTERPRETER=`win_short_path_for_make "$JAVAINTERPRETER"` elif test "$cross_compiling" != "yes"; then case $CPUNAME in - AARCH64|AXP|X86_64|HPPA|IA64|POWERPC64|S390X|SPARC64|GODSON64) + AARCH64|AXP|X86_64|HPPA|IA64|POWERPC64|S390X|SPARC64|GODSON64|RISCV64) if test -f "$JAVAINTERPRETER" -a "`$JAVAINTERPRETER -version 2>&1 | $GREP -i 64-bit`" = "" >/dev/null; then AC_MSG_WARN([You are building 64-bit binaries but the JDK $JAVAINTERPRETER is 32-bit]) AC_MSG_ERROR([You should pass the --with-jdk-home option pointing to a 64-bit JDK]) @@ -12871,7 +12877,7 @@ AC_SUBST(RHINO_JAR) # platforms there. supports_multilib= case "$host_cpu" in -x86_64 | powerpc64 | powerpc64le | s390x | aarch64 | mips64 | mips64el) +x86_64 | powerpc64 | powerpc64le | s390x | aarch64 | mips64 | mips64el | riscv64) if test "$SAL_TYPES_SIZEOFLONG" = "8"; then supports_multilib="yes" fi diff --git a/jvmfwk/inc/vendorbase.hxx b/jvmfwk/inc/vendorbase.hxx index 779fc8f7a46f2..ef60720768f44 100644 --- a/jvmfwk/inc/vendorbase.hxx +++ b/jvmfwk/inc/vendorbase.hxx @@ -59,6 +59,8 @@ OpenJDK at least, but probably not true for Lemotes JDK */ #else #define JFW_PLUGIN_ARCH "mips64el" #endif +#elif defined RISCV64 +#define JFW_PLUGIN_ARCH "riscv64" #elif defined S390X #define JFW_PLUGIN_ARCH "s390x" #elif defined S390 diff --git a/solenv/gbuild/platform/LINUX_RISCV64_GCC.mk b/solenv/gbuild/platform/LINUX_RISCV64_GCC.mk new file mode 100644 index 0000000000000..9e007101d8ac7 --- /dev/null +++ b/solenv/gbuild/platform/LINUX_RISCV64_GCC.mk @@ -0,0 +1,15 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +#please make generic modifications to unxgcc.mk or linux.mk +gb_COMPILEROPTFLAGS := -Os + +include $(GBUILDDIR)/platform/linux.mk + +# vim: set noet sw=4: