Fully implement the Wasm UNO bridge cpp2uno direction

...after 875997c896 "Properly implement
cppu::throwException for Emscripten" had implemented only those parts that were
absolutely necessary for that exception throwing.  As detailed in the commit
message there, wasmcallgen has been extended to additionally generate all the
required vtable slot call trampoline code (which cannot be generated on the fly
for Wasm, as would be done for other platforms).  Consequently, some of the
"callvirtualfunction"-centric file names have been changed to "generated" as the
output of wasmcallgen is now more general.  (And wasmcallgen itself should also
be renamed, in a follow-up commit.  And when adding to the wasmcallgen code
here, some existing parts of its implementation have been cleaned up, too.)

There is no direct way to test this half of the Wasm UNO bridge directly from
unotest/source/embindtest/embindtest.js, so a new
org.libreoffice.embindtest.BridgeTest singleton has been added, which triggers
new test code in unotest/source/embindtest/embindtest.cxx that tests the bridge
in a way similar to testtools' bridgetest machinery.

Change-Id: I521a1d6c2160aedc814f7603b0b99861e5fbd1eb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170374
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
This commit is contained in:
Stephan Bergmann 2024-07-11 12:53:01 +02:00
parent 8c5f93ee35
commit 74829f2a64
11 changed files with 940 additions and 261 deletions

View file

@ -10,19 +10,19 @@
$(eval $(call gb_CustomTarget_CustomTarget,bridges/gcc3_wasm))
$(eval $(call gb_CustomTarget_register_targets,bridges/gcc3_wasm, \
callvirtualfunction-wrapper.cxx \
callvirtualfunction-impls.s \
generated-cxx.cxx \
generated-asm.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/generated-asm.s \
$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/generated-cxx.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/generated-cxx.cxx \
$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/generated-asm.s \
$(gb_CustomTarget_workdir)/bridges/gcc3_wasm/exports \
+$(call gb_UnoApi_get_target,udkapi) +$(call gb_UnoApi_get_target,offapi)

View file

@ -85,10 +85,10 @@ else ifeq ($(OS),EMSCRIPTEN)
bridges_SELECTED_BRIDGE := gcc3_wasm
bridge_exception_objects := abi cpp2uno uno2cpp
$(eval $(call gb_Library_add_generated_asmobjects,$(CPPU_ENV)_uno, \
CustomTarget/bridges/gcc3_wasm/callvirtualfunction-impls \
CustomTarget/bridges/gcc3_wasm/generated-asm \
))
$(eval $(call gb_Library_add_generated_exception_objects,$(CPPU_ENV)_uno, \
CustomTarget/bridges/gcc3_wasm/callvirtualfunction-wrapper \
CustomTarget/bridges/gcc3_wasm/generated-cxx \
))
$(eval $(call gb_Library_use_static_libraries,$(CPPU_ENV)_uno, \
emscriptencxxabi \

View file

@ -12,10 +12,16 @@
#include <sal/config.h>
#include <string_view>
#include <vector>
#include <sal/types.h>
void callVirtualFunction(std::string_view signature, sal_uInt32 target, sal_uInt64 const* arguments,
void* returnValue);
sal_uInt64 vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPtr,
std::vector<sal_uInt64> const& arguments, unsigned indirectRet);
void const* getVtableSlotFunction(std::string_view signature);
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -9,6 +9,7 @@
#include <sal/config.h>
#include <cstring>
#include <typeinfo>
#include <emscripten.h>
@ -24,6 +25,7 @@
#include <cppinterfaceproxy.hxx>
#include <types.hxx>
#include <vtablefactory.hxx>
#include <wasm/generated.hxx>
#include "abi.hxx"
@ -176,19 +178,21 @@ void raiseException(uno_Any* any, uno_Mapping* mapping)
__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<sal_uInt64> arguments,
unsigned /*indirectRect*/)
sal_uInt64 call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
css::uno::TypeDescription const& description,
typelib_TypeDescriptionReference* returnType, sal_Int32 count,
typelib_MethodParameter* parameters, std::vector<sal_uInt64> arguments,
unsigned indirectRet)
{
typelib_TypeDescription* rtd = nullptr;
if (returnType != nullptr)
{
TYPELIB_DANGER_GET(&rtd, returnType);
}
void* retin = nullptr;
auto const retConv = rtd != nullptr && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
void* retin = reinterpret_cast<void*>(indirectRet) != nullptr && !retConv
? reinterpret_cast<void*>(indirectRet)
: rtd == nullptr ? nullptr : alloca(rtd->nSize);
void** args = static_cast<void**>(alloca(count * sizeof(void*)));
void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
typelib_TypeDescription** argtds
@ -198,7 +202,8 @@ void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
{
if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
{
assert(false);
args[i] = arguments.data() + i;
argtds[i] = nullptr;
}
else
{
@ -246,11 +251,54 @@ void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
}
raiseException(&exc, proxy->getBridge()->getUno2Cpp());
}
assert(false);
for (sal_Int32 i = 0; i != count; ++i)
{
if (argtds[i] != nullptr)
{
if (parameters[i].bOut)
{
uno_destructData(cppArgs[i], argtds[i],
reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
uno_copyAndConvertData(cppArgs[i], args[i], argtds[i],
proxy->getBridge()->getUno2Cpp());
}
uno_destructData(args[i], argtds[i], nullptr);
TYPELIB_DANGER_RELEASE(argtds[i]);
}
}
sal_uInt64 retVal = {};
if (retConv)
{
uno_copyAndConvertData(reinterpret_cast<void*>(indirectRet), retin, rtd,
proxy->getBridge()->getUno2Cpp());
uno_destructData(retin, rtd, nullptr);
}
else if (rtd != nullptr)
{
// Make sure to sign-extend the return value for small signed integer types:
switch (rtd->eTypeClass)
{
case typelib_TypeClass_BYTE:
retVal = static_cast<int>(*static_cast<sal_Int8 const*>(retin));
break;
case typelib_TypeClass_SHORT:
retVal = static_cast<int>(*static_cast<sal_Int16 const*>(retin));
break;
default:
std::memcpy(&retVal, retin, rtd->nSize);
break;
}
}
if (rtd != nullptr)
{
TYPELIB_DANGER_RELEASE(rtd);
}
return retVal;
}
}
void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPtr,
std::vector<sal_uInt64> const& arguments, unsigned indirectRet)
sal_uInt64 vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPtr,
std::vector<sal_uInt64> const& arguments, unsigned indirectRet)
{
bridges::cpp_uno::shared::CppInterfaceProxy* proxy
= bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
@ -265,10 +313,10 @@ void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPt
if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex)
{
// Getter:
call(proxy, desc,
reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(desc.get())
->pAttributeTypeRef,
0, nullptr, arguments, indirectRet);
return call(proxy, desc,
reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(desc.get())
->pAttributeTypeRef,
0, nullptr, arguments, indirectRet);
}
else
{
@ -278,7 +326,7 @@ void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPt
reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(desc.get())
->pAttributeTypeRef,
true, false };
call(proxy, desc, nullptr, 1, &param, arguments, indirectRet);
return call(proxy, desc, nullptr, 1, &param, arguments, indirectRet);
}
break;
case typelib_TypeClass_INTERFACE_METHOD:
@ -286,10 +334,10 @@ void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPt
{
case 1:
proxy->acquireProxy();
break;
return {};
case 2:
proxy->releaseProxy();
break;
return {};
case 0:
{
typelib_TypeDescription* td = nullptr;
@ -309,78 +357,135 @@ void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned thisPt
reinterpret_cast<uno_AcquireFunc>(css::uno::cpp_acquire));
ifc->release();
TYPELIB_DANGER_RELEASE(td);
break;
return {};
}
TYPELIB_DANGER_RELEASE(td);
}
}
[[fallthrough]];
default:
call(proxy, desc,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->pReturnTypeRef,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->nParams,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->pParams,
arguments, indirectRet);
break;
return call(
proxy, desc,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->pReturnTypeRef,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->nParams,
reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
->pParams,
arguments, indirectRet);
}
break;
default:
O3TL_UNREACHABLE;
}
}
extern "C" void vtableSlotFunction_0_0Ii(unsigned indirectRet, unsigned thisPtr, unsigned arg1)
namespace
{
vtableCall(0, 0, thisPtr, { sal_uInt64(arg1) }, indirectRet);
void appendSignatureOffsets(OStringBuffer& buffer, sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
buffer.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset));
}
extern "C" void vtableSlotFunction_1_0v(unsigned thisPtr)
void appendSignatureReturnType(OStringBuffer& buffer, typelib_TypeDescriptionReference* type)
{
vtableCall(1, 0, thisPtr, {}, reinterpret_cast<unsigned>(nullptr));
switch (type->eTypeClass)
{
case typelib_TypeClass_VOID:
buffer.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:
buffer.append('i');
break;
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
buffer.append('j');
break;
case typelib_TypeClass_FLOAT:
buffer.append('f');
break;
case typelib_TypeClass_DOUBLE:
buffer.append('d');
break;
case typelib_TypeClass_STRING:
case typelib_TypeClass_TYPE:
case typelib_TypeClass_ANY:
case typelib_TypeClass_SEQUENCE:
case typelib_TypeClass_INTERFACE:
buffer.append('I');
break;
case typelib_TypeClass_STRUCT:
{
css::uno::TypeDescription td(type);
switch (abi_wasm::getKind(
reinterpret_cast<typelib_CompoundTypeDescription const*>(td.get())))
{
case abi_wasm::StructKind::Empty:
break;
case abi_wasm::StructKind::I32:
buffer.append('i');
break;
case abi_wasm::StructKind::I64:
buffer.append('j');
break;
case abi_wasm::StructKind::F32:
buffer.append('f');
break;
case abi_wasm::StructKind::F64:
buffer.append('d');
break;
case abi_wasm::StructKind::General:
buffer.append('I');
break;
}
break;
}
default:
O3TL_UNREACHABLE;
}
}
extern "C" void vtableSlotFunction_2_0v(unsigned thisPtr)
void appendSignatureParameter(OStringBuffer& buffer, bool out,
typelib_TypeDescriptionReference const* type)
{
vtableCall(2, 0, thisPtr, {}, reinterpret_cast<unsigned>(nullptr));
}
extern "C" void vtableSlotFunction_3_0vi(unsigned thisPtr, unsigned arg1)
{
vtableCall(3, 0, thisPtr, { arg1 }, reinterpret_cast<unsigned>(nullptr));
}
extern "C" void vtableSlotFunction_4_0v(unsigned thisPtr)
{
vtableCall(4, 0, thisPtr, {}, reinterpret_cast<unsigned>(nullptr));
}
void const* getVtableSlotFunction(std::string_view signature)
{
if (signature == "0_0Ii")
if (!out && bridges::cpp_uno::shared::isSimpleType(type))
{
return reinterpret_cast<void const*>(vtableSlotFunction_0_0Ii);
switch (type->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_ENUM:
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_CHAR:
buffer.append('i');
break;
case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_HYPER:
buffer.append('j');
break;
case typelib_TypeClass_FLOAT:
buffer.append('f');
break;
case typelib_TypeClass_DOUBLE:
buffer.append('d');
break;
default:
O3TL_UNREACHABLE;
}
}
if (signature == "1_0v")
else
{
return reinterpret_cast<void const*>(vtableSlotFunction_1_0v);
buffer.append('i');
}
if (signature == "2_0v")
{
return reinterpret_cast<void const*>(vtableSlotFunction_2_0v);
}
if (signature == "3_0vi")
{
return reinterpret_cast<void const*>(vtableSlotFunction_3_0vi);
}
if (signature == "4_0v")
{
return reinterpret_cast<void const*>(vtableSlotFunction_4_0v);
}
throw css::uno::RuntimeException("Wasm bridge cannot fill virtual function slot with signature "
+ OUString::fromUtf8(signature));
}
}
@ -396,132 +501,37 @@ unsigned char* VtableFactory::addLocalFunctions(Slot** slots, unsigned char* cod
switch (type->ppMembers[i]->eTypeClass)
{
case typelib_TypeClass_INTERFACE_ATTRIBUTE:
(s++)->fn = nullptr; //TODO
{
auto const atd = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(
css::uno::TypeDescription(type->ppMembers[i]).get());
OStringBuffer sigGetter;
appendSignatureOffsets(sigGetter, functionOffset, vtableOffset);
appendSignatureReturnType(sigGetter, atd->pAttributeTypeRef);
(s++)->fn = getVtableSlotFunction(sigGetter);
++functionOffset;
if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(
css::uno::TypeDescription(type->ppMembers[i]).get())
->bReadOnly)
{
(s++)->fn = nullptr; //TODO
OStringBuffer sigSetter;
appendSignatureOffsets(sigSetter, functionOffset, vtableOffset);
sigSetter.append('v');
appendSignatureParameter(sigSetter, false, atd->pAttributeTypeRef);
(s++)->fn = getVtableSlotFunction(sigSetter);
++functionOffset;
}
break;
}
case typelib_TypeClass_INTERFACE_METHOD:
{
OStringBuffer sig;
sig.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset));
auto const mtd = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
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 (abi_wasm::getKind(
reinterpret_cast<typelib_CompoundTypeDescription const*>(rtd.get())))
{
case abi_wasm::StructKind::Empty:
break;
case abi_wasm::StructKind::I32:
sig.append('i');
break;
case abi_wasm::StructKind::I64:
sig.append('j');
break;
case abi_wasm::StructKind::F32:
sig.append('f');
break;
case abi_wasm::StructKind::F64:
sig.append('d');
break;
case abi_wasm::StructKind::General:
sig.append('I');
break;
}
break;
}
default:
O3TL_UNREACHABLE;
}
OStringBuffer sig;
appendSignatureOffsets(sig, functionOffset, vtableOffset);
appendSignatureReturnType(sig, mtd->pReturnTypeRef);
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');
}
appendSignatureParameter(sig, mtd->pParams[j].bOut, mtd->pParams[j].pTypeRef);
}
(s++)->fn = getVtableSlotFunction(sig);
++functionOffset;

View file

@ -33,7 +33,7 @@
#include <types.hxx>
#include <unointerfaceproxy.hxx>
#include <vtables.hxx>
#include <wasm/callvirtualfunction.hxx>
#include <wasm/generated.hxx>
#include "abi.hxx"

View file

@ -4449,6 +4449,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,org/libreoffice/embindtest, \
XTest \
))
$(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,org/libreoffice/embindtest, \
BridgeTest \
Test \
))
endif

View file

@ -0,0 +1,16 @@
/* -*- 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 {
singleton BridgeTest: com::sun::star::task::XJob;
}; }; };
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -25,9 +25,12 @@
#include <codemaker/typemanager.hxx>
#include <codemaker/unotype.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/temporary.hxx>
#include <o3tl/unreachable.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <osl/thread.h>
#include <rtl/character.hxx>
#include <rtl/process.h>
#include <rtl/ref.hxx>
#include <rtl/strbuf.hxx>
@ -49,9 +52,9 @@ namespace
" wasmcallgen <cpp-output> <asm-output> <exp-output> <registries>\n\n"
"where each <registry> 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 <cpp-output>/<asm-output>, and to-be-exported exception RTTI\n"
"symbols are written to <exp-output>.\n";
".idl file tree. For all primary registries, Wasm UNO bridge code is written to\n"
"<cpp-output>/<asm-output>, and to-be-exported exception RTTI symbols are written\n"
"to <exp-output>.\n";
std::exit(EXIT_FAILURE);
}
@ -245,14 +248,13 @@ StructKind getKind(rtl::Reference<TypeManager> const& manager, std::u16string_vi
}
}
OString computeSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method const& method)
void appendCallSignatureReturnType(OStringBuffer& buffer,
rtl::Reference<TypeManager> const& manager, OUString const& type)
{
OStringBuffer buf;
switch (manager->getSort(resolveAllTypedefs(manager, method.returnType)))
switch (manager->getSort(resolveAllTypedefs(manager, type)))
{
case codemaker::UnoType::Sort::Void:
buf.append('v');
buffer.append('v');
break;
case codemaker::UnoType::Sort::Boolean:
case codemaker::UnoType::Sort::Byte:
@ -262,101 +264,328 @@ OString computeSignature(rtl::Reference<TypeManager> const& manager,
case codemaker::UnoType::Sort::UnsignedLong:
case codemaker::UnoType::Sort::Char:
case codemaker::UnoType::Sort::Enum:
buf.append('i');
buffer.append('i');
break;
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
buf.append('j');
buffer.append('j');
break;
case codemaker::UnoType::Sort::Float:
buf.append('f');
buffer.append('f');
break;
case codemaker::UnoType::Sort::Double:
buf.append('d');
buffer.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");
buffer.append("vi");
break;
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
{
switch (getKind(manager, method.returnType))
switch (getKind(manager, type))
{
case StructKind::Empty:
break;
case StructKind::I32:
buf.append('i');
buffer.append('i');
break;
case StructKind::I64:
buf.append('j');
buffer.append('j');
break;
case StructKind::F32:
buf.append('f');
buffer.append('f');
break;
case StructKind::F64:
buf.append('d');
buffer.append('d');
break;
case StructKind::General:
buf.append("vi");
buffer.append("vi");
break;
}
break;
}
default:
throw CannotDumpException("unexpected entity \"" + method.returnType
+ "\" in call to computeSignature");
throw CannotDumpException("unexpected entity \"" + type
+ "\" in call to appendCallSignatureReturnType");
}
}
void appendCallSignatureParameter(
OStringBuffer& buffer, rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const& type)
{
if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
{
switch (manager->getSort(resolveAllTypedefs(manager, 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:
buffer.append('i');
break;
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
buffer.append('j');
break;
case codemaker::UnoType::Sort::Float:
buffer.append('f');
break;
case codemaker::UnoType::Sort::Double:
buffer.append('d');
break;
default:
throw CannotDumpException("unexpected entity \"" + type
+ "\" in call to appendCallSignatureParameter");
}
}
else
{
buffer.append('i');
}
}
OString computeGetterCallSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Attribute const& attribute)
{
OStringBuffer buf;
appendCallSignatureReturnType(buf, manager, attribute.type);
buf.append('i');
return buf.makeStringAndClear();
}
OString computeSetterCallSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Attribute const& attribute)
{
OStringBuffer buf("vi");
appendCallSignatureParameter(
buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type);
return buf.makeStringAndClear();
}
OString computeMethodCallSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method const& method)
{
OStringBuffer buf;
appendCallSignatureReturnType(buf, manager, method.returnType);
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');
}
appendCallSignatureParameter(buf, manager, param.direction, param.type);
}
return buf.makeStringAndClear();
}
void appendSlotSignatureOffsets(OStringBuffer& buffer, sal_Int32 functionOffset,
sal_Int32 vtableOffset)
{
buffer.append(OString::number(functionOffset) + "_" + OString::number(vtableOffset));
}
void appendSlotSignatureReturnType(OStringBuffer& buffer,
rtl::Reference<TypeManager> const& manager, OUString const& type)
{
switch (manager->getSort(resolveAllTypedefs(manager, type)))
{
case codemaker::UnoType::Sort::Void:
buffer.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:
buffer.append('i');
break;
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
buffer.append('j');
break;
case codemaker::UnoType::Sort::Float:
buffer.append('f');
break;
case codemaker::UnoType::Sort::Double:
buffer.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:
buffer.append('I');
break;
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
{
switch (getKind(manager, type))
{
case StructKind::Empty:
break;
case StructKind::I32:
buffer.append('i');
break;
case StructKind::I64:
buffer.append('j');
break;
case StructKind::F32:
buffer.append('f');
break;
case StructKind::F64:
buffer.append('d');
break;
case StructKind::General:
buffer.append('I');
break;
}
break;
}
default:
throw CannotDumpException("unexpected entity \"" + type
+ "\" in call to appendSlotSignatureReturnType");
}
}
void appendSlotSignatureParameter(
OStringBuffer& buffer, rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method::Parameter::Direction direction, OUString const& type)
{
if (direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
{
switch (manager->getSort(resolveAllTypedefs(manager, 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:
buffer.append('i');
break;
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
buffer.append('j');
break;
case codemaker::UnoType::Sort::Float:
buffer.append('f');
break;
case codemaker::UnoType::Sort::Double:
buffer.append('d');
break;
default:
throw CannotDumpException("unexpected entity \"" + type
+ "\" in call to appendSlotSignatureParameter");
}
}
else
{
buffer.append('i');
}
}
OString computeGetterSlotSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Attribute const& attribute,
sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
OStringBuffer buf;
appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
appendSlotSignatureReturnType(buf, manager, attribute.type);
return buf.makeStringAndClear();
}
OString computeSetterSlotSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Attribute const& attribute,
sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
OStringBuffer buf;
appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
buf.append('v');
appendSlotSignatureParameter(
buf, manager, unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN, attribute.type);
return buf.makeStringAndClear();
}
OString computeMethodSlotSignature(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity::Method const& method,
sal_Int32 functionOffset, sal_Int32 vtableOffset)
{
OStringBuffer buf;
appendSlotSignatureOffsets(buf, functionOffset, vtableOffset);
appendSlotSignatureReturnType(buf, manager, method.returnType);
for (auto const& param : method.parameters)
{
appendSlotSignatureParameter(buf, manager, param.direction, param.type);
}
return buf.makeStringAndClear();
}
void computeSlotSignatures(rtl::Reference<TypeManager> const& manager,
unoidl::InterfaceTypeEntity const& interface, sal_Int32& functionOffset,
sal_Int32& vtableOffset, std::set<OString>& slotSignatures)
{
auto const orgVtableOffset = vtableOffset;
auto firstBase = true;
for (auto const& base : interface.getDirectMandatoryBases())
{
auto const ent = manager->getManager()->findEntity(base.name);
if (!ent.is() || ent->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
{
throw CannotDumpException("unexpected base type \"" + base.name
+ "\" in call to computeSlotSignatures");
}
sal_Int32 freshFunctionOffset = 0;
computeSlotSignatures(manager, *static_cast<unoidl::InterfaceTypeEntity const*>(ent.get()),
firstBase ? functionOffset : freshFunctionOffset, vtableOffset,
slotSignatures);
vtableOffset += 4;
firstBase = false;
}
for (auto const& attr : interface.getDirectAttributes())
{
slotSignatures.insert(
computeGetterSlotSignature(manager, attr, functionOffset, orgVtableOffset));
++functionOffset;
if (!attr.readOnly)
{
slotSignatures.insert(
computeSetterSlotSignature(manager, attr, functionOffset, orgVtableOffset));
++functionOffset;
}
}
for (auto const& meth : interface.getDirectMethods())
{
slotSignatures.insert(
computeMethodSlotSignature(manager, meth, functionOffset, orgVtableOffset));
++functionOffset;
}
}
void appendRttiSymbolSegment(OStringBuffer& buffer, OUString const& id)
{
OString s(OUStringToOString(id, RTL_TEXTENCODING_ASCII_US));
@ -384,7 +613,8 @@ OString computeRttiSymbol(std::vector<OUString> const& path, OUString const& id)
void scan(rtl::Reference<TypeManager> const& manager,
rtl::Reference<unoidl::MapCursor> const& cursor, std::vector<OUString>& path,
std::set<OString>& signatures, std::set<OString>& rttis)
std::set<OString>& callSignatures, std::set<OString>& slotSignatures,
std::set<OString>& rttis)
{
assert(cursor.is());
for (;;)
@ -400,19 +630,31 @@ void scan(rtl::Reference<TypeManager> const& manager,
case unoidl::Entity::SORT_MODULE:
path.push_back(id);
scan(manager, static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(), path,
signatures, rttis);
callSignatures, slotSignatures, 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 :
static_cast<unoidl::InterfaceTypeEntity const*>(ent.get())->getDirectMethods())
{
auto const ite = static_cast<unoidl::InterfaceTypeEntity const*>(ent.get());
for (auto const& attr : ite->getDirectAttributes())
{
signatures.insert(computeSignature(manager, meth));
callSignatures.insert(computeGetterCallSignature(manager, attr));
if (!attr.readOnly)
{
callSignatures.insert(computeSetterCallSignature(manager, attr));
}
}
for (auto const& meth : ite->getDirectMethods())
{
callSignatures.insert(computeMethodCallSignature(manager, meth));
}
computeSlotSignatures(manager, *ite, o3tl::temporary<sal_Int32>(0),
o3tl::temporary<sal_Int32>(0), slotSignatures);
break;
}
default:
break;
}
@ -447,11 +689,12 @@ SAL_IMPLEMENT_MAIN()
}
}
std::vector<OUString> path;
std::set<OString> signatures;
std::set<OString> callSignatures;
std::set<OString> slotSignatures;
std::set<OString> rttis;
for (auto const& prov : mgr->getPrimaryProviders())
{
scan(mgr, prov->createRootCursor(), path, signatures, rttis);
scan(mgr, prov->createRootCursor(), path, callSignatures, slotSignatures, rttis);
}
std::ofstream cppOut(cppPathname, std::ios_base::out | std::ios_base::trunc);
if (!cppOut)
@ -460,18 +703,20 @@ SAL_IMPLEMENT_MAIN()
std::exit(EXIT_FAILURE);
}
cppOut << "#include <sal/config.h>\n"
"#include <bit>\n"
"#include <string_view>\n"
"#include <com/sun/star/uno/RuntimeException.hpp>\n"
"#include <rtl/ustring.hxx>\n"
"#include <wasm/callvirtualfunction.hxx>\n";
for (auto const& sig : signatures)
"#include <sal/types.h>\n"
"#include <wasm/generated.hxx>\n";
for (auto const& sig : callSignatures)
{
cppOut << "extern \"C\" void callVirtualFunction_" << sig
<< "(sal_uInt32 target, sal_uInt64 const * arguments, void * returnValue);\n";
}
cppOut << "void callVirtualFunction(std::string_view signature, sal_uInt32 target, "
"sal_uInt64 const * arguments, void * returnValue) {\n";
for (auto const& sig : signatures)
for (auto const& sig : callSignatures)
{
cppOut << " if (signature == \"" << sig << "\") {\n"
<< " callVirtualFunction_" << sig << "(target, arguments, returnValue);\n"
@ -481,6 +726,145 @@ SAL_IMPLEMENT_MAIN()
cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot call virtual function "
"with signature \" + OUString::fromUtf8(signature));\n"
"}\n";
if (!slotSignatures.empty())
{
cppOut << "namespace {\n";
}
for (auto const& sig : slotSignatures)
{
auto const i1 = sig.indexOf('_');
assert(i1 != -1);
sal_Int32 i2 = i1 + 1;
for (;; ++i2)
{
assert(i2 < sig.getLength());
if (!rtl::isAsciiDigit(static_cast<unsigned char>(sig[i2])))
{
break;
}
}
assert(i2 != i1);
cppOut << "extern \"C\" ";
switch (sig[i2])
{
case 'd':
cppOut << "double";
break;
case 'f':
cppOut << "float";
break;
case 'i':
cppOut << "unsigned";
break;
case 'j':
cppOut << "unsigned long long";
break;
default:
cppOut << "void";
break;
}
cppOut << " vtableSlotFunction_" << sig << "(";
if (sig[i2] == 'I')
{
cppOut << "unsigned indirectRet, ";
}
cppOut << "unsigned thisPtr";
for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i)
{
cppOut << ", ";
switch (sig[i])
{
case 'd':
cppOut << "double";
break;
case 'f':
cppOut << "float";
break;
case 'i':
cppOut << "unsigned";
break;
case 'j':
cppOut << "unsigned long long";
break;
default:
O3TL_UNREACHABLE;
}
cppOut << " arg" << (i - i2);
}
cppOut << ") { ";
switch (sig[i2])
{
case 'd':
cppOut << "return std::bit_cast<double>(static_cast<unsigned long long>(";
break;
case 'f':
cppOut << "return std::bit_cast<float>(static_cast<unsigned>(";
break;
case 'i':
cppOut << "return static_cast<unsigned>(";
break;
case 'j':
cppOut << "return static_cast<unsigned long long>(";
break;
}
cppOut << "vtableCall(" << sig.subView(0, i1) << ", "
<< sig.subView(i1 + 1, i2 - (i1 + 1)) << ", thisPtr, {";
for (sal_Int32 i = i2 + 1; i != sig.getLength(); ++i)
{
if (i != i2 + 1)
{
cppOut << ", ";
}
cppOut << "sal_uInt64(";
switch (sig[i])
{
case 'd':
cppOut << "std::bit_cast<unsigned long long>(";
break;
case 'f':
cppOut << "std::bit_cast<unsigned>(";
break;
}
cppOut << "arg" << (i - i2) << ")";
switch (sig[i])
{
case 'd':
case 'f':
cppOut << ")";
break;
}
}
cppOut << "}, "
<< (sig[i2] == 'I' ? "indirectRet" : "reinterpret_cast<unsigned>(nullptr)")
<< ")";
switch (sig[i2])
{
case 'd':
case 'f':
cppOut << "))";
break;
case 'i':
case 'j':
cppOut << ")";
break;
}
cppOut << "; }\n";
}
if (!slotSignatures.empty())
{
cppOut << "}\n";
}
cppOut << "void const * getVtableSlotFunction(std::string_view signature) {\n";
for (auto const& sig : slotSignatures)
{
cppOut << " if (signature == \"" << sig << "\") {\n"
<< " return reinterpret_cast<void const*>(vtableSlotFunction_" << sig
<< ");\n"
<< " }\n";
}
cppOut << " throw css::uno::RuntimeException(\"Wasm bridge cannot fill virtual function "
"slot with signature \" + OUString::fromUtf8(signature));\n"
"}\n";
cppOut.close();
if (!cppOut)
{
@ -495,11 +879,11 @@ SAL_IMPLEMENT_MAIN()
}
asmOut << "\t.text\n"
"\t.tabletype __indirect_function_table, funcref\n";
for (auto const& sig : signatures)
for (auto const& sig : callSignatures)
{
asmOut << "\t.functype callVirtualFunction_" << sig << " (i32, i32, i32) -> ()\n";
}
for (auto const& sig : signatures)
for (auto const& sig : callSignatures)
{
asmOut << "\t.section .text.callVirtualFunction_" << sig
<< ",\"\",@\n"

View file

@ -12,6 +12,11 @@
environment="@CPPU_ENV@"
loader="com.sun.star.loader.SharedLibrary"
xmlns="http://openoffice.org/2010/uno-components">
<implementation
constructor="org_libreoffice_comp_embindtest_BridgeTest_get_implementation"
name="org.libreoffice.comp.embindtest.BridgeTest">
<singleton name="org.libreoffice.embindtest.BridgeTest"/>
</implementation>
<implementation
constructor="org_libreoffice_comp_embindtest_Test_get_implementation"
name="org.libreoffice.comp.embindtest.Test">

View file

@ -9,6 +9,10 @@
#include <sal/config.h>
#include <cassert>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/task/XJob.hpp>
#include <com/sun/star/task/XJobExecutor.hpp>
#include <com/sun/star/uno/Any.hxx>
@ -26,9 +30,14 @@
#include <org/libreoffice/embindtest/Struct.hpp>
#include <org/libreoffice/embindtest/StructLong.hpp>
#include <org/libreoffice/embindtest/StructString.hpp>
#include <org/libreoffice/embindtest/Test.hpp>
#include <org/libreoffice/embindtest/XTest.hpp>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <uno/dispatcher.hxx>
#include <uno/environment.h>
#include <uno/environment.hxx>
#include <uno/mapping.hxx>
namespace com::sun::star::uno
{
@ -601,6 +610,244 @@ class Test : public cppu::WeakImplHelper<org::libreoffice::embindtest::XTest>
OUString stringAttribute_;
};
class BridgeTest : public cppu::WeakImplHelper<css::task::XJob>
{
public:
explicit BridgeTest(css::uno::Reference<css::uno::XComponentContext> const& context)
: context_(context)
{
}
private:
css::uno::Any SAL_CALL
execute(css::uno::Sequence<css::beans::NamedValue> const& Arguments) override
{
if (Arguments.hasElements())
{
throw css::lang::IllegalArgumentException(u"BridgeTest execute args not empty"_ustr, {},
0);
}
auto const envCppOrig = css::uno::Environment::getCurrent();
css::uno::Environment envUno;
uno_createEnvironment(reinterpret_cast<uno_Environment**>(&envUno),
u"" UNO_LB_UNO ""_ustr.pData, nullptr);
css::uno::Mapping cpp2uno(envCppOrig.get(), envUno.get());
css::uno::Environment envCpp;
if (!cpp2uno.is())
{
throw css::uno::RuntimeException(u"cannot get C++ to UNO mapping"_ustr);
}
uno_createEnvironment(reinterpret_cast<uno_Environment**>(&envCpp),
envCppOrig.getTypeName().pData, nullptr);
css::uno::Mapping uno2cpp(envUno.get(), envCpp.get());
if (!uno2cpp.is())
{
throw css::uno::RuntimeException(u"cannot get UNO to C++ mapping"_ustr);
}
css::uno::UnoInterfaceReference ifcUno;
cpp2uno.mapInterface(reinterpret_cast<void**>(&ifcUno.m_pUnoI),
org::libreoffice::embindtest::Test::get(context_).get(),
cppu::UnoType<org::libreoffice::embindtest::XTest>::get());
if (!ifcUno.is())
{
throw css::uno::RuntimeException(u"cannot map from C++ to UNO"_ustr);
}
css::uno::Reference<org::libreoffice::embindtest::XTest> ifcCpp;
uno2cpp.mapInterface(reinterpret_cast<void**>(&ifcCpp), ifcUno.get(),
cppu::UnoType<org::libreoffice::embindtest::XTest>::get());
if (!ifcCpp.is())
{
throw css::uno::RuntimeException(u"cannot map from UNO to C++"_ustr);
}
{
auto const val = ifcCpp->getBoolean();
assert(val);
auto const ok = ifcCpp->isBoolean(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getByte();
assert(val == -12);
auto const ok = ifcCpp->isByte(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getShort();
assert(val == -1234);
auto const ok = ifcCpp->isShort(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getUnsignedShort();
assert(val == 54321);
auto const ok = ifcCpp->isUnsignedShort(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getLong();
assert(val == -123456);
auto const ok = ifcCpp->isLong(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getUnsignedLong();
assert(val == 3456789012);
auto const ok = ifcCpp->isUnsignedLong(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getHyper();
assert(val == -123456789);
auto const ok = ifcCpp->isHyper(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getUnsignedHyper();
assert(val == 9876543210);
auto const ok = ifcCpp->isUnsignedHyper(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getFloat();
assert(val == -10.25);
auto const ok = ifcCpp->isFloat(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getDouble();
assert(val == 100.5);
auto const ok = ifcCpp->isDouble(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getChar();
assert(val == u'Ö');
auto const ok = ifcCpp->isChar(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getString();
assert(val == u""_ustr);
auto const ok = ifcCpp->isString(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getType();
assert(val == cppu::UnoType<sal_Int32>::get());
auto const ok = ifcCpp->isType(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getEnum();
assert(val == org::libreoffice::embindtest::Enum_E_2);
auto const ok = ifcCpp->isEnum(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getStruct();
assert((val == org::libreoffice::embindtest::Struct{ -123456, 100.5, u""_ustr }));
auto const ok = ifcCpp->isStruct(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getStructLong();
assert(val == org::libreoffice::embindtest::StructLong{ -123456 });
auto const ok = ifcCpp->isStructLong(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getStructString();
assert(val == org::libreoffice::embindtest::StructString{ u""_ustr });
auto const ok = ifcCpp->isStructString(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getAnyVoid();
assert(val == css::uno::Any());
auto const ok = ifcCpp->isAnyVoid(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getSequenceBoolean();
assert((val == css::uno::Sequence<sal_Bool>{ true, true, false }));
auto const ok = ifcCpp->isSequenceBoolean(val);
assert(ok == css::uno::Any(true));
}
{
auto const val = ifcCpp->getNull();
assert(val == css::uno::Reference<org::libreoffice::embindtest::XTest>());
auto const ok = ifcCpp->isNull(val);
assert(ok == css::uno::Any(true));
}
{
sal_Bool value1;
sal_Int8 value2;
sal_Int16 value3;
sal_uInt16 value4;
sal_Int32 value5;
sal_uInt32 value6;
sal_Int64 value7;
sal_uInt64 value8;
float value9;
double value10;
sal_Unicode value11;
OUString value12;
css::uno::Type value13;
css::uno::Any value14;
css::uno::Sequence<OUString> value15;
org::libreoffice::embindtest::Enum value16;
org::libreoffice::embindtest::Struct value17;
css::uno::Reference<org::libreoffice::embindtest::XTest> value18;
ifcCpp->getOut(value1, value2, value3, value4, value5, value6, value7, value8, value9,
value10, value11, value12, value13, value14, value15, value16, value17,
value18);
assert(value1);
assert(value2 == -12);
assert(value3 == -1234);
assert(value4 == 54321);
assert(value5 == -123456);
assert(value6 == 3456789012);
assert(value7 == -123456789);
assert(value8 == 9876543210);
assert(value9 == -10.25);
assert(value10 == 100.5);
assert(value11 == u'Ö');
assert(value12 == u""_ustr);
assert(value13 == cppu::UnoType<sal_Int32>::get());
assert(value14 == css::uno::Any(sal_Int32(-123456)));
assert((value15
== css::uno::Sequence<OUString>{ u"foo"_ustr, u"barr"_ustr, u"bazzz"_ustr }));
assert(value16 == org::libreoffice::embindtest::Enum_E_2);
assert((value17 == org::libreoffice::embindtest::Struct{ -123456, 100.5, u""_ustr }));
assert(value18 == ifcCpp);
}
try
{
ifcCpp->throwRuntimeException();
assert(false);
}
catch (css::uno::RuntimeException& e)
{
assert(e.Message.startsWith("test"));
}
{
ifcCpp->setStringAttribute(u""_ustr);
auto const val = ifcCpp->getStringAttribute();
assert(val == u""_ustr);
}
return css::uno::Any(true);
}
css::uno::Reference<css::uno::XComponentContext> context_;
};
}
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
org_libreoffice_comp_embindtest_BridgeTest_get_implementation(
css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
{
return cppu::acquire(new BridgeTest(context));
}
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*

View file

@ -1107,6 +1107,16 @@ Module.addOnPostRun(function() {
console.assert(ret.get() === 'hä');
ret.delete();
}
{
const args = new Module.uno_Sequence_com$sun$star$beans$NamedValue(
0, Module.uno_Sequence.FromSize);
const ret =
Module.uno.org.libreoffice.embindtest.BridgeTest(Module.getUnoComponentContext()).
execute(args);
args.delete();
console.assert(ret.get() === true);
ret.delete();
}
});
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */