1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
15 #include <emscripten.h>
17 #include <com/sun/star/uno/RuntimeException.hpp>
18 #include <o3tl/string_view.hxx>
19 #include <o3tl/unreachable.hxx>
20 #include <rtl/strbuf.hxx>
21 #include <typelib/typeclass.h>
22 #include <typelib/typedescription.hxx>
25 #include <cppinterfaceproxy.hxx>
27 #include <vtablefactory.hxx>
28 #include <wasm/generated.hxx>
32 EM_JS(void*, jsGetExportedSymbol
, (char const* name
),
35 const val
= Module
["_" + UTF8ArrayToString(HEAPU8
, name
)];
36 return typeof val
=== "number" || typeof val
=== "bigint" ? val
: 0;
41 using bridges::cpp_uno::shared::VtableFactory
;
43 struct VtableFactory::Slot
48 VtableFactory::Slot
* VtableFactory::mapBlockToVtable(void* block
)
50 return static_cast<Slot
*>(block
) + 2;
53 std::size_t VtableFactory::getBlockSize(sal_Int32 slotCount
)
55 return (slotCount
+ 2) * sizeof(Slot
);
60 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
61 // on such proxy objects not crash:
67 VtableFactory::Slot
* VtableFactory::initializeBlock(void* block
, sal_Int32 slotCount
, sal_Int32
,
68 typelib_InterfaceTypeDescription
*)
70 Slot
* slots
= mapBlockToVtable(block
);
71 slots
[-2].fn
= nullptr;
72 slots
[-1].fn
= &typeid(ProxyRtti
);
73 return slots
+ slotCount
;
81 std::type_info
* getRtti(typelib_TypeDescription
const& type
);
84 typedef std::unordered_map
<OUString
, std::type_info
*> Map
;
90 std::type_info
* Rtti::getRtti(typelib_TypeDescription
const& type
)
92 OUString
unoName(type
.pTypeName
);
93 osl::MutexGuard
g(mutex_
);
94 Map::iterator
i(map_
.find(unoName
));
97 OStringBuffer
b("_ZTI");
98 auto const ns
= unoName
.indexOf('.') != 0;
103 for (sal_Int32 j
= 0; j
!= -1;)
106 OUStringToOString(o3tl::getToken(unoName
, 0, '.', j
), RTL_TEXTENCODING_ASCII_US
));
107 b
.append(OString::number(s
.getLength()) + s
);
113 OString
sym(b
.makeStringAndClear());
114 std::type_info
* rtti
= static_cast<std::type_info
*>(jsGetExportedSymbol(sym
.getStr()));
117 char const* rttiName
= strdup(sym
.getStr() + std::strlen("_ZTI"));
118 if (rttiName
== nullptr)
120 throw std::bad_alloc();
122 assert(type
.eTypeClass
== typelib_TypeClass_EXCEPTION
);
123 typelib_CompoundTypeDescription
const& ctd
124 = reinterpret_cast<typelib_CompoundTypeDescription
const&>(type
);
125 if (ctd
.pBaseTypeDescription
== nullptr)
127 rtti
= new __cxxabiv1::__class_type_info(rttiName
);
131 std::type_info
* base
= getRtti(ctd
.pBaseTypeDescription
->aBase
);
132 auto const sicti
= new __cxxabiv1::__si_class_type_info(rttiName
);
133 sicti
->__base_type
= static_cast<__cxxabiv1::__class_type_info
*>(base
);
137 i
= map_
.insert(Map::value_type(unoName
, rtti
)).first
;
142 struct theRttiFactory
: public rtl::Static
<Rtti
, theRttiFactory
>
146 std::type_info
* getRtti(typelib_TypeDescription
const& type
)
148 return theRttiFactory::get().getRtti(type
);
151 extern "C" void* /*_GLIBCXX_CDTOR_CALLABI*/ deleteException(void* exception
)
153 __cxxabiv1::__cxa_exception
* header
= static_cast<__cxxabiv1::__cxa_exception
*>(exception
) - 1;
154 assert(header
->exceptionDestructor
== &deleteException
);
155 OUString
unoName(emscriptencxxabi::toUnoName(header
->exceptionType
->name()));
156 typelib_TypeDescription
* td
= nullptr;
157 typelib_typedescription_getByName(&td
, unoName
.pData
);
158 assert(td
!= nullptr);
159 uno_destructData(exception
, td
, &css::uno::cpp_release
);
160 typelib_typedescription_release(td
);
164 void raiseException(uno_Any
* any
, uno_Mapping
* mapping
)
166 typelib_TypeDescription
* td
= nullptr;
167 TYPELIB_DANGER_GET(&td
, any
->pType
);
170 throw css::uno::RuntimeException("no typedescription for "
171 + OUString::unacquired(&any
->pType
->pTypeName
));
173 void* exc
= __cxxabiv1::__cxa_allocate_exception(td
->nSize
);
174 uno_copyAndConvertData(exc
, any
->pData
, td
, mapping
);
175 uno_any_destruct(any
, nullptr);
176 std::type_info
* rtti
= getRtti(*td
);
177 TYPELIB_DANGER_RELEASE(td
);
178 __cxxabiv1::__cxa_throw(exc
, rtti
, deleteException
);
181 sal_uInt64
call(bridges::cpp_uno::shared::CppInterfaceProxy
* proxy
,
182 css::uno::TypeDescription
const& description
,
183 typelib_TypeDescriptionReference
* returnType
, sal_Int32 count
,
184 typelib_MethodParameter
* parameters
, std::vector
<sal_uInt64
> arguments
,
185 unsigned indirectRet
)
187 typelib_TypeDescription
* rtd
= nullptr;
188 if (returnType
!= nullptr)
190 TYPELIB_DANGER_GET(&rtd
, returnType
);
192 auto const retConv
= rtd
!= nullptr && bridges::cpp_uno::shared::relatesToInterfaceType(rtd
);
193 void* retin
= reinterpret_cast<void*>(indirectRet
) != nullptr && !retConv
194 ? reinterpret_cast<void*>(indirectRet
)
195 : rtd
== nullptr ? nullptr : alloca(rtd
->nSize
);
196 void** args
= static_cast<void**>(alloca(count
* sizeof(void*)));
197 void** cppArgs
= static_cast<void**>(alloca(count
* sizeof(void*)));
198 typelib_TypeDescription
** argtds
199 = static_cast<typelib_TypeDescription
**>(alloca(count
* sizeof(typelib_TypeDescription
*)));
200 std::size_t argument_index
= 0;
201 for (sal_Int32 i
= 0; i
!= count
; ++i
)
203 if (!parameters
[i
].bOut
&& bridges::cpp_uno::shared::isSimpleType(parameters
[i
].pTypeRef
))
205 args
[i
] = arguments
.data() + i
;
210 cppArgs
[i
] = reinterpret_cast<void*>(arguments
[argument_index
++]);
211 typelib_TypeDescription
* ptd
= nullptr;
212 TYPELIB_DANGER_GET(&ptd
, parameters
[i
].pTypeRef
);
213 if (!parameters
[i
].bIn
)
215 args
[i
] = alloca(ptd
->nSize
);
218 else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd
))
220 args
[i
] = alloca(ptd
->nSize
);
221 uno_copyAndConvertData(args
[i
], cppArgs
[i
], ptd
, proxy
->getBridge()->getCpp2Uno());
226 args
[i
] = cppArgs
[i
];
228 TYPELIB_DANGER_RELEASE(ptd
);
233 uno_Any
* pexc
= &exc
;
234 proxy
->getUnoI()->pDispatcher(proxy
->getUnoI(), description
.get(), retin
, args
, &pexc
);
237 for (sal_Int32 i
= 0; i
!= count
; ++i
)
239 if (argtds
[i
] != nullptr)
241 if (parameters
[i
].bIn
)
243 uno_destructData(args
[i
], argtds
[i
], nullptr);
245 TYPELIB_DANGER_RELEASE(argtds
[i
]);
250 TYPELIB_DANGER_RELEASE(rtd
);
252 raiseException(&exc
, proxy
->getBridge()->getUno2Cpp());
254 for (sal_Int32 i
= 0; i
!= count
; ++i
)
256 if (argtds
[i
] != nullptr)
258 if (parameters
[i
].bOut
)
260 uno_destructData(cppArgs
[i
], argtds
[i
],
261 reinterpret_cast<uno_ReleaseFunc
>(css::uno::cpp_release
));
262 uno_copyAndConvertData(cppArgs
[i
], args
[i
], argtds
[i
],
263 proxy
->getBridge()->getUno2Cpp());
265 uno_destructData(args
[i
], argtds
[i
], nullptr);
266 TYPELIB_DANGER_RELEASE(argtds
[i
]);
269 sal_uInt64 retVal
= {};
272 uno_copyAndConvertData(reinterpret_cast<void*>(indirectRet
), retin
, rtd
,
273 proxy
->getBridge()->getUno2Cpp());
274 uno_destructData(retin
, rtd
, nullptr);
276 else if (rtd
!= nullptr)
278 // Make sure to sign-extend the return value for small signed integer types:
279 switch (rtd
->eTypeClass
)
281 case typelib_TypeClass_BYTE
:
282 retVal
= static_cast<int>(*static_cast<sal_Int8
const*>(retin
));
284 case typelib_TypeClass_SHORT
:
285 retVal
= static_cast<int>(*static_cast<sal_Int16
const*>(retin
));
288 std::memcpy(&retVal
, retin
, rtd
->nSize
);
294 TYPELIB_DANGER_RELEASE(rtd
);
300 sal_uInt64
vtableCall(sal_Int32 functionIndex
, sal_Int32 vtableOffset
, unsigned thisPtr
,
301 std::vector
<sal_uInt64
> const& arguments
, unsigned indirectRet
)
303 bridges::cpp_uno::shared::CppInterfaceProxy
* proxy
304 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
305 reinterpret_cast<char*>(thisPtr
) - vtableOffset
);
306 typelib_InterfaceTypeDescription
* type
= proxy
->getTypeDescr();
307 assert(functionIndex
< type
->nMapFunctionIndexToMemberIndex
);
308 sal_Int32 pos
= type
->pMapFunctionIndexToMemberIndex
[functionIndex
];
309 css::uno::TypeDescription
desc(type
->ppAllMembers
[pos
]);
310 switch (desc
.get()->eTypeClass
)
312 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
313 if (type
->pMapMemberIndexToFunctionIndex
[pos
] == functionIndex
)
316 return call(proxy
, desc
,
317 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(desc
.get())
319 0, nullptr, arguments
, indirectRet
);
324 typelib_MethodParameter param
326 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(desc
.get())
329 return call(proxy
, desc
, nullptr, 1, ¶m
, arguments
, indirectRet
);
332 case typelib_TypeClass_INTERFACE_METHOD
:
333 switch (functionIndex
)
336 proxy
->acquireProxy();
339 proxy
->releaseProxy();
343 typelib_TypeDescription
* td
= nullptr;
345 &td
, (reinterpret_cast<css::uno::Type
*>(arguments
[0])->getTypeLibType()));
346 if (td
!= nullptr && td
->eTypeClass
== typelib_TypeClass_INTERFACE
)
348 css::uno::XInterface
* ifc
= nullptr;
349 proxy
->getBridge()->getCppEnv()->getRegisteredInterface(
350 proxy
->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc
),
351 proxy
->getOid().pData
,
352 reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
));
356 reinterpret_cast<uno_Any
*>(indirectRet
), &ifc
, td
,
357 reinterpret_cast<uno_AcquireFunc
>(css::uno::cpp_acquire
));
359 TYPELIB_DANGER_RELEASE(td
);
362 TYPELIB_DANGER_RELEASE(td
);
369 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(desc
.get())
371 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(desc
.get())
373 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(desc
.get())
375 arguments
, indirectRet
);
384 void appendSignatureOffsets(OStringBuffer
& buffer
, sal_Int32 functionOffset
, sal_Int32 vtableOffset
)
386 buffer
.append(OString::number(functionOffset
) + "_" + OString::number(vtableOffset
));
389 void appendSignatureReturnType(OStringBuffer
& buffer
, typelib_TypeDescriptionReference
* type
)
391 switch (type
->eTypeClass
)
393 case typelib_TypeClass_VOID
:
396 case typelib_TypeClass_BOOLEAN
:
397 case typelib_TypeClass_BYTE
:
398 case typelib_TypeClass_SHORT
:
399 case typelib_TypeClass_UNSIGNED_SHORT
:
400 case typelib_TypeClass_LONG
:
401 case typelib_TypeClass_UNSIGNED_LONG
:
402 case typelib_TypeClass_CHAR
:
403 case typelib_TypeClass_ENUM
:
406 case typelib_TypeClass_HYPER
:
407 case typelib_TypeClass_UNSIGNED_HYPER
:
410 case typelib_TypeClass_FLOAT
:
413 case typelib_TypeClass_DOUBLE
:
416 case typelib_TypeClass_STRING
:
417 case typelib_TypeClass_TYPE
:
418 case typelib_TypeClass_ANY
:
419 case typelib_TypeClass_SEQUENCE
:
420 case typelib_TypeClass_INTERFACE
:
423 case typelib_TypeClass_STRUCT
:
425 css::uno::TypeDescription
td(type
);
426 switch (abi_wasm::getKind(
427 reinterpret_cast<typelib_CompoundTypeDescription
const*>(td
.get())))
429 case abi_wasm::StructKind::Empty
:
431 case abi_wasm::StructKind::I32
:
434 case abi_wasm::StructKind::I64
:
437 case abi_wasm::StructKind::F32
:
440 case abi_wasm::StructKind::F64
:
443 case abi_wasm::StructKind::General
:
454 void appendSignatureParameter(OStringBuffer
& buffer
, bool out
,
455 typelib_TypeDescriptionReference
const* type
)
457 if (!out
&& bridges::cpp_uno::shared::isSimpleType(type
))
459 switch (type
->eTypeClass
)
461 case typelib_TypeClass_BOOLEAN
:
462 case typelib_TypeClass_BYTE
:
463 case typelib_TypeClass_SHORT
:
464 case typelib_TypeClass_UNSIGNED_SHORT
:
465 case typelib_TypeClass_LONG
:
466 case typelib_TypeClass_ENUM
:
467 case typelib_TypeClass_UNSIGNED_LONG
:
468 case typelib_TypeClass_CHAR
:
471 case typelib_TypeClass_HYPER
:
472 case typelib_TypeClass_UNSIGNED_HYPER
:
475 case typelib_TypeClass_FLOAT
:
478 case typelib_TypeClass_DOUBLE
:
492 unsigned char* VtableFactory::addLocalFunctions(Slot
** slots
, unsigned char* code
,
493 typelib_InterfaceTypeDescription
const* type
,
494 sal_Int32 functionOffset
, sal_Int32 functionCount
,
495 sal_Int32 vtableOffset
)
497 *slots
-= functionCount
;
499 for (sal_Int32 i
= 0; i
!= type
->nMembers
; ++i
)
501 switch (type
->ppMembers
[i
]->eTypeClass
)
503 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
505 auto const atd
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(
506 css::uno::TypeDescription(type
->ppMembers
[i
]).get());
507 OStringBuffer sigGetter
;
508 appendSignatureOffsets(sigGetter
, functionOffset
, vtableOffset
);
509 appendSignatureReturnType(sigGetter
, atd
->pAttributeTypeRef
);
510 (s
++)->fn
= getVtableSlotFunction(sigGetter
);
512 if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(
513 css::uno::TypeDescription(type
->ppMembers
[i
]).get())
516 OStringBuffer sigSetter
;
517 appendSignatureOffsets(sigSetter
, functionOffset
, vtableOffset
);
518 sigSetter
.append('v');
519 appendSignatureParameter(sigSetter
, false, atd
->pAttributeTypeRef
);
520 (s
++)->fn
= getVtableSlotFunction(sigSetter
);
525 case typelib_TypeClass_INTERFACE_METHOD
:
527 auto const mtd
= reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(
528 css::uno::TypeDescription(type
->ppMembers
[i
]).get());
530 appendSignatureOffsets(sig
, functionOffset
, vtableOffset
);
531 appendSignatureReturnType(sig
, mtd
->pReturnTypeRef
);
532 for (sal_Int32 j
= 0; j
!= mtd
->nParams
; ++j
)
534 appendSignatureParameter(sig
, mtd
->pParams
[j
].bOut
, mtd
->pParams
[j
].pTypeRef
);
536 (s
++)->fn
= getVtableSlotFunction(sig
);
547 void VtableFactory::flushCode(unsigned char const*, unsigned char const*) {}
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */