bridges/Library_cpp_uno.mk | 1 bridges/source/cpp_uno/gcc3_wasm/abi.cxx | 84 +++++++++++++++++++++++++++ bridges/source/cpp_uno/gcc3_wasm/abi.hxx | 74 +++++++++++++++++++++++ bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx | 37 +++++++++-- unotest/source/embindtest/embindtest.js | 19 ++++++ 5 files changed, 208 insertions(+), 7 deletions(-)
New commits: commit 7175431a4b2154113c2c3c28f7ae8a8f14a84c7a Author: Stephan Bergmann <[email protected]> AuthorDate: Tue May 28 15:32:50 2024 +0200 Commit: Stephan Bergmann <[email protected]> CommitDate: Wed May 29 10:35:01 2024 +0200 Implement exception catching (Without 22ce8ed05be37d676739a578b05cc5217109fd87 "Emscripten: Unconditional --enable-wasm-exceptions", this would have failed to link due to missing __cxa_current_exception_type and __cxa_get_globals.) Change-Id: If89a3c62e4d2ac24d68f867b2fd7a4cd813d5a39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168176 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <[email protected]> diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk index c42778f359c1..462fd538e104 100644 --- a/bridges/Library_cpp_uno.mk +++ b/bridges/Library_cpp_uno.mk @@ -83,6 +83,7 @@ bridge_exception_objects := cpp2uno uno2cpp bridge_noopt_objects := except else ifeq ($(OS),EMSCRIPTEN) bridges_SELECTED_BRIDGE := gcc3_wasm +bridge_exception_objects := abi bridge_noopt_objects := cpp2uno except uno2cpp $(eval $(call gb_Library_add_generated_asmobjects,$(CPPU_ENV)_uno, \ CustomTarget/bridges/gcc3_wasm/callvirtualfunction-impls \ diff --git a/bridges/source/cpp_uno/gcc3_wasm/abi.cxx b/bridges/source/cpp_uno/gcc3_wasm/abi.cxx new file mode 100644 index 000000000000..5d21cd1d8522 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_wasm/abi.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <sal/config.h> + +#include <cassert> +#include <cstddef> +#include <typeinfo> + +#include <com/sun/star/uno/RuntimeException.hpp> +#include <cppu/unotype.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <typelib/typedescription.h> +#include <uno/any2.h> +#include <uno/mapping.h> + +#include "abi.hxx" + +namespace +{ +OUString toUnoName(char const* name) +{ + assert(name != nullptr); + OUStringBuffer b; + bool scoped = *name == 'N'; + if (scoped) + { + ++name; + } + for (;;) + { + assert(*name >= '0' && *name <= '9'); + std::size_t n = *name++ - '0'; + while (*name >= '0' && *name <= '9') + { + n = 10 * n + (*name++ - '0'); + } + b.appendAscii(name, n); + name += n; + if (!scoped) + { + assert(*name == 0); + break; + } + if (*name == 'E') + { + assert(name[1] == 0); + break; + } + b.append('.'); + } + return b.makeStringAndClear(); +} +} + +void abi_wasm::mapException(__cxxabiv1::__cxa_exception* exception, std::type_info const* type, + uno_Any* any, uno_Mapping* mapping) +{ + assert(exception != nullptr); + assert(type != nullptr); + OUString unoName(toUnoName(type->name())); + typelib_TypeDescription* td = nullptr; + typelib_typedescription_getByName(&td, unoName.pData); + if (td == nullptr) + { + css::uno::RuntimeException e("exception type not found: " + unoName); + uno_type_any_constructAndConvert( + any, &e, cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(), mapping); + } + else + { + uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping); + typelib_typedescription_release(td); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/bridges/source/cpp_uno/gcc3_wasm/abi.hxx b/bridges/source/cpp_uno/gcc3_wasm/abi.hxx new file mode 100644 index 000000000000..67dbd06c0390 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_wasm/abi.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include <sal/config.h> + +#include <cstddef> +#include <cstdint> +#include <typeinfo> + +#include <cxxabi.h> + +#include <config_cxxabi.h> +#include <uno/any2.h> +#include <uno/mapping.h> + +#if !HAVE_CXXABI_H_CXA_EXCEPTION +// <https://github.com/emscripten-core/emscripten/>, system/lib/libcxxabi/src/cxa_exception.h: +namespace __cxxabiv1 +{ +struct __cxa_exception +{ + std::size_t referenceCount; + std::type_info* exceptionType; + // In wasm, destructors return 'this' as in ARM + void* (*exceptionDestructor)(void*); + std::uint8_t caught; + std::uint8_t rethrown; + void* adjustedPtr; + // Add padding to ensure that the size of __cxa_exception is a multiple of + // the maximum useful alignment for the target machine. This ensures that + // the thrown object that follows has that correct alignment. + void* padding; +}; +} +#endif + +#if !HAVE_CXXABI_H_CXA_EH_GLOBALS +// <https://github.com/emscripten-core/emscripten/>, system/lib/libcxxabi/src/cxa_exception.h: +namespace __cxxabiv1 +{ +struct __cxa_eh_globals +{ + __cxa_exception* caughtExceptions; + unsigned int uncaughtExceptions; +#if defined _LIBCXXABI_ARM_EHABI + __cxa_exception* propagatingExceptions; +#endif +}; +} +#endif + +#if !HAVE_CXXABI_H_CXA_GET_GLOBALS +// <https://github.com/emscripten-core/emscripten/>, system/lib/libcxxabi/src/cxa_exception.h: +namespace __cxxabiv1 +{ +extern "C" __cxa_eh_globals* __cxa_get_globals(); +} +#endif + +namespace abi_wasm +{ +void mapException(__cxxabiv1::__cxa_exception* exception, std::type_info const* type, uno_Any* any, + uno_Mapping* mapping); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx index 537b8f89a872..4b4cdb2bbadb 100644 --- a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx +++ b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx @@ -9,12 +9,16 @@ #include <sal/config.h> +#include <exception> +#include <typeinfo> #include <vector> #include <alloca.h> +#include <com/sun/star/uno/Exception.hpp> #include <com/sun/star/uno/RuntimeException.hpp> #include <com/sun/star/uno/genfunc.hxx> +#include <o3tl/runtimetooustring.hxx> #include <o3tl/unreachable.hxx> #include <rtl/strbuf.hxx> #include <typelib/typeclass.h> @@ -27,9 +31,10 @@ #include <types.hxx> #include <unointerfaceproxy.hxx> #include <vtables.hxx> - #include <wasm/callvirtualfunction.hxx> +#include "abi.hxx" + using namespace ::com::sun::star::uno; namespace @@ -245,14 +250,32 @@ void call(bridges::cpp_uno::shared::UnoInterfaceProxy* proxy, } try { - callVirtualFunction(sig, (*thisPtr)[slot.index], args.data(), ret); + try + { + callVirtualFunction(sig, (*thisPtr)[slot.index], args.data(), ret); + } + 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"); + } } - catch (...) + catch (css::uno::Exception&) { - css::uno::RuntimeException TODO("Wasm bridge TODO"); - uno_type_any_construct(*exception, &TODO, - cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(), - nullptr); + __cxxabiv1::__cxa_exception* header + = reinterpret_cast<__cxxabiv1::__cxa_eh_globals*>(__cxxabiv1::__cxa_get_globals()) + ->caughtExceptions; + abi_wasm::mapException(header, __cxxabiv1::__cxa_current_exception_type(), *exception, + proxy->getBridge()->getCpp2Uno()); for (sal_Int32 i = 0; i != count; ++i) { if (cppArgs[i] != nullptr) diff --git a/unotest/source/embindtest/embindtest.js b/unotest/source/embindtest/embindtest.js index cdd214f08fd5..a98f828d9eba 100644 --- a/unotest/source/embindtest/embindtest.js +++ b/unotest/source/embindtest/embindtest.js @@ -1094,6 +1094,25 @@ Module.addOnPostRun(function() { outparam.val.delete(); outparam.delete(); } + { + const params = new Module.uno_Sequence_any(0, Module.uno_Sequence.FromSize); + const outparamindex = new Module.uno_InOutParam_sequence_short; + const outparam = new Module.uno_InOutParam_sequence_any; + try { + const ret = invoke.invoke('throwRuntimeException', params, outparamindex, outparam); + console.assert(false); + ret.delete(); + } catch (e) { + const [type, message] = getExceptionMessage(e); + console.assert(type === 'com::sun::star::reflection::InvocationTargetException'); + console.assert(message === undefined); //TODO + //TODO: inspect wrapped css.uno.RuntimeException + decrementExceptionRefcount(e); + } + params.delete(); + outparamindex.delete(); + outparam.delete(); + } }); /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
