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: */

Reply via email to