tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_wasm / cpp2uno.cxx
blob000a364e0c400505d8f8dec1cb90955304f7d9c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <cstring>
13 #include <typeinfo>
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>
24 #include <bridge.hxx>
25 #include <cppinterfaceproxy.hxx>
26 #include <types.hxx>
27 #include <vtablefactory.hxx>
28 #include <wasm/generated.hxx>
30 #include "abi.hxx"
32 EM_JS(void*, jsGetExportedSymbol, (char const* name),
33 // clang-format off
35 const val = Module["_" + UTF8ArrayToString(HEAPU8, name)];
36 return typeof val === "number" || typeof val === "bigint" ? val : 0;
38 // clang-format on
41 using bridges::cpp_uno::shared::VtableFactory;
43 struct VtableFactory::Slot
45 void const* fn;
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);
58 namespace
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:
62 struct ProxyRtti
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;
76 namespace
78 class Rtti
80 public:
81 std::type_info* getRtti(typelib_TypeDescription const& type);
83 private:
84 typedef std::unordered_map<OUString, std::type_info*> Map;
86 osl::Mutex mutex_;
87 Map 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));
95 if (i == map_.end())
97 OStringBuffer b("_ZTI");
98 auto const ns = unoName.indexOf('.') != 0;
99 if (ns)
101 b.append('N');
103 for (sal_Int32 j = 0; j != -1;)
105 OString s(
106 OUStringToOString(o3tl::getToken(unoName, 0, '.', j), RTL_TEXTENCODING_ASCII_US));
107 b.append(OString::number(s.getLength()) + s);
109 if (ns)
111 b.append('E');
113 OString sym(b.makeStringAndClear());
114 std::type_info* rtti = static_cast<std::type_info*>(jsGetExportedSymbol(sym.getStr()));
115 if (rtti == nullptr)
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);
129 else
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);
134 rtti = sicti;
137 i = map_.insert(Map::value_type(unoName, rtti)).first;
139 return i->second;
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);
161 return exception;
164 void raiseException(uno_Any* any, uno_Mapping* mapping)
166 typelib_TypeDescription* td = nullptr;
167 TYPELIB_DANGER_GET(&td, any->pType);
168 if (td == nullptr)
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;
206 argtds[i] = nullptr;
208 else
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);
216 argtds[i] = ptd;
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());
222 argtds[i] = ptd;
224 else
226 args[i] = cppArgs[i];
227 argtds[i] = nullptr;
228 TYPELIB_DANGER_RELEASE(ptd);
232 uno_Any exc;
233 uno_Any* pexc = &exc;
234 proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
235 if (pexc != nullptr)
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]);
248 if (rtd != nullptr)
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 = {};
270 if (retConv)
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));
283 break;
284 case typelib_TypeClass_SHORT:
285 retVal = static_cast<int>(*static_cast<sal_Int16 const*>(retin));
286 break;
287 default:
288 std::memcpy(&retVal, retin, rtd->nSize);
289 break;
292 if (rtd != nullptr)
294 TYPELIB_DANGER_RELEASE(rtd);
296 return retVal;
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)
315 // Getter:
316 return call(proxy, desc,
317 reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(desc.get())
318 ->pAttributeTypeRef,
319 0, nullptr, arguments, indirectRet);
321 else
323 // Setter:
324 typelib_MethodParameter param
325 = { nullptr,
326 reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(desc.get())
327 ->pAttributeTypeRef,
328 true, false };
329 return call(proxy, desc, nullptr, 1, &param, arguments, indirectRet);
331 break;
332 case typelib_TypeClass_INTERFACE_METHOD:
333 switch (functionIndex)
335 case 1:
336 proxy->acquireProxy();
337 return {};
338 case 2:
339 proxy->releaseProxy();
340 return {};
341 case 0:
343 typelib_TypeDescription* td = nullptr;
344 TYPELIB_DANGER_GET(
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));
353 if (ifc != nullptr)
355 uno_any_construct(
356 reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
357 reinterpret_cast<uno_AcquireFunc>(css::uno::cpp_acquire));
358 ifc->release();
359 TYPELIB_DANGER_RELEASE(td);
360 return {};
362 TYPELIB_DANGER_RELEASE(td);
365 [[fallthrough]];
366 default:
367 return call(
368 proxy, desc,
369 reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
370 ->pReturnTypeRef,
371 reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
372 ->nParams,
373 reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(desc.get())
374 ->pParams,
375 arguments, indirectRet);
377 default:
378 O3TL_UNREACHABLE;
382 namespace
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:
394 buffer.append('v');
395 break;
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:
404 buffer.append('i');
405 break;
406 case typelib_TypeClass_HYPER:
407 case typelib_TypeClass_UNSIGNED_HYPER:
408 buffer.append('j');
409 break;
410 case typelib_TypeClass_FLOAT:
411 buffer.append('f');
412 break;
413 case typelib_TypeClass_DOUBLE:
414 buffer.append('d');
415 break;
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:
421 buffer.append('I');
422 break;
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:
430 break;
431 case abi_wasm::StructKind::I32:
432 buffer.append('i');
433 break;
434 case abi_wasm::StructKind::I64:
435 buffer.append('j');
436 break;
437 case abi_wasm::StructKind::F32:
438 buffer.append('f');
439 break;
440 case abi_wasm::StructKind::F64:
441 buffer.append('d');
442 break;
443 case abi_wasm::StructKind::General:
444 buffer.append('I');
445 break;
447 break;
449 default:
450 O3TL_UNREACHABLE;
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:
469 buffer.append('i');
470 break;
471 case typelib_TypeClass_HYPER:
472 case typelib_TypeClass_UNSIGNED_HYPER:
473 buffer.append('j');
474 break;
475 case typelib_TypeClass_FLOAT:
476 buffer.append('f');
477 break;
478 case typelib_TypeClass_DOUBLE:
479 buffer.append('d');
480 break;
481 default:
482 O3TL_UNREACHABLE;
485 else
487 buffer.append('i');
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;
498 auto s = *slots;
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);
511 ++functionOffset;
512 if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(
513 css::uno::TypeDescription(type->ppMembers[i]).get())
514 ->bReadOnly)
516 OStringBuffer sigSetter;
517 appendSignatureOffsets(sigSetter, functionOffset, vtableOffset);
518 sigSetter.append('v');
519 appendSignatureParameter(sigSetter, false, atd->pAttributeTypeRef);
520 (s++)->fn = getVtableSlotFunction(sigSetter);
521 ++functionOffset;
523 break;
525 case typelib_TypeClass_INTERFACE_METHOD:
527 auto const mtd = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
528 css::uno::TypeDescription(type->ppMembers[i]).get());
529 OStringBuffer sig;
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);
537 ++functionOffset;
538 break;
540 default:
541 O3TL_UNREACHABLE;
544 return code;
547 void VtableFactory::flushCode(unsigned char const*, unsigned char const*) {}
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */