summaryrefslogtreecommitdiff
path: root/bridges
diff options
context:
space:
mode:
authorStephan Bergmann <stephan.bergmann@allotropia.de>2024-05-08 09:46:55 +0200
committerStephan Bergmann <stephan.bergmann@allotropia.de>2024-05-08 13:01:04 +0200
commita469aea9c0b532d928cd41e389c9c51de1af06f0 (patch)
tree8a2f5ff87b20d601372c52d65db86b82b540e08a /bridges
parent90f19126fa405a0632eae4ee8525b66bbce12625 (diff)
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.bergmann@allotropia.de> Tested-by: Jenkins
Diffstat (limited to 'bridges')
-rw-r--r--bridges/CustomTarget_gcc3_wasm.mk26
-rw-r--r--bridges/Library_cpp_uno.mk6
-rw-r--r--bridges/Module_bridges.mk1
-rw-r--r--bridges/inc/wasm/callvirtualfunction.hxx21
-rw-r--r--bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx226
5 files changed, 279 insertions, 1 deletions
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;
}