[Libreoffice-commits] core.git: Branch 'feature/wasm' - 2 commits - bridges/Library_cpp_uno.mk bridges/Module_bridges.mk bridges/source cppu/source Repository.mk static/environment.js

Thorsten Behrens (via logerrit) logerrit at kemper.freedesktop.org
Sat Sep 25 16:05:51 UTC 2021


 Repository.mk                                  |    2 
 bridges/Library_cpp_uno.mk                     |    4 
 bridges/Module_bridges.mk                      |    2 
 bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx   |  540 +++++++++++++++++++++++++
 bridges/source/cpp_uno/gcc3_wasm/except.cxx    |  406 ++++++++++++++++++
 bridges/source/cpp_uno/gcc3_wasm/rtti.h        |  410 ++++++++++++++++++
 bridges/source/cpp_uno/gcc3_wasm/share.hxx     |   57 ++
 bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx   |  537 ++++++++++++++++++++++++
 bridges/source/cpp_uno/gcc3_wasm/unwind-cxx.h  |  283 +++++++++++++
 bridges/source/cpp_uno/gcc3_wasm/wasm_helper.s |  233 ++++++++++
 cppu/source/uno/lbenv.cxx                      |    6 
 cppu/source/uno/lbmap.cxx                      |    3 
 static/environment.js                          |    2 
 13 files changed, 2472 insertions(+), 13 deletions(-)

New commits:
commit 92f8bff563a46d7d1af494287e0a79f834f3214c
Author:     Thorsten Behrens <thorsten.behrens at allotropia.de>
AuthorDate: Sat Sep 25 18:04:18 2021 +0200
Commit:     Thorsten Behrens <thorsten.behrens at allotropia.de>
CommitDate: Sat Sep 25 18:04:18 2021 +0200

    Also log DEBUG traces while we're developing this
    
    Change-Id: I076f98826a5fec5278041c5a098473e06a0034e5

diff --git a/static/environment.js b/static/environment.js
index 9e4e263f3c73..61663cb148e6 100644
--- a/static/environment.js
+++ b/static/environment.js
@@ -1,3 +1,3 @@
 Module.preRun.push(function() {
-    ENV.SAL_LOG = "+INFO+WARN"
+    ENV.SAL_LOG = "+INFO+WARN+DEBUG"
 });
commit 4ed35537ac603f0119e52c4835918350e5437b9c
Author:     Thorsten Behrens <thorsten.behrens at allotropia.de>
AuthorDate: Sat Sep 25 18:03:31 2021 +0200
Commit:     Thorsten Behrens <thorsten.behrens at allotropia.de>
CommitDate: Sat Sep 25 18:03:31 2021 +0200

    Add dummy bridge for WASM

diff --git a/Repository.mk b/Repository.mk
index 75f7dd74c8f1..dc65b260a69a 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -610,13 +610,11 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \
 ))
 
 $(eval $(call gb_Helper_register_plugins_for_install,PLAINLIBS_URE,ure, \
-	$(if $(filter EMSCRIPTEN,$(OS)),, \
 		$(if $(filter MSC,$(COM)), \
 			$(if $(filter INTEL,$(CPUNAME)),msci_uno) \
 			$(if $(filter X86_64,$(CPUNAME)),mscx_uno) \
 			$(if $(filter AARCH64,$(CPUNAME)),msca_uno) \
 		, gcc3_uno) \
-	) \
 ))
 
 $(eval $(call gb_Helper_register_libraries_for_install,PRIVATELIBS_URE,ure, \
diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk
index 8a4ec4c10f48..58a8bef7c3c9 100644
--- a/bridges/Library_cpp_uno.mk
+++ b/bridges/Library_cpp_uno.mk
@@ -85,6 +85,10 @@ else ifeq ($(COM),MSC)
 bridges_SELECTED_BRIDGE := msvc_win32_intel
 bridge_exception_objects := cpp2uno uno2cpp
 bridge_noopt_objects := except
+else ifeq ($(OS),EMSCRIPTEN)
+bridges_SELECTED_BRIDGE := gcc3_wasm
+bridge_noopt_objects := cpp2uno except uno2cpp
+#bridge_asm_objects := wasm_helper
 endif
 
 else ifeq ($(CPUNAME),M68K)
diff --git a/bridges/Module_bridges.mk b/bridges/Module_bridges.mk
index 1c7fb1789b8e..3016bf2c404f 100644
--- a/bridges/Module_bridges.mk
+++ b/bridges/Module_bridges.mk
@@ -9,7 +9,6 @@
 
 $(eval $(call gb_Module_Module,bridges))
 
-ifneq ($(OS),EMSCRIPTEN)
 $(eval $(call gb_Module_add_targets,bridges,\
 	Library_cpp_uno \
 	$(if $(ENABLE_JAVA),\
@@ -30,6 +29,5 @@ else ifneq ($(words $(bridges_SELECTED_BRIDGE)),1)
 $(call gb_Output_error,multiple bridges selected for build: $(bridges_SELECTED_BRIDGE))
 endif
 endif
-endif
 
 # vim: set noet sw=4 ts=4:
diff --git a/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx
new file mode 100644
index 000000000000..90e1d372da03
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx
@@ -0,0 +1,540 @@
+/* -*- 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 <com/sun/star/uno/RuntimeException.hpp>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "share.hxx"
+
+
+
+extern "C" int codeSnippets[];
+const int nFunIndexes = 8;
+const int nVtableOffsets = 4;
+
+
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+    static typelib_TypeClass cpp2uno_call(
+        bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+        const typelib_TypeDescription * pMemberTypeDescr,
+        typelib_TypeDescriptionReference * pReturnTypeRef,
+        sal_Int32 nParams,
+        typelib_MethodParameter * pParams,
+        void ** pCallStack,
+        sal_Int64 * pRegisterReturn /* space for register return */ )
+    {
+        // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
+        char *pTopStack = (char *)pCallStack;
+        char *pFloatRegs = pTopStack + 2;
+        char *pGPRegs =  pTopStack + (2+8)*8;
+        char *pStackedArgs = pTopStack + (2+8+8)*8;
+
+        int nGPR = 0;
+        int nFPR = 0;
+
+        // return
+        typelib_TypeDescription * pReturnTypeDescr = 0;
+        if (pReturnTypeRef)
+            TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+        void * pUnoReturn = 0;
+        // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+        void * pCppReturn = 0;
+
+        if (pReturnTypeDescr)
+        {
+            if (!arm::return_in_x8(pReturnTypeRef))
+                pUnoReturn = pRegisterReturn; // direct way for simple types
+            else // complex return via x8
+            {
+                pCppReturn = pCallStack[0];
+
+                pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+                    pReturnTypeDescr )
+                        ? alloca( pReturnTypeDescr->nSize )
+                        : pCppReturn); // direct way
+            }
+        }
+
+        // Skip 'this'
+        pGPRegs += 8;
+        nGPR++;
+
+        // Parameters
+        void ** pUnoArgs = (void **)alloca( sizeof(void *) * nParams );
+        void ** pCppArgs = (void **)alloca( sizeof(void *) * nParams );
+
+        // Indices of values this have to be converted (interface conversion
+        // cpp<=>uno)
+        int * pTempIndices = (int *)alloca( sizeof(int) * nParams);
+
+        // Type descriptions for reconversions
+        typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)alloca( sizeof(typelib_TypeDescription *) * nParams);
+
+        int nTempIndices = 0;
+
+        for ( int 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 ))
+            {
+                if (nFPR < 8 && (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT ||
+                                 pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE))
+                {
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pFloatRegs;
+                    pFloatRegs += 8;
+                    nFPR++;
+                }
+                else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+                {
+                    if ((pStackedArgs - pTopStack) % 4)
+                        pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                    pStackedArgs += 4;
+                }
+                else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE)
+                {
+                    if ((pStackedArgs - pTopStack) % 8)
+                        pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                    pStackedArgs += 8;
+                }
+                else if (nGPR < 8)
+                {
+                    pCppArgs[nPos] = pUnoArgs[nPos] = pGPRegs;
+                    pGPRegs += 8;
+                    nGPR++;
+                }
+                else
+                switch (pParamTypeDescr->eTypeClass)
+                {
+                    case typelib_TypeClass_HYPER:
+                    case typelib_TypeClass_UNSIGNED_HYPER:
+                        if ((pStackedArgs - pTopStack) % 8)
+                            pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+                        pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                        pStackedArgs += 8;
+                        break;
+                    case typelib_TypeClass_ENUM:
+                    case typelib_TypeClass_LONG:
+                    case typelib_TypeClass_UNSIGNED_LONG:
+                        if ((pStackedArgs - pTopStack) % 4)
+                            pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
+                        pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                        pStackedArgs += 4;
+                        break;
+                    case typelib_TypeClass_CHAR:
+                    case typelib_TypeClass_SHORT:
+                    case typelib_TypeClass_UNSIGNED_SHORT:
+                        if ((pStackedArgs - pTopStack) % 2)
+                            pStackedArgs += 1;
+                        pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                        pStackedArgs += 2;
+                        break;
+                    case typelib_TypeClass_BOOLEAN:
+                    case typelib_TypeClass_BYTE:
+                        pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+                        pStackedArgs += 1;
+                        break;
+                    default:
+                        assert(!"should not happen");
+                        break;
+                }
+                // no longer needed
+                TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+            }
+            else // ptr to complex value | ref
+            {
+                if (nGPR < 8)
+                {
+                    pCppArgs[nPos] = *(void **)pGPRegs;
+                    pGPRegs += 8;
+                }
+                else
+                {
+                    if ((pStackedArgs - pTopStack) % 8)
+                        pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+                    pCppArgs[nPos] = pStackedArgs;
+                    pStackedArgs += 8;
+                }
+
+                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 ),
+                        pCppArgs[nPos], pParamTypeDescr,
+                        pThis->getBridge()->getCpp2Uno() );
+                    pTempIndices[nTempIndices] = nPos; // has to be reconverted
+                    // will be released at reconversion
+                    ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+                }
+                else // direct way
+                {
+                    pUnoArgs[nPos] = pCppArgs[nPos];
+                    // no longer needed
+                    TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+                }
+            }
+        }
+
+        // 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 );
+
+        // in case an exception occurred...
+        if (pUnoExc)
+        {
+            // destruct temporary in/inout params
+            for ( ; nTempIndices--; )
+            {
+                int 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--; )
+            {
+                int 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 );
+                }
+                *(void **)pRegisterReturn = pCppReturn;
+            }
+            if (pReturnTypeDescr)
+            {
+                typelib_TypeClass eRet =
+                    (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+                TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+                return eRet;
+            }
+            else
+                return typelib_TypeClass_VOID;
+        }
+    }
+
+
+    static void cpp_mediate(sal_Int32 nFunctionIndex,
+                            sal_Int32 nVtableOffset,
+                            void ** pCallStack)
+    {
+        sal_Int64 nRegReturn;
+        sal_Int64 *pRegisterReturn = &nRegReturn;
+
+        // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
+        // _this_ ptr is patched cppu_XInterfaceProxy object
+        void *pThis = pCallStack[2 + 8];
+
+        pThis = static_cast< char * >(pThis) - nVtableOffset;
+        bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+            bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+                pThis);
+
+        typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+        // determine called method
+        assert( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex );
+
+        if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+        {
+            throw RuntimeException( "illegal vtable index!", (XInterface *)pCppI );
+        }
+
+        sal_Int32 nMemberPos =
+            pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+        assert( nMemberPos < pTypeDescr->nAllMembers );
+
+        TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+        typelib_TypeClass eRet;
+        switch (aMemberDescr.get()->eTypeClass)
+        {
+        case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+        {
+            if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
+                nFunctionIndex)
+            {
+                // is GET method
+                eRet = cpp2uno_call(
+                    pCppI, aMemberDescr.get(),
+                    ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+                    0, 0, // no params
+                    pCallStack, pRegisterReturn );
+            }
+            else
+            {
+                // is SET method
+                typelib_MethodParameter aParam;
+                aParam.pTypeRef =
+                    ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+                aParam.bIn      = sal_True;
+                aParam.bOut     = sal_False;
+
+                eRet = cpp2uno_call(
+                    pCppI, aMemberDescr.get(),
+                    0, // indicates void return
+                    1, &aParam,
+                    pCallStack, pRegisterReturn );
+            }
+            break;
+        }
+        case typelib_TypeClass_INTERFACE_METHOD:
+        {
+            // is METHOD
+            switch (nFunctionIndex)
+            {
+            case 1: // acquire()
+                pCppI->acquireProxy(); // non virtual call!
+                eRet = typelib_TypeClass_VOID;
+                break;
+            case 2: // release()
+                pCppI->releaseProxy(); // non virtual call!
+                eRet = typelib_TypeClass_VOID;
+                break;
+            case 0: // queryInterface() opt
+            {
+                typelib_TypeDescription * pTD = 0;
+                TYPELIB_DANGER_GET(&pTD,
+                    reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
+                if (pTD)
+                {
+                    XInterface * pInterface = 0;
+                    (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+                        pCppI->getBridge()->getCppEnv(),
+                        (void **)&pInterface, pCppI->getOid().pData,
+                        (typelib_InterfaceTypeDescription *)pTD );
+
+                    if (pInterface)
+                    {
+                        ::uno_any_construct(
+                            reinterpret_cast< uno_Any * >( pCallStack[0] ),
+                            &pInterface, pTD, cpp_acquire );
+                        pInterface->release();
+                        TYPELIB_DANGER_RELEASE( pTD );
+                        *(void **)pRegisterReturn = pCallStack[0];
+                        eRet = typelib_TypeClass_ANY;
+                        break;
+                    }
+                    TYPELIB_DANGER_RELEASE( pTD );
+                }
+            } // else perform queryInterface()
+            [[fallthrough]];
+            default:
+                eRet = cpp2uno_call(
+                    pCppI, aMemberDescr.get(),
+                    ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+                    ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+                    ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+                    pCallStack, pRegisterReturn );
+            }
+            break;
+        }
+        default:
+        {
+            throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+        }
+        }
+
+        (void)eRet;
+        return;
+    }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+
+extern "C" void cpp_vtable_call( sal_Int32 func, sal_Int32 offset,
+                                 void **pStack )
+{
+    cpp_mediate(func, offset, pStack);
+}
+
+namespace
+{
+    unsigned char *codeSnippet(const typelib_InterfaceTypeDescription *type,
+                               const typelib_TypeDescription *member,
+                               sal_Int32 functionIndex,
+                               sal_Int32 vtableOffset)
+    {
+        // For now temporarily assert when we get here. The intent is
+        // that we won't need the code snippets at all on iOS.
+        assert(false);
+
+        assert(functionIndex < nFunIndexes);
+        if (!(functionIndex < nFunIndexes))
+            return NULL;
+
+        assert(vtableOffset < nVtableOffsets);
+        if (!(vtableOffset < nVtableOffsets))
+            return NULL;
+
+        // The codeSnippets table is indexed by functionIndex and vtableOffset
+
+        int index = functionIndex*nVtableOffsets + vtableOffset;
+        unsigned char *result = ((unsigned char *) &codeSnippets) + codeSnippets[index];
+
+        SAL_INFO( "bridges", "codeSnippet(" << OUString(type->aBase.pTypeName) << "::" << OUString(member->pTypeName) << "): [" << functionIndex << "," << vtableOffset << "]=" << (void *) result << " (" << std::hex << ((int*)result)[0] << "," << ((int*)result)[1] << "," << ((int*)result)[2] << "," << ((int*)result)[3] << ")");
+
+        return result;
+    }
+}
+
+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);
+}
+
+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;
+    slots[-1].fn = 0;
+    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]);
+        assert(member != 0);
+        switch (member->eTypeClass)
+        {
+            case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+            {
+                typelib_InterfaceAttributeTypeDescription *pAttrTD =
+                    reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
+
+                // Getter:
+                (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+
+                // Setter:
+                if (!pAttrTD->bReadOnly)
+                {
+                    (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+                }
+                break;
+            }
+            case typelib_TypeClass_INTERFACE_METHOD:
+            {
+                (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+                break;
+            }
+        default:
+            assert(false);
+            break;
+        }
+        TYPELIB_DANGER_RELEASE(member);
+    }
+    return code;
+}
+
+
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+    unsigned char const *, unsigned char const *)
+{
+    // No dynamic code generation so nothing to flush
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/except.cxx b/bridges/source/cpp_uno/gcc3_wasm/except.cxx
new file mode 100644
index 000000000000..aebe016052ab
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/except.cxx
@@ -0,0 +1,406 @@
+/* -*- 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 "sal/config.h"
+
+#include <cassert>
+#include <new>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+#include <cxxabi.h>
+#include <dlfcn.h>
+
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include "com/sun/star/uno/genfunc.hxx"
+#include <sal/log.hxx>
+#include "osl/mutex.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "typelib/typedescription.h"
+#include "uno/any2.h"
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+namespace {
+
+struct Fake_type_info {
+    virtual ~Fake_type_info() = delete;
+    char const * name;
+};
+
+struct Fake_class_type_info: Fake_type_info {
+    virtual ~Fake_class_type_info() override = delete;
+};
+
+struct Fake_si_class_type_info: Fake_class_type_info {
+    virtual ~Fake_si_class_type_info() override = delete;
+    void const * base;
+};
+
+struct Base {};
+struct Derived: Base {};
+
+std::type_info * createFake_class_type_info(char const * name) {
+    char * buf = new char[sizeof (Fake_class_type_info)];
+
+    *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+        &typeid(Base));
+        // copy __cxxabiv1::__class_type_info vtable into place
+    Fake_class_type_info * fake = reinterpret_cast<Fake_class_type_info *>(buf);
+    fake->name = name;
+    return reinterpret_cast<std::type_info *>(
+        static_cast<Fake_type_info *>(fake));
+}
+
+std::type_info * createFake_si_class_type_info(
+    char const * name, std::type_info const * base)
+{
+    char * buf = new char[sizeof (Fake_si_class_type_info)];
+
+    *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+        &typeid(Derived));
+        // copy __cxxabiv1::__si_class_type_info vtable into place
+    Fake_si_class_type_info * fake
+        = reinterpret_cast<Fake_si_class_type_info *>(buf);
+    fake->name = name;
+    fake->base = base;
+    return reinterpret_cast<std::type_info *>(
+        static_cast<Fake_type_info *>(fake));
+}
+
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+void dummy_can_throw_anything( char const * )
+{
+}
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+    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 OSL_DEBUG_LEVEL > 1
+    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, std::type_info *, OUStringHash > t_rtti_map;
+
+    Mutex m_mutex;
+    t_rtti_map m_rttis;
+    t_rtti_map m_generatedRttis;
+
+    void * m_hApp;
+
+public:
+    RTTI();
+    ~RTTI();
+
+    std::type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+    : m_hApp( dlopen( nullptr, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+    dlclose( m_hApp );
+}
+
+
+std::type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+    std::type_info * rtti;
+
+    OUString const & unoName = OUString::unacquired(&pTypeDescr->aBase.pTypeName);
+
+    MutexGuard guard( m_mutex );
+    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+    if (iFind == 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 = static_cast<std::type_info *>(dlsym( m_hApp, symName.getStr() ));
+
+        if (rtti)
+        {
+            std::pair< t_rtti_map::iterator, bool > insertion(
+                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+            SAL_WARN_IF( !insertion.second,
+                         "bridges",
+                         "inserting new rtti failed" );
+        }
+        else
+        {
+            // try to lookup the symbol in the generated rtti map
+            t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
+            if (iFind2 == m_generatedRttis.end())
+            {
+                // we must generate it !
+                // symbol and rtti-name is nearly identical,
+                // the symbol is prefixed with _ZTI
+                char * rttiName = strdup(symName.getStr() + 4);
+                if (rttiName == nullptr) {
+                    throw std::bad_alloc();
+                }
+#if OSL_DEBUG_LEVEL > 1
+                fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+                if (pTypeDescr->pBaseTypeDescription)
+                {
+                    // ensure availability of base
+                    std::type_info * base_rtti = getRTTI(
+                        pTypeDescr->pBaseTypeDescription );
+                    rtti = createFake_si_class_type_info(rttiName, base_rtti);
+                }
+                else
+                {
+                    rtti = createFake_class_type_info(rttiName);
+                }
+
+                std::pair< t_rtti_map::iterator, bool > insertion(
+                    m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+                SAL_WARN_IF( !insertion.second,
+                             "bridges",
+                             "inserting new generated rtti failed" );
+            }
+            else // taking already generated rtti
+            {
+                rtti = iFind2->second;
+            }
+        }
+    }
+    else
+    {
+        rtti = iFind->second;
+    }
+
+    return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+    __cxa_exception const * header = static_cast<__cxa_exception const *>(pExc) - 1;
+    // The libcxxabi commit
+    // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+    // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+    // LLVM 5.0 changed the size of __cxa_exception by adding
+    //
+    //   __attribute__((aligned))
+    //
+    // to the final member unwindHeader, on x86-64 effectively adding a hole of
+    // size 8 in front of that member (changing its offset from 88 to 96,
+    // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+    // from 8 to 16); a hack to dynamically determine whether we run against a
+    // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+    // point to this function (the use of __cxa_exception in fillUnoException is
+    // unaffected, as it only accesses members towards the start of the struct,
+    // through a pointer known to actually point at the start).  The libcxxabi commit
+    // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+    // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+    // removes the need for this hack, so it can be removed again once we can be sure that we only
+    // run against libcxxabi from LLVM >= 6:
+    if (header->exceptionDestructor != &deleteException) {
+        header = reinterpret_cast<__cxa_exception const *>(
+            reinterpret_cast<char const *>(header) - 8);
+        assert(header->exceptionDestructor == &deleteException);
+    }
+    typelib_TypeDescription * pTD = nullptr;
+    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 );
+    }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+    OString cstr(
+        OUStringToOString(
+            OUString::unacquired( &pUnoExc->pType->pTypeName ),
+            RTL_TEXTENCODING_ASCII_US ) );
+    fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+    void * pCppExc;
+    std::type_info * rtti;
+
+    {
+    // construct cpp exception object
+    typelib_TypeDescription * pTypeDescr = nullptr;
+    TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+    assert(pTypeDescr);
+    if (! pTypeDescr)
+    {
+        throw RuntimeException(
+            "cannot get typedescription for type " +
+            OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+    }
+
+    pCppExc = __cxxabiv1::__cxa_allocate_exception( pTypeDescr->nSize );
+    ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+    // destruct uno exception
+    ::uno_any_destruct( pUnoExc, nullptr );
+    // avoiding locked counts
+    static RTTI rtti_data;
+    rtti = rtti_data.getRTTI(reinterpret_cast<typelib_CompoundTypeDescription*>(pTypeDescr));
+    TYPELIB_DANGER_RELEASE( pTypeDescr );
+    assert(rtti && "### no rtti for throwing exception!");
+    if (! rtti)
+    {
+        throw RuntimeException(
+            "no rtti for type " +
+            OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+    }
+    }
+
+    // void __cxa_throw(void* thrown_exception,
+    //                  struct std::type_info * tinfo,
+    //                  void (*dest)(void*));
+    __cxxabiv1::__cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+    __cxa_exception * header = __cxxabiv1::__cxa_get_globals()->caughtExceptions;
+    if (! header)
+    {
+        RuntimeException aRE( "no exception header!" );
+        Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+        SAL_WARN("bridges", aRE.Message);
+        return;
+    }
+
+    // Very bad HACK to find out whether we run against a libcxxabi that has a new
+    // __cxa_exception::reserved member at the start, introduced with LLVM 10
+    // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+    // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility".  The layout of the
+    // start of __cxa_exception is
+    //
+    //  [8 byte  void *reserve]
+    //   8 byte  size_t referenceCount
+    //
+    // where the (bad, hacky) assumption is that reserve (if present) is null
+    // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+    // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+    // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+    // __cxa_dependent_exception, the referenceCount member is rather
+    //
+    //   8 byte  void* primaryException
+    //
+    // but which also will always be set to a non-null value in __cxa_rethrow_primary_exception).
+    // As described in the definition of __cxa_exception
+    // (bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx), this hack (together with the "#if 0"
+    // there) can be dropped once we can be sure that we only run against new libcxxabi that has the
+    // reserve member:
+    if (*reinterpret_cast<void **>(header) == nullptr) {
+        header = reinterpret_cast<__cxa_exception *>(reinterpret_cast<void **>(header) + 1);
+    }
+
+    std::type_info *exceptionType = nullptr; // TODO: __cxxabiv1::__cxa_current_exception_type();
+
+    typelib_TypeDescription * pExcTypeDescr = nullptr;
+    OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+    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 (nullptr == pExcTypeDescr)
+    {
+        RuntimeException aRE( "exception type not found: " + unoName );
+        Type const & rType = cppu::UnoType<decltype(aRE)>::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_wasm/rtti.h b/bridges/source/cpp_uno/gcc3_wasm/rtti.h
new file mode 100644
index 000000000000..fd8ef3715082
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/rtti.h
@@ -0,0 +1,410 @@
+// Copyright (C) 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+// Written by Nathan Sidwell, Codesourcery LLC, <nathan at codesourcery.com>
+#ifndef __RTTI_H
+#define __RTTI_H
+
+#include <typeinfo>
+
+namespace __cxxabiv1
+{
+  // Type information for int, float etc.
+  class __fundamental_type_info : public std::type_info
+  {
+  public:
+    explicit
+    __fundamental_type_info(const char* __n) : std::type_info(__n) { }
+
+    virtual
+    ~__fundamental_type_info();
+  };
+
+  // Type information for array objects.
+  class __array_type_info : public std::type_info
+  {
+  public:
+    explicit
+    __array_type_info(const char* __n) : std::type_info(__n) { }
+
+    virtual
+    ~__array_type_info();
+  };
+
+  // Type information for functions (both member and non-member).
+  class __function_type_info : public std::type_info
+  {
+  public:
+    explicit
+    __function_type_info(const char* __n) : std::type_info(__n) { }
+
+    virtual
+    ~__function_type_info();
+
+  protected:
+    // Implementation defined member function.
+    virtual bool
+    __is_function_p() const;
+  };
+
+  // Type information for enumerations.
+  class __enum_type_info : public std::type_info
+  {
+  public:
+    explicit
+    __enum_type_info(const char* __n) : std::type_info(__n) { }
+
+    virtual
+    ~__enum_type_info();
+  };
+
+  // Common type information for simple pointers and pointers to member.
+  class __pbase_type_info : public std::type_info
+  {
+  public:
+    unsigned int        __flags; // Qualification of the target object.
+    const std::type_info*   __pointee; // Type of pointed to object.
+
+    explicit
+    __pbase_type_info(const char* __n, int __quals,
+              const std::type_info* __type)
+    : std::type_info(__n), __flags(__quals), __pointee(__type)
+    { }
+
+    virtual
+    ~__pbase_type_info();
+
+    // Implementation defined type.
+    enum __masks
+      {
+    __const_mask = 0x1,
+    __volatile_mask = 0x2,
+    __restrict_mask = 0x4,
+    __incomplete_mask = 0x8,
+    __incomplete_class_mask = 0x10
+      };
+
+  protected:
+    __pbase_type_info(const __pbase_type_info&);
+
+    __pbase_type_info&
+    operator=(const __pbase_type_info&);
+
+    // Implementation defined member functions.
+    virtual bool
+    __do_catch(const std::type_info* __thr_type, void** __thr_obj,
+           unsigned int __outer) const;
+
+    inline virtual bool
+    __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+            unsigned __outer) const;
+  };
+
+  // Type information for simple pointers.
+  class __pointer_type_info : public __pbase_type_info
+  {
+  public:
+    explicit
+    __pointer_type_info(const char* __n, int __quals,
+            const std::type_info* __type)
+    : __pbase_type_info (__n, __quals, __type) { }
+
+
+    virtual
+    ~__pointer_type_info();
+
+  protected:
+    // Implementation defined member functions.
+    virtual bool
+    __is_pointer_p() const;
+
+    virtual bool
+    __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+            unsigned __outer) const;
+  };
+
+  class __class_type_info;
+
+  // Type information for a pointer to member variable.
+  class __pointer_to_member_type_info : public __pbase_type_info
+  {
+  public:
+    __class_type_info* __context;   // Class of the member.
+
+    explicit
+    __pointer_to_member_type_info(const char* __n, int __quals,
+                  const std::type_info* __type,
+                  __class_type_info* __klass)
+    : __pbase_type_info(__n, __quals, __type), __context(__klass) { }
+
+    virtual
+    ~__pointer_to_member_type_info();
+
+  protected:
+    __pointer_to_member_type_info(const __pointer_to_member_type_info&);
+
+    __pointer_to_member_type_info&
+    operator=(const __pointer_to_member_type_info&);
+
+    // Implementation defined member function.
+    virtual bool
+    __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+            unsigned __outer) const;
+  };
+
+  // Helper class for __vmi_class_type.
+  class __base_class_type_info
+  {
+  public:
+    const __class_type_info*    __base_type;  // Base class type.
+    long            __offset_flags;  // Offset and info.
+
+    enum __offset_flags_masks
+      {
+    __virtual_mask = 0x1,
+    __public_mask = 0x2,
+    __hwm_bit = 2,
+    __offset_shift = 8          // Bits to shift offset.
+      };
+
+    // Implementation defined member functions.
+    bool
+    __is_virtual_p() const
+    { return __offset_flags & __virtual_mask; }
+
+    bool
+    __is_public_p() const
+    { return __offset_flags & __public_mask; }
+
+    ptrdiff_t
+    __offset() const
+    {
+      // This shift, being of a signed type, is implementation
+      // defined. GCC implements such shifts as arithmetic, which is
+      // what we want.
+      return static_cast<ptrdiff_t>(__offset_flags) >> __offset_shift;
+    }
+  };
+
+  // Type information for a class.
+  class __class_type_info : public std::type_info
+  {
+  public:
+    explicit
+    __class_type_info (const char *__n) : type_info(__n) { }
+
+    virtual
+    ~__class_type_info ();
+
+    // Implementation defined types.
+    // The type sub_kind tells us about how a base object is contained
+    // within a derived object. We often do this lazily, hence the
+    // UNKNOWN value. At other times we may use NOT_CONTAINED to mean
+    // not publicly contained.
+    enum __sub_kind
+      {
+    // We have no idea.
+    __unknown = 0,
+
+    // Not contained within us (in some circumstances this might
+    // mean not contained publicly)
+    __not_contained,
+
+    // Contained ambiguously.
+    __contained_ambig,
+
+    // Via a virtual path.
+    __contained_virtual_mask = __base_class_type_info::__virtual_mask,
+
+    // Via a public path.
+    __contained_public_mask = __base_class_type_info::__public_mask,
+
+    // Contained within us.
+    __contained_mask = 1 << __base_class_type_info::__hwm_bit,
+
+    __contained_private = __contained_mask,
+    __contained_public = __contained_mask | __contained_public_mask
+      };
+
+    struct __upcast_result;
+    struct __dyncast_result;
+
+  protected:
+    // Implementation defined member functions.
+    virtual bool
+    __do_upcast(const __class_type_info* __dst_type, void**__obj_ptr) const;
+
+    virtual bool
+    __do_catch(const type_info* __thr_type, void** __thr_obj,
+           unsigned __outer) const;
+
+  public:
+    // Helper for upcast. See if DST is us, or one of our bases.
+    // Return false if not found, true if found.
+    virtual bool
+    __do_upcast(const __class_type_info* __dst, const void* __obj,
+        __upcast_result& __restrict __result) const;
+
+    // Indicate whether SRC_PTR of type SRC_TYPE is contained publicly
+    // within OBJ_PTR. OBJ_PTR points to a base object of our type,
+    // which is the destination type. SRC2DST indicates how SRC
+    // objects might be contained within this type.  If SRC_PTR is one
+    // of our SRC_TYPE bases, indicate the virtuality. Returns
+    // not_contained for non containment or private containment.
+    inline __sub_kind
+    __find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+              const __class_type_info* __src_type,
+              const void* __src_ptr) const;
+
+    // Helper for dynamic cast. ACCESS_PATH gives the access from the
+    // most derived object to this base. DST_TYPE indicates the
+    // desired type we want. OBJ_PTR points to a base of our type
+    // within the complete object. SRC_TYPE indicates the static type
+    // started from and SRC_PTR points to that base within the most
+    // derived object. Fill in RESULT with what we find. Return true
+    // if we have located an ambiguous match.
+    virtual bool
+    __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+         const __class_type_info* __dst_type, const void* __obj_ptr,
+         const __class_type_info* __src_type, const void* __src_ptr,
+         __dyncast_result& __result) const;
+
+    // Helper for find_public_subobj. SRC2DST indicates how SRC_TYPE
+    // bases are inherited by the type started from -- which is not
+    // necessarily the current type. The current type will be a base
+    // of the destination type.  OBJ_PTR points to the current base.
+    virtual __sub_kind
+    __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+             const __class_type_info* __src_type,
+             const void* __src_ptr) const;
+  };
+
+  // Type information for a class with a single non-virtual base.
+  class __si_class_type_info : public __class_type_info
+  {
+  public:
+    const __class_type_info* __base_type;
+
+    explicit
+    __si_class_type_info(const char *__n, const __class_type_info *__base)
+    : __class_type_info(__n), __base_type(__base) { }
+
+    virtual
+    ~__si_class_type_info();
+
+  protected:
+    __si_class_type_info(const __si_class_type_info&);
+
+    __si_class_type_info&
+    operator=(const __si_class_type_info&);
+
+    // Implementation defined member functions.
+    virtual bool
+    __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+         const __class_type_info* __dst_type, const void* __obj_ptr,
+         const __class_type_info* __src_type, const void* __src_ptr,
+         __dyncast_result& __result) const;
+
+    virtual __sub_kind
+    __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+             const __class_type_info* __src_type,
+             const void* __sub_ptr) const;
+
+    virtual bool
+    __do_upcast(const __class_type_info*__dst, const void*__obj,
+        __upcast_result& __restrict __result) const;
+  };
+
+  // Type information for a class with multiple and/or virtual bases.
+  class __vmi_class_type_info : public __class_type_info
+  {
+  public:
+    unsigned int        __flags;  // Details about the class hierarchy.
+    unsigned int        __base_count;  // Number of direct bases.
+
+    // The array of bases uses the trailing array struct hack so this
+    // class is not constructable with a normal constructor. It is
+    // internally generated by the compiler.
+    __base_class_type_info  __base_info[1];  // Array of bases.
+
+    explicit
+    __vmi_class_type_info(const char* __n, int ___flags)
+    : __class_type_info(__n), __flags(___flags), __base_count(0) { }
+
+    virtual
+    ~__vmi_class_type_info();
+
+    // Implementation defined types.
+    enum __flags_masks
+      {
+    __non_diamond_repeat_mask = 0x1, // Distinct instance of repeated base.
+    __diamond_shaped_mask = 0x2, // Diamond shaped multiple inheritance.
+    __flags_unknown_mask = 0x10
+      };
+
+  protected:
+    // Implementation defined member functions.
+    virtual bool
+    __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+         const __class_type_info* __dst_type, const void* __obj_ptr,
+         const __class_type_info* __src_type, const void* __src_ptr,
+         __dyncast_result& __result) const;
+
+    virtual __sub_kind
+    __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+             const __class_type_info* __src_type,
+             const void* __src_ptr) const;
+
+    virtual bool
+    __do_upcast(const __class_type_info* __dst, const void* __obj,
+        __upcast_result& __restrict __result) const;
+  };
+
+  // Dynamic cast runtime.
+  // src2dst has the following possible values
+  //  >-1: src_type is a unique public non-virtual base of dst_type
+  //       dst_ptr + src2dst == src_ptr
+  //   -1: unspecified relationship
+  //   -2: src_type is not a public base of dst_type
+  //   -3: src_type is a multiple public non-virtual base of dst_type
+  extern "C" void*
+  __dynamic_cast(const void* __src_ptr, // Starting object.
+         const __class_type_info* __src_type, // Static type of object.
+         const __class_type_info* __dst_type, // Desired target type.
+         ptrdiff_t __src2dst); // How src and dst are related.
+
+
+  // Returns the type_info for the currently handled exception [15.3/8], or
+  // null if there is none.
+  extern "C" std::type_info*
+  __cxa_current_exception_type();
+} // namespace __cxxabiv1
+
+// User programs should use the alias `abi'.
+namespace abi = __cxxabiv1;
+
+
+#endif // __RTTI_H
diff --git a/bridges/source/cpp_uno/gcc3_wasm/share.hxx b/bridges/source/cpp_uno/gcc3_wasm/share.hxx
new file mode 100644
index 000000000000..65461d7fd37f
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/share.hxx
@@ -0,0 +1,57 @@
+/* -*- 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 <typeinfo>
+#include <exception>
+#include <cstddef>
+
+// from opensource.apple.com: libcppabi-24.4/include/rtti.h
+#include "rtti.h"
+
+// from opensource.apple.com: libcppabi-24.4/include/unwind-cxx.h
+#include "unwind-cxx.h"
+
+// Import the __cxxabiv1 a.k.a. "abi" namespace
+using namespace abi;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+    void dummy_can_throw_anything( char const * );
+
+    void raiseException(
+        uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+    void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+    bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive = false);
+}
+
+namespace arm
+{
+    enum armlimits {
+        MAX_GPR_REGS = 8,
+        MAX_FPR_REGS = 8
+    };
+    bool return_in_x8( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
new file mode 100644
index 000000000000..38ee3c1208b8
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
@@ -0,0 +1,537 @@
+/* -*- 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 <sal/config.h>
+
+#include <exception>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace arm
+{
+    bool is_hfa_struct(const typelib_TypeDescription * type)
+    {
+        const typelib_CompoundTypeDescription * p
+            = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+        if (p->nMembers >= 4)
+            return false;
+        for (sal_Int32 i = 0; i < p->nMembers; ++i)
+        {
+            if ((p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_FLOAT &&
+                 p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_DOUBLE) ||
+                p->ppTypeRefs[i]->eTypeClass != p->ppTypeRefs[0]->eTypeClass)
+                return false;
+        }
+        return true;
+    }
+
+    bool return_in_x8( 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 x0, x1
+            bool bRet = pTypeDescr->nSize > 16;
+
+            if (is_hfa_struct(pTypeDescr))
+                bRet = false;
+
+            TYPELIB_DANGER_RELEASE( pTypeDescr );
+            return bRet;
+        }
+        return true;
+    }
+}
+
+void MapReturn(sal_uInt64 x0, sal_uInt64 x1, double d0, typelib_TypeDescriptionReference *pReturnType, sal_uInt64 *pRegisterReturn)
+{
+    switch( pReturnType->eTypeClass )
+    {
+    case typelib_TypeClass_HYPER:
+    case typelib_TypeClass_UNSIGNED_HYPER:
+        pRegisterReturn[1] = x1;
+        [[fallthrough]];
+    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:
+        pRegisterReturn[0] = x0;
+        break;
+    case typelib_TypeClass_FLOAT:
+        *(float*)pRegisterReturn = *(float*)&d0;
+        break;
+    case typelib_TypeClass_DOUBLE:
+        *(double*)pRegisterReturn = d0;
+        break;
+    case typelib_TypeClass_STRUCT:
+    case typelib_TypeClass_EXCEPTION:
+        if (!arm::return_in_x8(pReturnType))
+        {
+            pRegisterReturn[0] = x0;
+            pRegisterReturn[1] = x1;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+namespace
+{
+void callVirtualMethod(
+    void *pThis,
+    sal_Int32 nVtableIndex,
+    void *pRegisterReturn,
+    typelib_TypeDescriptionReference *pReturnType,
+    sal_uInt64 *pStack,
+    int nStack,
+    sal_uInt64 *pGPR,
+    double *pFPR)
+{
+    // never called
+    if (! pThis)
+        CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+    if ( nStack )
+    {
+        // 16-bytes aligned
+        sal_uInt32 nStackBytes = ( ( nStack + 3 ) >> 2 ) * 16;
+        sal_uInt32 *stack = (sal_uInt32 *) alloca( nStackBytes );
+        memcpy( stack, pStack, nStackBytes );
+    }
+
+    sal_uInt64 pMethod = *((sal_uInt64*)pThis);
+    pMethod += 8 * nVtableIndex;
+    pMethod = *((sal_uInt64 *)pMethod);
+
+    // For value returned in registers
+    sal_uInt64 x0;
+    sal_uInt64 x1;
+    double d0;
+
+    // TODO: this is all dummy
+
+    MapReturn(x0, x1, d0, pReturnType, (sal_uInt64 *) pRegisterReturn);
+}
+}
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+        if ( nr < arm::MAX_GPR_REGS ) \
+                pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+        else \
+                *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+        if ( nr < arm::MAX_GPR_REGS ) \
+                pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+        else \
+                *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+        if ( nr < arm::MAX_GPR_REGS ) \
+                pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+        else \
+                *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+        if ( nr < arm::MAX_GPR_REGS ) \
+                pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+        else \
+                *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS ) \
+        if ( nr < arm::MAX_FPR_REGS ) \
+                pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+        else \
+                *pDS++ = *reinterpret_cast<double *>( pSV );
+
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
+        INSERT_DOUBLE( pSV, nr, pGPR, pDS )
+
+namespace {
+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: values|ptr ...
+    sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+2) * sizeof(sal_Int64) );
+    sal_uInt64 * pStackStart = pStack;
+
+    sal_uInt64 pGPR[arm::MAX_GPR_REGS];
+    int nGPR = 0;
+
+    // storage and counter for SIMD/FP registers
+    double pFPR[arm::MAX_FPR_REGS];
+    int nFPR = 0;
+
+    // return
+    typelib_TypeDescription * pReturnTypeDescr = 0;
+    TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+    assert( pReturnTypeDescr);
+
+    void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+    if (pReturnTypeDescr)
+    {
+        if (!arm::return_in_x8( pReturnTypeRef ) )
+            pCppReturn = pUnoReturn; // direct way for simple types
+        else
+        {
+            // complex return via x8
+            pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+                    ? alloca( pReturnTypeDescr->nSize )
+                    : pUnoReturn); // direct way
+        }
+    }
+    // push this
+    void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+        + aVtableSlot.offset;
+    INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+    // stack space
+    // args
+    void ** pCppArgs  = (void **)alloca( sizeof(void *) * nParams );
+
+    // indices of values this have to be converted (interface conversion cpp<=>uno)
+    int * pTempIndices = (int *)alloca( sizeof(int) * nParams );
+
+    // type descriptions for reconversions
+    typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)alloca( sizeof(void *) * 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_HYPER:
+            case typelib_TypeClass_UNSIGNED_HYPER:
+                INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
+                break;
+            case typelib_TypeClass_LONG:
+            case typelib_TypeClass_UNSIGNED_LONG:
+            case typelib_TypeClass_ENUM:
+                INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+                break;
+            case typelib_TypeClass_SHORT:
+            case typelib_TypeClass_CHAR:
+            case typelib_TypeClass_UNSIGNED_SHORT:
+                INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+                break;
+            case typelib_TypeClass_BOOLEAN:
+            case typelib_TypeClass_BYTE:
+                INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+                break;
+            case typelib_TypeClass_FLOAT:
+                INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR, pStack );
+                break;
+            case typelib_TypeClass_DOUBLE:
+                INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, 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]), nGPR, pGPR, pStack );
+        }
+    }
+
+    assert( nGPR <= arm::MAX_GPR_REGS );
+    assert( nFPR <= arm::MAX_FPR_REGS );
+
+    try
+    {
+        try {
+            callVirtualMethod(
+                pAdjustedThisPtr, aVtableSlot.index,
+                pCppReturn, pReturnTypeRef,
+                pStackStart,
+                (pStack - pStackStart),
+                pGPR,
+                pFPR);
+        } 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);
+#if OSL_DEBUG_LEVEL > 0
+    typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+    switch (pMemberDescr->eTypeClass)
+    {
+    case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+    {
+#if OSL_DEBUG_LEVEL > 0
+        // determine vtable call index
+        sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+        assert( nMemberPos < pTypeDescr->nAllMembers && "### member pos out of range!");
+#endif
+
+        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;
+            cpp_call(
+                pThis, aVtableSlot, // get, then set method
+                pReturnTypeRef,
+                1, &aParam,
+                pReturn, pArgs, ppException );
+
+            typelib_typedescriptionreference_release( pReturnTypeRef );
+        }
+
+        break;
+    }
+    case typelib_TypeClass_INTERFACE_METHOD:
+    {
+#if OSL_DEBUG_LEVEL > 0
+        // determine vtable call index
+        sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+        assert(nMemberPos < pTypeDescr->nAllMembers && "### member pos out of range!");
+#endif
+
+        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->getBridge()->getUnoEnv()->getRegisteredInterface)(
+                    pThis->getBridge()->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()
+        [[fallthrough]];
+        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<decltype(aExc)>::get();
+        // binary identical null reference
+        ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+    }
+    }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/unwind-cxx.h b/bridges/source/cpp_uno/gcc3_wasm/unwind-cxx.h
new file mode 100644
index 000000000000..8b81d9f4aa7a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/unwind-cxx.h
@@ -0,0 +1,283 @@
+// -*- C++ -*- Exception handling and frame unwind runtime interface routines.
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+// This is derived from the C++ ABI for IA-64.  Where we diverge
+// for cross-architecture compatibility are noted with "@@@".
+
+#ifndef _UNWIND_CXX_H
+#define _UNWIND_CXX_H 1
+
+// Level 2: C++ ABI
+
+#include <typeinfo>
+#include <exception>
+
+#include <stddef.h>
+#include "unwind.h"
+
+
+typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+typedef signed   _Unwind_Sword __attribute__((__mode__(__word__)));
+typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+//typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
+//typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+
+#pragma GCC visibility push(default)
+
+namespace __cxxabiv1
+{
+
+// A C++ exception object consists of a header, which is a wrapper around
+// an unwind object header with additional C++ specific information,
+// followed by the exception object itself.
+
+struct __cxa_exception
+{
+#if __LP64__
+#if 0
+    // This is a new field added with LLVM 10
+    // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+    // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility".  The HACK in
+    // fillUnoException (bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx) tries to find out at
+    // runtime whether a __cxa_exception has this member.  Once we can be sure that we only run
+    // against new libcxxabi that has this member, we can drop the "#if 0" here and drop the hack
+    // in fillUnoException.
+
+    // Now _Unwind_Exception is marked with __attribute__((aligned)),
+    // which implies __cxa_exception is also aligned. Insert padding
+    // in the beginning of the struct, rather than before unwindHeader.
+    void *reserve;
+#endif
+
+	// This is a new field to support C++ 0x exception_ptr.
+	// For binary compatibility it is at the start of this
+	// struct which is prepended to the object thrown in
+	// __cxa_allocate_exception.
+  size_t referenceCount;
+#endif
+  // Manage the exception object itself.
+  std::type_info *exceptionType;
+  void (*exceptionDestructor)(void *); 
+
+  // The C++ standard has entertaining rules wrt calling set_terminate
+  // and set_unexpected in the middle of the exception cleanup process.
+  void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+  std::terminate_handler terminateHandler;
+
+  // The caught exception stack threads through here.
+  __cxa_exception *nextException;
+
+  // How many nested handlers have caught this exception.  A negated
+  // value is a signal that this object has been rethrown.
+  int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+  // Stack of exceptions in cleanups.
+  __cxa_exception* nextPropagatingException;
+
+  // The number of active cleanup handlers for this exception.
+  int propagationCount;
+#else
+  // Cache parsed handler data from the personality routine Phase 1
+  // for Phase 2 and __cxa_call_unexpected.
+  int handlerSwitchValue;
+  const unsigned char *actionRecord;
+  const unsigned char *languageSpecificData;
+  _Unwind_Ptr catchTemp;
+  void *adjustedPtr;
+#endif
+#if !__LP64__
+	// This is a new field to support C++ 0x exception_ptr.
+	// For binary compatibility it is placed where the compiler
+	// previously adding padded to 64-bit align unwindHeader.
+  size_t referenceCount;
+#endif
+
+  // The generic exception header.  Must be last.
+  _Unwind_Exception unwindHeader;
+};
+
+// Each thread in a C++ program has access to a __cxa_eh_globals object.
+struct __cxa_eh_globals
+{
+  __cxa_exception *caughtExceptions;
+  unsigned int uncaughtExceptions;
+#ifdef __ARM_EABI_UNWINDER__
+  __cxa_exception* propagatingExceptions;
+#endif
+};
+
+
+// The __cxa_eh_globals for the current thread can be obtained by using
+// either of the following functions.  The "fast" version assumes at least
+// one prior call of __cxa_get_globals has been made from the current
+// thread, so no initialization is necessary.
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
+
+// Allocate memory for the exception plus the thrown object.
+extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw();
+
+// Free the space allocated for the exception.
+extern "C" void __cxa_free_exception(void *thrown_exception) throw();
+
+#pragma GCC visibility push(hidden)
+extern "C" void *__cxa_allocate_dependent_exception() throw();
+extern "C" void __cxa_free_dependent_exception(void *thrown_exception) throw();
+#pragma GCC visibility pop
+
+// Throw the exception.
+extern "C" void __cxa_throw (void *thrown_exception,
+                             std::type_info *tinfo,
+                             void (*dest) (void *))
+     __attribute__((noreturn));
+
+// Used to implement exception handlers.
+extern "C" void *__cxa_get_exception_ptr (void *) throw();
+extern "C" void *__cxa_begin_catch (void *) throw();
+extern "C" void __cxa_end_catch ();
+extern "C" void __cxa_rethrow () __attribute__((noreturn));
+
+// These facilitate code generation for recurring situations.
+extern "C" void __cxa_bad_cast ();
+extern "C" void __cxa_bad_typeid ();
+
+// @@@ These are not directly specified by the IA-64 C++ ABI.
+
+// Handles re-checking the exception specification if unexpectedHandler
+// throws, and if bad_exception needs to be thrown.  Called from the
+// compiler.
+extern "C" void __cxa_call_unexpected (void *) __attribute__((noreturn));
+extern "C" void __cxa_call_terminate (void*) __attribute__((noreturn));
+
+#ifdef __ARM_EABI_UNWINDER__
+// Arm EABI specified routines.
+typedef enum {
+  ctm_failed = 0,
+  ctm_succeeded = 1,
+  ctm_succeeded_with_ptr_to_base = 2
+} __cxa_type_match_result;
+extern "C" bool __cxa_type_match(_Unwind_Exception*, const std::type_info*,
+				 bool, void**);
+extern "C" void __cxa_begin_cleanup (_Unwind_Exception*);
+extern "C" void __cxa_end_cleanup (void);
+#endif
+
+// These are explicitly GNU C++ specific.
+
+// Acquire the C++ exception header from the C++ object.
+static inline __cxa_exception *
+__get_exception_header_from_obj (void *ptr)
+{
+  return reinterpret_cast<__cxa_exception *>(ptr) - 1;
+}
+
+// Acquire the C++ exception header from the generic exception header.
+static inline __cxa_exception *
+__get_exception_header_from_ue (_Unwind_Exception *exc)
+{
+  return reinterpret_cast<__cxa_exception *>(exc + 1) - 1;
+}
+
+#ifdef __ARM_EABI_UNWINDER__
+static inline bool
+__is_gxx_exception_class(_Unwind_Exception_Class c)
+{
+  // TODO: Take advantage of the fact that c will always be word aligned.
+  return c[0] == 'G'
+	 && c[1] == 'N'
+	 && c[2] == 'U'
+	 && c[3] == 'C'
+	 && c[4] == 'C'
+	 && c[5] == '+'
+	 && c[6] == '+';
+}
+
+static inline void
+__GXX_INIT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
+{
+  c[0] = 'G';
+  c[1] = 'N';
+  c[2] = 'U';
+  c[3] = 'C';
+  c[4] = 'C';
+  c[5] = '+';
+  c[6] = '+';
+  c[7] = '\0';
+}
+
+static inline void*
+__gxx_caught_object(_Unwind_Exception* eo)
+{
+  return (void*)eo->barrier_cache.bitpattern[0];
+}
+#else // !__ARM_EABI_UNWINDER__
+// This is the exception class we report -- "GNUCC++\0".
+const _Unwind_Exception_Class __gxx_exception_class
+= ((((((((_Unwind_Exception_Class) 'G' 
+	 << 8 | (_Unwind_Exception_Class) 'N')
+	<< 8 | (_Unwind_Exception_Class) 'U')
+       << 8 | (_Unwind_Exception_Class) 'C')
+      << 8 | (_Unwind_Exception_Class) 'C')
+     << 8 | (_Unwind_Exception_Class) '+')
+    << 8 | (_Unwind_Exception_Class) '+')
+   << 8 | (_Unwind_Exception_Class) '\0');
+
+static inline bool
+__is_gxx_exception_class(_Unwind_Exception_Class c)
+{
+  return (c & ((_Unwind_Exception_Class)~0 << 8)) == __gxx_exception_class;
+}
+
+#define __GXX_INIT_EXCEPTION_CLASS(c) c = __gxx_exception_class
+
+// GNU C++ personality routine, Version 0.
+extern "C" _Unwind_Reason_Code __gxx_personality_v0
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *);
+
+// GNU C++ sjlj personality routine, Version 0.
+extern "C" _Unwind_Reason_Code __gxx_personality_sj0
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *);
+
+static inline void*
+__gxx_caught_object(_Unwind_Exception* eo)
+{
+  __cxa_exception* header = __get_exception_header_from_ue (eo);
+  return header->adjustedPtr;
+}
+#endif // !__ARM_EABI_UNWINDER__
+
+} /* namespace __cxxabiv1 */
+
+#pragma GCC visibility pop
+
+#endif // _UNWIND_CXX_H
diff --git a/bridges/source/cpp_uno/gcc3_wasm/wasm_helper.s b/bridges/source/cpp_uno/gcc3_wasm/wasm_helper.s
new file mode 100644
index 000000000000..12308f1a9855
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/wasm_helper.s
@@ -0,0 +1,233 @@
+// -*- Mode: Asm; tab-width: 4; tab-stop-list: (4 12 32); comment-column: 30; comment-start: "// "; indent-tabs-mode: nil -*-
+//
+// 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 .
+//
+    .section        __TEXT,__text,regular,pure_instructions
+
+    .p2align        2
+codeSnippet_0_0:
+    mov x14, 0
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_0_1:
+    mov x14, 0
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_0_2:
+    mov x14, 0
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_0_3:
+    mov x14, 0
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_1_0:
+    mov x14, 1
+    mov x15, 0
+    b _privateSnippetExecutor
+    .long 0x000001
+    .long 0
+codeSnippet_1_1:
+    mov x14, 1
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_1_2:
+    mov x14, 1
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_1_3:
+    mov x14, 1
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_2_0:
+    mov x14, 2
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_2_1:
+    mov x14, 2
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_2_2:
+    mov x14, 2
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_2_3:
+    mov x14, 2
+    mov x15, 3
+    b _privateSnippetExecutor
+    .long 0x000002
+    .long 3
+codeSnippet_3_0:
+    mov x14, 3
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_3_1:
+    mov x14, 3
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_3_2:
+    mov x14, 3
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_3_3:
+    mov x14, 3
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_4_0:
+    mov x14, 4
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_4_1:
+    mov x14, 4
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_4_2:
+    mov x14, 4
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_4_3:
+    mov x14, 4
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_5_0:
+    mov x14, 5
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_5_1:
+    mov x14, 5
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_5_2:
+    mov x14, 5
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_5_3:
+    mov x14, 5
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_6_0:
+    mov x14, 6
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_6_1:
+    mov x14, 6
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_6_2:
+    mov x14, 6
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_6_3:
+    mov x14, 6
+    mov x15, 3
+    b _privateSnippetExecutor
+codeSnippet_7_0:
+    mov x14, 7
+    mov x15, 0
+    b _privateSnippetExecutor
+codeSnippet_7_1:
+    mov x14, 7
+    mov x15, 1
+    b _privateSnippetExecutor
+codeSnippet_7_2:
+    mov x14, 7
+    mov x15, 2
+    b _privateSnippetExecutor
+codeSnippet_7_3:
+    mov x14, 7
+    mov x15, 3
+    b _privateSnippetExecutor
+
+    .globl _codeSnippets
+_codeSnippets:
+    .long codeSnippet_0_0 - _codeSnippets
+    .long codeSnippet_0_1 - _codeSnippets
+    .long codeSnippet_0_2 - _codeSnippets
+    .long codeSnippet_0_3 - _codeSnippets
+    .long codeSnippet_1_0 - _codeSnippets
+    .long codeSnippet_1_1 - _codeSnippets
+    .long codeSnippet_1_2 - _codeSnippets
+    .long codeSnippet_1_3 - _codeSnippets
+    .long codeSnippet_2_0 - _codeSnippets
+    .long codeSnippet_2_1 - _codeSnippets
+    .long codeSnippet_2_2 - _codeSnippets
+    .long codeSnippet_2_3 - _codeSnippets
+    .long codeSnippet_3_0 - _codeSnippets
+    .long codeSnippet_3_1 - _codeSnippets
+    .long codeSnippet_3_2 - _codeSnippets
+    .long codeSnippet_3_3 - _codeSnippets
+    .long codeSnippet_4_0 - _codeSnippets
+    .long codeSnippet_4_1 - _codeSnippets
+    .long codeSnippet_4_2 - _codeSnippets
+    .long codeSnippet_4_3 - _codeSnippets
+    .long codeSnippet_5_0 - _codeSnippets
+    .long codeSnippet_5_1 - _codeSnippets
+    .long codeSnippet_5_2 - _codeSnippets
+    .long codeSnippet_5_3 - _codeSnippets
+    .long codeSnippet_6_0 - _codeSnippets
+    .long codeSnippet_6_1 - _codeSnippets
+    .long codeSnippet_6_2 - _codeSnippets
+    .long codeSnippet_6_3 - _codeSnippets
+    .long codeSnippet_7_0 - _codeSnippets
+    .long codeSnippet_7_1 - _codeSnippets
+    .long codeSnippet_7_2 - _codeSnippets
+    .long codeSnippet_7_3 - _codeSnippets
+
+
+
+    .private_extern _privateSnippetExecutor
+    .globl  _privateSnippetExecutor
+    .p2align        2
+_privateSnippetExecutor:
+    .cfi_startproc
+    .cfi_def_cfa w29, 16
+    .cfi_offset w30, -8
+    .cfi_offset w29, -16
+
+    // _privateSnippetExecutor is jumped to from codeSnippet_*
+
+    // push all GP, FP/SIMD registers to the stack
+    stp x6, x7, [sp, #-16]!
+    stp x4, x5, [sp, #-16]!
+    stp x2, x3, [sp, #-16]!
+    stp x0, x1, [sp, #-16]!
+    stp d6, d7, [sp, #-16]!
+    stp d4, d5, [sp, #-16]!
+    stp d2, d3, [sp, #-16]!
+    stp d0, d1, [sp, #-16]!
+
+    // push x8 (RC pointer) and lr to stack
+    stp     x8, lr, [sp, #-16]!
+
+    // First argument (x15 set up in the codeSnippet instance)
+    // Second argument: The pointer to all the above
+    mov x0, x14
+    mov x1, x15
+    mov x2, sp
+    bl  _cpp_vtable_call
+
+    // restore x8 (RC pointer) and lr (skip RC from cpp_vtable_call)
+    ldp x8, lr, [sp, #0]
+
+    // restore stack
+    add sp, sp, #144
+
+    // continue with throw/catch
+    ret lr
+    .cfi_endproc
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/cppu/source/uno/lbenv.cxx b/cppu/source/uno/lbenv.cxx
index 01d5a2bab1df..c9a2d89933d5 100644
--- a/cppu/source/uno/lbenv.cxx
+++ b/cppu/source/uno/lbenv.cxx
@@ -1002,7 +1002,6 @@ void EnvironmentsData::getRegisteredEnvironments(
 bool loadEnv(OUString const  & cLibStem,
                     uno_Environment * pEnv)
 {
-#ifndef __EMSCRIPTEN__
 #ifdef DISABLE_DYNLOADING
     uno_initEnvironmentFunc fpInit;
 
@@ -1042,11 +1041,6 @@ bool loadEnv(OUString const  & cLibStem,
 
     (*fpInit)( pEnv ); // init of environment
     return true;
-#else
-    (void)cLibStem;
-    (void)pEnv;
-    return false;
-#endif
 }
 
 }
diff --git a/cppu/source/uno/lbmap.cxx b/cppu/source/uno/lbmap.cxx
index 850633817048..6906be3ea71f 100644
--- a/cppu/source/uno/lbmap.cxx
+++ b/cppu/source/uno/lbmap.cxx
@@ -329,10 +329,8 @@ static void setNegativeBridge( const OUString & rBridgeName )
 
 static uno_ext_getMappingFunc selectMapFunc( const OUString & rBridgeName )
 {
-#ifndef EMSCRIPTEN
     if (rBridgeName.equalsAscii( CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" ))
         return CPPU_ENV_uno_ext_getMapping;
-#endif
 #if HAVE_FEATURE_JAVA
     if (rBridgeName.equalsAscii( "java" "_uno" ))
         return java_uno_ext_getMapping;
@@ -424,6 +422,7 @@ static Mapping loadExternalMapping(
             OSL_ASSERT( aExt.is() );
             if (aExt.is())
                 return aExt;
+            SAL_INFO("cppu", "Could not load external mapping for " << aName);
         }
 #else
         // find proper lib


More information about the Libreoffice-commits mailing list