Repository.mk                                      |    2 
 bridges/CustomTarget_gcc3_wasm.mk                  |   26 
 bridges/Library_cpp_uno.mk                         |    6 
 bridges/Module_bridges.mk                          |    1 
 bridges/inc/wasm/callvirtualfunction.hxx           |   21 
 bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx       |  226 +++++++
 offapi/UnoApi_offapi.mk                            |    2 
 offapi/org/libreoffice/embindtest/StructLong.idl   |   18 
 offapi/org/libreoffice/embindtest/StructString.idl |   18 
 offapi/org/libreoffice/embindtest/XTest.idl        |    4 
 solenv/gbuild/extensions/pre_BuildTools.mk         |    2 
 static/Executable_wasmcallgen.mk                   |   26 
 static/Module_static.mk                            |    1 
 static/source/wasmcallgen/wasmcallgen.cxx          |  610 +++++++++++++++++++++
 unotest/source/embindtest/embindtest.cxx           |   23 
 unotest/source/embindtest/embindtest.js            |  330 +++++++++++
 16 files changed, 1313 insertions(+), 3 deletions(-)

New commits:
commit a469aea9c0b532d928cd41e389c9c51de1af06f0
Author:     Stephan Bergmann <stephan.bergm...@allotropia.de>
AuthorDate: Wed May 8 09:46:55 2024 +0200
Commit:     Stephan Bergmann <stephan.bergm...@allotropia.de>
CommitDate: Wed May 8 13:01:04 2024 +0200

    Emscripten: Towards a working C++ UNO bridge
    
    ...by making the general UNO -> C++ function call case work (modulo handling
    exceptions, which I'll look into later).
    
    Wasm call_indirect unfortunately needs to statically know the call target's
    signature, so we statically need to know all possible signatures.  So 
introduce
    wasmcallgen helper to scan the existing UNOIDL API upfront and generate the
    relevant callvirtualfunction-wrapper.cxx and callvirtualfunction-inst.s 
code.
    (The good thing is that the number of different signatures is somewhat 
limited,
    each parameter can only be one of i32, i64, f32, or f64.  So even if 
3rd-party
    extensions bring along new UNOIDL interface methods, chances are relatively 
high
    that the signatures needed for them would already be covered by the existing
    ones.)
    
    Testing this can nicely be done in unotest/source/embindtest/embindtest.js 
via
    css.script.Invocation (which internally exercises the relevant code).  
(Instead
    of adding individual org.libreoffice.embindtest.StructLong/String etc., it 
would
    be nicer to introduce some polymorphic StructOne<T>, but the Emind UNO 
binding
    does not support polymorphic structs, so the embindtest.js code would not 
work.)
    
    Change-Id: If829c9e3772bfd27561f3ad743d38a71d11545b6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167308
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>
    Tested-by: Jenkins

diff --git a/Repository.mk b/Repository.mk
index e910b6d572b7..b6ebf64dcf39 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -33,7 +33,7 @@ $(eval $(call gb_Helper_register_executables,NONE, \
        concat-deps \
        cpp \
        cppunittester \
-       $(if $(or $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),$(filter 
EMSCRIPTEN,$(OS))),embindmaker) \
+       $(if $(or $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),$(filter 
EMSCRIPTEN,$(OS))),embindmaker wasmcallgen) \
        gbuildtojson \
        $(if $(filter MSC,$(COM)), \
                gcc-wrapper \
diff --git a/bridges/CustomTarget_gcc3_wasm.mk 
b/bridges/CustomTarget_gcc3_wasm.mk
new file mode 100644
index 000000000000..a88da8577282
--- /dev/null
+++ b/bridges/CustomTarget_gcc3_wasm.mk
@@ -0,0 +1,26 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,bridges/gcc3_wasm))
+
+$(eval $(call gb_CustomTarget_register_targets,bridges/gcc3_wasm, \
+    callvirtualfunction-wrapper.cxx \
+    callvirtualfunction-impls.s \
+))
+
+$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-impls.s \
+$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-wrapper.cxx: \
+        $(call gb_Executable_get_target_for_build,wasmcallgen) $(call 
gb_UnoApi_get_target,udkapi) \
+        $(call gb_UnoApi_get_target,offapi)
+       $(call gb_Executable_get_command,wasmcallgen) \
+        
$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-wrapper.cxx \
+        
$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-impls.s \
+        +$(call gb_UnoApi_get_target,udkapi) +$(call 
gb_UnoApi_get_target,offapi)
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk
index dcf83cf34e5b..c42778f359c1 100644
--- a/bridges/Library_cpp_uno.mk
+++ b/bridges/Library_cpp_uno.mk
@@ -84,6 +84,12 @@ bridge_noopt_objects := except
 else ifeq ($(OS),EMSCRIPTEN)
 bridges_SELECTED_BRIDGE := gcc3_wasm
 bridge_noopt_objects := cpp2uno except uno2cpp
+$(eval $(call gb_Library_add_generated_asmobjects,$(CPPU_ENV)_uno, \
+    CustomTarget/bridges/gcc3_wasm/callvirtualfunction-impls \
+))
+$(eval $(call gb_Library_add_generated_exception_objects,$(CPPU_ENV)_uno, \
+    CustomTarget/bridges/gcc3_wasm/callvirtualfunction-wrapper \
+))
 endif
 
 else ifeq ($(CPUNAME),M68K)
diff --git a/bridges/Module_bridges.mk b/bridges/Module_bridges.mk
index 3016bf2c404f..def86fea4cb7 100644
--- a/bridges/Module_bridges.mk
+++ b/bridges/Module_bridges.mk
@@ -20,6 +20,7 @@ $(eval $(call gb_Module_add_targets,bridges,\
                $(if $(filter ANDROID LINUX,$(OS)),\
                        CustomTarget_gcc3_linux_arm) \
        ) \
+       $(if $(filter EMSCRIPTEN,$(OS)),CustomTarget_gcc3_wasm) \
 ))
 
 ifeq (,$(filter build,$(gb_Module_SKIPTARGETS)))
diff --git a/bridges/inc/wasm/callvirtualfunction.hxx 
b/bridges/inc/wasm/callvirtualfunction.hxx
new file mode 100644
index 000000000000..23b446cd45b3
--- /dev/null
+++ b/bridges/inc/wasm/callvirtualfunction.hxx
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <sal/types.h>
+
+void callVirtualFunction(std::string_view signature, sal_uInt32 target, 
sal_uInt64 const* arguments,
+                         void* returnValue);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx 
b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
index ddb51166b51e..41a471bcc9b0 100644
--- a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
+++ b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
@@ -7,15 +7,81 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include <sal/config.h>
+
+#include <vector>
+
 #include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Type.hxx>
+#include <o3tl/unreachable.hxx>
+#include <rtl/strbuf.hxx>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
 
 #include <bridge.hxx>
 #include <types.hxx>
 #include <unointerfaceproxy.hxx>
 #include <vtables.hxx>
 
+#include <wasm/callvirtualfunction.hxx>
+
 using namespace ::com::sun::star::uno;
 
+namespace
+{
+enum class StructKind
+{
+    Empty,
+    I32,
+    I64,
+    F32,
+    F64,
+    General
+};
+
+StructKind getKind(typelib_CompoundTypeDescription const* type)
+{
+    if (type->nMembers > 1)
+    {
+        return StructKind::General;
+    }
+    auto k = StructKind::Empty;
+    if (type->pBaseTypeDescription != nullptr)
+    {
+        k = getKind(type->pBaseTypeDescription);
+    }
+    if (type->nMembers == 0)
+    {
+        return k;
+    }
+    if (k != StructKind::Empty)
+    {
+        return StructKind::General;
+    }
+    switch (type->ppTypeRefs[0]->eTypeClass)
+    {
+        case typelib_TypeClass_BOOLEAN:
+        case typelib_TypeClass_BYTE:
+        case typelib_TypeClass_SHORT:
+        case typelib_TypeClass_UNSIGNED_SHORT:
+        case typelib_TypeClass_LONG:
+        case typelib_TypeClass_UNSIGNED_LONG:
+        case typelib_TypeClass_CHAR:
+        case typelib_TypeClass_ENUM:
+            return StructKind::I32;
+        case typelib_TypeClass_HYPER:
+        case typelib_TypeClass_UNSIGNED_HYPER:
+            return StructKind::I64;
+        case typelib_TypeClass_FLOAT:
+            return StructKind::F32;
+        case typelib_TypeClass_DOUBLE:
+            return StructKind::F64;
+        default:
+            return StructKind::General;
+    }
+}
+}
+
 namespace bridges::cpp_uno::shared
 {
 void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const 
typelib_TypeDescription* pMemberDescr,
@@ -71,7 +137,165 @@ void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const 
typelib_TypeDescripti
                 } // else perform queryInterface()
                     [[fallthrough]];
                 default:
-                    std::abort();
+                {
+                    auto const mtd
+                        = 
reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(
+                            pMemberDescr);
+                    OStringBuffer sig;
+                    std::vector<sal_uInt64> args;
+                    switch (mtd->pReturnTypeRef->eTypeClass)
+                    {
+                        case typelib_TypeClass_VOID:
+                            sig.append('v');
+                            break;
+                        case typelib_TypeClass_BOOLEAN:
+                        case typelib_TypeClass_BYTE:
+                        case typelib_TypeClass_SHORT:
+                        case typelib_TypeClass_UNSIGNED_SHORT:
+                        case typelib_TypeClass_LONG:
+                        case typelib_TypeClass_UNSIGNED_LONG:
+                        case typelib_TypeClass_CHAR:
+                        case typelib_TypeClass_ENUM:
+                            sig.append('i');
+                            break;
+                        case typelib_TypeClass_HYPER:
+                        case typelib_TypeClass_UNSIGNED_HYPER:
+                            sig.append('j');
+                            break;
+                        case typelib_TypeClass_FLOAT:
+                            sig.append('f');
+                            break;
+                        case typelib_TypeClass_DOUBLE:
+                            sig.append('d');
+                            break;
+                        case typelib_TypeClass_STRING:
+                        case typelib_TypeClass_TYPE:
+                        case typelib_TypeClass_ANY:
+                        case typelib_TypeClass_SEQUENCE:
+                        case typelib_TypeClass_INTERFACE:
+                            sig.append("vi");
+                            
args.push_back(reinterpret_cast<sal_uInt32>(pReturn));
+                            break;
+                        case typelib_TypeClass_STRUCT:
+                        {
+                            typelib_TypeDescription* td = nullptr;
+                            
css::uno::Type(mtd->pReturnTypeRef).getDescription(&td);
+                            switch (getKind(
+                                
reinterpret_cast<typelib_CompoundTypeDescription const*>(td)))
+                            {
+                                case StructKind::Empty:
+                                    break;
+                                case StructKind::I32:
+                                    sig.append('i');
+                                    break;
+                                case StructKind::I64:
+                                    sig.append('j');
+                                    break;
+                                case StructKind::F32:
+                                    sig.append('f');
+                                    break;
+                                case StructKind::F64:
+                                    sig.append('d');
+                                    break;
+                                case StructKind::General:
+                                    sig.append("vi");
+                                    
args.push_back(reinterpret_cast<sal_uInt32>(pReturn));
+                                    break;
+                            }
+                            break;
+                        }
+                        default:
+                            O3TL_UNREACHABLE;
+                    }
+                    sig.append('i');
+                    args.push_back(reinterpret_cast<sal_uInt32>(pThis->pCppI));
+                    for (sal_Int32 i = 0; i != mtd->nParams; ++i)
+                    {
+                        if (mtd->pParams[i].bOut)
+                        {
+                            sig.append('i');
+                            
args.push_back(reinterpret_cast<sal_uInt32>(pArgs[i]));
+                        }
+                        else
+                        {
+                            switch (mtd->pParams[i].pTypeRef->eTypeClass)
+                            {
+                                case typelib_TypeClass_BOOLEAN:
+                                    sig.append('i');
+                                    args.push_back(*reinterpret_cast<sal_Bool 
const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_BYTE:
+                                    sig.append('i');
+                                    args.push_back(*reinterpret_cast<sal_Int8 
const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_SHORT:
+                                    sig.append('i');
+                                    args.push_back(*reinterpret_cast<sal_Int16 
const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_UNSIGNED_SHORT:
+                                    sig.append('i');
+                                    
args.push_back(*reinterpret_cast<sal_uInt16 const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_LONG:
+                                case typelib_TypeClass_ENUM:
+                                    sig.append('i');
+                                    args.push_back(*reinterpret_cast<sal_Int32 
const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_UNSIGNED_LONG:
+                                    sig.append('i');
+                                    
args.push_back(*reinterpret_cast<sal_uInt32 const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_HYPER:
+                                    sig.append('j');
+                                    args.push_back(*reinterpret_cast<sal_Int64 
const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_UNSIGNED_HYPER:
+                                    sig.append('j');
+                                    
args.push_back(*reinterpret_cast<sal_uInt64 const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_FLOAT:
+                                    sig.append('f');
+                                    
args.push_back(*reinterpret_cast<sal_uInt32 const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_DOUBLE:
+                                    sig.append('d');
+                                    
args.push_back(*reinterpret_cast<sal_uInt64 const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_CHAR:
+                                    sig.append('i');
+                                    
args.push_back(*reinterpret_cast<sal_Unicode const*>(pArgs[i]));
+                                    break;
+                                case typelib_TypeClass_STRING:
+                                case typelib_TypeClass_TYPE:
+                                case typelib_TypeClass_ANY:
+                                case typelib_TypeClass_SEQUENCE:
+                                case typelib_TypeClass_STRUCT:
+                                case typelib_TypeClass_INTERFACE:
+                                    sig.append('i');
+                                    
args.push_back(reinterpret_cast<sal_uInt32>(pArgs[i]));
+                                    break;
+                                default:
+                                    O3TL_UNREACHABLE;
+                            }
+                        }
+                    }
+                    try
+                    {
+                        callVirtualFunction(sig,
+                                            (*reinterpret_cast<sal_uInt32 
const* const*>(
+                                                
pThis->pCppI))[aVtableSlot.index],
+                                            args.data(), pReturn);
+                        *ppException = nullptr;
+                    }
+                    catch (...)
+                    {
+                        css::uno::RuntimeException TODO("Wasm bridge TODO");
+                        uno_type_any_construct(
+                            *ppException, &TODO,
+                            
cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
+                            nullptr);
+                    }
+                }
             }
             break;
         }
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 8e93cd59389f..fe01fc172776 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -4444,6 +4444,8 @@ $(eval $(call 
gb_UnoApi_add_idlfiles,offapi,org/libreoffice/embindtest, \
     Enum \
     Exception \
     Struct \
+    StructLong \
+    StructString \
     XTest \
 ))
 $(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,org/libreoffice/embindtest, \
diff --git a/offapi/org/libreoffice/embindtest/StructLong.idl 
b/offapi/org/libreoffice/embindtest/StructLong.idl
new file mode 100644
index 000000000000..22447486b3f3
--- /dev/null
+++ b/offapi/org/libreoffice/embindtest/StructLong.idl
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+module org { module libreoffice { module embindtest {
+
+struct StructLong {
+    long m;
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/offapi/org/libreoffice/embindtest/StructString.idl 
b/offapi/org/libreoffice/embindtest/StructString.idl
new file mode 100644
index 000000000000..e0c1464cfc84
--- /dev/null
+++ b/offapi/org/libreoffice/embindtest/StructString.idl
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+module org { module libreoffice { module embindtest {
+
+struct StructString {
+    string m;
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/offapi/org/libreoffice/embindtest/XTest.idl 
b/offapi/org/libreoffice/embindtest/XTest.idl
index b84753ebb8c6..ac8549d05397 100644
--- a/offapi/org/libreoffice/embindtest/XTest.idl
+++ b/offapi/org/libreoffice/embindtest/XTest.idl
@@ -40,6 +40,10 @@ interface XTest {
     boolean isEnum([in] Enum value);
     Struct getStruct();
     boolean isStruct([in] Struct value);
+    StructLong getStructLong();
+    boolean isStructLong([in] StructLong value);
+    StructString getStructString();
+    boolean isStructString([in] StructString value);
     any getAnyVoid();
     boolean isAnyVoid([in] any value);
     any getAnyBoolean();
diff --git a/solenv/gbuild/extensions/pre_BuildTools.mk 
b/solenv/gbuild/extensions/pre_BuildTools.mk
index 2522a4e7680c..63db68dc7b2a 100644
--- a/solenv/gbuild/extensions/pre_BuildTools.mk
+++ b/solenv/gbuild/extensions/pre_BuildTools.mk
@@ -16,7 +16,7 @@ gb_BUILD_TOOLS_executables = \
                climaker \
                cpp \
                cppumaker \
-               $(if $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),embindmaker) \
+               $(if $(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),embindmaker 
wasmcallgen) \
                gencoll_rule \
                genconv_dict \
                gendict \
diff --git a/static/Executable_wasmcallgen.mk b/static/Executable_wasmcallgen.mk
new file mode 100644
index 000000000000..77f5d9daf782
--- /dev/null
+++ b/static/Executable_wasmcallgen.mk
@@ -0,0 +1,26 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Executable_Executable,wasmcallgen))
+
+$(eval $(call gb_Executable_add_exception_objects,wasmcallgen, \
+    static/source/wasmcallgen/wasmcallgen \
+))
+
+$(eval $(call gb_Executable_use_libraries,wasmcallgen, \
+    sal \
+    salhelper \
+    unoidl \
+))
+
+$(eval $(call gb_Executable_use_static_libraries,wasmcallgen, \
+    codemaker \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/static/Module_static.mk b/static/Module_static.mk
index ff036fac3213..7403da211d27 100644
--- a/static/Module_static.mk
+++ b/static/Module_static.mk
@@ -34,6 +34,7 @@ endif
 ifneq ($(filter EMSCRIPTEN,$(BUILD_TYPE_FOR_HOST)),)
 $(eval $(call gb_Module_add_targets,static, \
     Executable_embindmaker \
+    Executable_wasmcallgen \
 ))
 endif
 
diff --git a/static/source/wasmcallgen/wasmcallgen.cxx 
b/static/source/wasmcallgen/wasmcallgen.cxx
new file mode 100644
index 000000000000..0453bdb8aff8
--- /dev/null
+++ b/static/source/wasmcallgen/wasmcallgen.cxx
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <ios>
+#include <iostream>
+#include <set>
+#include <string>
+#include <string_view>
+#include <utility>
+
+#include <codemaker/global.hxx>
+#include <codemaker/typemanager.hxx>
+#include <codemaker/unotype.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <rtl/process.h>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/main.h>
+#include <sal/types.h>
+#include <unoidl/unoidl.hxx>
+
+namespace
+{
+[[noreturn]] void badUsage()
+{
+    std::cerr
+        << "Usage:

"
+           "  wasmcallgen <cpp-output> <asm-output> <registries>

"
+           "where each <registry> is '+' (primary) or ':' (secondary), 
followed by: either a
"
+           "new- or legacy-format .rdb file, a single .idl file, or a root 
directory of an
"
+           ".idl file tree.  For all primary registries, Wasm UNO bridge 
callvirtualfunction
"
+           "code is written to <cpp-output>/<asm-output>.
";
+    std::exit(EXIT_FAILURE);
+}
+
+std::string getPathnameArgument(sal_uInt32 argument)
+{
+    OUString arg;
+    rtl_getAppCommandArg(argument, &arg.pData);
+    OString path;
+    auto const enc = osl_getThreadTextEncoding();
+    if (!arg.convertToString(&path, enc,
+                             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+                                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+    {
+        std::cerr << "Cannot convert \"" << arg << "\" to system encoding " << 
enc << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    return std::string(path);
+}
+
+std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument)
+{
+    OUString arg;
+    rtl_getAppCommandArg(argument, &arg.pData);
+    bool primary;
+    if (arg.startsWith(u"+", &arg))
+    {
+        primary = true;
+    }
+    else if (arg.startsWith(u":", &arg))
+    {
+        primary = false;
+    }
+    else
+    {
+        std::cerr << "Bad registry argument \"" << arg << "\"
";
+        std::exit(EXIT_FAILURE);
+    }
+    OUString url;
+    auto const e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
+    if (e1 != osl::FileBase::E_None)
+    {
+        std::cerr << "Cannot convert \"" << arg << "\" to file URL, error code 
" << +e1 << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    OUString cwd;
+    auto const e2 = osl_getProcessWorkingDir(&cwd.pData);
+    if (e2 != osl_Process_E_None)
+    {
+        std::cerr << "Cannot obtain working directory, error code " << +e2 << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    OUString abs;
+    auto const e3 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
+    if (e3 != osl::FileBase::E_None)
+    {
+        std::cerr << "Cannot make \"" << url << "\" into an absolute file URL, 
error code " << +e3
+                  << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    return { abs, primary };
+}
+
+OUString resolveAllTypedefs(rtl::Reference<TypeManager> const& manager, 
std::u16string_view name)
+{
+    sal_Int32 k1;
+    OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1)));
+    for (;;)
+    {
+        rtl::Reference<unoidl::Entity> ent;
+        if (manager->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef)
+        {
+            break;
+        }
+        sal_Int32 k2;
+        n = b2u(codemaker::UnoType::decompose(
+            u2b(static_cast<unoidl::TypedefEntity*>(ent.get())->getType()), 
&k2));
+        k1 += k2; //TODO: overflow
+    }
+    OUStringBuffer b;
+    for (sal_Int32 i = 0; i != k1; ++i)
+    {
+        b.append("[]");
+    }
+    b.append(n);
+    return b.makeStringAndClear();
+}
+
+enum class StructKind
+{
+    Empty,
+    I32,
+    I64,
+    F32,
+    F64,
+    General
+};
+
+StructKind getKind(rtl::Reference<TypeManager> const& manager, 
std::u16string_view type)
+{
+    std::vector<OUString> args;
+    rtl::Reference<unoidl::Entity> ent;
+    OUString singleMemberType;
+    switch (manager->decompose(type, true, nullptr, nullptr, &args, &ent))
+    {
+        case codemaker::UnoType::Sort::PlainStruct:
+        {
+            auto const strct = static_cast<unoidl::PlainStructTypeEntity 
const*>(ent.get());
+            if (strct->getDirectMembers().size() > 1)
+            {
+                return StructKind::General;
+            }
+            auto k = StructKind::Empty;
+            if (!strct->getDirectBase().isEmpty())
+            {
+                k = getKind(manager, strct->getDirectBase());
+            }
+            if (strct->getDirectMembers().empty())
+            {
+                return k;
+            }
+            if (k != StructKind::Empty)
+            {
+                return StructKind::General;
+            }
+            singleMemberType = strct->getDirectMembers()[0].type;
+            break;
+        }
+        case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
+        {
+            auto const strct
+                = static_cast<unoidl::PolymorphicStructTypeTemplateEntity 
const*>(ent.get());
+            switch (strct->getMembers().size())
+            {
+                case 0:
+                    return StructKind::Empty;
+                case 1:
+                    if (strct->getMembers()[0].parameterized)
+                    {
+                        auto const i = 
std::find(strct->getTypeParameters().begin(),
+                                                 
strct->getTypeParameters().end(),
+                                                 strct->getMembers()[0].type);
+                        if (i == strct->getTypeParameters().end())
+                        {
+                            throw CannotDumpException("bad type parameter \""
+                                                      + 
strct->getMembers()[0].type
+                                                      + "\" in call to 
getKind");
+                        }
+                        auto const n = i - strct->getTypeParameters().begin();
+                        if (o3tl::make_unsigned(n) > args.size())
+                        {
+                            throw CannotDumpException("bad type parameter \""
+                                                      + 
strct->getMembers()[0].type
+                                                      + "\" in call to 
getKind");
+                        }
+                        singleMemberType = args[n];
+                    }
+                    else
+                    {
+                        singleMemberType = strct->getMembers()[0].type;
+                    }
+                    break;
+                default:
+                    return StructKind::General;
+            }
+            break;
+        }
+        default:
+            throw CannotDumpException(OUString::Concat("unexpected entity \"") 
+ type
+                                      + "\" in call to getKind");
+    }
+    switch (manager->getSort(resolveAllTypedefs(manager, singleMemberType)))
+    {
+        case codemaker::UnoType::Sort::Boolean:
+        case codemaker::UnoType::Sort::Byte:
+        case codemaker::UnoType::Sort::Short:
+        case codemaker::UnoType::Sort::UnsignedShort:
+        case codemaker::UnoType::Sort::Long:
+        case codemaker::UnoType::Sort::UnsignedLong:
+        case codemaker::UnoType::Sort::Char:
+        case codemaker::UnoType::Sort::Enum:
+            return StructKind::I32;
+        case codemaker::UnoType::Sort::Hyper:
+        case codemaker::UnoType::Sort::UnsignedHyper:
+            return StructKind::I64;
+        case codemaker::UnoType::Sort::Float:
+            return StructKind::F32;
+        case codemaker::UnoType::Sort::Double:
+            return StructKind::F64;
+        default:
+            return StructKind::General;
+    }
+}
+
+OString computeSignature(rtl::Reference<TypeManager> const& manager,
+                         unoidl::InterfaceTypeEntity::Method const& method)
+{
+    OStringBuffer buf;
+    switch (manager->getSort(resolveAllTypedefs(manager, method.returnType)))
+    {
+        case codemaker::UnoType::Sort::Void:
+            buf.append('v');
+            break;
+        case codemaker::UnoType::Sort::Boolean:
+        case codemaker::UnoType::Sort::Byte:
+        case codemaker::UnoType::Sort::Short:
+        case codemaker::UnoType::Sort::UnsignedShort:
+        case codemaker::UnoType::Sort::Long:
+        case codemaker::UnoType::Sort::UnsignedLong:
+        case codemaker::UnoType::Sort::Char:
+        case codemaker::UnoType::Sort::Enum:
+            buf.append('i');
+            break;
+        case codemaker::UnoType::Sort::Hyper:
+        case codemaker::UnoType::Sort::UnsignedHyper:
+            buf.append('j');
+            break;
+        case codemaker::UnoType::Sort::Float:
+            buf.append('f');
+            break;
+        case codemaker::UnoType::Sort::Double:
+            buf.append('d');
+            break;
+        case codemaker::UnoType::Sort::String:
+        case codemaker::UnoType::Sort::Type:
+        case codemaker::UnoType::Sort::Any:
+        case codemaker::UnoType::Sort::Sequence:
+        case codemaker::UnoType::Sort::Interface:
+            buf.append("vi");
+            break;
+        case codemaker::UnoType::Sort::PlainStruct:
+        case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
+        {
+            switch (getKind(manager, method.returnType))
+            {
+                case StructKind::Empty:
+                    break;
+                case StructKind::I32:
+                    buf.append('i');
+                    break;
+                case StructKind::I64:
+                    buf.append('j');
+                    break;
+                case StructKind::F32:
+                    buf.append('f');
+                    break;
+                case StructKind::F64:
+                    buf.append('d');
+                    break;
+                case StructKind::General:
+                    buf.append("vi");
+                    break;
+            }
+            break;
+        }
+        default:
+            throw CannotDumpException("unexpected entity \"" + 
method.returnType
+                                      + "\" in call to computeSignature");
+    }
+    buf.append('i');
+    for (auto const& param : method.parameters)
+    {
+        if (param.direction == 
unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
+        {
+            switch (manager->getSort(resolveAllTypedefs(manager, param.type)))
+            {
+                case codemaker::UnoType::Sort::Boolean:
+                case codemaker::UnoType::Sort::Byte:
+                case codemaker::UnoType::Sort::Short:
+                case codemaker::UnoType::Sort::UnsignedShort:
+                case codemaker::UnoType::Sort::Long:
+                case codemaker::UnoType::Sort::UnsignedLong:
+                case codemaker::UnoType::Sort::Char:
+                case codemaker::UnoType::Sort::Enum:
+                case codemaker::UnoType::Sort::String:
+                case codemaker::UnoType::Sort::Type:
+                case codemaker::UnoType::Sort::Any:
+                case codemaker::UnoType::Sort::Sequence:
+                case codemaker::UnoType::Sort::PlainStruct:
+                case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
+                case codemaker::UnoType::Sort::Interface:
+                    buf.append('i');
+                    break;
+                case codemaker::UnoType::Sort::Hyper:
+                case codemaker::UnoType::Sort::UnsignedHyper:
+                    buf.append('j');
+                    break;
+                case codemaker::UnoType::Sort::Float:
+                    buf.append('f');
+                    break;
+                case codemaker::UnoType::Sort::Double:
+                    buf.append('d');
+                    break;
+                default:
+                    throw CannotDumpException("unexpected entity \"" + 
param.type
+                                              + "\" in call to 
computeSignature");
+            }
+        }
+        else
+        {
+            buf.append('i');
+        }
+    }
+    return buf.makeStringAndClear();
+}
+
+void scan(rtl::Reference<TypeManager> const& manager,
+          rtl::Reference<unoidl::MapCursor> const& cursor, std::set<OString>& 
signatures)
+{
+    assert(cursor.is());
+    for (;;)
+    {
+        OUString id;
+        auto const ent = cursor->getNext(&id);
+        if (!ent.is())
+        {
+            break;
+        }
+        switch (ent->getSort())
+        {
+            case unoidl::Entity::SORT_MODULE:
+                scan(manager, 
static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(),
+                     signatures);
+                break;
+            case unoidl::Entity::SORT_INTERFACE_TYPE:
+                for (auto const& meth :
+                     static_cast<unoidl::InterfaceTypeEntity 
const*>(ent.get())->getDirectMethods())
+                {
+                    signatures.insert(computeSignature(manager, meth));
+                }
+                break;
+            default:
+                break;
+        }
+    }
+}
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+    try
+    {
+        auto const args = rtl_getAppCommandArgCount();
+        if (args < 2)
+        {
+            badUsage();
+        }
+        auto const cppPathname = getPathnameArgument(0);
+        auto const asmPathname = getPathnameArgument(1);
+        rtl::Reference<TypeManager> mgr(new TypeManager);
+        for (sal_uInt32 i = 2; i != args; ++i)
+        {
+            auto const & [ uri, primary ] = parseRegistryArgument(i);
+            try
+            {
+                mgr->loadProvider(uri, primary);
+            }
+            catch (unoidl::NoSuchFileException&)
+            {
+                std::cerr << "Input <" << uri << "> does not exist
";
+                std::exit(EXIT_FAILURE);
+            }
+        }
+        std::set<OString> signatures;
+        for (auto const& prov : mgr->getPrimaryProviders())
+        {
+            scan(mgr, prov->createRootCursor(), signatures);
+        }
+        std::ofstream cppOut(cppPathname, std::ios_base::out | 
std::ios_base::trunc);
+        if (!cppOut)
+        {
+            std::cerr << "Cannot open \"" << cppPathname << "\" for writing
";
+            std::exit(EXIT_FAILURE);
+        }
+        cppOut << "#include <sal/config.h>
"
+                  "#include <string_view>
"
+                  "#include <com/sun/star/uno/RuntimeException.hpp>
"
+                  "#include <rtl/ustring.hxx>
"
+                  "#include <wasm/callvirtualfunction.hxx>
";
+        for (auto const& sig : signatures)
+        {
+            cppOut << "extern \"C\" void callVirtualFunction_" << sig
+                   << "(sal_uInt32 target, sal_uInt64 const * arguments, void 
* returnValue);
";
+        }
+        cppOut << "void callVirtualFunction(std::string_view signature, 
sal_uInt32 target, "
+                  "sal_uInt64 const * arguments, void * returnValue) {
";
+        for (auto const& sig : signatures)
+        {
+            cppOut << "    if (signature == \"" << sig << "\") {
"
+                   << "        callVirtualFunction_" << sig << "(target, 
arguments, returnValue);
"
+                   << "        return;
"
+                   << "    }
";
+        }
+        cppOut << "    throw css::uno::RuntimeException(\"Wasm bridge cannot 
call virtual function "
+                  "with signature \" + OUString::fromUtf8(signature));
"
+                  "}
";
+        cppOut.close();
+        if (!cppOut)
+        {
+            std::cerr << "Failed to write \"" << cppPathname << "\"
";
+            std::exit(EXIT_FAILURE);
+        }
+        std::ofstream asmOut(asmPathname, std::ios_base::out | 
std::ios_base::trunc);
+        if (!asmOut)
+        {
+            std::cerr << "Cannot open \"" << asmPathname << "\" for writing
";
+            std::exit(EXIT_FAILURE);
+        }
+        asmOut << "    .text
"
+                  "    .tabletype __indirect_function_table, funcref
";
+        for (auto const& sig : signatures)
+        {
+            asmOut << "        .functype callVirtualFunction_" << sig << " 
(i32, i32, i32) -> ()
";
+        }
+        for (auto const& sig : signatures)
+        {
+            asmOut << "        .section .text.callVirtualFunction_" << sig
+                   << ",\"\",@
"
+                      "        .globl callVirtualFunction_"
+                   << sig
+                   << "
"
+                      "        .type callVirtualFunction_"
+                   << sig
+                   << ",@function
"
+                      "callVirtualFunction_"
+                   << sig
+                   << ":
"
+                      "        .functype callVirtualFunction_"
+                   << sig << " (i32, i32, i32) -> ()
";
+            if (sig[0] != 'v')
+            {
+                asmOut << "    local.get 2
";
+            }
+            unsigned off = 0;
+            for (auto c : sig.subView(1))
+            {
+                asmOut << "    local.get 1
"
+                          "    ";
+                switch (c)
+                {
+                    case 'd':
+                        asmOut << "f64";
+                        break;
+                    case 'f':
+                        asmOut << "f32";
+                        break;
+                    case 'i':
+                        asmOut << "i32";
+                        break;
+                    case 'j':
+                        asmOut << "i64";
+                        break;
+                    default:
+                        assert(false);
+                }
+                asmOut << ".load " << off << "
";
+                off += 8; //TODO: overflow
+            }
+            asmOut << "        local.get 0
"
+                      "        call_indirect (";
+            auto first = true;
+            for (auto c : sig.subView(1))
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    asmOut << ", ";
+                }
+                switch (c)
+                {
+                    case 'd':
+                        asmOut << "f64";
+                        break;
+                    case 'f':
+                        asmOut << "f32";
+                        break;
+                    case 'i':
+                        asmOut << "i32";
+                        break;
+                    case 'j':
+                        asmOut << "i64";
+                        break;
+                    default:
+                        assert(false);
+                }
+            }
+            asmOut << ") -> (";
+            switch (sig[0])
+            {
+                case 'd':
+                    asmOut << "f64";
+                    break;
+                case 'f':
+                    asmOut << "f32";
+                    break;
+                case 'i':
+                    asmOut << "i32";
+                    break;
+                case 'j':
+                    asmOut << "i64";
+                    break;
+                case 'v':
+                    break;
+                default:
+                    assert(false);
+            }
+            asmOut << ")
";
+            if (sig[0] != 'v')
+            {
+                asmOut << "    ";
+                switch (sig[0])
+                {
+                    case 'd':
+                        asmOut << "f64";
+                        break;
+                    case 'f':
+                        asmOut << "f32";
+                        break;
+                    case 'i':
+                        asmOut << "i32";
+                        break;
+                    case 'j':
+                        asmOut << "i64";
+                        break;
+                    default:
+                        assert(false);
+                }
+                asmOut << ".store 0
";
+            }
+            asmOut << "        end_function
";
+        }
+        asmOut.close();
+        if (!asmOut)
+        {
+            std::cerr << "Failed to write \"" << asmPathname << "\"
";
+            std::exit(EXIT_FAILURE);
+        }
+        return EXIT_SUCCESS;
+    }
+    catch (unoidl::FileFormatException const& e)
+    {
+        std::cerr << "Bad input <" << e.getUri() << ">: " << e.getDetail() << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    catch (CannotDumpException const& e)
+    {
+        std::cerr << "Failure: " << e.getMessage() << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    catch (std::exception const& e)
+    {
+        std::cerr << "Failure: " << e.what() << "
";
+        std::exit(EXIT_FAILURE);
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/unotest/source/embindtest/embindtest.cxx 
b/unotest/source/embindtest/embindtest.cxx
index c5fcea1dc42e..7b65ed3ed776 100644
--- a/unotest/source/embindtest/embindtest.cxx
+++ b/unotest/source/embindtest/embindtest.cxx
@@ -24,6 +24,8 @@
 #include <org/libreoffice/embindtest/Enum.hpp>
 #include <org/libreoffice/embindtest/Exception.hpp>
 #include <org/libreoffice/embindtest/Struct.hpp>
+#include <org/libreoffice/embindtest/StructLong.hpp>
+#include <org/libreoffice/embindtest/StructString.hpp>
 #include <org/libreoffice/embindtest/XTest.hpp>
 #include <rtl/ustring.hxx>
 #include <sal/types.h>
@@ -112,6 +114,27 @@ class Test : public 
cppu::WeakImplHelper<org::libreoffice::embindtest::XTest>
         return value == org::libreoffice::embindtest::Struct{ -123456, 100.5, 
u"hä"_ustr };
     }
 
+    org::libreoffice::embindtest::StructLong SAL_CALL getStructLong() override
+    {
+        return { -123456 };
+    }
+
+    sal_Bool SAL_CALL isStructLong(org::libreoffice::embindtest::StructLong 
const& value) override
+    {
+        return value.m == -123456;
+    }
+
+    org::libreoffice::embindtest::StructString SAL_CALL getStructString() 
override
+    {
+        return { u"hä"_ustr };
+    }
+
+    sal_Bool SAL_CALL
+    isStructString(org::libreoffice::embindtest::StructString const& value) 
override
+    {
+        return value.m == u"hä";
+    }
+
     css::uno::Any SAL_CALL getAnyVoid() override { return {}; }
 
     sal_Bool SAL_CALL isAnyVoid(css::uno::Any const& value) override
diff --git a/unotest/source/embindtest/embindtest.js 
b/unotest/source/embindtest/embindtest.js
index 16efe9acf169..3944f399e3b1 100644
--- a/unotest/source/embindtest/embindtest.js
+++ b/unotest/source/embindtest/embindtest.js
@@ -697,6 +697,336 @@ Module.addOnPostRun(function() {
     
test.passJobExecutor(css.task.XJobExecutor.reference(obj.implXJobExecutor));
     test.passInterface(css.uno.XInterface.reference(obj.implXTypeProvider));
     obj.release();
+
+    const args = new Module.uno_Sequence_any(
+        [new 
Module.uno_Any(Module.uno_Type.Interface('com.sun.star.uno.XInterface'), 
test)]);
+    const invoke = css.script.XInvocation2.query(css.script.Invocation.create(
+        Module.getUnoComponentContext()).createInstanceWithArguments(args));
+    args.get(0).delete();
+    args.delete();
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getBoolean', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isBoolean', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getByte', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isByte', params2, outparamindex, outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getShort', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isShort', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getUnsignedShort', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isUnsignedShort', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getLong', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isLong', params2, outparamindex, outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getUnsignedLong', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isUnsignedLong', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getHyper', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isHyper', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getUnsignedHyper', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isUnsignedHyper', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getFloat', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isFloat', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getDouble', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isDouble', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getChar', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isChar', params2, outparamindex, outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getString', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isString', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getType', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isType', params2, outparamindex, outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getEnum', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isEnum', params2, outparamindex, outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getStruct', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isStruct', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getStructLong', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isStructLong', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getStructString', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isStructString', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getAnyLong', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isAnyLong', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
+    {
+        const params1 = new Module.uno_Sequence_any(0, 
Module.uno_Sequence.FromSize);
+        const outparamindex = new Module.uno_InOutParam_sequence_short;
+        const outparam = new Module.uno_InOutParam_sequence_any;
+        const ret1 = invoke.invoke('getSequenceLong', params1, outparamindex, 
outparam);
+        console.log(ret1.get());
+        const params2 = new Module.uno_Sequence_any([ret1]);
+        const ret2 = invoke.invoke('isSequenceLong', params2, outparamindex, 
outparam);
+        console.log(ret2.get());
+        console.assert(ret2.get());
+        ret1.delete();
+        params1.delete();
+        ret2.delete();
+        params2.delete();
+        outparamindex.delete();
+        outparam.delete();
+    }
 });
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to