diff --git a/bridges/CustomTarget_gcc3_wasm.mk b/bridges/CustomTarget_gcc3_wasm.mk index a88da8577282..7452fc477e4f 100644 --- a/bridges/CustomTarget_gcc3_wasm.mk +++ b/bridges/CustomTarget_gcc3_wasm.mk @@ -12,15 +12,18 @@ $(eval $(call gb_CustomTarget_CustomTarget,bridges/gcc3_wasm)) $(eval $(call gb_CustomTarget_register_targets,bridges/gcc3_wasm, \ callvirtualfunction-wrapper.cxx \ callvirtualfunction-impls.s \ + exports \ )) $(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-impls.s \ -$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-wrapper.cxx: \ +$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/callvirtualfunction-wrapper.cxx \ +$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/exports: \ $(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 \ + $(gb_CustomTarget_workdir)/bridges/gcc3_wasm/exports \ +$(call gb_UnoApi_get_target,udkapi) +$(call gb_UnoApi_get_target,offapi) # vim: set noet sw=4 ts=4: diff --git a/bridges/source/cpp_uno/gcc3_wasm/abi.hxx b/bridges/source/cpp_uno/gcc3_wasm/abi.hxx index e09b68ebd76f..b60f6383fd1a 100644 --- a/bridges/source/cpp_uno/gcc3_wasm/abi.hxx +++ b/bridges/source/cpp_uno/gcc3_wasm/abi.hxx @@ -13,6 +13,7 @@ #include +#define __USING_WASM_EXCEPTIONS__ #include #include @@ -20,6 +21,81 @@ #include #include +// , system/lib/libcxxabi/src/private_typeinfo.h: +namespace __cxxabiv1 +{ +class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info +{ +public: + /*MODIFIED:*/ __shim_type_info(char const* name) + : type_info(name) + { + } + _LIBCXXABI_HIDDEN virtual ~__shim_type_info(); + + _LIBCXXABI_HIDDEN virtual void noop1() const; + _LIBCXXABI_HIDDEN virtual void noop2() const; + _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info* thrown_type, + void*& adjustedPtr) const = 0; +}; +} + +#if !HAVE_CXXABI_H_CLASS_TYPE_INFO +// , system/lib/libcxxabi/src/private_typeinfo.h: +namespace __cxxabiv1 +{ +class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info +{ +public: + /*MODIFIED:*/ __class_type_info(char const* name) + : __shim_type_info(name) + { + } + _LIBCXXABI_HIDDEN virtual ~__class_type_info(); + + _LIBCXXABI_HIDDEN void process_static_type_above_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, const void*, int) const; + _LIBCXXABI_HIDDEN void process_static_type_below_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, int) const; + _LIBCXXABI_HIDDEN void process_found_base_class(void /*MODIFIED: __dynamic_cast_info*/*, void*, + int) const; + _LIBCXXABI_HIDDEN virtual void search_above_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, const void*, int, bool) const; + _LIBCXXABI_HIDDEN virtual void search_below_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, int, bool) const; + _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info*, void*&) const; + _LIBCXXABI_HIDDEN virtual void + has_unambiguous_public_base(void /*MODIFIED: __dynamic_cast_info*/*, void*, int) const; +}; +} +#endif + +#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO +// , +// libstdc++-v3/libsupc++/cxxabi.h: +namespace __cxxabiv1 +{ +class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info +{ +public: + const __class_type_info* __base_type; + + /*MODIFIED:*/ __si_class_type_info(char const* name) + : __class_type_info(name) + { + } + _LIBCXXABI_HIDDEN virtual ~__si_class_type_info(); + + _LIBCXXABI_HIDDEN virtual void search_above_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, const void*, int, bool) const; + _LIBCXXABI_HIDDEN virtual void search_below_dst(void /*MODIFIED: __dynamic_cast_info*/*, + const void*, int, bool) const; + _LIBCXXABI_HIDDEN virtual void + has_unambiguous_public_base(void /*MODIFIED: __dynamic_cast_info*/*, void*, int) const; +}; +} +#endif + #if !HAVE_CXXABI_H_CXA_EH_GLOBALS // , system/lib/libcxxabi/src/cxa_exception.h: namespace __cxxabiv1 diff --git a/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx index dc02fda3946e..2877a706a67a 100644 --- a/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx @@ -7,13 +7,40 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + +#include + +#include + +#include +#include +#include +#include +#include #include + +#include +#include +#include #include +#include "abi.hxx" + +EM_JS(void*, jsGetExportedSymbol, (char const* name), + // clang-format off +{ + const val = Module["_" + UTF8ArrayToString(HEAPU8, name)]; + return typeof val === "number" || typeof val === "bigint" ? val : 0; +} + // clang-format on +); + using bridges::cpp_uno::shared::VtableFactory; struct VtableFactory::Slot { + void const* fn; }; VtableFactory::Slot* VtableFactory::mapBlockToVtable(void* block) @@ -26,18 +53,537 @@ std::size_t VtableFactory::getBlockSize(sal_Int32 slotCount) return (slotCount + 2) * sizeof(Slot); } +namespace +{ +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti +{ +}; +} + VtableFactory::Slot* VtableFactory::initializeBlock(void* block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription*) { Slot* slots = mapBlockToVtable(block); + slots[-2].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } -unsigned char* VtableFactory::addLocalFunctions(Slot**, unsigned char*, - typelib_InterfaceTypeDescription const*, sal_Int32, - sal_Int32, sal_Int32) +namespace { - std::abort(); +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; + } +} + +class Rtti +{ +public: + std::type_info* getRtti(typelib_TypeDescription const& type); + +private: + typedef std::unordered_map Map; + + osl::Mutex mutex_; + Map map_; +}; + +std::type_info* Rtti::getRtti(typelib_TypeDescription const& type) +{ + OUString unoName(type.pTypeName); + osl::MutexGuard g(mutex_); + Map::iterator i(map_.find(unoName)); + if (i == map_.end()) + { + OStringBuffer b("_ZTI"); + auto const ns = unoName.indexOf('.') != 0; + if (ns) + { + b.append('N'); + } + for (sal_Int32 j = 0; j != -1;) + { + OString s( + OUStringToOString(o3tl::getToken(unoName, 0, '.', j), RTL_TEXTENCODING_ASCII_US)); + b.append(OString::number(s.getLength()) + s); + } + if (ns) + { + b.append('E'); + } + OString sym(b.makeStringAndClear()); + std::type_info* rtti = static_cast(jsGetExportedSymbol(sym.getStr())); + if (rtti == nullptr) + { + char const* rttiName = strdup(sym.getStr() + std::strlen("_ZTI")); + if (rttiName == nullptr) + { + throw std::bad_alloc(); + } + assert(type.eTypeClass == typelib_TypeClass_EXCEPTION); + typelib_CompoundTypeDescription const& ctd + = reinterpret_cast(type); + if (ctd.pBaseTypeDescription == nullptr) + { + rtti = new __cxxabiv1::__class_type_info(rttiName); + } + else + { + std::type_info* base = getRtti(ctd.pBaseTypeDescription->aBase); + auto const sicti = new __cxxabiv1::__si_class_type_info(rttiName); + sicti->__base_type = static_cast<__cxxabiv1::__class_type_info*>(base); + rtti = sicti; + } + } + i = map_.insert(Map::value_type(unoName, rtti)).first; + } + return i->second; +} + +struct theRttiFactory : public rtl::Static +{ +}; + +std::type_info* getRtti(typelib_TypeDescription const& type) +{ + return theRttiFactory::get().getRtti(type); +} + +extern "C" void* /*_GLIBCXX_CDTOR_CALLABI*/ deleteException(void* exception) +{ + __cxxabiv1::__cxa_exception* header = static_cast<__cxxabiv1::__cxa_exception*>(exception) - 1; + assert(header->exceptionDestructor == &deleteException); + OUString unoName(emscriptencxxabi::toUnoName(header->exceptionType->name())); + typelib_TypeDescription* td = nullptr; + typelib_typedescription_getByName(&td, unoName.pData); + assert(td != nullptr); + uno_destructData(exception, td, &css::uno::cpp_release); + typelib_typedescription_release(td); + return exception; +} + +void raiseException(uno_Any* any, uno_Mapping* mapping) +{ + typelib_TypeDescription* td = nullptr; + TYPELIB_DANGER_GET(&td, any->pType); + if (td == nullptr) + { + throw css::uno::RuntimeException("no typedescription for " + + OUString::unacquired(&any->pType->pTypeName)); + } + void* exc = __cxxabiv1::__cxa_allocate_exception(td->nSize); + uno_copyAndConvertData(exc, any->pData, td, mapping); + uno_any_destruct(any, nullptr); + std::type_info* rtti = getRtti(*td); + TYPELIB_DANGER_RELEASE(td); + __cxxabiv1::__cxa_throw(exc, rtti, deleteException); +} + +void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy, + css::uno::TypeDescription const& description, + typelib_TypeDescriptionReference* returnType, sal_Int32 count, + typelib_MethodParameter* parameters, std::vector arguments, + unsigned /*indirectRect*/) +{ + typelib_TypeDescription* rtd = nullptr; + if (returnType != nullptr) + { + TYPELIB_DANGER_GET(&rtd, returnType); + } + void* retin = nullptr; + + void** args = static_cast(alloca(count * sizeof(void*))); + void** cppArgs = static_cast(alloca(count * sizeof(void*))); + typelib_TypeDescription** argtds + = static_cast(alloca(count * sizeof(typelib_TypeDescription*))); + std::size_t argument_index = 0; + for (sal_Int32 i = 0; i != count; ++i) + { + if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef)) + { + assert(false); + } + else + { + cppArgs[i] = reinterpret_cast(arguments[argument_index++]); + typelib_TypeDescription* ptd = nullptr; + TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef); + if (!parameters[i].bIn) + { + args[i] = alloca(ptd->nSize); + argtds[i] = ptd; + } + else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) + { + args[i] = alloca(ptd->nSize); + uno_copyAndConvertData(args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno()); + argtds[i] = ptd; + } + else + { + args[i] = cppArgs[i]; + argtds[i] = nullptr; + TYPELIB_DANGER_RELEASE(ptd); + } + } + } + uno_Any exc; + uno_Any* pexc = &exc; + proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc); + if (pexc != nullptr) + { + for (sal_Int32 i = 0; i != count; ++i) + { + if (argtds[i] != nullptr) + { + if (parameters[i].bIn) + { + uno_destructData(args[i], argtds[i], nullptr); + } + TYPELIB_DANGER_RELEASE(argtds[i]); + } + } + if (rtd != nullptr) + { + TYPELIB_DANGER_RELEASE(rtd); + } + raiseException(&exc, proxy->getBridge()->getUno2Cpp()); + } + assert(false); +} + +void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPtr, + std::vector const& arguments, unsigned indirectRet) +{ + bridges::cpp_uno::shared::CppInterfaceProxy* proxy + = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( + reinterpret_cast(thisPtr) - vtableOffset); + typelib_InterfaceTypeDescription* type = proxy->getTypeDescr(); + assert(functionIndex < type->nMapFunctionIndexToMemberIndex); + sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex]; + css::uno::TypeDescription desc(type->ppAllMembers[pos]); + switch (desc.get()->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) + { + // Getter: + call(proxy, desc, + reinterpret_cast(desc.get()) + ->pAttributeTypeRef, + 0, nullptr, arguments, indirectRet); + } + else + { + // Setter: + typelib_MethodParameter param + = { nullptr, + reinterpret_cast(desc.get()) + ->pAttributeTypeRef, + true, false }; + call(proxy, desc, nullptr, 1, ¶m, arguments, indirectRet); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + switch (functionIndex) + { + case 1: + proxy->acquireProxy(); + break; + case 2: + proxy->releaseProxy(); + break; + case 0: + { + typelib_TypeDescription* td = nullptr; + TYPELIB_DANGER_GET( + &td, (reinterpret_cast(arguments[0])->getTypeLibType())); + if (td != nullptr && td->eTypeClass == typelib_TypeClass_INTERFACE) + { + css::uno::XInterface* ifc = nullptr; + proxy->getBridge()->getCppEnv()->getRegisteredInterface( + proxy->getBridge()->getCppEnv(), reinterpret_cast(&ifc), + proxy->getOid().pData, + reinterpret_cast(td)); + if (ifc != nullptr) + { + uno_any_construct( + reinterpret_cast(indirectRet), &ifc, td, + reinterpret_cast(css::uno::cpp_acquire)); + ifc->release(); + TYPELIB_DANGER_RELEASE(td); + break; + } + TYPELIB_DANGER_RELEASE(td); + } + } + [[fallthrough]]; + default: + call(proxy, desc, + reinterpret_cast(desc.get()) + ->pReturnTypeRef, + reinterpret_cast(desc.get()) + ->nParams, + reinterpret_cast(desc.get()) + ->pParams, + arguments, indirectRet); + break; + } + break; + default: + O3TL_UNREACHABLE; + } +} + +extern "C" void vtableSlotFunction_0_0Ii(unsigned indirectRet, unsigned thisPtr, unsigned arg1) +{ + vtableCall(0, 0, thisPtr, { sal_uInt64(arg1) }, indirectRet); +} + +extern "C" void vtableSlotFunction_1_0v(unsigned thisPtr) +{ + vtableCall(1, 0, thisPtr, {}, reinterpret_cast(nullptr)); +} + +extern "C" void vtableSlotFunction_2_0v(unsigned thisPtr) +{ + vtableCall(2, 0, thisPtr, {}, reinterpret_cast(nullptr)); +} + +extern "C" void vtableSlotFunction_3_0vi(unsigned thisPtr, unsigned arg1) +{ + vtableCall(3, 0, thisPtr, { arg1 }, reinterpret_cast(nullptr)); +} + +extern "C" void vtableSlotFunction_4_0v(unsigned thisPtr) +{ + vtableCall(4, 0, thisPtr, {}, reinterpret_cast(nullptr)); +} + +void const* getVtableSlotFunction(std::string_view signature) +{ + if (signature == "0_0Ii") + { + return reinterpret_cast(vtableSlotFunction_0_0Ii); + } + if (signature == "1_0v") + { + return reinterpret_cast(vtableSlotFunction_1_0v); + } + if (signature == "2_0v") + { + return reinterpret_cast(vtableSlotFunction_2_0v); + } + if (signature == "3_0vi") + { + return reinterpret_cast(vtableSlotFunction_3_0vi); + } + if (signature == "4_0v") + { + return reinterpret_cast(vtableSlotFunction_4_0v); + } + throw css::uno::RuntimeException("Wasm bridge cannot fill virtual function slot with signature " + + OUString::fromUtf8(signature)); +} +} + +unsigned char* VtableFactory::addLocalFunctions(Slot** slots, unsigned char* code, + typelib_InterfaceTypeDescription const* type, + sal_Int32 functionOffset, sal_Int32 functionCount, + sal_Int32 vtableOffset) +{ + *slots -= functionCount; + auto s = *slots; + for (sal_Int32 i = 0; i != type->nMembers; ++i) + { + switch (type->ppMembers[i]->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + (s++)->fn = nullptr; //TODO + ++functionOffset; + if (!reinterpret_cast( + css::uno::TypeDescription(type->ppMembers[i]).get()) + ->bReadOnly) + { + (s++)->fn = nullptr; //TODO + ++functionOffset; + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + OStringBuffer sig; + sig.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset)); + auto const mtd = reinterpret_cast( + css::uno::TypeDescription(type->ppMembers[i]).get()); + 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('I'); + break; + case typelib_TypeClass_STRUCT: + { + css::uno::TypeDescription rtd(mtd->pReturnTypeRef); + switch (getKind( + reinterpret_cast(rtd.get()))) + { + 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('I'); + break; + } + break; + } + default: + O3TL_UNREACHABLE; + } + for (sal_Int32 j = 0; j != mtd->nParams; ++j) + { + if (!mtd->pParams[j].bOut + && bridges::cpp_uno::shared::isSimpleType(mtd->pParams[j].pTypeRef)) + { + switch (mtd->pParams[j].pTypeRef->eTypeClass) + { + case typelib_TypeClass_BOOLEAN: + sig.append('i'); + break; + case typelib_TypeClass_BYTE: + sig.append('i'); + break; + case typelib_TypeClass_SHORT: + sig.append('i'); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + sig.append('i'); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_ENUM: + sig.append('i'); + break; + case typelib_TypeClass_UNSIGNED_LONG: + sig.append('i'); + break; + case typelib_TypeClass_HYPER: + sig.append('j'); + break; + 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_CHAR: + sig.append('i'); + break; + default: + O3TL_UNREACHABLE; + } + } + else + { + sig.append('i'); + } + } + (s++)->fn = getVtableSlotFunction(sig); + ++functionOffset; + break; + } + default: + O3TL_UNREACHABLE; + } + } + return code; } void VtableFactory::flushCode(unsigned char const*, unsigned char const*) {} diff --git a/cppuhelper/source/exc_thrower.cxx b/cppuhelper/source/exc_thrower.cxx index eec416775038..db2c9b0d5a46 100644 --- a/cppuhelper/source/exc_thrower.cxx +++ b/cppuhelper/source/exc_thrower.cxx @@ -167,7 +167,7 @@ ExceptionThrower::ExceptionThrower() uno_Interface::pDispatcher = ExceptionThrower_dispatch; } -#if defined(IOS) || defined(ANDROID) || defined(EMSCRIPTEN) +#if defined(IOS) || defined(ANDROID) #define RETHROW_FAKE_EXCEPTIONS 1 #else #define RETHROW_FAKE_EXCEPTIONS 0 @@ -255,7 +255,7 @@ void SAL_CALL throwException( Any const & exc ) Any SAL_CALL getCaughtException() { // why does this differ from RETHROW_FAKE_EXCEPTIONS? -#if defined(ANDROID) || defined(EMSCRIPTEN) +#if defined(ANDROID) return Any(); #else Mapping cpp2uno(Environment::getCurrent(), Environment(u"" UNO_LB_UNO ""_ustr)); diff --git a/desktop/CustomTarget_soffice_bin-emscripten-exports.mk b/desktop/CustomTarget_soffice_bin-emscripten-exports.mk new file mode 100644 index 000000000000..eec384150801 --- /dev/null +++ b/desktop/CustomTarget_soffice_bin-emscripten-exports.mk @@ -0,0 +1,25 @@ +# -*- 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,desktop/soffice_bin-emscripten-exports)) + +$(eval $(call gb_CustomTarget_register_targets,desktop/soffice_bin-emscripten-exports, \ + exports \ +)) + +$(gb_CustomTarget_workdir)/desktop/soffice_bin-emscripten-exports/exports: \ + $(SRCDIR)/desktop/util/Executable_soffice_bin-emscripten-exports \ + $(gb_CustomTarget_workdir)/bridges/gcc3_wasm/exports + # Prior to "Allow comments in response files. (#21330)" towards + # emsdk 3.1.54, comment lines were not supported, so filter them out here for now: + grep -v '^#' $(SRCDIR)/desktop/util/Executable_soffice_bin-emscripten-exports >$@ + cat $(gb_CustomTarget_workdir)/bridges/gcc3_wasm/exports >>$@ + +# vim: set noet sw=4 ts=4: diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk index 163bfb6409f2..f159c877f447 100644 --- a/desktop/Executable_soffice_bin.mk +++ b/desktop/Executable_soffice_bin.mk @@ -61,8 +61,11 @@ $(call gb_LinkTarget_get_target,$(call gb_Executable_get_linktarget,soffice_bin) $(call gb_LinkTarget_get_headers_target,$(call gb_Executable_get_linktarget,soffice_bin)) : $(call gb_StaticLibrary_get_headers_target,unoembind) $(call gb_LinkTarget__static_lib_dummy_depend,unoembind) +$(call gb_Executable_get_linktarget_target,soffice_bin): \ + $(gb_CustomTarget_workdir)/desktop/soffice_bin-emscripten-exports/exports + $(eval $(call gb_Executable_add_ldflags,soffice_bin,\ - -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"$(COMMA)"_malloc"$(COMMA)"_free"] -Wl$(COMMA)--whole-archive $(call gb_StaticLibrary_get_target,unoembind) -Wl$(COMMA)--no-whole-archive \ + -s EXPORTED_FUNCTIONS=@$(gb_CustomTarget_workdir)/desktop/soffice_bin-emscripten-exports/exports -Wl$(COMMA)--whole-archive $(call gb_StaticLibrary_get_target,unoembind) -Wl$(COMMA)--no-whole-archive \ )) ifeq ($(ENABLE_QT6),TRUE) $(eval $(call gb_Executable_add_ldflags,soffice_bin, \ diff --git a/desktop/Module_desktop.mk b/desktop/Module_desktop.mk index de56f3bd139f..862662e2acf2 100644 --- a/desktop/Module_desktop.mk +++ b/desktop/Module_desktop.mk @@ -105,6 +105,12 @@ endif endif # $(OS) +ifeq ($(OS),EMSCRIPTEN) +$(eval $(call gb_Module_add_targets,desktop, \ + CustomTarget_soffice_bin-emscripten-exports \ +)) +endif + ifneq (,$(filter Extension_test-active,$(MAKECMDGOALS))) $(eval $(call gb_Module_add_targets,desktop, \ Extension_test-active \ diff --git a/desktop/util/Executable_soffice_bin-emscripten-exports b/desktop/util/Executable_soffice_bin-emscripten-exports new file mode 100644 index 000000000000..2206ccccb2d5 --- /dev/null +++ b/desktop/util/Executable_soffice_bin-emscripten-exports @@ -0,0 +1,14 @@ +# +# 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/. +# +_main +_libreofficekit_hook +_libreofficekit_hook_2 +_lok_preinit +_lok_preinit_2 +_malloc +_free diff --git a/include/bridges/emscriptencxxabi/cxxabi.hxx b/include/bridges/emscriptencxxabi/cxxabi.hxx index 8c380961cb60..eda61f1229e4 100644 --- a/include/bridges/emscriptencxxabi/cxxabi.hxx +++ b/include/bridges/emscriptencxxabi/cxxabi.hxx @@ -16,6 +16,7 @@ #include #include +#define __USING_WASM_EXCEPTIONS__ #include #include @@ -67,7 +68,7 @@ struct __cxa_exception #endif // Manage the exception object itself. std::type_info* exceptionType; -#if 1 //MODIFIED: #ifdef __USING_WASM_EXCEPTIONS__ +#ifdef __USING_WASM_EXCEPTIONS__ // In wasm, destructors return their argument void*(/*MODIFIED: _LIBCXXABI_DTOR_FUNC*/ *exceptionDestructor)(void*); #else diff --git a/static/source/wasmcallgen/wasmcallgen.cxx b/static/source/wasmcallgen/wasmcallgen.cxx index 0453bdb8aff8..2c61a48c6b25 100644 --- a/static/source/wasmcallgen/wasmcallgen.cxx +++ b/static/source/wasmcallgen/wasmcallgen.cxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -44,11 +46,12 @@ namespace { std::cerr << "Usage:\n\n" - " wasmcallgen \n\n" + " wasmcallgen \n\n" "where each is '+' (primary) or ':' (secondary), followed by: either a\n" "new- or legacy-format .rdb file, a single .idl file, or a root directory of an\n" ".idl file tree. For all primary registries, Wasm UNO bridge callvirtualfunction\n" - "code is written to /.\n"; + "code is written to /, and to-be-exported exception RTTI\n" + "symbols are written to .\n"; std::exit(EXIT_FAILURE); } @@ -354,8 +357,34 @@ OString computeSignature(rtl::Reference const& manager, return buf.makeStringAndClear(); } +void appendRttiSymbolSegment(OStringBuffer& buffer, OUString const& id) +{ + OString s(OUStringToOString(id, RTL_TEXTENCODING_ASCII_US)); + buffer.append(OString::number(s.getLength()) + s); +} + +OString computeRttiSymbol(std::vector const& path, OUString const& id) +{ + OStringBuffer buf("__ZTI"); + if (!path.empty()) + { + buf.append('N'); + for (auto const& i : path) + { + appendRttiSymbolSegment(buf, i); + } + } + appendRttiSymbolSegment(buf, id); + if (!path.empty()) + { + buf.append('E'); + } + return buf.makeStringAndClear(); +} + void scan(rtl::Reference const& manager, - rtl::Reference const& cursor, std::set& signatures) + rtl::Reference const& cursor, std::vector& path, + std::set& signatures, std::set& rttis) { assert(cursor.is()); for (;;) @@ -369,8 +398,13 @@ void scan(rtl::Reference const& manager, switch (ent->getSort()) { case unoidl::Entity::SORT_MODULE: - scan(manager, static_cast(ent.get())->createCursor(), - signatures); + path.push_back(id); + scan(manager, static_cast(ent.get())->createCursor(), path, + signatures, rttis); + path.pop_back(); + break; + case unoidl::Entity::SORT_EXCEPTION_TYPE: + rttis.insert(computeRttiSymbol(path, id)); break; case unoidl::Entity::SORT_INTERFACE_TYPE: for (auto const& meth : @@ -391,14 +425,15 @@ SAL_IMPLEMENT_MAIN() try { auto const args = rtl_getAppCommandArgCount(); - if (args < 2) + if (args < 3) { badUsage(); } auto const cppPathname = getPathnameArgument(0); auto const asmPathname = getPathnameArgument(1); + auto const expPathname = getPathnameArgument(2); rtl::Reference mgr(new TypeManager); - for (sal_uInt32 i = 2; i != args; ++i) + for (sal_uInt32 i = 3; i != args; ++i) { auto const & [ uri, primary ] = parseRegistryArgument(i); try @@ -411,10 +446,12 @@ SAL_IMPLEMENT_MAIN() std::exit(EXIT_FAILURE); } } + std::vector path; std::set signatures; + std::set rttis; for (auto const& prov : mgr->getPrimaryProviders()) { - scan(mgr, prov->createRootCursor(), signatures); + scan(mgr, prov->createRootCursor(), path, signatures, rttis); } std::ofstream cppOut(cppPathname, std::ios_base::out | std::ios_base::trunc); if (!cppOut) @@ -588,6 +625,22 @@ SAL_IMPLEMENT_MAIN() std::cerr << "Failed to write \"" << asmPathname << "\"\n"; std::exit(EXIT_FAILURE); } + std::ofstream expOut(expPathname, std::ios_base::out | std::ios_base::trunc); + if (!expOut) + { + std::cerr << "Cannot open \"" << expPathname << "\" for writing\n"; + std::exit(EXIT_FAILURE); + } + for (auto const& rtti : rttis) + { + expOut << rtti.getStr() << "\n"; + } + expOut.close(); + if (!expOut) + { + std::cerr << "Failed to write \"" << expPathname << "\"\n"; + std::exit(EXIT_FAILURE); + } return EXIT_SUCCESS; } catch (unoidl::FileFormatException const& e)