diff options
author | Stephan Bergmann <stephan.bergmann@allotropia.de> | 2024-05-08 09:46:55 +0200 |
---|---|---|
committer | Stephan Bergmann <stephan.bergmann@allotropia.de> | 2024-05-08 13:01:04 +0200 |
commit | a469aea9c0b532d928cd41e389c9c51de1af06f0 (patch) | |
tree | 8a2f5ff87b20d601372c52d65db86b82b540e08a /bridges | |
parent | 90f19126fa405a0632eae4ee8525b66bbce12625 (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.mk | 26 | ||||
-rw-r--r-- | bridges/Library_cpp_uno.mk | 6 | ||||
-rw-r--r-- | bridges/Module_bridges.mk | 1 | ||||
-rw-r--r-- | bridges/inc/wasm/callvirtualfunction.hxx | 21 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx | 226 |
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; } |