summaryrefslogtreecommitdiffstats
path: root/bridges
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /bridges
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--bridges/CustomTarget_gcc3_linux_arm.mk25
-rw-r--r--bridges/Jar_java_uno.mk30
-rw-r--r--bridges/Library_cpp_uno.mk297
-rw-r--r--bridges/Library_java_uno.mk37
-rw-r--r--bridges/Makefile14
-rw-r--r--bridges/Module_bridges.mk33
-rw-r--r--bridges/Package_jnilib_java_uno.mk14
-rw-r--r--bridges/README.md6
-rw-r--r--bridges/inc/bridge.hxx116
-rw-r--r--bridges/inc/cppinterfaceproxy.hxx98
-rw-r--r--bridges/inc/except.hxx36
-rw-r--r--bridges/inc/msvc/amd64.hxx59
-rw-r--r--bridges/inc/msvc/arm64.hxx59
-rw-r--r--bridges/inc/msvc/cpp2uno.hxx31
-rw-r--r--bridges/inc/msvc/except.hxx117
-rw-r--r--bridges/inc/msvc/x86.hxx68
-rw-r--r--bridges/inc/types.hxx67
-rw-r--r--bridges/inc/unointerfaceproxy.hxx105
-rw-r--r--bridges/inc/vtablefactory.hxx221
-rw-r--r--bridges/inc/vtables.hxx97
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx551
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/except.cxx406
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/ios64_helper.s233
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/rtti.h407
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/share.hxx57
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/uno2cpp.cxx565
-rw-r--r--bridges/source/cpp_uno/gcc3_ios/unwind-cxx.h285
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx373
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx157
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx69
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx30
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx606
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx519
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s83
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx676
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_alpha/except.cxx257
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_alpha/share.hxx87
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_alpha/uno2cpp.cxx536
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S70
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/call.hxx28
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx593
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/except.cxx327
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/share.hxx159
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx758
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_hppa/call.cxx133
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx720
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_hppa/except.cxx298
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_hppa/share.hxx92
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_hppa/uno2cpp.cxx526
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_ia64/call.s29
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx681
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_ia64/except.cxx256
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_ia64/share.hxx122
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_ia64/uno2cpp.cxx694
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/call.hxx28
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/call.s308
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.cxx150
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.hxx37
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx527
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/except.cxx302
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/share.hxx156
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx392
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.cxx163
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.hxx55
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/call.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/call.s138
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx564
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/except.cxx251
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/share.hxx82
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_loongarch64/uno2cpp.cxx479
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx528
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_m68k/except.cxx297
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_m68k/share.hxx84
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_m68k/uno2cpp.cxx497
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx813
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips/except.cxx289
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips/share.hxx84
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx602
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/call.hxx35
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/call.s134
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx711
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/except.cxx289
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/share.hxx89
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_mips64/uno2cpp.cxx592
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx792
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc/except.cxx258
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc/share.hxx84
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc/uno2cpp.cxx686
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx755
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc64/except.cxx256
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc64/share.hxx90
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_powerpc64/uno2cpp.cxx712
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/abi.cxx95
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/abi.hxx23
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/call.s81
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx825
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx282
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx85
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx616
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx656
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_s390x/except.cxx257
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_s390x/share.hxx87
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_s390x/uno2cpp.cxx541
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc/call.s28
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx580
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc/except.cxx291
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc/share.hxx92
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc/uno2cpp.cxx609
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc64/call.s77
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx751
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc64/except.cxx291
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc64/share.hxx98
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_sparc64/uno2cpp.cxx853
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/abi.cxx305
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/abi.hxx67
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/call.hxx31
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/call.s142
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.cxx178
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.hxx37
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx541
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx256
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.cxx272
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx191
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_x86-64/uno2cpp.cxx437
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx305
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx67
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/call.cxx81
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/call.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx178
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx37
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx543
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx407
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx156
-rw-r--r--bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx442
-rw-r--r--bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx47
-rw-r--r--bridges/source/cpp_uno/gcc3_wasm/except.cxx22
-rw-r--r--bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx93
-rw-r--r--bridges/source/cpp_uno/msvc_shared/cpp2uno.cxx354
-rw-r--r--bridges/source/cpp_uno/msvc_shared/except.cxx339
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx158
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx34
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S72
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx519
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/except.cxx234
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx341
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S72
-rw-r--r--bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx228
-rw-r--r--bridges/source/cpp_uno/msvc_win32_intel/except.cxx189
-rw-r--r--bridges/source/cpp_uno/msvc_win32_intel/uno2cpp.cxx460
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/call.asm112
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx29
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx335
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx465
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx454
-rw-r--r--bridges/source/cpp_uno/shared/bridge.cxx210
-rw-r--r--bridges/source/cpp_uno/shared/component.cxx224
-rw-r--r--bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx145
-rw-r--r--bridges/source/cpp_uno/shared/types.cxx117
-rw-r--r--bridges/source/cpp_uno/shared/unointerfaceproxy.cxx126
-rw-r--r--bridges/source/cpp_uno/shared/vtablefactory.cxx403
-rw-r--r--bridges/source/cpp_uno/shared/vtables.cxx146
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java61
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java225
-rw-r--r--bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest1
-rw-r--r--bridges/source/jni_uno/jni_base.h258
-rw-r--r--bridges/source/jni_uno/jni_bridge.cxx577
-rw-r--r--bridges/source/jni_uno/jni_bridge.h118
-rw-r--r--bridges/source/jni_uno/jni_data.cxx2476
-rw-r--r--bridges/source/jni_uno/jni_helper.h151
-rw-r--r--bridges/source/jni_uno/jni_info.cxx978
-rw-r--r--bridges/source/jni_uno/jni_info.h366
-rw-r--r--bridges/source/jni_uno/jni_java2uno.cxx624
-rw-r--r--bridges/source/jni_uno/jni_uno2java.cxx804
-rw-r--r--bridges/source/jni_uno/jniunoenvironmentdata.hxx54
-rw-r--r--bridges/source/jni_uno/nativethreadpool.cxx227
178 files changed, 50126 insertions, 0 deletions
diff --git a/bridges/CustomTarget_gcc3_linux_arm.mk b/bridges/CustomTarget_gcc3_linux_arm.mk
new file mode 100644
index 0000000000..327f1e06a5
--- /dev/null
+++ b/bridges/CustomTarget_gcc3_linux_arm.mk
@@ -0,0 +1,25 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,bridges/source/cpp_uno/gcc3_linux_arm))
+
+$(call gb_CustomTarget_get_target,bridges/source/cpp_uno/gcc3_linux_arm) : \
+ $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist
+
+$(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.o : \
+ $(SRCDIR)/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S \
+ | $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/.dir
+ $(gb_CXX) -c -o $@ $< -fPIC
+
+$(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist : \
+ $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.o \
+ | $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/.dir
+ echo $< > $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Jar_java_uno.mk b/bridges/Jar_java_uno.mk
new file mode 100644
index 0000000000..14be1adcc6
--- /dev/null
+++ b/bridges/Jar_java_uno.mk
@@ -0,0 +1,30 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_Jar_Jar,java_uno))
+
+$(eval $(call gb_Jar_use_jars,java_uno,\
+ libreoffice \
+))
+
+$(eval $(call gb_Jar_set_manifest,java_uno,$(SRCDIR)/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest))
+
+$(eval $(call gb_Jar_set_packageroot,java_uno,com))
+
+$(eval $(call gb_Jar_add_manifest_classpath,java_uno,\
+ libreoffice.jar \
+ $(if $(filter MACOSX,$(OS)),../../Frameworks/,../) \
+))
+
+$(eval $(call gb_Jar_add_sourcefiles,java_uno,\
+ bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder \
+ bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk
new file mode 100644
index 0000000000..7b10348e83
--- /dev/null
+++ b/bridges/Library_cpp_uno.mk
@@ -0,0 +1,297 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_Library_Library,$(CPPU_ENV)_uno))
+
+ifeq ($(CPUNAME),ARM)
+
+ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_arm
+bridge_noopt_objects := cpp2uno except uno2cpp
+# HACK
+$(call gb_Library_get_linktarget_target,gcc3_uno) : \
+ $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist
+$(call gb_Library_get_linktarget_target,gcc3_uno) : \
+ EXTRAOBJECTLISTS += $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist
+endif
+
+else ifeq ($(CPUNAME),AARCH64)
+
+ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX MACOSX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_aarch64
+bridge_asm_objects := vtableslotcall
+bridge_exception_objects := abi cpp2uno uno2cpp
+
+$(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno, \
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/callvirtualfunction, \
+ $(if $(HAVE_GCC_STACK_CLASH_PROTECTION),-fno-stack-clash-protection) \
+ $(if $(COM_IS_CLANG),-fasynchronous-unwind-tables) \
+))
+
+else ifeq ($(OS),iOS)
+bridges_SELECTED_BRIDGE := gcc3_ios
+bridge_noopt_objects := cpp2uno except uno2cpp
+bridge_asm_objects := ios64_helper
+
+else ifeq ($(COM),MSC)
+bridges_SELECTED_BRIDGE := msvc_win32_arm64
+bridge_exception_objects := cpp2uno uno2cpp abi
+bridge_noopt_objects := except
+bridge_asm_objects := callvirtualfunction vtableslotcall
+
+endif
+
+else ifeq ($(CPUNAME),AXP)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_alpha
+bridge_exception_objects := cpp2uno except uno2cpp
+endif
+
+else ifeq ($(CPUNAME),HPPA)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_hppa
+bridge_noopt_objects := call cpp2uno except uno2cpp
+endif
+
+else ifeq ($(CPUNAME),IA64)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_ia64
+bridge_asm_objects := call
+bridge_exception_objects := except
+bridge_noopt_objects := cpp2uno uno2cpp
+endif
+
+else ifeq ($(CPUNAME),INTEL)
+
+ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX NETBSD OPENBSD HAIKU,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_intel
+bridge_asm_objects := call
+bridge_exception_objects := cpp2uno except uno2cpp
+bridge_noncallexception_objects := callvirtualmethod
+else ifeq ($(COM),MSC)
+bridges_SELECTED_BRIDGE := msvc_win32_intel
+bridge_exception_objects := cpp2uno uno2cpp
+bridge_noopt_objects := except
+else ifeq ($(OS),EMSCRIPTEN)
+bridges_SELECTED_BRIDGE := gcc3_wasm
+bridge_noopt_objects := cpp2uno except uno2cpp
+endif
+
+else ifeq ($(CPUNAME),M68K)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_m68k
+bridge_noopt_objects := cpp2uno except uno2cpp
+endif
+
+else ifeq ($(CPUNAME),MIPS)
+
+ifneq ($(filter LINUX,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_mips
+bridge_noopt_objects := cpp2uno uno2cpp
+bridge_exception_objects := except
+endif
+
+else ifeq ($(CPUNAME),MIPS64)
+
+ifneq ($(filter LINUX,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_mips64
+bridge_asm_objects := call
+bridge_noopt_objects := cpp2uno uno2cpp
+bridge_exception_objects := except
+endif
+
+else ifeq ($(CPUNAME),LOONGARCH64)
+
+ifneq ($(filter LINUX,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_loongarch64
+bridge_asm_objects := call
+bridge_noopt_objects := abi cpp2uno uno2cpp
+bridge_exception_objects := except
+endif
+
+else ifeq ($(CPUNAME),RISCV64)
+
+ifneq ($(filter LINUX,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_riscv64
+bridge_asm_objects := call
+bridge_noopt_objects := abi cpp2uno uno2cpp
+bridge_exception_objects := except
+endif
+
+else ifeq ($(CPUNAME),POWERPC)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_powerpc
+bridge_noopt_objects := uno2cpp
+bridge_exception_objects := cpp2uno except
+endif
+
+else ifeq ($(CPUNAME),POWERPC64)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_powerpc64
+bridge_noopt_objects := cpp2uno uno2cpp
+bridge_exception_objects := except
+endif
+
+else ifeq ($(CPUNAME),S390X)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_s390x
+bridge_exception_objects := cpp2uno except uno2cpp
+endif
+
+else ifeq ($(CPUNAME),SPARC)
+
+ifneq ($(filter DRAGONFLY FREEBSD LINUX NETBSD OPENBSD,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_sparc
+bridge_asm_objects := call
+bridge_noopt_objects := except
+bridge_exception_objects := cpp2uno uno2cpp
+endif
+
+else ifeq ($(OS)-$(CPUNAME),LINUX-SPARC64)
+
+bridges_SELECTED_BRIDGE := gcc3_linux_sparc64
+bridge_asm_objects := call
+bridge_noopt_objects := cpp2uno uno2cpp
+bridge_exception_objects := except
+
+else ifeq ($(CPUNAME),X86_64)
+
+ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX NETBSD OPENBSD HAIKU,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_linux_x86-64
+bridge_asm_objects := call
+bridge_noncallexception_noopt_objects := callvirtualmethod
+bridge_exception_objects := abi cpp2uno except rtti uno2cpp
+else ifneq ($(filter MACOSX iOS,$(OS)),)
+bridges_SELECTED_BRIDGE := gcc3_macosx_x86-64
+bridge_exception_objects := abi call cpp2uno except uno2cpp
+bridge_noncallexception_noopt_objects := callvirtualmethod
+else ifeq ($(COM),MSC)
+bridges_SELECTED_BRIDGE := msvc_win32_x86-64
+bridge_exception_objects := cpp2uno uno2cpp
+bridge_noopt_objects := except
+bridge_asm_objects := call
+endif
+
+endif
+
+$(eval $(call gb_Library_use_internal_comprehensive_api,$(CPPU_ENV)_uno,\
+ udkapi \
+))
+
+ifeq ($(OS),MACOSX)
+ifeq ($(CPUNAME),AARCH64)
+$(eval $(call gb_Library_use_internal_comprehensive_api,$(CPPU_ENV)_uno,\
+ offapi \
+))
+endif
+endif
+
+$(eval $(call gb_Library_set_include,$(CPPU_ENV)_uno,\
+ -I$(SRCDIR)/bridges/inc \
+ $$(INCLUDE) \
+))
+
+ifeq ($(HAVE_POSIX_FALLOCATE),YES)
+$(eval $(call gb_Library_add_defs,$(CPPU_ENV)_uno,\
+ -DHAVE_POSIX_FALLOCATE \
+))
+endif
+
+# In case someone enabled the non-standard -fomit-frame-pointer which does not
+# work with the .cxx sources of this library.
+# LTO causes crashes when enabled for this library
+# In case the compiler supports AVX this code segfaults so specifically turn
+# it off.
+ifeq ($(COM),GCC)
+$(eval $(call gb_Library_add_cxxflags,gcc3_uno,\
+ -fno-omit-frame-pointer \
+ -fno-strict-aliasing \
+ -fno-lto \
+ $(if $(filter TRUE,$(HAVE_GCC_AVX)),-mno-avx) \
+))
+
+ifeq ($(filter ANDROID WNT DRAGONFLY FREEBSD NETBSD OPENBSD MACOSX iOS HAIKU,$(OS)),)
+$(eval $(call gb_Library_add_libs,gcc3_uno,\
+ -ldl \
+))
+endif
+endif
+
+ifeq ($(COM),GCC)
+ifneq ($(COM_IS_CLANG),TRUE)
+bridges_NON_CALL_EXCEPTIONS_FLAGS := -fnon-call-exceptions
+endif
+endif
+
+$(eval $(call gb_Library_use_libraries,$(CPPU_ENV)_uno,\
+ cppu \
+ sal \
+))
+
+$(foreach obj,$(bridge_exception_objects),\
+ $(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj))) \
+)
+$(foreach obj,$(bridge_noncallexception_objects),\
+ $(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj) \
+ , $(bridges_NON_CALL_EXCEPTIONS_FLAGS) )) \
+)
+$(foreach obj,$(bridge_noopt_objects),\
+ $(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj) \
+ , $(gb_COMPILERNOOPTFLAGS))) \
+ )
+$(foreach obj,$(bridge_noncallexception_noopt_objects),\
+ $(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj) \
+ , $(gb_COMPILERNOOPTFLAGS) $(bridges_NON_CALL_EXCEPTIONS_FLAGS) )) \
+ )
+$(foreach obj,$(bridge_cxx_objects),\
+ $(eval $(call gb_Library_add_cxxobjects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj))) \
+ )
+$(foreach obj,$(bridge_asm_objects),\
+ $(eval $(call gb_Library_add_asmobjects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/$(bridges_SELECTED_BRIDGE)/$(obj))) \
+ )
+
+$(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/shared/bridge \
+ bridges/source/cpp_uno/shared/component \
+ bridges/source/cpp_uno/shared/types \
+ bridges/source/cpp_uno/shared/unointerfaceproxy \
+ bridges/source/cpp_uno/shared/vtablefactory \
+ bridges/source/cpp_uno/shared/vtables \
+ ))
+
+ifeq ($(COM),MSC)
+$(eval $(call gb_Library_add_exception_objects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/msvc_shared/cpp2uno \
+ bridges/source/cpp_uno/msvc_shared/except \
+))
+endif
+
+$(eval $(call gb_Library_add_cxxobjects,$(CPPU_ENV)_uno,\
+ bridges/source/cpp_uno/shared/cppinterfaceproxy \
+ , $(gb_COMPILERNOOPTFLAGS) $(gb_LinkTarget_EXCEPTIONFLAGS) \
+ ))
+
+ifeq ($(DISABLE_DYNLOADING),TRUE)
+$(eval $(call gb_Library_set_plugin_for_nodep,$(CPPU_ENV)_uno,cppu))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Library_java_uno.mk b/bridges/Library_java_uno.mk
new file mode 100644
index 0000000000..cdf8308a96
--- /dev/null
+++ b/bridges/Library_java_uno.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_Library_Library,java_uno))
+
+$(eval $(call gb_Library_use_internal_comprehensive_api,java_uno,\
+ udkapi \
+))
+
+$(eval $(call gb_Library_set_include,java_uno,\
+ -I$(SRCDIR)/bridges/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_libraries,java_uno,\
+ cppu \
+ jvmaccess \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_add_exception_objects,java_uno,\
+ bridges/source/jni_uno/jni_bridge \
+ bridges/source/jni_uno/jni_data \
+ bridges/source/jni_uno/jni_info \
+ bridges/source/jni_uno/jni_java2uno \
+ bridges/source/jni_uno/jni_uno2java \
+ bridges/source/jni_uno/nativethreadpool \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Makefile b/bridges/Makefile
new file mode 100644
index 0000000000..0997e62848
--- /dev/null
+++ b/bridges/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Module_bridges.mk b/bridges/Module_bridges.mk
new file mode 100644
index 0000000000..3016bf2c40
--- /dev/null
+++ b/bridges/Module_bridges.mk
@@ -0,0 +1,33 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_Module_Module,bridges))
+
+$(eval $(call gb_Module_add_targets,bridges,\
+ Library_cpp_uno \
+ $(if $(ENABLE_JAVA),\
+ Jar_java_uno \
+ Library_java_uno \
+ $(if $(filter MACOSX,$(OS)),Package_jnilib_java_uno) \
+ ) \
+ $(if $(filter ARM,$(CPUNAME)),\
+ $(if $(filter ANDROID LINUX,$(OS)),\
+ CustomTarget_gcc3_linux_arm) \
+ ) \
+))
+
+ifeq (,$(filter build,$(gb_Module_SKIPTARGETS)))
+ifeq ($(strip $(bridges_SELECTED_BRIDGE)),)
+$(call gb_Output_error,no bridge selected for build: bailing out)
+else ifneq ($(words $(bridges_SELECTED_BRIDGE)),1)
+$(call gb_Output_error,multiple bridges selected for build: $(bridges_SELECTED_BRIDGE))
+endif
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/Package_jnilib_java_uno.mk b/bridges/Package_jnilib_java_uno.mk
new file mode 100644
index 0000000000..446613fc93
--- /dev/null
+++ b/bridges/Package_jnilib_java_uno.mk
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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_Package_Package,bridges_jnilib_java_uno,$(SRCDIR)))
+
+$(eval $(call gb_Package_add_symbolic_link,bridges_jnilib_java_uno,$(LIBO_URE_LIB_FOLDER)/$(basename $(notdir $(call gb_Library_get_target,java_uno))).jnilib,$(notdir $(call gb_Library_get_target,java_uno))))
+
+# vim: set noet sw=4 ts=4:
diff --git a/bridges/README.md b/bridges/README.md
new file mode 100644
index 0000000000..37c4485eec
--- /dev/null
+++ b/bridges/README.md
@@ -0,0 +1,6 @@
+# UNO Bridges
+
+Bridges from various C++ ABIs, Java JNI, MS .NET to UNO and back. A bridge for .NET is in
+`cli_ure`.
+
+Also implementation of the UNO Remote Protocol.
diff --git a/bridges/inc/bridge.hxx b/bridges/inc/bridge.hxx
new file mode 100644
index 0000000000..0a6da78859
--- /dev/null
+++ b/bridges/inc/bridge.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <uno/environment.h>
+#include <uno/mapping.h>
+
+namespace bridges::cpp_uno::shared {
+
+// private:
+extern "C" void freeMapping(uno_Mapping *);
+
+// private:
+extern "C" void acquireMapping(uno_Mapping *);
+
+// private:
+extern "C" void releaseMapping(uno_Mapping *);
+
+// private:
+extern "C" void cpp2unoMapping(
+ uno_Mapping *, void **, void *, typelib_InterfaceTypeDescription *);
+
+// private:
+extern "C" void uno2cppMapping(
+ uno_Mapping *, void **, void *, typelib_InterfaceTypeDescription *);
+
+/**
+ * Holding environments and mappings.
+ */
+class Bridge {
+public:
+ // Interface for generic/component.cxx:
+
+ static uno_Mapping * createMapping(
+ uno_ExtEnvironment * pCppEnv, uno_ExtEnvironment * pUnoEnv,
+ bool bExportCpp2Uno);
+
+ // Interface for Cpp/UnoInterfaceProxy:
+
+ void acquire();
+ void release();
+
+ // Interface for individual CPP--UNO bridges:
+
+ uno_ExtEnvironment * getCppEnv() { return pCppEnv; }
+ uno_ExtEnvironment * getUnoEnv() { return pUnoEnv; }
+
+ uno_Mapping * getCpp2Uno() { return &aCpp2Uno; }
+ uno_Mapping * getUno2Cpp() { return &aUno2Cpp; }
+
+private:
+ Bridge(Bridge const &) = delete;
+ Bridge& operator =(const Bridge&) = delete;
+
+ Bridge(
+ uno_ExtEnvironment * pCppEnv_, uno_ExtEnvironment * pUnoEnv_,
+ bool bExportCpp2Uno_);
+
+ ~Bridge();
+
+ struct Mapping: public uno_Mapping {
+ Bridge * pBridge;
+ };
+
+ std::atomic<std::size_t> nRef;
+
+ uno_ExtEnvironment * pCppEnv;
+ uno_ExtEnvironment * pUnoEnv;
+
+ Mapping aCpp2Uno;
+ Mapping aUno2Cpp;
+
+ bool bExportCpp2Uno;
+
+ friend void freeMapping(uno_Mapping * pMapping);
+
+ friend void acquireMapping(uno_Mapping * pMapping);
+
+ friend void releaseMapping(uno_Mapping * pMapping);
+
+ friend void cpp2unoMapping(
+ uno_Mapping * pMapping, void ** ppUnoI, void * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr);
+
+ friend void uno2cppMapping(
+ uno_Mapping * pMapping, void ** ppCppI, void * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/cppinterfaceproxy.hxx b/bridges/inc/cppinterfaceproxy.hxx
new file mode 100644
index 0000000000..5b5c85dc7d
--- /dev/null
+++ b/bridges/inc/cppinterfaceproxy.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+#include <uno/environment.h>
+#include "vtablefactory.hxx"
+
+namespace com::sun::star::uno { class XInterface; }
+
+namespace bridges::cpp_uno::shared {
+
+class Bridge;
+
+extern "C" void freeCppInterfaceProxy(
+ uno_ExtEnvironment * pEnv, void * pInterface);
+
+/**
+ * A cpp proxy wrapping a uno interface.
+ */
+class CppInterfaceProxy {
+public:
+ // Interface for Bridge:
+
+ static com::sun::star::uno::XInterface * create(
+ Bridge * pBridge, uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId);
+
+ // Interface for individual CPP--UNO bridges:
+
+ Bridge * getBridge() { return pBridge; }
+ uno_Interface * getUnoI() { return pUnoI; }
+ typelib_InterfaceTypeDescription * getTypeDescr() { return pTypeDescr; }
+ const OUString& getOid() const { return oid; }
+
+ // non virtual methods called on incoming vtable calls #1, #2
+ void acquireProxy();
+ void releaseProxy();
+
+ static CppInterfaceProxy * castInterfaceToProxy(void * pInterface);
+
+private:
+ CppInterfaceProxy(CppInterfaceProxy const &) = delete;
+ CppInterfaceProxy& operator =(const CppInterfaceProxy&) = delete;
+
+ CppInterfaceProxy(
+ Bridge * pBridge_, uno_Interface * pUnoI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_,
+ OUString aOId_);
+
+ ~CppInterfaceProxy();
+
+ static com::sun::star::uno::XInterface * castProxyToInterface(
+ CppInterfaceProxy * pProxy);
+
+ std::atomic<std::size_t> nRef;
+ Bridge * pBridge;
+
+ // mapping information
+ uno_Interface * pUnoI; // wrapped interface
+ typelib_InterfaceTypeDescription * pTypeDescr;
+ OUString oid;
+
+ VtableFactory::Slot * vtables[1] = {};
+
+ friend void freeCppInterfaceProxy(
+ uno_ExtEnvironment * pEnv, void * pInterface);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/except.hxx b/bridges/inc/except.hxx
new file mode 100644
index 0000000000..7d7db224f8
--- /dev/null
+++ b/bridges/inc/except.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// extern "C" void** __cdecl __current_exception()
+// is defined in MSVS14.0/VC/crt/src/vcruntime/frame.cpp:
+// return &__vcrt_getptd()->_curexception;
+//
+// __vcrt_getptd is defined in vcruntime_internal.h:
+//typedef struct __vcrt_ptd
+//{
+// // C++ Exception Handling (EH) state
+// unsigned long _NLG_dwCode; // Required by NLG routines
+//[...]
+//void* _curexception; // current exception
+//[...]
+extern "C" void** __current_exception();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/amd64.hxx b/bridges/inc/msvc/amd64.hxx
new file mode 100644
index 0000000000..eea88ea96f
--- /dev/null
+++ b/bridges/inc/msvc/amd64.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <msvc/except.hxx>
+
+#pragma pack(push, 8)
+
+struct ExceptionType final
+{
+ sal_Int32 _n0; // flags
+ sal_uInt32 _pTypeInfo; // typeinfo
+ sal_Int32 _n1, _n2, _n3; // thiscast
+ sal_Int32 _n4; // object_size
+ sal_uInt32 _pCopyCtor; // copyctor
+ ExceptionTypeInfo exc_type_info;
+
+ explicit ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+ typelib_TypeDescription* pTD) noexcept;
+
+ ExceptionType(const ExceptionType&) = delete;
+ ExceptionType& operator=(const ExceptionType&) = delete;
+};
+
+struct RaiseInfo final
+{
+ sal_Int32 _n0;
+ sal_uInt32 _pDtor;
+ sal_Int32 _n2;
+ sal_uInt32 _types;
+
+ // Additional fields
+ typelib_TypeDescription* _pTD;
+ unsigned char* _code;
+ sal_uInt64 _codeBase;
+
+ explicit RaiseInfo(typelib_TypeDescription* pTD) noexcept;
+};
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/arm64.hxx b/bridges/inc/msvc/arm64.hxx
new file mode 100644
index 0000000000..fb095446b0
--- /dev/null
+++ b/bridges/inc/msvc/arm64.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <msvc/except.hxx>
+
+#pragma pack(push, 8)
+
+struct ExceptionType final
+{
+ sal_Int32 _n0; // flags
+ sal_uInt32 _pTypeInfo; // typeinfo
+ sal_Int32 _n1, _n2, _n3; // thiscast
+ sal_Int32 _n4; // object_size
+ sal_uInt32 _pCopyCtor; // copyctor
+ ExceptionTypeInfo exc_type_info;
+
+ explicit ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+ typelib_TypeDescription* pTD) throw();
+
+ ExceptionType(const ExceptionType&) = delete;
+ ExceptionType& operator=(const ExceptionType&) = delete;
+};
+
+struct RaiseInfo final
+{
+ sal_Int32 _n0;
+ sal_uInt32 _pDtor;
+ sal_Int32 _n2;
+ sal_uInt32 _types;
+
+ // Additional fields
+ typelib_TypeDescription* _pTD;
+ unsigned char* _code;
+ sal_uInt64 _codeBase;
+
+ explicit RaiseInfo(typelib_TypeDescription* pTD) throw();
+};
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/cpp2uno.hxx b/bridges/inc/msvc/cpp2uno.hxx
new file mode 100644
index 0000000000..47091ed3bc
--- /dev/null
+++ b/bridges/inc/msvc/cpp2uno.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <sal/config.h>
+#include <typelib/typeclass.h>
+
+typelib_TypeClass __cdecl cpp_mediate(void** pCallStack, sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset, sal_Int64* const pRegisterReturn);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/except.hxx b/bridges/inc/msvc/except.hxx
new file mode 100644
index 0000000000..f1403a43af
--- /dev/null
+++ b/bridges/inc/msvc/except.hxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <sal/config.h>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <mutex>
+#include <unordered_map>
+
+typedef struct _uno_Any uno_Any;
+typedef struct _uno_Mapping uno_Mapping;
+
+int msvc_filterCppException(EXCEPTION_POINTERS*, uno_Any*, uno_Mapping*);
+void msvc_raiseException(uno_Any*, uno_Mapping*);
+
+constexpr DWORD MSVC_EH_MAGIC_PARAM = 0x19930520;
+// The NT Exception code that msvcrt uses ('msc' | 0xE0000000)
+constexpr DWORD MSVC_EH_MAGIC_CODE = 0xE06D7363;
+
+#if defined(_M_IX86)
+#define MSVC_EH_PARAMETERS 3 // Number of parameters in exception record for x86
+#elif defined(_M_AMD64) || defined(_M_ARM64)
+#define MSVC_EH_PARAMETERS 4 // Number of parameters in exception record for AMD64
+#else
+#error "Unsupported machine type"
+#endif
+
+class type_info;
+struct RaiseInfo;
+typedef std::unordered_map<OUString, void*> t_string2PtrMap;
+typedef struct _typelib_TypeDescription typelib_TypeDescription;
+
+// fixed class, because sizeof(ExceptionTypeInfo) must be sizeof(type_info)
+// this is tested by a static_assert, so can't break.
+class ExceptionTypeInfo final
+{
+ friend int msvc_filterCppException(EXCEPTION_POINTERS*, uno_Any*, uno_Mapping*);
+
+ void* m_data;
+ char m_d_name[1];
+
+public:
+ explicit ExceptionTypeInfo(void* data, const char* d_name) noexcept
+ : m_data(data)
+ {
+ ::strcpy(m_d_name, d_name); // #100211# - checked
+ }
+ virtual ~ExceptionTypeInfo() noexcept;
+};
+
+class ExceptionTypeInfoWrapper final
+{
+ int type_info_size;
+ ExceptionTypeInfo info;
+
+public:
+ explicit ExceptionTypeInfoWrapper(void* m_data, const char* m_d_name) noexcept
+ : info(m_data, m_d_name)
+ {
+ type_info_size = sizeof(ExceptionTypeInfo) + strlen(m_d_name);
+ }
+
+ type_info* get_type_info() { return reinterpret_cast<type_info*>(&info); }
+ int get_type_info_size() { return type_info_size; }
+};
+
+class RTTInfos final
+{
+ osl::Mutex m_aMutex;
+ t_string2PtrMap m_allRTTI;
+
+ RTTInfos() noexcept;
+ ExceptionTypeInfoWrapper* getInfo(OUString const& rUNOname) noexcept;
+
+public:
+ ~RTTInfos();
+
+ static type_info* get(OUString const& rUNOname, int* len = nullptr) noexcept;
+};
+
+class ExceptionInfos final
+{
+ std::mutex m_aMutex;
+ t_string2PtrMap m_allRaiseInfos;
+
+public:
+ static RaiseInfo* getRaiseInfo(typelib_TypeDescription* pTD) noexcept;
+
+ static DWORD allocationGranularity;
+
+ ExceptionInfos() noexcept;
+ ~ExceptionInfos() noexcept;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/x86.hxx b/bridges/inc/msvc/x86.hxx
new file mode 100644
index 0000000000..24c55499f1
--- /dev/null
+++ b/bridges/inc/msvc/x86.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <msvc/except.hxx>
+
+#pragma pack(push, 8)
+
+struct ObjectFunction final
+{
+ char somecode[12];
+ typelib_TypeDescription* _pTypeDescr; // type of object
+
+ inline static void* operator new(size_t nSize);
+ inline static void operator delete(void* pMem);
+
+ ObjectFunction(typelib_TypeDescription* pTypeDescr, void* fpFunc) throw();
+ ~ObjectFunction() throw();
+};
+
+struct ExceptionType final
+{
+ sal_Int32 _n0;
+ type_info* _pTypeInfo;
+ sal_Int32 _n1, _n2, _n3, _n4;
+ ObjectFunction* _pCopyCtor;
+ sal_Int32 _n5;
+
+ explicit ExceptionType(typelib_TypeDescription* pTypeDescr) throw();
+ ~ExceptionType() throw();
+
+ // Copy assignment is forbidden and not implemented.
+ ExceptionType(const ExceptionType&) = delete;
+ ExceptionType& operator=(const ExceptionType&) = delete;
+};
+
+struct RaiseInfo final
+{
+ sal_Int32 _n0;
+ ObjectFunction* _pDtor;
+ sal_Int32 _n2;
+ void* _types;
+ sal_Int32 _n3, _n4;
+
+ explicit RaiseInfo(typelib_TypeDescription* pTypeDescr) throw();
+ ~RaiseInfo() throw();
+};
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/types.hxx b/bridges/inc/types.hxx
new file mode 100644
index 0000000000..597d55909d
--- /dev/null
+++ b/bridges/inc/types.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+namespace bridges::cpp_uno::shared
+{
+/**
+ * Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT,
+ * UNSIGNED SHORT, LONG, UNSIGNED LONG, HYPER, UNSIGNED HYPER, FLOAT, DOUBLE,
+ * CHAR, or an enum type).
+ *
+ * @param typeClass a type class
+ * @return true if the given type is "simple"
+ */
+bool isSimpleType(typelib_TypeClass typeClass);
+
+/**
+ * Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT,
+ * UNSIGNED SHORT, LONG, UNSIGNED LONG, HYPER, UNSIGNED HYPER, FLOAT, DOUBLE,
+ * CHAR, or an enum type).
+ *
+ * @param type a non-null pointer to a type description reference
+ * @return true if the given type is "simple"
+ */
+bool isSimpleType(typelib_TypeDescriptionReference const* type);
+
+/**
+ * Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT,
+ * UNSIGNED SHORT, LONG, UNSIGNED LONG, HYPER, UNSIGNED HYPER, FLOAT, DOUBLE,
+ * CHAR, or an enum type).
+ *
+ * @param type a non-null pointer to a type description
+ * @return true if the given type is "simple"
+ */
+bool isSimpleType(typelib_TypeDescription const* type);
+
+/**
+ * Determines whether a type relates to an interface type (is itself an
+ * interface type, or might contain entities of interface type).
+ *
+ * @param type a non-null pointer to a type description
+ * @return true if the given type relates to an interface type
+ */
+bool relatesToInterfaceType(typelib_TypeDescription const* type);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/unointerfaceproxy.hxx b/bridges/inc/unointerfaceproxy.hxx
new file mode 100644
index 0000000000..d20a7c3549
--- /dev/null
+++ b/bridges/inc/unointerfaceproxy.hxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+#include <uno/environment.h>
+
+namespace com::sun::star::uno { class XInterface; }
+
+namespace bridges::cpp_uno::shared {
+
+class Bridge;
+
+extern "C" void freeUnoInterfaceProxy(
+ uno_ExtEnvironment * pEnv, void * pProxy);
+
+// private:
+extern "C" void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException);
+ // this function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge
+
+// private:
+extern "C" void acquireProxy(uno_Interface *);
+
+// private:
+extern "C" void releaseProxy(uno_Interface *);
+
+/**
+ * A uno proxy wrapping a cpp interface.
+ */
+class UnoInterfaceProxy: public uno_Interface {
+public:
+ // Interface for Bridge:
+
+ static UnoInterfaceProxy * create(
+ Bridge * pBridge, com::sun::star::uno::XInterface * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId);
+
+ // Interface for individual CPP--UNO bridges:
+
+ Bridge * getBridge() { return pBridge; }
+ com::sun::star::uno::XInterface * getCppI() { return pCppI; }
+
+private:
+ UnoInterfaceProxy(UnoInterfaceProxy const &) = delete;
+ UnoInterfaceProxy& operator =(const UnoInterfaceProxy&) = delete;
+
+ UnoInterfaceProxy(
+ Bridge * pBridge_, com::sun::star::uno::XInterface * pCppI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_,
+ OUString aOId_);
+
+ ~UnoInterfaceProxy();
+
+ std::atomic<std::size_t> nRef;
+ Bridge * pBridge;
+
+ // mapping information
+ com::sun::star::uno::XInterface * pCppI; // wrapped interface
+ typelib_InterfaceTypeDescription * pTypeDescr;
+ OUString oid;
+
+ friend void freeUnoInterfaceProxy(
+ uno_ExtEnvironment * pEnv, void * pProxy);
+
+ friend void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException);
+
+ friend void acquireProxy(uno_Interface * pUnoI);
+
+ friend void releaseProxy(uno_Interface * pUnoI);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/vtablefactory.hxx b/bridges/inc/vtablefactory.hxx
new file mode 100644
index 0000000000..9afcb83709
--- /dev/null
+++ b/bridges/inc/vtablefactory.hxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/alloc.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.hxx>
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+
+/*See: http://people.redhat.com/drepper/selinux-mem.html*/
+#if defined(LINUX) || defined(OPENBSD) || defined(FREEBSD) \
+ || defined(NETBSD) || defined(DRAGONFLY) || defined (ANDROID) \
+ || defined(HAIKU)
+#define USE_DOUBLE_MMAP
+#endif
+
+namespace bridges::cpp_uno::shared {
+
+/** Hand out vtable structures for interface type descriptions.
+ */
+class VtableFactory {
+public:
+ // This structure is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** A vtable slot.
+ */
+ struct Slot;
+
+ /** A raw vtable block.
+ */
+ struct Block {
+ /** The start of the raw vtable block.
+
+ It points to the start of the allocated memory block, whereas the
+ vtable pointer typically points some bytes into the block (e.g.,
+ skipping an RTTI pointer, see mapBlockToVtable). Also, the block
+ contains any generated code snippets, after the vtable itself.
+ */
+ void * start;
+
+#ifdef USE_DOUBLE_MMAP
+ /** When separately mmapping the block for writing and executing
+ exec points to the same memory as start, except start is used
+ exclusively for writing and exec for executing
+ */
+ void * exec;
+
+ /** File handle for the underlying anonymous file
+ */
+ int fd;
+#endif
+
+ /** The size of the raw vtable block, in bytes.
+ */
+ sal_Size size;
+ };
+
+ /** The vtable structure corresponding to an interface type.
+ */
+ struct Vtables {
+ /** The number of blocks/vtables.
+ */
+ sal_Int32 count;
+
+ /** An array of blocks, representing the multiple vtables of a
+ (multiple-inheritance) type.
+
+ <p>A block is a raw vtable. It points to the start of the allocated
+ memory block, whereas the vtable pointer typically points some bytes
+ into the block (e.g., skipping an RTTI pointer, see
+ mapBlockToVtable). Also, the block contains any generated code
+ snippets, after the vtable itself.</p>
+ */
+ std::unique_ptr<Block[]> blocks;
+
+ Vtables()
+ : count(0)
+ {
+ }
+ };
+
+ VtableFactory();
+
+ ~VtableFactory();
+
+ /** Given an interface type description, return its corresponding vtable
+ structure.
+ */
+ const Vtables& getVtables(typelib_InterfaceTypeDescription * type);
+
+ // This function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** Given a pointer to a block, turn it into a vtable pointer.
+ */
+ static Slot * mapBlockToVtable(void * block);
+
+private:
+ class GuardedBlocks;
+ friend class GuardedBlocks;
+
+ class BaseOffset;
+
+ VtableFactory(VtableFactory const &) = delete;
+ VtableFactory& operator =(const VtableFactory&) = delete;
+
+ bool createBlock(Block &block, sal_Int32 slotCount) const;
+
+ void freeBlock(Block const & block) const;
+
+ sal_Int32 createVtables(
+ GuardedBlocks & blocks, BaseOffset const & baseOffset,
+ typelib_InterfaceTypeDescription * type, sal_Int32 vtableNumber,
+ typelib_InterfaceTypeDescription * mostDerived, bool includePrimary)
+ const;
+
+ // This function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** Calculate the size of a raw vtable block.
+
+ @param slotCount the number of virtual function slots the returned
+ vtable block shall support (if there are any platform-specific slots,
+ like an RTTI pointer, or a pointer to a destructor, they are not covered
+ by slotCount)
+ @return the size of the raw vtable block, in bytes
+ */
+ static std::size_t getBlockSize(sal_Int32 slotCount);
+
+ // This function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** Initialize a raw vtable block.
+
+ @param block the start address of the raw vtable block
+ @param slotCount the number of slots
+ @param vtableNumber zero-based count across all the most derived type's
+ vtables (for vtable's "offset to top" slot)
+ @param type non-null most derived type (for vtable's "typeinfo pointer"
+ slot)
+ @return a pointer past the last vtable slot
+ */
+ static Slot * initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32 vtableNumber,
+ typelib_InterfaceTypeDescription * type);
+
+ // This function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** Fill the vtable slots corresponding to all local (i.e., not inherited)
+ functions of a given interface type (and generate any necessary code
+ snippets for them).
+
+ @param slots on input, points past the vtable slot to be filled with
+ the last virtual function local to the given type; on output, points to
+ the vtable slot filled with the first virtual function local to the
+ given type
+ @param code points to the start of the area where code snippets can be
+ generated
+ @param writetoexecdiff when the same code area is mapped twice, once for
+ writing for code-generation, and once for code-execution, then this
+ records the offset from a writable address to its executable address
+ @param type the interface type description for which to generate vtable
+ slots
+ @param functionOffset the function offset of the first vtable slot
+ (typically coded into the code snippet for that vtable slot)
+ @param functionCount the number of vtable slots to fill (the number of
+ local functions of the given type, passed in so that it doesn't need to
+ be recomputed)
+ @param vtableOffset the offset of this vtable (needed to adjust the
+ this pointer, typically coded into the code snippets for all the filled
+ vtable slots)
+ @return a pointer to the remaining code snippet area
+ */
+ static unsigned char * addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+#ifdef USE_DOUBLE_MMAP
+ sal_PtrDiff writetoexecdiff,
+#endif
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset);
+
+ // This function is not defined in the generic part, but instead has to be
+ // defined individually for each CPP--UNO bridge:
+ /** Flush all the generated code snippets of a vtable, on platforms that
+ require it.
+
+ @param begin points to the start of the code snippet area
+ @param end points behind the end of the code snippet area
+ */
+ static void flushCode(
+ unsigned char const * begin, unsigned char const * end);
+
+ typedef std::unordered_map< OUString, Vtables > Map;
+
+ std::mutex m_mutex;
+ Map m_map;
+
+ rtl_arena_type * m_arena;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/vtables.hxx b/bridges/inc/vtables.hxx
new file mode 100644
index 0000000000..57ee58f53a
--- /dev/null
+++ b/bridges/inc/vtables.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+namespace bridges::cpp_uno::shared
+{
+/**
+ * Calculate the number of local functions of an interface type.
+ *
+ * <p><em>Local</em> functions are those not inherited from any base types. The
+ * number of <em>functions</em> is potentially larger than the number of
+ * <em>members</em>, as each read&ndash;write attribute member counts as two
+ * functions.</p>
+ *
+ * @param type a non-null pointer to an interface type description, for which
+ * <code>typelib_typedescription_complete</code> must already have been
+ * executed
+ * @return the number of local functions of the given interface type
+ */
+sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const* type);
+
+/**
+ * Calculate the number of primary functions of an interface type.
+ *
+ * <p>The number of primary functions of an interface is the number of local
+ * functions of that interface (see <code>getLocalFunctions</code>), plus the
+ * number of primary functions of that interface's first base type (if it has at
+ * least one base type).</p>
+ *
+ * @param type a pointer to an interface type description; may be null
+ * @return the number of primary functions of the given interface type, or zero
+ * if the given interface type is null
+ */
+sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription* type);
+
+/**
+ * Represents a vtable slot of a C++ class.
+ */
+struct VtableSlot
+{
+ /**
+ * The offset of the vtable.
+ *
+ * <p>Multiple-inheritance C++ classes have more than one vtable. The
+ * offset is logical (<em>not</em> a byte offset), and must be
+ * non-negative.</p>
+ */
+ sal_Int32 offset;
+
+ /**
+ * The index within the vtable.
+ *
+ * <p>The index is logical (<em>not</em> a byte offset), and must be
+ * non-negative.</p>
+ */
+ sal_Int32 index;
+};
+
+/**
+ * Calculates the vtable slot associated with an interface attribute member.
+ *
+ * @param ifcMember a non-null pointer to an interface attribute member
+ * description
+ * @return the vtable slot associated with the given interface member
+ */
+VtableSlot getVtableSlot(typelib_InterfaceAttributeTypeDescription const* ifcMember);
+
+/**
+ * Calculates the vtable slot associated with an interface method member.
+ *
+ * @param ifcMember a non-null pointer to an interface method member description
+ * @return the vtable slot associated with the given interface member
+ */
+VtableSlot getVtableSlot(typelib_InterfaceMethodTypeDescription const* ifcMember);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx
new file mode 100644
index 0000000000..9ba5af0124
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "share.hxx"
+
+
+
+extern "C" int codeSnippets[];
+const int nFunIndexes = 8;
+const int nVtableOffsets = 4;
+
+
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+ static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams,
+ typelib_MethodParameter * pParams,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
+ char *pTopStack = (char *)pCallStack;
+ char *pFloatRegs = pTopStack + 2;
+ char *pGPRegs = pTopStack + (2+8)*8;
+ char *pStackedArgs = pTopStack + (2+8+8)*8;
+
+ int nGPR = 0;
+ int nFPR = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+ void * pCppReturn = 0;
+
+ if (pReturnTypeDescr)
+ {
+ if (!arm::return_in_x8(pReturnTypeRef))
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ else // complex return via x8
+ {
+ pCppReturn = pCallStack[0];
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+
+ // Skip 'this'
+ pGPRegs += 8;
+ nGPR++;
+
+ // Parameters
+ void ** pUnoArgs = (void **)alloca( sizeof(void *) * nParams );
+ void ** pCppArgs = (void **)alloca( sizeof(void *) * nParams );
+
+ // Indices of values this have to be converted (interface conversion
+ // cpp<=>uno)
+ int * pTempIndices = (sal_Int32 *)alloca( sizeof(int) * nParams);
+
+ // Type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)alloca( sizeof(typelib_TypeDescription *) * nParams);
+
+ int nTempIndices = 0;
+
+ for ( int nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut &&
+ bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ if (nFPR < 8 && (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT ||
+ pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE))
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = pFloatRegs;
+ pFloatRegs += 8;
+ nFPR++;
+ }
+ else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+ {
+ if ((pStackedArgs - pTopStack) % 4)
+ pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 4;
+ }
+ else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE)
+ {
+ if ((pStackedArgs - pTopStack) % 8)
+ pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 8;
+ }
+ else if (nGPR < 8)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = pGPRegs;
+ pGPRegs += 8;
+ nGPR++;
+ }
+ else
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if ((pStackedArgs - pTopStack) % 8)
+ pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 8;
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if ((pStackedArgs - pTopStack) % 4)
+ pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 4;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if ((pStackedArgs - pTopStack) % 2)
+ pStackedArgs += 1;
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 2;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
+ pStackedArgs += 1;
+ break;
+ default:
+ assert(!"should not happen");
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (nGPR < 8)
+ {
+ pCppArgs[nPos] = *(void **)pGPRegs;
+ pGPRegs += 8;
+ }
+ else
+ {
+ if ((pStackedArgs - pTopStack) % 8)
+ pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
+ pCppArgs[nPos] = pStackedArgs;
+ pStackedArgs += 8;
+ }
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] =
+ alloca( pParamTypeDescr->nSize ),
+ pCppArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ int nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex],
+ ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
+ pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ int nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr =
+ ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
+ cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn,
+ pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet =
+ (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ static void cpp_mediate(sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** pCallStack)
+ {
+ sal_Int64 nRegReturn;
+ sal_Int64 *pRegisterReturn = &nRegReturn;
+
+ // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
+ // _this_ ptr is patched cppu_XInterfaceProxy object
+ void *pThis = pCallStack[2 + 8];
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ // determine called method
+ assert( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex );
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ throw RuntimeException( "illegal vtable index!", (XInterface *)pCppI );
+ }
+
+ sal_Int32 nMemberPos =
+ pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert( nMemberPos < pTypeDescr->nAllMembers );
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
+ nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ pCallStack, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET(&pTD,
+ reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pCallStack[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = pCallStack[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ [[fallthrough]];
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+
+ (void)eRet;
+ return;
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+
+extern "C" void cpp_vtable_call( sal_Int32 func, sal_Int32 offset,
+ void **pStack )
+{
+ cpp_mediate(func, offset, pStack);
+}
+
+namespace
+{
+ unsigned char *codeSnippet(const typelib_InterfaceTypeDescription *type,
+ const typelib_TypeDescription *member,
+ sal_Int32 functionIndex,
+ sal_Int32 vtableOffset)
+ {
+ // For now temporarily assert when we get here. The intent is
+ // that we won't need the code snippets at all on iOS.
+ assert(false);
+
+ assert(functionIndex < nFunIndexes);
+ if (!(functionIndex < nFunIndexes))
+ return NULL;
+
+ assert(vtableOffset < nVtableOffsets);
+ if (!(vtableOffset < nVtableOffsets))
+ return NULL;
+
+ // The codeSnippets table is indexed by functionIndex and vtableOffset
+
+ int index = functionIndex*nVtableOffsets + vtableOffset;
+ unsigned char *result = ((unsigned char *) &codeSnippets) + codeSnippets[index];
+
+ SAL_INFO( "bridges", "codeSnippet(" << OUString(type->aBase.pTypeName) << "::" << OUString(member->pTypeName) << "): [" << functionIndex << "," << vtableOffset << "]=" << (void *) result << " (" << std::hex << ((int*)result)[0] << "," << ((int*)result)[1] << "," << ((int*)result)[2] << "," << ((int*)result)[3] << ")");
+
+ return result;
+ }
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots,
+ unsigned char * code,
+ typelib_InterfaceTypeDescription const * type,
+ sal_Int32 functionOffset,
+ sal_Int32 functionCount,
+ sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription *pAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
+
+ // Getter:
+ (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+
+ // Setter:
+ if (!pAttrTD->bReadOnly)
+ {
+ (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
+ break;
+ }
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *, unsigned char const *)
+{
+ // No dynamic code generation so nothing to flush
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_ios/except.cxx b/bridges/source/cpp_uno/gcc3_ios/except.cxx
new file mode 100644
index 0000000000..d5c49859db
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/except.cxx
@@ -0,0 +1,406 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "sal/config.h"
+
+#include <cassert>
+#include <new>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+#include <cxxabi.h>
+#include <dlfcn.h>
+
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include "com/sun/star/uno/genfunc.hxx"
+#include <sal/log.hxx>
+#include "osl/mutex.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "typelib/typedescription.h"
+#include "uno/any2.h"
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+namespace {
+
+struct Fake_type_info {
+ virtual ~Fake_type_info() = delete;
+ char const * name;
+};
+
+struct Fake_class_type_info: Fake_type_info {
+ virtual ~Fake_class_type_info() override = delete;
+};
+
+struct Fake_si_class_type_info: Fake_class_type_info {
+ virtual ~Fake_si_class_type_info() override = delete;
+ void const * base;
+};
+
+struct Base {};
+struct Derived: Base {};
+
+std::type_info * createFake_class_type_info(char const * name) {
+ char * buf = new char[sizeof (Fake_class_type_info)];
+
+ *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+ &typeid(Base));
+ // copy __cxxabiv1::__class_type_info vtable into place
+ Fake_class_type_info * fake = reinterpret_cast<Fake_class_type_info *>(buf);
+ fake->name = name;
+ return reinterpret_cast<std::type_info *>(
+ static_cast<Fake_type_info *>(fake));
+}
+
+std::type_info * createFake_si_class_type_info(
+ char const * name, std::type_info const * base)
+{
+ char * buf = new char[sizeof (Fake_si_class_type_info)];
+
+ *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+ &typeid(Derived));
+ // copy __cxxabiv1::__si_class_type_info vtable into place
+ Fake_si_class_type_info * fake
+ = reinterpret_cast<Fake_si_class_type_info *>(buf);
+ fake->name = name;
+ fake->base = base;
+ return reinterpret_cast<std::type_info *>(
+ static_cast<Fake_type_info *>(fake));
+}
+
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+void dummy_can_throw_anything( char const * )
+{
+}
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, std::type_info *, OUStringHash > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ std::type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( nullptr, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+std::type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ std::type_info * rtti;
+
+ OUString const & unoName = OUString::unacquired(&pTypeDescr->aBase.pTypeName);
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = static_cast<std::type_info *>(dlsym( m_hApp, symName.getStr() ));
+
+ if (rtti)
+ {
+ std::pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second,
+ "bridges",
+ "inserting new rtti failed" );
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
+ if (iFind2 == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char * rttiName = strdup(symName.getStr() + 4);
+ if (rttiName == nullptr) {
+ throw std::bad_alloc();
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ std::type_info * base_rtti = getRTTI(
+ pTypeDescr->pBaseTypeDescription );
+ rtti = createFake_si_class_type_info(rttiName, base_rtti);
+ }
+ else
+ {
+ rtti = createFake_class_type_info(rttiName);
+ }
+
+ std::pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second,
+ "bridges",
+ "inserting new generated rtti failed" );
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind2->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = static_cast<__cxa_exception const *>(pExc) - 1;
+ // The libcxxabi commit
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+ // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+ // LLVM 5.0 changed the size of __cxa_exception by adding
+ //
+ // __attribute__((aligned))
+ //
+ // to the final member unwindHeader, on x86-64 effectively adding a hole of
+ // size 8 in front of that member (changing its offset from 88 to 96,
+ // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+ // from 8 to 16); a hack to dynamically determine whether we run against a
+ // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+ // point to this function (the use of __cxa_exception in fillUnoException is
+ // unaffected, as it only accesses members towards the start of the struct,
+ // through a pointer known to actually point at the start). The libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+ // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+ // removes the need for this hack, so it can be removed again once we can be sure that we only
+ // run against libcxxabi from LLVM >= 6:
+ if (header->exceptionDestructor != &deleteException) {
+ header = reinterpret_cast<__cxa_exception const *>(
+ reinterpret_cast<char const *>(header) - 8);
+ assert(header->exceptionDestructor == &deleteException);
+ }
+ typelib_TypeDescription * pTD = nullptr;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ std::type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ "cannot get typedescription for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxxabiv1::__cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = rtti_data.getRTTI(reinterpret_cast<typelib_CompoundTypeDescription*>(pTypeDescr));
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ "no rtti for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ // void __cxa_throw(void* thrown_exception,
+ // struct std::type_info * tinfo,
+ // void (*dest)(void*));
+ __cxxabiv1::__cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxxabiv1::__cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ // Very bad HACK to find out whether we run against a libcxxabi that has a new
+ // __cxa_exception::reserved member at the start, introduced with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of the
+ // start of __cxa_exception is
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // where the (bad, hacky) assumption is that reserve (if present) is null
+ // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+ // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+ // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+ // __cxa_dependent_exception, the referenceCount member is rather
+ //
+ // 8 byte void* primaryException
+ //
+ // but which also will always be set to a non-null value in __cxa_rethrow_primary_exception).
+ // As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx), this hack (together with the "#if 0"
+ // there) can be dropped once we can be sure that we only run against new libcxxabi that has the
+ // reserve member:
+ if (*reinterpret_cast<void **>(header) == nullptr) {
+ header = reinterpret_cast<__cxa_exception *>(reinterpret_cast<void **>(header) + 1);
+ }
+
+ std::type_info *exceptionType = __cxxabiv1::__cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = nullptr;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (nullptr == pExcTypeDescr)
+ {
+ RuntimeException aRE( "exception type not found: " + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_ios/ios64_helper.s b/bridges/source/cpp_uno/gcc3_ios/ios64_helper.s
new file mode 100644
index 0000000000..12308f1a98
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/ios64_helper.s
@@ -0,0 +1,233 @@
+// -*- Mode: Asm; tab-width: 4; tab-stop-list: (4 12 32); comment-column: 30; comment-start: "// "; indent-tabs-mode: nil -*-
+//
+// 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/.
+//
+// This file incorporates work covered by the following license notice:
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed
+// with this work for additional information regarding copyright
+// ownership. The ASF licenses this file to you under the Apache
+// License, Version 2.0 (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of
+// the License at http://www.apache.org/licenses/LICENSE-2.0 .
+//
+ .section __TEXT,__text,regular,pure_instructions
+
+ .p2align 2
+codeSnippet_0_0:
+ mov x14, 0
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_0_1:
+ mov x14, 0
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_0_2:
+ mov x14, 0
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_0_3:
+ mov x14, 0
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_1_0:
+ mov x14, 1
+ mov x15, 0
+ b _privateSnippetExecutor
+ .long 0x000001
+ .long 0
+codeSnippet_1_1:
+ mov x14, 1
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_1_2:
+ mov x14, 1
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_1_3:
+ mov x14, 1
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_2_0:
+ mov x14, 2
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_2_1:
+ mov x14, 2
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_2_2:
+ mov x14, 2
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_2_3:
+ mov x14, 2
+ mov x15, 3
+ b _privateSnippetExecutor
+ .long 0x000002
+ .long 3
+codeSnippet_3_0:
+ mov x14, 3
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_3_1:
+ mov x14, 3
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_3_2:
+ mov x14, 3
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_3_3:
+ mov x14, 3
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_4_0:
+ mov x14, 4
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_4_1:
+ mov x14, 4
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_4_2:
+ mov x14, 4
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_4_3:
+ mov x14, 4
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_5_0:
+ mov x14, 5
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_5_1:
+ mov x14, 5
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_5_2:
+ mov x14, 5
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_5_3:
+ mov x14, 5
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_6_0:
+ mov x14, 6
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_6_1:
+ mov x14, 6
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_6_2:
+ mov x14, 6
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_6_3:
+ mov x14, 6
+ mov x15, 3
+ b _privateSnippetExecutor
+codeSnippet_7_0:
+ mov x14, 7
+ mov x15, 0
+ b _privateSnippetExecutor
+codeSnippet_7_1:
+ mov x14, 7
+ mov x15, 1
+ b _privateSnippetExecutor
+codeSnippet_7_2:
+ mov x14, 7
+ mov x15, 2
+ b _privateSnippetExecutor
+codeSnippet_7_3:
+ mov x14, 7
+ mov x15, 3
+ b _privateSnippetExecutor
+
+ .globl _codeSnippets
+_codeSnippets:
+ .long codeSnippet_0_0 - _codeSnippets
+ .long codeSnippet_0_1 - _codeSnippets
+ .long codeSnippet_0_2 - _codeSnippets
+ .long codeSnippet_0_3 - _codeSnippets
+ .long codeSnippet_1_0 - _codeSnippets
+ .long codeSnippet_1_1 - _codeSnippets
+ .long codeSnippet_1_2 - _codeSnippets
+ .long codeSnippet_1_3 - _codeSnippets
+ .long codeSnippet_2_0 - _codeSnippets
+ .long codeSnippet_2_1 - _codeSnippets
+ .long codeSnippet_2_2 - _codeSnippets
+ .long codeSnippet_2_3 - _codeSnippets
+ .long codeSnippet_3_0 - _codeSnippets
+ .long codeSnippet_3_1 - _codeSnippets
+ .long codeSnippet_3_2 - _codeSnippets
+ .long codeSnippet_3_3 - _codeSnippets
+ .long codeSnippet_4_0 - _codeSnippets
+ .long codeSnippet_4_1 - _codeSnippets
+ .long codeSnippet_4_2 - _codeSnippets
+ .long codeSnippet_4_3 - _codeSnippets
+ .long codeSnippet_5_0 - _codeSnippets
+ .long codeSnippet_5_1 - _codeSnippets
+ .long codeSnippet_5_2 - _codeSnippets
+ .long codeSnippet_5_3 - _codeSnippets
+ .long codeSnippet_6_0 - _codeSnippets
+ .long codeSnippet_6_1 - _codeSnippets
+ .long codeSnippet_6_2 - _codeSnippets
+ .long codeSnippet_6_3 - _codeSnippets
+ .long codeSnippet_7_0 - _codeSnippets
+ .long codeSnippet_7_1 - _codeSnippets
+ .long codeSnippet_7_2 - _codeSnippets
+ .long codeSnippet_7_3 - _codeSnippets
+
+
+
+ .private_extern _privateSnippetExecutor
+ .globl _privateSnippetExecutor
+ .p2align 2
+_privateSnippetExecutor:
+ .cfi_startproc
+ .cfi_def_cfa w29, 16
+ .cfi_offset w30, -8
+ .cfi_offset w29, -16
+
+ // _privateSnippetExecutor is jumped to from codeSnippet_*
+
+ // push all GP, FP/SIMD registers to the stack
+ stp x6, x7, [sp, #-16]!
+ stp x4, x5, [sp, #-16]!
+ stp x2, x3, [sp, #-16]!
+ stp x0, x1, [sp, #-16]!
+ stp d6, d7, [sp, #-16]!
+ stp d4, d5, [sp, #-16]!
+ stp d2, d3, [sp, #-16]!
+ stp d0, d1, [sp, #-16]!
+
+ // push x8 (RC pointer) and lr to stack
+ stp x8, lr, [sp, #-16]!
+
+ // First argument (x15 set up in the codeSnippet instance)
+ // Second argument: The pointer to all the above
+ mov x0, x14
+ mov x1, x15
+ mov x2, sp
+ bl _cpp_vtable_call
+
+ // restore x8 (RC pointer) and lr (skip RC from cpp_vtable_call)
+ ldp x8, lr, [sp, #0]
+
+ // restore stack
+ add sp, sp, #144
+
+ // continue with throw/catch
+ ret lr
+ .cfi_endproc
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/cpp_uno/gcc3_ios/rtti.h b/bridges/source/cpp_uno/gcc3_ios/rtti.h
new file mode 100644
index 0000000000..88413ea27a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/rtti.h
@@ -0,0 +1,407 @@
+// Copyright (C) 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+// Written by Nathan Sidwell, Codesourcery LLC, <nathan@codesourcery.com>
+
+#pragma once
+
+#include <typeinfo>
+
+namespace __cxxabiv1
+{
+ // Type information for int, float etc.
+ class __fundamental_type_info : public std::type_info
+ {
+ public:
+ explicit
+ __fundamental_type_info(const char* __n) : std::type_info(__n) { }
+
+ virtual
+ ~__fundamental_type_info();
+ };
+
+ // Type information for array objects.
+ class __array_type_info : public std::type_info
+ {
+ public:
+ explicit
+ __array_type_info(const char* __n) : std::type_info(__n) { }
+
+ virtual
+ ~__array_type_info();
+ };
+
+ // Type information for functions (both member and non-member).
+ class __function_type_info : public std::type_info
+ {
+ public:
+ explicit
+ __function_type_info(const char* __n) : std::type_info(__n) { }
+
+ virtual
+ ~__function_type_info();
+
+ protected:
+ // Implementation defined member function.
+ virtual bool
+ __is_function_p() const;
+ };
+
+ // Type information for enumerations.
+ class __enum_type_info : public std::type_info
+ {
+ public:
+ explicit
+ __enum_type_info(const char* __n) : std::type_info(__n) { }
+
+ virtual
+ ~__enum_type_info();
+ };
+
+ // Common type information for simple pointers and pointers to member.
+ class __pbase_type_info : public std::type_info
+ {
+ public:
+ unsigned int __flags; // Qualification of the target object.
+ const std::type_info* __pointee; // Type of pointed to object.
+
+ explicit
+ __pbase_type_info(const char* __n, int __quals,
+ const std::type_info* __type)
+ : std::type_info(__n), __flags(__quals), __pointee(__type)
+ { }
+
+ virtual
+ ~__pbase_type_info();
+
+ // Implementation defined type.
+ enum __masks
+ {
+ __const_mask = 0x1,
+ __volatile_mask = 0x2,
+ __restrict_mask = 0x4,
+ __incomplete_mask = 0x8,
+ __incomplete_class_mask = 0x10
+ };
+
+ protected:
+ __pbase_type_info(const __pbase_type_info&);
+
+ __pbase_type_info&
+ operator=(const __pbase_type_info&);
+
+ // Implementation defined member functions.
+ virtual bool
+ __do_catch(const std::type_info* __thr_type, void** __thr_obj,
+ unsigned int __outer) const;
+
+ inline virtual bool
+ __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+ unsigned __outer) const;
+ };
+
+ // Type information for simple pointers.
+ class __pointer_type_info : public __pbase_type_info
+ {
+ public:
+ explicit
+ __pointer_type_info(const char* __n, int __quals,
+ const std::type_info* __type)
+ : __pbase_type_info (__n, __quals, __type) { }
+
+
+ virtual
+ ~__pointer_type_info();
+
+ protected:
+ // Implementation defined member functions.
+ virtual bool
+ __is_pointer_p() const;
+
+ virtual bool
+ __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+ unsigned __outer) const;
+ };
+
+ class __class_type_info;
+
+ // Type information for a pointer to member variable.
+ class __pointer_to_member_type_info : public __pbase_type_info
+ {
+ public:
+ __class_type_info* __context; // Class of the member.
+
+ explicit
+ __pointer_to_member_type_info(const char* __n, int __quals,
+ const std::type_info* __type,
+ __class_type_info* __klass)
+ : __pbase_type_info(__n, __quals, __type), __context(__klass) { }
+
+ virtual
+ ~__pointer_to_member_type_info();
+
+ protected:
+ __pointer_to_member_type_info(const __pointer_to_member_type_info&);
+
+ __pointer_to_member_type_info&
+ operator=(const __pointer_to_member_type_info&);
+
+ // Implementation defined member function.
+ virtual bool
+ __pointer_catch(const __pbase_type_info* __thr_type, void** __thr_obj,
+ unsigned __outer) const;
+ };
+
+ // Helper class for __vmi_class_type.
+ class __base_class_type_info
+ {
+ public:
+ const __class_type_info* __base_type; // Base class type.
+ long __offset_flags; // Offset and info.
+
+ enum __offset_flags_masks
+ {
+ __virtual_mask = 0x1,
+ __public_mask = 0x2,
+ __hwm_bit = 2,
+ __offset_shift = 8 // Bits to shift offset.
+ };
+
+ // Implementation defined member functions.
+ bool
+ __is_virtual_p() const
+ { return __offset_flags & __virtual_mask; }
+
+ bool
+ __is_public_p() const
+ { return __offset_flags & __public_mask; }
+
+ ptrdiff_t
+ __offset() const
+ {
+ // This shift, being of a signed type, is implementation
+ // defined. GCC implements such shifts as arithmetic, which is
+ // what we want.
+ return static_cast<ptrdiff_t>(__offset_flags) >> __offset_shift;
+ }
+ };
+
+ // Type information for a class.
+ class __class_type_info : public std::type_info
+ {
+ public:
+ explicit
+ __class_type_info (const char *__n) : type_info(__n) { }
+
+ virtual
+ ~__class_type_info ();
+
+ // Implementation defined types.
+ // The type sub_kind tells us about how a base object is contained
+ // within a derived object. We often do this lazily, hence the
+ // UNKNOWN value. At other times we may use NOT_CONTAINED to mean
+ // not publicly contained.
+ enum __sub_kind
+ {
+ // We have no idea.
+ __unknown = 0,
+
+ // Not contained within us (in some circumstances this might
+ // mean not contained publicly)
+ __not_contained,
+
+ // Contained ambiguously.
+ __contained_ambig,
+
+ // Via a virtual path.
+ __contained_virtual_mask = __base_class_type_info::__virtual_mask,
+
+ // Via a public path.
+ __contained_public_mask = __base_class_type_info::__public_mask,
+
+ // Contained within us.
+ __contained_mask = 1 << __base_class_type_info::__hwm_bit,
+
+ __contained_private = __contained_mask,
+ __contained_public = __contained_mask | __contained_public_mask
+ };
+
+ struct __upcast_result;
+ struct __dyncast_result;
+
+ protected:
+ // Implementation defined member functions.
+ virtual bool
+ __do_upcast(const __class_type_info* __dst_type, void**__obj_ptr) const;
+
+ virtual bool
+ __do_catch(const type_info* __thr_type, void** __thr_obj,
+ unsigned __outer) const;
+
+ public:
+ // Helper for upcast. See if DST is us, or one of our bases.
+ // Return false if not found, true if found.
+ virtual bool
+ __do_upcast(const __class_type_info* __dst, const void* __obj,
+ __upcast_result& __restrict __result) const;
+
+ // Indicate whether SRC_PTR of type SRC_TYPE is contained publicly
+ // within OBJ_PTR. OBJ_PTR points to a base object of our type,
+ // which is the destination type. SRC2DST indicates how SRC
+ // objects might be contained within this type. If SRC_PTR is one
+ // of our SRC_TYPE bases, indicate the virtuality. Returns
+ // not_contained for non containment or private containment.
+ inline __sub_kind
+ __find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+ const __class_type_info* __src_type,
+ const void* __src_ptr) const;
+
+ // Helper for dynamic cast. ACCESS_PATH gives the access from the
+ // most derived object to this base. DST_TYPE indicates the
+ // desired type we want. OBJ_PTR points to a base of our type
+ // within the complete object. SRC_TYPE indicates the static type
+ // started from and SRC_PTR points to that base within the most
+ // derived object. Fill in RESULT with what we find. Return true
+ // if we have located an ambiguous match.
+ virtual bool
+ __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+ const __class_type_info* __dst_type, const void* __obj_ptr,
+ const __class_type_info* __src_type, const void* __src_ptr,
+ __dyncast_result& __result) const;
+
+ // Helper for find_public_subobj. SRC2DST indicates how SRC_TYPE
+ // bases are inherited by the type started from -- which is not
+ // necessarily the current type. The current type will be a base
+ // of the destination type. OBJ_PTR points to the current base.
+ virtual __sub_kind
+ __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+ const __class_type_info* __src_type,
+ const void* __src_ptr) const;
+ };
+
+ // Type information for a class with a single non-virtual base.
+ class __si_class_type_info : public __class_type_info
+ {
+ public:
+ const __class_type_info* __base_type;
+
+ explicit
+ __si_class_type_info(const char *__n, const __class_type_info *__base)
+ : __class_type_info(__n), __base_type(__base) { }
+
+ virtual
+ ~__si_class_type_info();
+
+ protected:
+ __si_class_type_info(const __si_class_type_info&);
+
+ __si_class_type_info&
+ operator=(const __si_class_type_info&);
+
+ // Implementation defined member functions.
+ virtual bool
+ __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+ const __class_type_info* __dst_type, const void* __obj_ptr,
+ const __class_type_info* __src_type, const void* __src_ptr,
+ __dyncast_result& __result) const;
+
+ virtual __sub_kind
+ __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+ const __class_type_info* __src_type,
+ const void* __sub_ptr) const;
+
+ virtual bool
+ __do_upcast(const __class_type_info*__dst, const void*__obj,
+ __upcast_result& __restrict __result) const;
+ };
+
+ // Type information for a class with multiple and/or virtual bases.
+ class __vmi_class_type_info : public __class_type_info
+ {
+ public:
+ unsigned int __flags; // Details about the class hierarchy.
+ unsigned int __base_count; // Number of direct bases.
+
+ // The array of bases uses the trailing array struct hack so this
+ // class is not constructable with a normal constructor. It is
+ // internally generated by the compiler.
+ __base_class_type_info __base_info[1]; // Array of bases.
+
+ explicit
+ __vmi_class_type_info(const char* __n, int ___flags)
+ : __class_type_info(__n), __flags(___flags), __base_count(0) { }
+
+ virtual
+ ~__vmi_class_type_info();
+
+ // Implementation defined types.
+ enum __flags_masks
+ {
+ __non_diamond_repeat_mask = 0x1, // Distinct instance of repeated base.
+ __diamond_shaped_mask = 0x2, // Diamond shaped multiple inheritance.
+ __flags_unknown_mask = 0x10
+ };
+
+ protected:
+ // Implementation defined member functions.
+ virtual bool
+ __do_dyncast(ptrdiff_t __src2dst, __sub_kind __access_path,
+ const __class_type_info* __dst_type, const void* __obj_ptr,
+ const __class_type_info* __src_type, const void* __src_ptr,
+ __dyncast_result& __result) const;
+
+ virtual __sub_kind
+ __do_find_public_src(ptrdiff_t __src2dst, const void* __obj_ptr,
+ const __class_type_info* __src_type,
+ const void* __src_ptr) const;
+
+ virtual bool
+ __do_upcast(const __class_type_info* __dst, const void* __obj,
+ __upcast_result& __restrict __result) const;
+ };
+
+ // Dynamic cast runtime.
+ // src2dst has the following possible values
+ // >-1: src_type is a unique public non-virtual base of dst_type
+ // dst_ptr + src2dst == src_ptr
+ // -1: unspecified relationship
+ // -2: src_type is not a public base of dst_type
+ // -3: src_type is a multiple public non-virtual base of dst_type
+ extern "C" void*
+ __dynamic_cast(const void* __src_ptr, // Starting object.
+ const __class_type_info* __src_type, // Static type of object.
+ const __class_type_info* __dst_type, // Desired target type.
+ ptrdiff_t __src2dst); // How src and dst are related.
+
+
+ // Returns the type_info for the currently handled exception [15.3/8], or
+ // null if there is none.
+ extern "C" std::type_info*
+ __cxa_current_exception_type();
+} // namespace __cxxabiv1
+
+// User programs should use the alias `abi'.
+namespace abi = __cxxabiv1;
diff --git a/bridges/source/cpp_uno/gcc3_ios/share.hxx b/bridges/source/cpp_uno/gcc3_ios/share.hxx
new file mode 100644
index 0000000000..65461d7fd3
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/share.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+// from opensource.apple.com: libcppabi-24.4/include/rtti.h
+#include "rtti.h"
+
+// from opensource.apple.com: libcppabi-24.4/include/unwind-cxx.h
+#include "unwind-cxx.h"
+
+// Import the __cxxabiv1 a.k.a. "abi" namespace
+using namespace abi;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ void dummy_can_throw_anything( char const * );
+
+ void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+ void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+ bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive = false);
+}
+
+namespace arm
+{
+ enum armlimits {
+ MAX_GPR_REGS = 8,
+ MAX_FPR_REGS = 8
+ };
+ bool return_in_x8( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_ios/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_ios/uno2cpp.cxx
new file mode 100644
index 0000000000..2614fd041a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/uno2cpp.cxx
@@ -0,0 +1,565 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef __arm64
+
+#include <sal/config.h>
+
+#include <exception>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace arm
+{
+ bool is_hfa_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ if (p->nMembers >= 4)
+ return false;
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if ((p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_FLOAT &&
+ p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_DOUBLE) ||
+ p->ppTypeRefs[i]->eTypeClass != p->ppTypeRefs[0]->eTypeClass)
+ return false;
+ }
+ return true;
+ }
+
+ bool return_in_x8( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ // A Composite Type not larger than 16 bytes is returned in x0, x1
+ bool bRet = pTypeDescr->nSize > 16;
+
+ if (is_hfa_struct(pTypeDescr))
+ bRet = false;
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return true;
+ }
+}
+
+void MapReturn(sal_uInt64 *pGPR, double *pFPR, typelib_TypeDescriptionReference *pReturnType, sal_uInt64 *pRegisterReturn)
+{
+ switch( pReturnType->eTypeClass )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pRegisterReturn[1] = pGPR[1];
+ [[fallthrough]];
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ pRegisterReturn[0] = pGPR[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = *(float*)&pFPR[0];
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = pFPR[0];
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (!arm::return_in_x8(pReturnType))
+ {
+ pRegisterReturn[0] = pGPR[0];
+ pRegisterReturn[1] = pGPR[1];
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+namespace
+{
+void callVirtualMethod(
+ void *pThis,
+ sal_Int32 nVtableIndex,
+ void *pRegisterReturn,
+ typelib_TypeDescriptionReference *pReturnType,
+ sal_uInt64 *pStack,
+ int nStack,
+ sal_uInt64 *pGPR,
+ double *pFPR)
+{
+ // never called
+ if (! pThis)
+ CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+ if ( nStack )
+ {
+ // 16-bytes aligned
+ sal_uInt32 nStackBytes = ( ( nStack + 3 ) >> 2 ) * 16;
+ sal_uInt32 *stack = (sal_uInt32 *) alloca( nStackBytes );
+ memcpy( stack, pStack, nStackBytes );
+ }
+
+ sal_uInt64 pMethod = *((sal_uInt64*)pThis);
+ pMethod += 8 * nVtableIndex;
+ pMethod = *((sal_uInt64 *)pMethod);
+
+ __asm__ __volatile__
+ (
+ // Assembly string
+ " ldp x0, x1, %[pgpr_0]\n"
+ " ldp x2, x3, %[pgpr_2]\n"
+ " ldp x4, x5, %[pgpr_4]\n"
+ " ldp x6, x7, %[pgpr_6]\n"
+ " ldr x8, %[pregisterreturn]\n"
+ " ldp d0, d1, %[pfpr_0]\n"
+ " ldp d2, d3, %[pfpr_2]\n"
+ " ldp d4, d5, %[pfpr_4]\n"
+ " ldp d6, d7, %[pfpr_6]\n"
+ " blr %[pmethod]\n"
+ " stp x0, x1, %[pgpr_0]\n"
+ " str d0, %[pfpr_0]\n"
+ // Input operands
+ :: [pgpr_0]"m" (pGPR[0]),
+ [pgpr_2]"m" (pGPR[2]),
+ [pgpr_4]"m" (pGPR[4]),
+ [pgpr_6]"m" (pGPR[6]),
+ [pregisterreturn]"m" (pRegisterReturn),
+ [pfpr_0]"m" (pFPR[0]),
+ [pfpr_2]"m" (pFPR[2]),
+ [pfpr_4]"m" (pFPR[4]),
+ [pfpr_6]"m" (pFPR[6]),
+ [pmethod]"r" (pMethod)
+ // Clobbers
+ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
+ );
+
+ MapReturn(pGPR, pFPR, pReturnType, (sal_uInt64 *) pRegisterReturn);
+}
+}
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS ) \
+ if ( nr < arm::MAX_FPR_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<double *>( pSV );
+
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
+ INSERT_DOUBLE( pSV, nr, pGPR, pDS )
+
+namespace {
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: values|ptr ...
+ sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+2) * sizeof(sal_Int64) );
+ sal_uInt64 * pStackStart = pStack;
+
+ sal_uInt64 pGPR[arm::MAX_GPR_REGS];
+ int nGPR = 0;
+
+ // storage and counter for SIMD/FP registers
+ double pFPR[arm::MAX_FPR_REGS];
+ int nFPR = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert( pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (!arm::return_in_x8( pReturnTypeRef ) )
+ pCppReturn = pUnoReturn; // direct way for simple types
+ else
+ {
+ // complex return via x8
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+ // stack space
+ // args
+ void ** pCppArgs = (void **)alloca( sizeof(void *) * nParams );
+
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ int * pTempIndices = (int *)alloca( sizeof(int) * nParams );
+
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)alloca( sizeof(void *) * nParams );
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+ }
+ }
+
+ assert( nGPR <= arm::MAX_GPR_REGS );
+ assert( nFPR <= arm::MAX_FPR_REGS );
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeRef,
+ pStackStart,
+ (pStack - pStackStart),
+ pGPR,
+ pFPR);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert( nMemberPos < pTypeDescr->nAllMembers && "### member pos out of range!");
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
+ (pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1;
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers && "### member pos out of range!");
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
+ (pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ [[fallthrough]];
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_ios/unwind-cxx.h b/bridges/source/cpp_uno/gcc3_ios/unwind-cxx.h
new file mode 100644
index 0000000000..aa35a5bc75
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_ios/unwind-cxx.h
@@ -0,0 +1,285 @@
+// -*- C++ -*- Exception handling and frame unwind runtime interface routines.
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+// This is derived from the C++ ABI for IA-64. Where we diverge
+// for cross-architecture compatibility are noted with "@@@".
+
+#ifndef _UNWIND_CXX_H
+#define _UNWIND_CXX_H 1
+
+// Level 2: C++ ABI
+
+#include <typeinfo>
+#include <exception>
+
+#include <stddef.h>
+#include "unwind.h"
+
+
+typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+#if !defined __IPHONE_16_4 || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_16_4
+typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
+#endif
+typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
+
+#pragma GCC visibility push(default)
+
+namespace __cxxabiv1
+{
+
+// A C++ exception object consists of a header, which is a wrapper around
+// an unwind object header with additional C++ specific information,
+// followed by the exception object itself.
+
+struct __cxa_exception
+{
+#if __LP64__
+#if 0
+ // This is a new field added with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The HACK in
+ // fillUnoException (bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx) tries to find out at
+ // runtime whether a __cxa_exception has this member. Once we can be sure that we only run
+ // against new libcxxabi that has this member, we can drop the "#if 0" here and drop the hack
+ // in fillUnoException.
+
+ // Now _Unwind_Exception is marked with __attribute__((aligned)),
+ // which implies __cxa_exception is also aligned. Insert padding
+ // in the beginning of the struct, rather than before unwindHeader.
+ void *reserve;
+#endif
+
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is at the start of this
+ // struct which is prepended to the object thrown in
+ // __cxa_allocate_exception.
+ size_t referenceCount;
+#endif
+ // Manage the exception object itself.
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ // The C++ standard has entertaining rules wrt calling set_terminate
+ // and set_unexpected in the middle of the exception cleanup process.
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ // The caught exception stack threads through here.
+ __cxa_exception *nextException;
+
+ // How many nested handlers have caught this exception. A negated
+ // value is a signal that this object has been rethrown.
+ int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+ // Stack of exceptions in cleanups.
+ __cxa_exception* nextPropagatingException;
+
+ // The number of active cleanup handlers for this exception.
+ int propagationCount;
+#else
+ // Cache parsed handler data from the personality routine Phase 1
+ // for Phase 2 and __cxa_call_unexpected.
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ _Unwind_Ptr catchTemp;
+ void *adjustedPtr;
+#endif
+#if !__LP64__
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is placed where the compiler
+ // previously adding padded to 64-bit align unwindHeader.
+ size_t referenceCount;
+#endif
+
+ // The generic exception header. Must be last.
+ _Unwind_Exception unwindHeader;
+};
+
+// Each thread in a C++ program has access to a __cxa_eh_globals object.
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+#ifdef __ARM_EABI_UNWINDER__
+ __cxa_exception* propagatingExceptions;
+#endif
+};
+
+
+// The __cxa_eh_globals for the current thread can be obtained by using
+// either of the following functions. The "fast" version assumes at least
+// one prior call of __cxa_get_globals has been made from the current
+// thread, so no initialization is necessary.
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
+
+// Allocate memory for the exception plus the thrown object.
+extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw();
+
+// Free the space allocated for the exception.
+extern "C" void __cxa_free_exception(void *thrown_exception) throw();
+
+#pragma GCC visibility push(hidden)
+extern "C" void *__cxa_allocate_dependent_exception() throw();
+extern "C" void __cxa_free_dependent_exception(void *thrown_exception) throw();
+#pragma GCC visibility pop
+
+// Throw the exception.
+extern "C" void __cxa_throw (void *thrown_exception,
+ std::type_info *tinfo,
+ void (*dest) (void *))
+ __attribute__((noreturn));
+
+// Used to implement exception handlers.
+extern "C" void *__cxa_get_exception_ptr (void *) throw();
+extern "C" void *__cxa_begin_catch (void *) throw();
+extern "C" void __cxa_end_catch ();
+extern "C" void __cxa_rethrow () __attribute__((noreturn));
+
+// These facilitate code generation for recurring situations.
+extern "C" void __cxa_bad_cast ();
+extern "C" void __cxa_bad_typeid ();
+
+// @@@ These are not directly specified by the IA-64 C++ ABI.
+
+// Handles re-checking the exception specification if unexpectedHandler
+// throws, and if bad_exception needs to be thrown. Called from the
+// compiler.
+extern "C" void __cxa_call_unexpected (void *) __attribute__((noreturn));
+extern "C" void __cxa_call_terminate (void*) __attribute__((noreturn));
+
+#ifdef __ARM_EABI_UNWINDER__
+// Arm EABI specified routines.
+typedef enum {
+ ctm_failed = 0,
+ ctm_succeeded = 1,
+ ctm_succeeded_with_ptr_to_base = 2
+} __cxa_type_match_result;
+extern "C" bool __cxa_type_match(_Unwind_Exception*, const std::type_info*,
+ bool, void**);
+extern "C" void __cxa_begin_cleanup (_Unwind_Exception*);
+extern "C" void __cxa_end_cleanup (void);
+#endif
+
+// These are explicitly GNU C++ specific.
+
+// Acquire the C++ exception header from the C++ object.
+static inline __cxa_exception *
+__get_exception_header_from_obj (void *ptr)
+{
+ return reinterpret_cast<__cxa_exception *>(ptr) - 1;
+}
+
+// Acquire the C++ exception header from the generic exception header.
+static inline __cxa_exception *
+__get_exception_header_from_ue (_Unwind_Exception *exc)
+{
+ return reinterpret_cast<__cxa_exception *>(exc + 1) - 1;
+}
+
+#ifdef __ARM_EABI_UNWINDER__
+static inline bool
+__is_gxx_exception_class(_Unwind_Exception_Class c)
+{
+ // TODO: Take advantage of the fact that c will always be word aligned.
+ return c[0] == 'G'
+ && c[1] == 'N'
+ && c[2] == 'U'
+ && c[3] == 'C'
+ && c[4] == 'C'
+ && c[5] == '+'
+ && c[6] == '+';
+}
+
+static inline void
+__GXX_INIT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
+{
+ c[0] = 'G';
+ c[1] = 'N';
+ c[2] = 'U';
+ c[3] = 'C';
+ c[4] = 'C';
+ c[5] = '+';
+ c[6] = '+';
+ c[7] = '\0';
+}
+
+static inline void*
+__gxx_caught_object(_Unwind_Exception* eo)
+{
+ return (void*)eo->barrier_cache.bitpattern[0];
+}
+#else // !__ARM_EABI_UNWINDER__
+// This is the exception class we report -- "GNUCC++\0".
+const _Unwind_Exception_Class __gxx_exception_class
+= ((((((((_Unwind_Exception_Class) 'G'
+ << 8 | (_Unwind_Exception_Class) 'N')
+ << 8 | (_Unwind_Exception_Class) 'U')
+ << 8 | (_Unwind_Exception_Class) 'C')
+ << 8 | (_Unwind_Exception_Class) 'C')
+ << 8 | (_Unwind_Exception_Class) '+')
+ << 8 | (_Unwind_Exception_Class) '+')
+ << 8 | (_Unwind_Exception_Class) '\0');
+
+static inline bool
+__is_gxx_exception_class(_Unwind_Exception_Class c)
+{
+ return (c & ((_Unwind_Exception_Class)~0 << 8)) == __gxx_exception_class;
+}
+
+#define __GXX_INIT_EXCEPTION_CLASS(c) c = __gxx_exception_class
+
+// GNU C++ personality routine, Version 0.
+extern "C" _Unwind_Reason_Code __gxx_personality_v0
+ (int, _Unwind_Action, _Unwind_Exception_Class,
+ struct _Unwind_Exception *, struct _Unwind_Context *);
+
+// GNU C++ sjlj personality routine, Version 0.
+extern "C" _Unwind_Reason_Code __gxx_personality_sj0
+ (int, _Unwind_Action, _Unwind_Exception_Class,
+ struct _Unwind_Exception *, struct _Unwind_Context *);
+
+static inline void*
+__gxx_caught_object(_Unwind_Exception* eo)
+{
+ __cxa_exception* header = __get_exception_header_from_ue (eo);
+ return header->adjustedPtr;
+}
+#endif // !__ARM_EABI_UNWINDER__
+
+} /* namespace __cxxabiv1 */
+
+#pragma GCC visibility pop
+
+#endif // _UNWIND_CXX_H
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx
new file mode 100644
index 0000000000..dcd27e95ae
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx
@@ -0,0 +1,373 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <typeinfo>
+
+#include <dlfcn.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <o3tl/string_view.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#include "abi.hxx"
+#include <osl/mutex.hxx>
+#include <unordered_map>
+
+namespace {
+
+OUString toUnoName(char const * name) {
+ assert(name != nullptr);
+ OUStringBuffer b;
+ bool scoped = *name == 'N';
+ if (scoped) {
+ ++name;
+ }
+ for (;;) {
+ assert(*name >= '0' && *name <= '9');
+ std::size_t n = *name++ - '0';
+ while (*name >= '0' && *name <= '9') {
+ n = 10 * n + (*name++ - '0');
+ }
+ b.appendAscii(name, n);
+ name += n;
+ if (!scoped) {
+ assert(*name == 0);
+ break;
+ }
+ if (*name == 'E') {
+ assert(name[1] == 0);
+ break;
+ }
+ b.append('.');
+ }
+ return b.makeStringAndClear();
+}
+
+class Rtti {
+public:
+ Rtti(): app_(dlopen(nullptr, RTLD_LAZY)) {}
+
+ ~Rtti() { dlclose(app_); }
+
+ std::type_info * getRtti(typelib_TypeDescription const & type);
+
+private:
+ typedef std::unordered_map<OUString, std::type_info *> Map;
+
+ void * app_;
+
+ 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("_ZTIN");
+ for (sal_Int32 j = 0; j != -1;) {
+ OString t(
+ OUStringToOString(
+ o3tl::getToken(unoName, 0, '.', j), RTL_TEXTENCODING_ASCII_US));
+ b.append(OString::number(t.getLength()) + t);
+ }
+ b.append('E');
+ OString sym(b.makeStringAndClear());
+ std::type_info * rtti = static_cast<std::type_info *>(
+ dlsym(app_, sym.getStr()));
+ if (rtti == nullptr) {
+ char const * rttiName = strdup(sym.getStr() + std::strlen("_ZTI"));
+ if (rttiName == nullptr) {
+ throw std::bad_alloc();
+ }
+#if defined MACOSX
+ // For the Apple ARM64 ABI, if the most significant ("non-unique RTTI") bit is set, it
+ // means that the instance of the name is not unique (and thus RTTI equality needs to be
+ // determined by string comparison rather than by pointer comparison):
+ rttiName = reinterpret_cast<char const *>(
+ reinterpret_cast<std::uintptr_t>(rttiName) | 0x8000'0000'0000'0000);
+#endif
+ assert(type.eTypeClass == typelib_TypeClass_EXCEPTION);
+ typelib_CompoundTypeDescription const & ctd
+ = reinterpret_cast<typelib_CompoundTypeDescription const &>(
+ type);
+ if (ctd.pBaseTypeDescription == nullptr) {
+ rtti = new __cxxabiv1::__class_type_info(rttiName);
+ } else {
+ std::type_info * base = getRtti(
+ ctd.pBaseTypeDescription->aBase);
+ rtti = new __cxxabiv1::__si_class_type_info(
+ rttiName,
+ static_cast<__cxxabiv1::__class_type_info *>(base));
+ }
+ }
+ i = map_.insert(Map::value_type(unoName, rtti)).first;
+ }
+ return i->second;
+}
+
+struct theRttiFactory: public rtl::Static<Rtti, theRttiFactory> {};
+
+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;
+#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
+ // First, the libcxxabi commit
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+ // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+ // LLVM 5.0 changed the size of __cxa_exception by adding
+ //
+ // __attribute__((aligned))
+ //
+ // to the final member unwindHeader, on x86-64 effectively adding a hole of
+ // size 8 in front of that member (changing its offset from 88 to 96,
+ // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+ // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
+ // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+ // point to this function (the use of __cxa_exception in mapException is
+ // unaffected, as it only accesses members towards the start of the struct,
+ // through a pointer known to actually point at the start). The libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+ // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+ // removes the need for this hack, so the "header1" hack can be removed again once we can be
+ // sure that we only run against libcxxabi from LLVM >= 6.
+ //
+ // Second, the libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
+ // the layout of the start of __cxa_exception to
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
+ // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
+ // offset by 8. As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
+ // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
+ // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
+ // that we only run against new libcxxabi that has the reserve member.
+ if (header->exceptionDestructor != &deleteException) {
+ auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
+ reinterpret_cast<char *>(header) - 8);
+ if (header1->exceptionDestructor == &deleteException) {
+ header = header1;
+ } else {
+ auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
+ reinterpret_cast<char *>(header) + 8);
+ if (header2->exceptionDestructor == &deleteException) {
+ header = header2;
+ } else {
+ assert(false);
+ }
+ }
+ }
+#endif
+ assert(header->exceptionDestructor == &deleteException);
+ OUString unoName(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);
+}
+
+enum StructKind {
+ STRUCT_KIND_EMPTY, STRUCT_KIND_FLOAT, STRUCT_KIND_DOUBLE, STRUCT_KIND_POD,
+ STRUCT_KIND_DTOR
+};
+
+StructKind getStructKind(typelib_CompoundTypeDescription const * type) {
+ StructKind k = type->pBaseTypeDescription == nullptr
+ ? STRUCT_KIND_EMPTY : getStructKind(type->pBaseTypeDescription);
+ for (sal_Int32 i = 0; i != type->nMembers; ++i) {
+ StructKind k2 = StructKind();
+ switch (type->ppTypeRefs[i]->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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ k2 = STRUCT_KIND_POD;
+ break;
+ case typelib_TypeClass_FLOAT:
+ k2 = STRUCT_KIND_FLOAT;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ k2 = STRUCT_KIND_DOUBLE;
+ break;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ k2 = STRUCT_KIND_DTOR;
+ break;
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
+ k2 = getStructKind(
+ reinterpret_cast<typelib_CompoundTypeDescription const *>(
+ td));
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ default:
+ assert(false);
+ }
+ switch (k2) {
+ case STRUCT_KIND_EMPTY:
+ // this means an empty sub-object, which nevertheless obtains a byte
+ // of storage (TODO: does it?), so the full object cannot be a
+ // homogeneous collection of float or double
+ case STRUCT_KIND_POD:
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ break;
+ case STRUCT_KIND_FLOAT:
+ case STRUCT_KIND_DOUBLE:
+ if (k == STRUCT_KIND_EMPTY) {
+ k = k2;
+ } else if (k != k2) {
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ }
+ break;
+ case STRUCT_KIND_DTOR:
+ return STRUCT_KIND_DTOR;
+ }
+ }
+ return k;
+}
+
+}
+
+namespace abi_aarch64 {
+
+void mapException(
+ __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping)
+{
+ assert(exception != nullptr);
+ assert(type != nullptr);
+ OUString unoName(toUnoName(type->name()));
+ typelib_TypeDescription * td = nullptr;
+ typelib_typedescription_getByName(&td, unoName.pData);
+ if (td == nullptr) {
+ css::uno::RuntimeException e("exception type not found: " + unoName);
+ uno_type_any_constructAndConvert(
+ any, &e,
+ cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
+ mapping);
+ } else {
+ uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping);
+ typelib_typedescription_release(td);
+ }
+}
+
+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);
+}
+
+ReturnKind getReturnKind(typelib_TypeDescription const * type) {
+ switch (type->eTypeClass) {
+ default:
+ assert(false);
+#ifdef NDEBUG
+ [[fallthrough]];
+#endif
+ case typelib_TypeClass_VOID:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ assert(type->nSize <= 16);
+ return RETURN_KIND_REG;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ return RETURN_KIND_INDIRECT;
+ case typelib_TypeClass_STRUCT:
+ if (type->nSize > 16) {
+ return RETURN_KIND_INDIRECT;
+ }
+ switch (getStructKind(
+ reinterpret_cast<typelib_CompoundTypeDescription const *>(
+ type)))
+ {
+ case STRUCT_KIND_FLOAT:
+ return RETURN_KIND_HFA_FLOAT;
+ case STRUCT_KIND_DOUBLE:
+ return RETURN_KIND_HFA_DOUBLE;
+ case STRUCT_KIND_DTOR:
+ return RETURN_KIND_INDIRECT;
+ default:
+ return RETURN_KIND_REG;
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx
new file mode 100644
index 0000000000..10495582dc
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <exception>
+#include <typeinfo>
+
+#include <cxxabi.h>
+#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h
+#define _GLIBCXX_CDTOR_CALLABI
+#endif
+#include <unwind.h>
+
+#include <config_cxxabi.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#if !HAVE_CXXABI_H_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __class_type_info: public std::type_info {
+public:
+ explicit __class_type_info(char const * n): type_info(n) {}
+ ~__class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __si_class_type_info: public __class_type_info {
+public:
+ __class_type_info const * __base_type;
+ explicit __si_class_type_info(
+ char const * n, __class_type_info const *base):
+ __class_type_info(n), __base_type(base) {}
+ ~__si_class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EXCEPTION
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>,
+// libcxxabi/src/cxa_exception.hpp:
+namespace __cxxabiv1 {
+struct __cxa_exception {
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+#if defined __LP64__ || LIBCXXABI_ARM_EHABI
+#ifdef MACOSX // on arm64
+ // This is a new field added with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". For non-MACOSX,
+ // the HACK in call (bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) tries to find out at
+ // runtime whether a __cxa_exception has this member. Once we can be sure that we only run
+ // against new libcxxabi that has this member, we can drop the "#ifdef MACOSX" here and drop the
+ // hack in call.
+
+ // Now _Unwind_Exception is marked with __attribute__((aligned)),
+ // which implies __cxa_exception is also aligned. Insert padding
+ // in the beginning of the struct, rather than before unwindHeader.
+ void *reserve;
+#endif
+ std::size_t referenceCount;
+#endif
+#endif
+ std::type_info * exceptionType;
+ void (* exceptionDestructor)(void *);
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+ __cxa_exception * nextException;
+ int handlerCount;
+ int handlerSwitchValue;
+ char const * actionRecord;
+ char const * languageSpecificData;
+ void * catchTemp;
+ void * adjustedPtr;
+ _Unwind_Exception unwindHeader;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EH_GLOBALS
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>:
+namespace __cxxabiv1 {
+struct __cxa_eh_globals {
+ __cxa_exception * caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_GET_GLOBALS
+namespace __cxxabiv1 {
+extern "C" __cxa_eh_globals * __cxa_get_globals() noexcept;
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_CURRENT_EXCEPTION_TYPE
+namespace __cxxabiv1 {
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_ALLOCATE_EXCEPTION
+namespace __cxxabiv1 {
+extern "C" void * __cxa_allocate_exception(std::size_t thrown_size) throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_THROW
+namespace __cxxabiv1 {
+extern "C" void __cxa_throw(
+ void * thrown_exception, void * tinfo, void (* dest)(void *))
+ __attribute__((noreturn));
+}
+#endif
+
+namespace abi_aarch64 {
+
+void mapException(
+ __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping);
+
+void raiseException(uno_Any * any, uno_Mapping * mapping);
+
+enum ReturnKind {
+ RETURN_KIND_REG, RETURN_KIND_HFA_FLOAT, RETURN_KIND_HFA_DOUBLE,
+ RETURN_KIND_INDIRECT };
+
+ReturnKind getReturnKind(typelib_TypeDescription const * type);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx
new file mode 100644
index 0000000000..b944f31cfd
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstring>
+
+#include <sal/types.h>
+#include <sal/alloca.h>
+
+#include "callvirtualfunction.hxx"
+
+void callVirtualFunction(
+ unsigned long function, unsigned long * gpr, unsigned long * fpr,
+ unsigned long * stack, sal_Int32 sp, void * ret)
+{
+ void * stackargs;
+ if (sp != 0) {
+ stackargs = alloca(((sp + 1) >> 1) * 16);
+ std::memcpy(stackargs, stack, sp * 8);
+ }
+ asm volatile(
+ "ldp x0, x1, [%[gpr_]]\n\t"
+ "ldp x2, x3, [%[gpr_], #16]\n\t"
+ "ldp x4, x5, [%[gpr_], #32]\n\t"
+ "ldp x6, x7, [%[gpr_], #48]\n\t"
+ "ldr x8, %[ret_]\n\t"
+ "ldr x9, %[function_]\n\t"
+ "ldp d0, d1, [%[fpr_]]\n\t"
+ "ldp d2, d3, [%[fpr_], #16]\n\t"
+ "ldp d4, d5, [%[fpr_], #32]\n\t"
+ "ldp d6, d7, [%[fpr_], #48]\n\t"
+ "blr x9\n\t"
+ "stp x0, x1, [%[gpr_]]\n\t"
+ "stp d0, d1, [%[fpr_]]\n\t"
+ "stp d2, d3, [%[fpr_], #16]\n\t"
+ :: [gpr_]"r" (gpr), [fpr_]"r" (fpr), [function_]"m" (function),
+ [ret_]"m" (ret),
+ "m" (stackargs) // dummy input to prevent optimizing the alloca away
+ : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17",
+#if !defined ANDROID && !defined MACOSX
+ "r18"/*TODO?*/,
+#endif
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
+ "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
+ "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+ "memory"
+ // only the bottom 64 bits of v8--15 need to be preserved by callees
+ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx
new file mode 100644
index 0000000000..a8b92785f4
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+void callVirtualFunction(
+ unsigned long function, unsigned long * gpr, unsigned long * fpr,
+ unsigned long * stack, sal_Int32 sp, void * ret);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx
new file mode 100644
index 0000000000..669c4443c5
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx
@@ -0,0 +1,606 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <typeinfo>
+
+#include <dlfcn.h>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "abi.hxx"
+#include "vtablecall.hxx"
+
+namespace {
+
+void call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * proxy,
+ css::uno::TypeDescription const & description,
+ typelib_TypeDescriptionReference * returnType, sal_Int32 count,
+ typelib_MethodParameter * parameters, unsigned long * gpr,
+ unsigned long * fpr, unsigned long * stack, void * indirectRet)
+{
+ typelib_TypeDescription * rtd = nullptr;
+ if (returnType != nullptr) {
+ TYPELIB_DANGER_GET(&rtd, returnType);
+ }
+ abi_aarch64::ReturnKind retKind = rtd == nullptr
+ ? abi_aarch64::RETURN_KIND_REG : abi_aarch64::getReturnKind(rtd);
+ bool retConv = rtd != nullptr
+ && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
+ void * retin = retKind == abi_aarch64::RETURN_KIND_INDIRECT && !retConv
+ ? 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 = static_cast<typelib_TypeDescription **>(
+ alloca(count * sizeof (typelib_TypeDescription *)));
+ sal_Int32 ngpr = 1;
+ sal_Int32 nfpr = 0;
+ sal_Int32 sp = 0;
+#ifdef MACOSX
+ sal_Int32 subsp = 0;
+#endif
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (!parameters[i].bOut
+ && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ switch (parameters[i].pTypeRef->eTypeClass) {
+#ifdef MACOSX
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 1;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ subsp = (subsp + 1) & ~0x1;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 2;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ subsp = (subsp + 3) & ~0x3;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 4;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = stack + sp;
+ sp++;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (nfpr < 8)
+ {
+ args[i] = fpr + nfpr;
+ nfpr++;
+ }
+ else
+ {
+ subsp = (subsp + 3) & ~0x3;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 4;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (nfpr < 8)
+ {
+ args[i] = fpr + nfpr;
+ nfpr++;
+ }
+ else
+ {
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = stack + sp;
+ sp++;
+ }
+ break;
+#else
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
+ break;
+#endif
+ default:
+ assert(false);
+ }
+ argtds[i] = nullptr;
+ } else {
+#ifdef MACOSX
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+#endif
+ cppArgs[i] = reinterpret_cast<void *>(
+ ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
+ 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);
+ }
+ abi_aarch64::raiseException(&exc, proxy->getBridge()->getUno2Cpp());
+ }
+ 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]);
+ }
+ }
+ void * retout = nullptr; // avoid false -Werror=maybe-uninitialized
+ switch (retKind) {
+ case abi_aarch64::RETURN_KIND_REG:
+ switch (rtd == nullptr ? typelib_TypeClass_VOID : rtd->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ break;
+#if defined MACOSX
+ case typelib_TypeClass_BOOLEAN:
+ assert(rtd->nSize == sizeof (bool));
+ *gpr = static_cast<unsigned long>(*static_cast<bool *>(retin));
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_BYTE:
+ assert(rtd->nSize == sizeof (sal_Int8));
+ *gpr = *static_cast<sal_Int8 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_SHORT:
+ assert(rtd->nSize == sizeof (sal_Int16));
+ *gpr = *static_cast<sal_Int16 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ assert(rtd->nSize == sizeof (sal_uInt16));
+ *gpr = *static_cast<sal_uInt16 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_CHAR:
+ assert(rtd->nSize == sizeof (sal_Unicode));
+ *gpr = *static_cast<sal_Unicode *>(retin);
+ assert(!retConv);
+ break;
+#else
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+#endif
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ std::memcpy(gpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_STRUCT:
+ if (retConv) {
+ retout = gpr;
+ } else {
+ std::memcpy(gpr, retin, rtd->nSize);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_FLOAT:
+ assert(rtd != nullptr);
+ switch (rtd->nSize) {
+ case 16:
+ std::memcpy(fpr + 3, static_cast<char *>(retin) + 12, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(fpr + 2, static_cast<char *>(retin) + 8, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(fpr + 1, static_cast<char *>(retin) + 4, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(fpr, retin, 4);
+ break;
+ default:
+ assert(false);
+ }
+ assert(!retConv);
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_DOUBLE:
+ assert(rtd != nullptr);
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case abi_aarch64::RETURN_KIND_INDIRECT:
+ retout = indirectRet;
+ break;
+ }
+ if (retConv) {
+ uno_copyAndConvertData(
+ retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
+ uno_destructData(retin, rtd, nullptr);
+ }
+ if (rtd != nullptr) {
+ TYPELIB_DANGER_RELEASE(rtd);
+ }
+}
+
+}
+
+void vtableCall(
+ sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ unsigned long * gpr, unsigned long * fpr, unsigned long * stack,
+ void * indirectRet)
+{
+ bridges::cpp_uno::shared::CppInterfaceProxy * proxy
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ reinterpret_cast<char *>(gpr[0]) - 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<typelib_InterfaceAttributeTypeDescription *>(
+ desc.get())->pAttributeTypeRef,
+ 0, nullptr, gpr, fpr, stack, indirectRet);
+ } else {
+ // Setter:
+ typelib_MethodParameter param = {
+ nullptr,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
+ desc.get())->pAttributeTypeRef,
+ true, false };
+ call(proxy, desc, nullptr, 1, &param, gpr, fpr, stack, 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<css::uno::Type *>(gpr[1])
+ ->getTypeLibType()));
+ if (td != nullptr && td->eTypeClass == typelib_TypeClass_INTERFACE) {
+ css::uno::XInterface * ifc = nullptr;
+ proxy->getBridge()->getCppEnv()->getRegisteredInterface(
+ proxy->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&ifc), proxy->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ td));
+ if (ifc != nullptr) {
+ uno_any_construct(
+ static_cast<uno_Any *>(indirectRet), &ifc, td,
+ reinterpret_cast<uno_AcquireFunc>(
+ css::uno::cpp_acquire));
+ ifc->release();
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ 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,
+ gpr, fpr, stack, indirectRet);
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+namespace {
+
+std::size_t const codeSnippetSize = 8 * 4;
+
+unsigned char * generateCodeSnippet(
+ unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
+{
+ // movz x9, <low functionIndex>
+ reinterpret_cast<unsigned int *>(code)[0] = 0xD2800009
+ | ((functionIndex & 0xFFFF) << 5);
+ // movk x9, <high functionIndex>, LSL #16
+ reinterpret_cast<unsigned int *>(code)[1] = 0xF2A00009
+ | ((functionIndex >> 16) << 5);
+ // movz x10, <low vtableOffset>
+ reinterpret_cast<unsigned int *>(code)[2] = 0xD280000A
+ | ((vtableOffset & 0xFFFF) << 5);
+ // movk x10, <high vtableOffset>, LSL #16
+ reinterpret_cast<unsigned int *>(code)[3] = 0xF2A0000A
+ | ((vtableOffset >> 16) << 5);
+ // ldr x11, +2*4
+ reinterpret_cast<unsigned int *>(code)[4] = 0x5800004B;
+ // br x11
+ reinterpret_cast<unsigned int *>(code)[5] = 0xD61F0160;
+ reinterpret_cast<unsigned long *>(code)[3]
+ = reinterpret_cast<unsigned long>(&vtableSlotCall);
+ return code + codeSnippetSize;
+}
+
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
+ return static_cast<Slot *>(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::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 * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+#ifdef USE_DOUBLE_MMAP
+ sal_PtrDiff writetoexecdiff,
+#endif
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+#ifndef USE_DOUBLE_MMAP
+ constexpr sal_PtrDiff writetoexecdiff = 0;
+#endif
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i != type->nMembers; ++i) {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
+ assert(td != nullptr);
+ switch (td->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription * atd
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription *>(td);
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(
+ code, functionOffset++, vtableOffset);
+ // Setter:
+ if (!atd->bReadOnly) {
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(
+ code, functionOffset++, vtableOffset);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(code, functionOffset++, vtableOffset);
+ break;
+ default:
+ assert(false);
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const * begin, unsigned char const * end)
+{
+#if !defined ANDROID && !defined MACOSX
+ static void (*clear_cache)(unsigned char const *, unsigned char const *)
+ = (void (*)(unsigned char const *, unsigned char const *)) dlsym(
+ RTLD_DEFAULT, "__clear_cache");
+ (*clear_cache)(begin, end);
+#else
+ // GCC clarified with
+ // <http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a90b0cdd444f6dde1084a439862cf507f6d3b2ae>
+ // "extend.texi (__clear_cache): Correct signature" that __builtin___clear_cache takes void*
+ // parameters, while Clang uses char* ever since
+ // <https://github.com/llvm/llvm-project/commit/c491a8d4577052bc6b3b4c72a7db6a7cfcbc2ed0> "Add
+ // support for __builtin___clear_cache in Clang" (TODO: see
+ // <https://bugs.llvm.org/show_bug.cgi?id=48489> "__builtin___clear_cache() has a different
+ // prototype than GCC"; once fixed for our Clang baseline, we can drop the reinterpret_casts):
+ __builtin___clear_cache(
+ reinterpret_cast<char *>(const_cast<unsigned char *>(begin)),
+ reinterpret_cast<char *>(const_cast<unsigned char *>(end)));
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx
new file mode 100644
index 0000000000..57beb6dfa1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstring>
+#include <exception>
+#include <typeinfo>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <rtl/textenc.h>
+#include <rtl/ustring.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+
+#include "abi.hxx"
+#include "callvirtualfunction.hxx"
+
+namespace {
+
+void pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass typeclass,
+ sal_Int32 * const subsp,
+#endif
+ unsigned long value, unsigned long * const stack, sal_Int32 * const sp,
+ unsigned long * const regs, sal_Int32 * const nregs)
+{
+#ifdef MACOSX
+ if (*nregs != 8)
+ {
+ regs[(*nregs)++] = value;
+ }
+ else
+ {
+ switch (typeclass) {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 1;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+ *subsp = (*subsp + 1) & ~0x1;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ *reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 2;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_FLOAT:
+ *subsp = (*subsp + 3) & ~0x3;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 4;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ default:
+ if (*subsp > 0)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ stack[*sp] = value;
+ (*sp)++;
+ break;
+ }
+ }
+#else
+ (*nregs != 8 ? regs[(*nregs)++] : stack[(*sp)++]) = value;
+#endif
+}
+
+void call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * proxy,
+ bridges::cpp_uno::shared::VtableSlot slot,
+ typelib_TypeDescriptionReference * returnType, sal_Int32 count,
+ typelib_MethodParameter * parameters, void * returnValue, void ** arguments,
+ uno_Any ** exception)
+{
+ typelib_TypeDescription * rtd = nullptr;
+ TYPELIB_DANGER_GET(&rtd, returnType);
+ abi_aarch64::ReturnKind retKind = abi_aarch64::getReturnKind(rtd);
+ bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
+ void * ret = retConv ? alloca(rtd->nSize) : returnValue;
+ unsigned long ** thisPtr
+ = reinterpret_cast<unsigned long **>(proxy->getCppI()) + slot.offset;
+ unsigned long * stack = static_cast<unsigned long *>(
+ alloca(count * sizeof (unsigned long)));
+ sal_Int32 sp = 0;
+#ifdef MACOSX
+ sal_Int32 subsp = 0;
+#endif
+ unsigned long gpr[8];
+ sal_Int32 ngpr = 0;
+ unsigned long fpr[8];
+ sal_Int32 nfpr = 0;
+ gpr[ngpr++] = reinterpret_cast<unsigned long>(thisPtr);
+ void ** cppArgs = static_cast<void **>(alloca(count * sizeof (void *)));
+ typelib_TypeDescription ** ptds =
+ static_cast<typelib_TypeDescription **>(
+ alloca(count * sizeof (typelib_TypeDescription *)));
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (!parameters[i].bOut &&
+ bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ cppArgs[i] = nullptr;
+ switch (parameters[i].pTypeRef->eTypeClass) {
+ case typelib_TypeClass_BOOLEAN:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ static_cast<unsigned long>(*static_cast<sal_Bool *>(arguments[i])), stack, &sp,
+ gpr, &ngpr);
+ break;
+ case typelib_TypeClass_BYTE:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int8 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_SHORT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int16 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt16 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_ENUM:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int32 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt32 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_HYPER:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int64 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt64 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_FLOAT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<unsigned int *>(arguments[i]), stack, &sp, fpr,
+ &nfpr);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<unsigned long *>(arguments[i]), stack, &sp,
+ fpr, &nfpr);
+ break;
+ case typelib_TypeClass_CHAR:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Unicode *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ default:
+ assert(false);
+ }
+ } else {
+ typelib_TypeDescription * ptd = nullptr;
+ TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
+ if (!parameters[i].bIn) {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_constructData(cppArgs[i], ptd);
+ ptds[i] = ptd;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
+ gpr, &ngpr);
+ } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_copyAndConvertData(
+ cppArgs[i], arguments[i], ptd,
+ proxy->getBridge()->getUno2Cpp());
+ ptds[i] = ptd;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
+ gpr, &ngpr);
+ } else {
+ cppArgs[i] = nullptr;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(arguments[i]), stack, &sp,
+ gpr, &ngpr);
+ TYPELIB_DANGER_RELEASE(ptd);
+ }
+ }
+ }
+ try {
+ try {
+ callVirtualFunction(
+ (*thisPtr)[slot.index], gpr, fpr, stack, sp, ret);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw "
+ + OStringToOUString(typeid(e).name(), RTL_TEXTENCODING_UTF8)
+ + ": " + OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8));
+ } catch (...) {
+ throw css::uno::RuntimeException(
+ "C++ code threw unknown exception");
+ }
+ } catch (css::uno::Exception &) {
+ __cxxabiv1::__cxa_exception * header = reinterpret_cast<__cxxabiv1::__cxa_eh_globals *>(
+ __cxxabiv1::__cxa_get_globals())->caughtExceptions;
+#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
+ // Very bad HACK to find out whether we run against a libcxxabi that has a new
+ // __cxa_exception::reserved member at the start, introduced with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of
+ // the start of __cxa_exception is
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // where the (bad, hacky) assumption is that reserve (if present) is null
+ // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+ // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+ // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+ // __cxa_dependent_exception, the referenceCount member is rather
+ //
+ // 8 byte void* primaryException
+ //
+ // but which also will always be set to a non-null value in
+ // __cxa_rethrow_primary_exception). As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), this hack (together with the
+ // "#ifdef MACOSX" there) can be dropped once we can be sure that we only run against new
+ // libcxxabi that has the reserve member:
+ if (*reinterpret_cast<void **>(header) == nullptr) {
+ header = reinterpret_cast<__cxxabiv1::__cxa_exception*>(
+ reinterpret_cast<void **>(header) + 1);
+ }
+#endif
+ abi_aarch64::mapException(
+ header,
+ __cxxabiv1::__cxa_current_exception_type(), *exception,
+ proxy->getBridge()->getCpp2Uno());
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (cppArgs[i] != nullptr) {
+ uno_destructData(
+ cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+ TYPELIB_DANGER_RELEASE(rtd);
+ return;
+ }
+ *exception = nullptr;
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (cppArgs[i] != nullptr) {
+ if (parameters[i].bOut) {
+ if (parameters[i].bIn) {
+ uno_destructData(arguments[i], ptds[i], nullptr);
+ }
+ uno_copyAndConvertData(
+ arguments[i], cppArgs[i], ptds[i],
+ proxy->getBridge()->getCpp2Uno());
+ }
+ uno_destructData(
+ cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+ switch (retKind) {
+ case abi_aarch64::RETURN_KIND_REG:
+ switch (rtd->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ std::memcpy(ret, gpr, rtd->nSize);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(ret, fpr, rtd->nSize);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_FLOAT:
+ switch (rtd->nSize) {
+ case 16:
+ std::memcpy(static_cast<char *>(ret) + 12, fpr + 3, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(static_cast<char *>(ret) + 8, fpr + 2, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(static_cast<char *>(ret) + 4, fpr + 1, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(ret, fpr, 4);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_DOUBLE:
+ std::memcpy(ret, fpr, rtd->nSize);
+ break;
+ case abi_aarch64::RETURN_KIND_INDIRECT:
+ break;
+ }
+ if (retConv) {
+ uno_copyAndConvertData(
+ returnValue, ret, rtd, proxy->getBridge()->getCpp2Uno());
+ uno_destructData(
+ ret, rtd, reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ }
+ TYPELIB_DANGER_RELEASE(rtd);
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr,
+ void * pReturn, void ** pArgs, uno_Any ** ppException)
+{
+ UnoInterfaceProxy * proxy = static_cast<UnoInterfaceProxy *>(pUnoI);
+ switch (pMemberDescr->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription const * atd
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberDescr);
+ VtableSlot slot(getVtableSlot(atd));
+ if (pReturn != nullptr) { // getter
+ call(
+ proxy, slot, atd->pAttributeTypeRef, 0, nullptr, pReturn, pArgs,
+ ppException);
+ } else { // setter
+ typelib_MethodParameter param = {
+ nullptr, atd->pAttributeTypeRef, true, false };
+ typelib_TypeDescriptionReference * rtd = nullptr;
+ typelib_typedescriptionreference_new(
+ &rtd, typelib_TypeClass_VOID, OUString("void").pData);
+ slot.index += 1;
+ call(proxy, slot, rtd, 1, &param, pReturn, pArgs, ppException);
+ typelib_typedescriptionreference_release(rtd);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const * mtd
+ = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const *>(
+ pMemberDescr);
+ VtableSlot slot(getVtableSlot(mtd));
+ switch (slot.index) {
+ case 1:
+ pUnoI->acquire(pUnoI);
+ *ppException = nullptr;
+ break;
+ case 2:
+ pUnoI->release(pUnoI);
+ *ppException = nullptr;
+ break;
+ case 0:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(
+ &td,
+ (static_cast<css::uno::Type *>(pArgs[0])
+ ->getTypeLibType()));
+ if (td != nullptr) {
+ uno_Interface * ifc = nullptr;
+ proxy->pBridge->getUnoEnv()->getRegisteredInterface(
+ proxy->pBridge->getUnoEnv(),
+ reinterpret_cast<void **>(&ifc), proxy->oid.pData,
+ reinterpret_cast<
+ typelib_InterfaceTypeDescription *>(td));
+ if (ifc != nullptr) {
+ uno_any_construct(
+ static_cast<uno_Any *>(pReturn), &ifc, td,
+ nullptr);
+ ifc->release(ifc);
+ TYPELIB_DANGER_RELEASE(td);
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ }
+ [[fallthrough]];
+ default:
+ call(
+ proxy, slot, mtd->pReturnTypeRef, mtd->nParams,
+ mtd->pParams, pReturn, pArgs, ppException);
+ break;
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx
new file mode 100644
index 0000000000..6ec92687c4
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+extern "C" {
+void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long* gpr,
+ unsigned long* fpr, unsigned long* stack, void* indirectRet);
+
+void vtableSlotCall();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s
new file mode 100644
index 0000000000..60bdb4c9cf
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s
@@ -0,0 +1,83 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .arch armv8-a
+ .text
+ .align 2
+#ifndef __APPLE__
+ .global vtableSlotCall
+ .hidden vtableSlotCall
+ .type vtableSlotCall, %function
+vtableSlotCall:
+#else
+ .global _vtableSlotCall
+_vtableSlotCall:
+#endif
+ .cfi_startproc
+ stp x29, x30, [sp, -192]!
+ .cfi_def_cfa_offset 192
+ .cfi_offset 29, -192
+ .cfi_offset 30, -184
+ add x11, sp, 192
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ .cfi_offset 19, -176
+ .cfi_offset 20, -168
+ add x20, sp, 128
+ add x19, sp, 64
+ stp x11, x11, [sp, 32]
+ str x11, [sp, 48]
+ stp wzr, wzr, [sp, 56]
+ stp x0, x1, [sp, 64]
+ mov w0, w9
+ mov w1, w10
+ stp x2, x3, [sp, 80]
+ mov x3, x20
+ mov x2, x19
+ stp x4, x5, [sp, 96]
+ mov x5, x8
+ mov x4, x11
+ stp x6, x7, [sp, 112]
+ stp d0, d1, [sp, 128]
+ stp d2, d3, [sp, 144]
+ stp d4, d5, [sp, 160]
+ stp d6, d7, [sp, 176]
+#ifndef __APPLE__
+ bl vtableCall
+#else
+ bl _vtableCall
+#endif
+ ldp x0, x1, [x19]
+ ldp d0, d1, [x20]
+ ldp d2, d3, [x20, #16]
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 192
+ .cfi_restore 30
+ .cfi_restore 29
+ .cfi_restore 19
+ .cfi_restore 20
+ .cfi_def_cfa_offset 0
+ ret
+ .cfi_endproc
+#ifndef __APPLE__
+ .size vtableSlotCall, .-vtableSlotCall
+ .section .note.GNU-stack, "", @progbits
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab */
diff --git a/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx
new file mode 100644
index 0000000000..98709f4c5e
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx
@@ -0,0 +1,676 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+#include <stdio.h>
+#include <typeinfo>
+
+//Calling Standards:
+// "Calling Standard for Alpha Systems"
+// (Tru64 UNIX Version 5.1 or higher, August 2000)
+//http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_HTML/ARH9MBTE/TITLE.HTM
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "as far as cpp2uno_call\n");
+#endif
+ int nregs = 0; //number of words passed in registers
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ gpreg++;
+ fpreg++;
+ nregs++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "arg %d of %d\n", nPos, nParams);
+#endif
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple type is %d\n", pParamTypeDescr->eTypeClass);
+#endif
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+ {
+ float tmp = (float) (*((double *)fpreg));
+ (*((float *) fpreg)) = tmp;
+ }
+
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ default:
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex, nregs is %d\n", nregs);
+#endif
+
+ void *pCppStack; //temporary stack pointer
+
+ if (nregs < axp::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw;
+ ovrflw++;
+ }
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of params\n");
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_uInt64 nOffsetAndIndex,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int64)==sizeof(void *), "### unexpected!");
+
+ sal_Int32 nVtableOffset = (nOffsetAndIndex >> 32);
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "nVTableOffset, nFunctionIndex are %x %x\n", nVtableOffset, nFunctionIndex);
+#endif
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= cpp_mediate () =\nGPR's (%d): ", 6 );
+ for ( unsigned int i = 0; i < 6; ++i )
+ fprintf( stderr, "0x%lx, ", gpreg[i] );
+ fprintf( stderr, "\n");
+ fprintf( stderr, "\nFPR's (%d): ", 6 );
+ for ( unsigned int i = 0; i < 6; ++i )
+ fprintf( stderr, "0x%lx (%f), ", fpreg[i], fpreg[i] );
+ fprintf( stderr, "\n");
+ }
+#endif
+
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // _this_ ptr is patched cppu_XInterfaceProxy object
+ void * pThis;
+ if( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ assert(nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex);
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+
+ return eRet;
+}
+
+long cpp_vtable_call(long r16, long r17, long r18, long r19, long r20, long r21, long firstonstack)
+{
+ register long r1 asm("$1");
+ sal_uInt64 nOffsetAndIndex = r1;
+
+ long sp = (long)&firstonstack;
+
+ sal_uInt64 gpreg[axp::MAX_GPR_REGS];
+ gpreg[0] = r16;
+ gpreg[1] = r17;
+ gpreg[2] = r18;
+ gpreg[3] = r19;
+ gpreg[4] = r20;
+ gpreg[5] = r21;
+
+ double fpreg[axp::MAX_SSE_REGS];
+ register double f16 asm("$f16"); fpreg[0] = f16;
+ register double f17 asm("$f17"); fpreg[1] = f17;
+ register double f18 asm("$f18"); fpreg[2] = f18;
+ register double f19 asm("$f19"); fpreg[3] = f19;
+ register double f20 asm("$f20"); fpreg[4] = f20;
+ register double f21 asm("$f21"); fpreg[5] = f21;
+
+ volatile long nRegReturn[1];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "before mediate with %lx\n",nOffsetAndIndex);
+ fprintf(stderr, "non-doubles are %x %x %x %x %x %x\n", gpreg[0], gpreg[1], gpreg[2], gpreg[3], gpreg[4], gpreg[5]);
+ fprintf(stderr, "doubles are %f %f %f %f %f %f\n", fpreg[0], fpreg[1], fpreg[2], fpreg[3], fpreg[4], fpreg[5]);
+#endif
+ typelib_TypeClass aType =
+ cpp_mediate( nOffsetAndIndex, (void**)gpreg, (void**)fpreg, (void**)sp,
+ (sal_Int64*)nRegReturn );
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "after mediate ret is %lx %ld\n", nRegReturn[0], nRegReturn[0]);
+#endif
+
+ switch( aType )
+ {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ nRegReturn[0] = (unsigned long)(*(unsigned char *)nRegReturn);
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_SHORT:
+ nRegReturn[0] = (unsigned long)(*(unsigned short *)nRegReturn);
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_LONG:
+ nRegReturn[0] = (unsigned long)(*(unsigned int *)nRegReturn);
+ break;
+ case typelib_TypeClass_VOID:
+ default:
+ break;
+ case typelib_TypeClass_FLOAT:
+ {
+ double tmp = (double) (*((float *)nRegReturn));
+ (*((double *) nRegReturn)) = tmp;
+ }
+ //deliberate fall through
+ case typelib_TypeClass_DOUBLE:
+ __asm__ ( "ldt $f0,%0\n\t"
+ : : "m" (*((double*)nRegReturn)) : "$f0");
+ break;
+ }
+ return nRegReturn[0];
+}
+
+const int codeSnippetSize = 32;
+
+unsigned char *codeSnippet( unsigned char * code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool simple_ret_type )
+{
+ if (! simple_ret_type)
+ nFunctionIndex |= 0x80000000;
+
+ unsigned char * p = code;
+ *(unsigned int*)&p[0] = 0x47fb0401; /* mov $27,$1 */
+ *(unsigned int*)&p[4] = 0xa43b0010; /* ldq $1,16($27) */
+ *(unsigned int*)&p[8] = 0xa77b0018; /* ldq $27,24($27) */
+ *(unsigned int*)&p[12] = 0x6bfb0000; /* jmp $31,($27),0 */
+ *(unsigned int*)&p[16] = nFunctionIndex;
+ *(unsigned int*)&p[20] = nVtableOffset;
+ *(unsigned long*)&p[24] = (unsigned long)cpp_vtable_call;
+ return (code + codeSnippetSize);
+}
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, unsigned char const *)
+{
+ //http://www.gnu.org/software/lightning/manual/html_node/Standard-functions.html
+ __asm__ __volatile__("call_pal 0x86");
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, true);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_alpha/except.cxx b/bridges/source/cpp_uno/gcc3_linux_alpha/except.cxx
new file mode 100644
index 0000000000..9331665fab
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_alpha/except.cxx
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ terminate();
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ if (! rtti)
+ terminate();
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ terminate();
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (! pExcTypeDescr)
+ terminate();
+
+ // construct uno exception any
+ ::uno_any_constructAndConvert( pExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ ::typelib_typedescription_release( pExcTypeDescr );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_alpha/share.hxx b/bridges/source/cpp_uno/gcc3_linux_alpha/share.hxx
new file mode 100644
index 0000000000..5e174f6b99
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_alpha/share.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+namespace axp
+{
+ enum axplimits { MAX_WORDS_IN_REGS = 6, MAX_GPR_REGS = 6, MAX_SSE_REGS = 6 };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_alpha/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_alpha/uno2cpp.cxx
new file mode 100644
index 0000000000..48a5f862b9
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_alpha/uno2cpp.cxx
@@ -0,0 +1,536 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+
+using namespace ::com::sun::star::uno;
+
+void MapReturn(long r0, typelib_TypeClass eTypeClass, sal_uInt64* pRegisterReturn)
+{
+ register float fret asm("$f0");
+ register double dret asm("$f0");
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr,"Mapping Return with %lx %ld %f\n", r0, r0, dret);
+#endif
+ switch (eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *pRegisterReturn = r0;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *(unsigned int*)pRegisterReturn = (unsigned int)r0;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)r0;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)r0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *reinterpret_cast<float *>( pRegisterReturn ) = fret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double *>( pRegisterReturn ) = dret;
+ break;
+ default:
+ break;
+ }
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of MapReturn with %x\n", pRegisterReturn ? *pRegisterReturn : 0);
+#endif
+}
+
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
+ { \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ { \
+ pFPR[nr++] = *reinterpret_cast<float *>( pSV ); \
+ } \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ }
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS ) \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+ if ( nr < axp::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+namespace
+{
+
+void callVirtualMethod(
+ void * pThis, sal_Int32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr,
+ sal_uInt64 *pStack, sal_uInt32 nStack,
+ sal_uInt64 *pGPR, sal_uInt32 nGPR,
+ double *pFPR, sal_uInt32 nFPR)
+{
+ // Should not happen, but...
+ if ( nFPR > axp::MAX_SSE_REGS )
+ nFPR = axp::MAX_SSE_REGS;
+ if ( nGPR > axp::MAX_GPR_REGS )
+ nGPR = axp::MAX_GPR_REGS;
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= nStack is %d\n", nStack );
+ fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
+ for ( unsigned int i = 0; i < nGPR; ++i )
+ fprintf( stderr, "0x%lx, ", pGPR[i] );
+ fprintf( stderr, "\nFPR's (%d): ", nFPR );
+ for ( unsigned int i = 0; i < nFPR; ++i )
+ fprintf( stderr, "0x%lx (%f), ", pFPR[i], pFPR[i] );
+ fprintf( stderr, "\nStack (%d): ", nStack );
+ for ( unsigned int i = 0; i < nStack; ++i )
+ fprintf( stderr, "0x%lx, ", pStack[i] );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
+ }
+#endif
+
+ // Load parameters to stack, if necessary
+ // Stack, if used, must be 8-bytes aligned
+ sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca( nStack * 8 );
+ memcpy( stack, pStack, nStack * 8 );
+
+ // To get pointer to method
+ // a) get the address of the vtable
+ sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
+ // b) get the address from the vtable entry at offset
+ pMethod += 8 * nVtableIndex;
+ pMethod = *((sal_uInt64 *)pMethod);
+
+ typedef void (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 );
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ switch (nFPR) //deliberate fall through
+ {
+ case 6:
+ asm volatile("ldt $f16,%0" :: "m"(pFPR[5]) : "$f16");
+ case 5:
+ asm volatile("ldt $f17,%0" :: "m"(pFPR[4]) : "$f17");
+ case 4:
+ asm volatile("ldt $f18,%0" :: "m"(pFPR[3]) : "$f18");
+ case 3:
+ asm volatile("ldt $f19,%0" :: "m"(pFPR[2]) : "$f19");
+ case 2:
+ asm volatile("ldt $f20,%0" :: "m"(pFPR[1]) : "$f20");
+ case 1:
+ asm volatile("ldt $f21,%0" :: "m"(pFPR[0]) : "$f21");
+ default:
+ break;
+ }
+
+ (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3], pGPR[4], pGPR[5]);
+ register sal_uInt64 r0 __asm__("$0");
+ MapReturn(r0, pReturnTypeDescr->eTypeClass, (sal_uInt64*)pRegisterReturn);
+}
+
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+3) * sizeof(sal_Int64) );
+ sal_uInt64 * pStackStart = pStack;
+
+ sal_uInt64 pGPR[axp::MAX_GPR_REGS];
+ double pFPR[axp::MAX_SSE_REGS];
+ sal_uInt32 nRegs = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ INSERT_INT64( &pCppReturn, nRegs, pGPR, pStack );
+ }
+ }
+ // push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+
+ INSERT_INT64( &pAdjustedThisPtr, nRegs, pGPR, pStack );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nRegs, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr,
+ pStackStart, (pStack - pStackStart),
+ pGPR, nRegs,
+ pFPR, nRegs );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "unoInterfaceProxyDispatch\n");
+#endif
+
+
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S b/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S
new file mode 100644
index 0000000000..4eff3ff0a0
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/armhelper.S
@@ -0,0 +1,70 @@
+@
+@ 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/.
+@
+@ This file incorporates work covered by the following license notice:
+@
+@ Licensed to the Apache Software Foundation (ASF) under one or more
+@ contributor license agreements. See the NOTICE file distributed
+@ with this work for additional information regarding copyright
+@ ownership. The ASF licenses this file to you under the Apache
+@ License, Version 2.0 (the "License"); you may not use this file
+@ except in compliance with the License. You may obtain a copy of
+@ the License at http://www.apache.org/licenses/LICENSE-2.0 .
+@
+
+@ ARM support code for OpenOffice C++/UNO bridging
+@
+@ Written by Peter Naulls <peter@chocky.org>
+@ Modified by Caolan McNamara <caolanm@redhat.com>
+@ Fixed by Michael Casadevall <mcasadevall@kubuntu.org>
+
+#ifdef __ARM_EABI__
+# define UNWIND
+#else
+# define UNWIND @
+#endif
+
+@ If the VFP ABI variant (armhf in Debian/Ubuntu) is used, an additional extra 64 bytes
+@ are taken up on the stack (the equivalent of the 8 double precision VFP registers)
+
+#ifdef __ARM_PCS_VFP
+# define PAD 80
+# define DISCARDED 84
+#else
+# define PAD 16
+# define DISCARDED 20
+#endif
+
+ .file "armhelper.s"
+ .text
+ .align 4
+ .global privateSnippetExecutor
+ .type privateSnippetExecutor, %function
+privateSnippetExecutor:
+ UNWIND .fnstart @ start of unwinder entry
+
+ stmfd sp!, {r0-r3} @ follow other parameters on stack
+ mov r0, ip @ r0 points to functionoffset/vtable
+ mov r1, sp @ r1 points to this and params
+#ifdef __ARM_PCS_VFP
+ vpush {d0-d7} @ floating point parameter on stack
+#endif
+ UNWIND .pad #PAD @ throw this data away on exception
+ @ (see cppuno.cxx:codeSnippet())
+ stmfd sp!, {r4,lr} @ save return address
+ @ (r4 pushed to preserve stack alignment)
+ UNWIND .save {r4,lr} @ restore these regs on exception
+
+ bl cpp_vtable_call(PLT)
+
+ add sp, sp, #4 @ no need to restore r4 (we didn't touch it)
+ ldr pc, [sp], #DISCARDED @ return, discarding function arguments
+
+ UNWIND .fnend @ end of unwinder entry
+
+ .size privateSnippetExecutor, . - privateSnippetExecutor
+ .section .note.GNU-stack,"",%progbits
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/call.hxx b/bridges/source/cpp_uno/gcc3_linux_arm/call.hxx
new file mode 100644
index 0000000000..dde56f6f59
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/call.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+extern "C" sal_Int64 cpp_vtable_call(long* pFunctionAndOffset, void** pCallStack);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx
new file mode 100644
index 0000000000..f476cf7df1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx
@@ -0,0 +1,593 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "share.hxx"
+#include "call.hxx"
+
+#include <dlfcn.h>
+
+#ifdef ANDROID
+#include <unistd.h>
+#endif
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+ typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ // pCallStack: ret, [return ptr], this, params
+ char * pTopStack = reinterpret_cast<char *>(pCallStack + 0);
+ char * pCppStack = pTopStack;
+
+#ifdef __ARM_PCS_VFP
+ int dc = 0;
+ char * pFloatArgs = reinterpret_cast<char *>(pCppStack - 64);
+#endif
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = nullptr;
+ // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+ void * pCppReturn = nullptr;
+
+ if (pReturnTypeDescr)
+ {
+ if (!arm::return_in_hidden_param(pReturnTypeRef))
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *reinterpret_cast<void **>(pCppStack);
+ pCppStack += sizeof(void *);
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32),
+ "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion
+ // cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr =
+ reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut &&
+ bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+#ifdef __ARM_EABI__
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#ifndef __ARM_PCS_VFP
+ case typelib_TypeClass_DOUBLE:
+#endif
+ if ((pCppStack - pTopStack) % 8) pCppStack+=sizeof(sal_Int32); //align to 8
+ break;
+ default:
+ break;
+ }
+#endif
+
+// For armhf we get the floating point arguments from a different area of the stack
+#ifdef __ARM_PCS_VFP
+ if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = pFloatArgs;
+ pFloatArgs += sizeof(float);
+ } else
+ if (pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE)
+ {
+ if ((pFloatArgs - pTopStack) % 8) pFloatArgs+=sizeof(float); //align to 8
+ pCppArgs[nPos] = pUnoArgs[nPos] = pFloatArgs;
+ pFloatArgs += sizeof(double);
+ if (++dc == arm::MAX_FPR_REGS) {
+ if (pCppStack - pTopStack < 16)
+ pCppStack = pTopStack + 16;
+ pFloatArgs = pCppStack;
+ }
+ } else
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = pCppStack;
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#ifndef __ARM_PCS_VFP
+ case typelib_TypeClass_DOUBLE:
+#endif
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] =
+ alloca( pParamTypeDescr->nSize ),
+ *reinterpret_cast<void **>(pCppStack), pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+#ifdef __ARM_PCS_VFP
+ // use the stack for output parameters or non floating point values
+ if (rParam.bOut ||
+ ((pParamTypeDescr->eTypeClass != typelib_TypeClass_DOUBLE)
+ && (pParamTypeDescr->eTypeClass != typelib_TypeClass_FLOAT))
+ )
+#endif
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex],
+ ppTempParamTypeDescr[nTempIndices], nullptr );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
+ pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr =
+ ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
+ cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn,
+ pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, nullptr );
+ }
+ // complex return ptr is set to eax
+ *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+ // pCallStack: [ret *], this, params
+ // _this_ ptr is patched cppu_XInterfaceProxy object
+ void *pThis;
+ if( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = pCallStack[1];
+ }
+ else
+ {
+ pThis = pCallStack[0];
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ reinterpret_cast<XInterface *>(pCppI));
+ }
+
+ // determine called method
+ assert(nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex);
+ sal_Int32 nMemberPos =
+ pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
+ nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pCallStack, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ nullptr, // indicates void return
+ 1, &aParam,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET(&pTD,
+ static_cast<Type *>(pCallStack[2])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface * pInterface = nullptr;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&pInterface), pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pCallStack[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *reinterpret_cast<void **>(pRegisterReturn) = pCallStack[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } [[fallthrough]]; // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pParams,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", reinterpret_cast<XInterface *>(pCppI) );
+ }
+ }
+
+ return eRet;
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+
+sal_Int64 cpp_vtable_call( long *pFunctionAndOffset,
+ void **pCallStack )
+{
+ sal_Int64 nRegReturn;
+ typelib_TypeClass aType = cpp_mediate( pFunctionAndOffset[0], pFunctionAndOffset[1], pCallStack,
+ &nRegReturn );
+
+ switch( aType )
+ {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ nRegReturn = static_cast<unsigned long>(*reinterpret_cast<unsigned char *>(&nRegReturn));
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_SHORT:
+ nRegReturn = static_cast<unsigned long>(*reinterpret_cast<unsigned short *>(&nRegReturn));
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_LONG:
+ nRegReturn = static_cast<unsigned long>(*reinterpret_cast<unsigned int *>(&nRegReturn));
+ break;
+ case typelib_TypeClass_VOID:
+ default:
+ break;
+ }
+
+ return nRegReturn;
+}
+
+namespace
+{
+ const int codeSnippetSize = 20;
+
+ unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
+ sal_Int32 vtableOffset, bool bHasHiddenParam)
+ {
+ if (bHasHiddenParam)
+ functionIndex |= 0x80000000;
+
+ unsigned long * p = reinterpret_cast<unsigned long *>(code);
+
+ // ARM (not thumb) mode instructions
+ // mov ip, pc
+ *p++ = 0xE1A0C00F;
+ // ldr pc, [pc, #4]
+ *p++ = 0xE59FF004;
+ *p++ = static_cast<unsigned long>(functionIndex);
+ *p++ = static_cast<unsigned long>(vtableOffset);
+ *p++ = reinterpret_cast<unsigned long>(privateSnippetExecutor);
+
+ return code + codeSnippetSize;
+ }
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::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 * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+#ifdef USE_DOUBLE_MMAP
+ sal_PtrDiff writetoexecdiff,
+#endif
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+#ifndef USE_DOUBLE_MMAP
+ const sal_PtrDiff writetoexecdiff = 0;
+#endif
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription * member = nullptr;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription *pAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
+
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ arm::return_in_hidden_param( pAttrTD->pAttributeTypeRef ));
+
+ // Setter:
+ if (!pAttrTD->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset, false);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ (s++)->fn = code + writetoexecdiff;
+
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(member);
+
+ code = codeSnippet(code, functionOffset++, vtableOffset,
+ arm::return_in_hidden_param(pMethodTD->pReturnTypeRef));
+ break;
+ }
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *beg, unsigned char const *end)
+{
+#ifndef ANDROID
+ static void (*clear_cache)(unsigned char const*, unsigned char const*)
+ = reinterpret_cast<void (*)(unsigned char const*, unsigned char const*)>
+ (dlsym(RTLD_DEFAULT, "__clear_cache"));
+ (*clear_cache)(beg, end);
+#else
+ cacheflush((long) beg, (long) end, 0);
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/except.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/except.cxx
new file mode 100644
index 0000000000..14bffa75ad
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/except.cxx
@@ -0,0 +1,327 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+extern sal_Int32 * pHack;
+extern sal_Int32 nHack;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ void dummy_can_throw_anything( char const * )
+ {
+ }
+
+ static OUString toUNOname( char const * p )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = *p++ - '0';
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+ }
+
+namespace {
+ class RTTI
+ {
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+#ifndef ANDROID
+ void * m_hApp;
+#endif
+
+ public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI(typelib_CompoundTypeDescription *);
+ };
+}
+
+ RTTI::RTTI()
+#ifndef ANDROID
+ : m_hApp( dlopen( nullptr, RTLD_LAZY ) )
+#endif
+ {
+ }
+
+ RTTI::~RTTI()
+ {
+#ifndef ANDROID
+ dlclose( m_hApp );
+#endif
+ }
+
+
+ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+ {
+ type_info * rtti;
+
+ OUString const & unoName = *reinterpret_cast<OUString const *>(&pTypeDescr->aBase.pTypeName);
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+#ifndef ANDROID
+ rtti = static_cast<type_info *>(dlsym( m_hApp, symName.getStr() ));
+#else
+ rtti = (type_info *)dlsym( RTLD_DEFAULT, symName.getStr() );
+#endif
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ (void) insertion;
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
+
+ if (iFind2 == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+
+#ifdef ANDROID
+ // This code is supposed to be used only used for
+ // inter-process UNO, says sberg. Thus it should
+ // be unnecessary and never reached for
+ // Android. But see above...
+
+ // assert(iFind2 != m_generatedRttis.end());
+ // return NULL;
+#endif
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI( pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), static_cast<__class_type_info *>(base_rtti) );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ (void) insertion;
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind2->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iFind->second;
+ }
+
+ return rtti;
+ }
+
+
+ static void deleteException( void * pExc )
+ {
+ __cxa_exception const * header = static_cast<__cxa_exception const *>(pExc) - 1;
+ typelib_TypeDescription * pTD = nullptr;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+ }
+
+ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ "cannot get typedescription for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = rtti_data.getRTTI(reinterpret_cast<typelib_CompoundTypeDescription*>(pTypeDescr));
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ "no rtti for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+ }
+
+#ifdef __ARM_EABI__
+ static void* getAdjustedPtr(__cxa_exception* header)
+ {
+ return reinterpret_cast<void*>(header->unwindHeader.barrier_cache.bitpattern[0]);
+ }
+#else
+ static void* getAdjustedPtr(__cxa_exception* header)
+ {
+ return header->adjustedPtr;
+ }
+#endif
+
+ void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+ {
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = nullptr;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (nullptr == pExcTypeDescr)
+ {
+ RuntimeException aRE( "exception type not found: " + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, getAdjustedPtr(header), pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx b/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx
new file mode 100644
index 0000000000..040ce60b92
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/share.hxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <sal/config.h>
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+#include <unwind.h>
+
+#include <cxxabi.h>
+#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h
+#define _GLIBCXX_CDTOR_CALLABI
+#endif
+
+#include <config_cxxabi.h>
+#include <uno/mapping.h>
+
+#if !HAVE_CXXABI_H_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __class_type_info: public std::type_info {
+public:
+ explicit __class_type_info(char const * n): type_info(n) {}
+ ~__class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __si_class_type_info: public __class_type_info {
+public:
+ __class_type_info const * __base_type;
+ explicit __si_class_type_info(
+ char const * n, __class_type_info const *base):
+ __class_type_info(n), __base_type(base) {}
+ ~__si_class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EXCEPTION
+namespace __cxxabiv1 {
+ struct __cxa_exception
+ {
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+#if defined __LP64__ || defined __ARM_EABI__
+ // Quoting android-ndk-r18b/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.hpp: "This is a
+ // new field to support C++ 0x exception_ptr. For binary compatibility it is at the start of
+ // this struct which is prepended to the object thrown in __cxa_allocate_exception."
+ std::size_t referenceCount;
+#endif
+#endif
+
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+#ifdef __ARM_EABI__
+ __cxa_exception *nextPropagatingException;
+ int propagationCount;
+#else
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+#endif
+ _Unwind_Exception unwindHeader;
+ };
+
+}
+#endif
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+ // -- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+#if !HAVE_CXXABI_H_CXA_ALLOCATE_EXCEPTION
+ extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+#endif
+#if !HAVE_CXXABI_H_CXA_THROW
+ extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo,
+ void (*dest) (void *) ) __attribute__((noreturn));
+#endif
+
+}
+
+#if !HAVE_CXXABI_H_CXA_EH_GLOBALS
+namespace __cxxabiv1 {
+ struct __cxa_eh_globals
+ {
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+#ifdef __ARM_EABI__
+ __cxa_exception *propagatingExceptions;
+#endif
+ };
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_GET_GLOBALS
+namespace __cxxabiv1 {
+ extern "C" __cxa_eh_globals * __cxa_get_globals() throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_CURRENT_EXCEPTION_TYPE
+namespace __cxxabiv1 {
+ extern "C" std::type_info *__cxa_current_exception_type() throw();
+}
+#endif
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+ void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+extern "C" void privateSnippetExecutor();
+
+namespace arm
+{
+ enum armlimits { MAX_GPR_REGS = 4, MAX_FPR_REGS = 8 };
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx
new file mode 100644
index 0000000000..001384e005
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_arm/uno2cpp.cxx
@@ -0,0 +1,758 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "share.hxx"
+
+#include <exception>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+/*
+ * Based on http://gcc.gnu.org/PR41443
+ * References to __SOFTFP__ are incorrect for EABI; the __SOFTFP__ code
+ * should be used for *soft-float ABI* whether or not VFP is enabled,
+ * and __SOFTFP__ does specifically mean soft-float not soft-float ABI.
+ *
+ * Changing the conditionals to __SOFTFP__ || __ARM_EABI__ then
+ * -mfloat-abi=softfp should work. -mfloat-abi=hard won't; that would
+ * need both a new macro to identify the hard-VFP ABI.
+ */
+#if !defined(__ARM_EABI__) && !defined(__SOFTFP__)
+#error Not Implemented
+
+/*
+ some possibly handy code to detect that we have VFP registers
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf.h>
+
+#define HWCAP_ARM_VFP 64
+
+int hasVFP()
+{
+ int fd = open ("/proc/self/auxv", O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ int ret = -1;
+
+ Elf32_auxv_t buf[128];
+ ssize_t n;
+ while ((ret == -1) && ((n = read(fd, buf, sizeof (buf))) > 0))
+ {
+ for (int i = 0; i < 128; ++i)
+ {
+ if (buf[i].a_type == AT_HWCAP)
+ {
+ ret = (buf[i].a_un.a_val & HWCAP_ARM_VFP) ? true : false;
+ break;
+ }
+ else if (buf[i].a_type == AT_NULL)
+ {
+ ret = -2;
+ break;
+ }
+ }
+ }
+
+ close (fd);
+ return ret;
+}
+
+#endif
+
+using namespace ::com::sun::star::uno;
+
+namespace arm
+{
+ static bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = nullptr;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != nullptr)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+ }
+
+#ifdef __ARM_PCS_VFP
+ static bool is_float_only_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_FLOAT &&
+ p->ppTypeRefs[i]->eTypeClass != typelib_TypeClass_DOUBLE)
+ return false;
+ }
+ return true;
+ }
+#endif
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ //A Composite Type not larger than 4 bytes is returned in r0
+ bool bRet = pTypeDescr->nSize > 4 || is_complex_struct(pTypeDescr);
+
+#ifdef __ARM_PCS_VFP
+ // In the VFP ABI, structs with only float/double values that fit in
+ // 16 bytes are returned in registers
+ if( pTypeDescr->nSize <= 16 && is_float_only_struct(pTypeDescr))
+ bRet = false;
+#endif
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return true;
+ }
+}
+
+static void MapReturn(sal_uInt32 r0, sal_uInt32 r1, typelib_TypeDescriptionReference * pReturnType, sal_uInt32* pRegisterReturn)
+{
+ switch( pReturnType->eTypeClass )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pRegisterReturn[1] = r1;
+ [[fallthrough]];
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ pRegisterReturn[0] = r0;
+ break;
+ case typelib_TypeClass_FLOAT:
+#if !defined(__ARM_PCS_VFP) && (defined(__ARM_EABI__) || defined(__SOFTFP__))
+ pRegisterReturn[0] = r0;
+#else
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized"
+#endif
+ register float fret asm("s0");
+ *reinterpret_cast<float *>(pRegisterReturn) = fret;
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+#endif
+ break;
+ case typelib_TypeClass_DOUBLE:
+#if !defined(__ARM_PCS_VFP) && (defined(__ARM_EABI__) || defined(__SOFTFP__))
+ pRegisterReturn[1] = r1;
+ pRegisterReturn[0] = r0;
+#else
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized"
+#endif
+ register double dret asm("d0");
+ *reinterpret_cast<double *>(pRegisterReturn) = dret;
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+#endif
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ if (!arm::return_in_hidden_param(pReturnType))
+ pRegisterReturn[0] = r0;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+namespace
+{
+
+void callVirtualMethod(
+ void * pThis,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnType,
+ sal_uInt32 *pStack,
+ sal_uInt32 nStack,
+ sal_uInt32 *pGPR,
+ sal_uInt32 nGPR,
+ double *pFPR) __attribute__((noinline));
+
+void callVirtualMethod(
+ void * pThis,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnType,
+ sal_uInt32 *pStack,
+ sal_uInt32 nStack,
+ sal_uInt32 *pGPR,
+ sal_uInt32 nGPR,
+ double *pFPR)
+{
+ // never called
+ if (! pThis)
+ CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+ if ( nStack )
+ {
+ // 8-bytes aligned
+ sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 8;
+ sal_uInt32 *stack = static_cast<sal_uInt32 *>(__builtin_alloca( nStackBytes ));
+ memcpy( stack, pStack, nStackBytes );
+ }
+
+ // Should not happen, but...
+ if ( nGPR > arm::MAX_GPR_REGS )
+ nGPR = arm::MAX_GPR_REGS;
+
+ sal_uInt32 pMethod = *static_cast<sal_uInt32 *>(pThis);
+ pMethod += 4 * nVtableIndex;
+ pMethod = *reinterpret_cast<sal_uInt32 *>(pMethod);
+
+ //Return registers
+ sal_uInt32 r0;
+ sal_uInt32 r1;
+
+ __asm__ __volatile__ (
+ //Fill in general purpose register arguments
+ "ldr r4, %[pgpr]\n\t"
+ "ldmia r4, {r0-r3}\n\t"
+
+#ifdef __ARM_PCS_VFP
+ //Fill in VFP register arguments as double precision values
+ "ldr r4, %[pfpr]\n\t"
+ "vldmia r4, {d0-d7}\n\t"
+#endif
+ //Make the call
+ "ldr r5, %[pmethod]\n\t"
+#ifndef __ARM_ARCH_4T__
+ "blx r5\n\t"
+#else
+ "mov lr, pc ; bx r5\n\t"
+#endif
+
+ //Fill in return values
+ "mov %[r0], r0\n\t"
+ "mov %[r1], r1\n\t"
+ : [r0]"=r" (r0), [r1]"=r" (r1)
+ : [pmethod]"m" (pMethod), [pgpr]"m" (pGPR), [pfpr]"m" (pFPR)
+ : "r0", "r1", "r2", "r3", "r4", "r5");
+
+ MapReturn(r0, r1, pReturnType, static_cast<sal_uInt32*>(pRegisterReturn));
+}
+}
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<const sal_uInt32*>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<const sal_uInt32*>( pSV );
+
+#ifdef __ARM_EABI__
+#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart ) \
+ if ( (nr < arm::MAX_GPR_REGS) && (nr % 2) ) \
+ { \
+ ++nr; \
+ } \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ { \
+ pGPR[nr++] = *static_cast<const sal_uInt32 *>( pSV ); \
+ pGPR[nr++] = *(static_cast<const sal_uInt32 *>( pSV ) + 1); \
+ } \
+ else \
+ { \
+ if ( (pDS - pStart) % 2) \
+ { \
+ ++pDS; \
+ } \
+ *pDS++ = static_cast<sal_uInt32 *>( pSV )[0]; \
+ *pDS++ = static_cast<sal_uInt32 *>( pSV )[1]; \
+ }
+#else
+#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart ) \
+ INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ INSERT_INT32( ((sal_uInt32*)pSV)+1, nr, pGPR, pDS )
+#endif
+
+#ifdef __ARM_PCS_VFP
+// Since single and double arguments share the same register bank the filling of the
+// registers is not always linear. Single values go to the first available single register,
+// while doubles need to have an 8 byte alignment, so only go into double registers starting
+// at every other single register. For ex a float, double, float sequence will fill registers
+// s0, d1, and s1, actually corresponding to the linear order s0,s1, d1.
+//
+// These use the single/double register array and counters and ignore the pGPR argument
+// nSR and nDR are the number of single and double precision registers that are no longer
+// available
+#define INSERT_FLOAT( pSV, nr, pGPR, pDS ) \
+ if (nSR % 2 == 0) {\
+ nSR = 2*nDR; \
+ }\
+ if ( nSR < arm::MAX_FPR_REGS*2 ) {\
+ pSPR[nSR++] = *static_cast<float const *>( pSV ); \
+ if ((nSR % 2 == 1) && (nSR > 2*nDR)) {\
+ nDR++; \
+ }\
+ }\
+ else \
+ {\
+ *pDS++ = *static_cast<float const *>( pSV );\
+ }
+#define INSERT_DOUBLE( pSV, nr, pGPR, pDS, pStart ) \
+ if ( nDR < arm::MAX_FPR_REGS ) { \
+ pFPR[nDR++] = *static_cast<double const *>( pSV ); \
+ }\
+ else\
+ {\
+ if ( (pDS - pStart) % 2) \
+ { \
+ ++pDS; \
+ } \
+ *reinterpret_cast<double *>(pDS) = *static_cast<double const *>( pSV );\
+ pDS += 2;\
+ }
+#else
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
+ INSERT_INT32( pSV, nr, pGPR, pDS )
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart ) \
+ INSERT_INT64( pSV, nr, pGPR, pDS, pStart )
+#endif
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *static_cast<sal_uInt16 const *>( pSV ); \
+ else \
+ *pDS++ = *static_cast<sal_uInt16 const *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+ if ( nr < arm::MAX_GPR_REGS ) \
+ pGPR[nr++] = *static_cast<sal_uInt8 const *>( pSV ); \
+ else \
+ *pDS++ = *static_cast<sal_uInt8 const *>( pSV );
+
+namespace {
+
+void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt32 * pStack = static_cast<sal_uInt32 *>(__builtin_alloca(
+ sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ));
+ sal_uInt32 * pStackStart = pStack;
+
+ sal_uInt32 pGPR[arm::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ // storage and counters for single and double precision VFP registers
+ double pFPR[arm::MAX_FPR_REGS];
+#ifdef __ARM_PCS_VFP
+ sal_uInt32 nDR = 0;
+ float *pSPR = reinterpret_cast< float *>(&pFPR);
+ sal_uInt32 nSR = 0;
+#endif
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ bool bSimpleReturn = !arm::return_in_hidden_param( pReturnTypeRef );
+
+ if (bSimpleReturn)
+ pCppReturn = pUnoReturn; // direct way for simple types
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? __builtin_alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+
+ INSERT_INT32( &pCppReturn, nGPR, pGPR, pStack );
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ INSERT_INT32( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+// uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos],
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "hyper is %p\n", pCppArgs[nPos]);
+#endif
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "long is %p\n", pCppArgs[nPos]);
+#endif
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nGPR, pGPR, pStack, pStackStart );
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT32( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeRef,
+ pStackStart,
+ (pStack - pStackStart),
+ pGPR, nGPR,
+ pFPR);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+
+ // NO exception occurred...
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
+ (pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1;
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
+ (pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } [[fallthrough]]; // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/call.cxx b/bridges/source/cpp_uno/gcc3_linux_hppa/call.cxx
new file mode 100644
index 0000000000..29f01bfbde
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_hppa/call.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star::uno;
+
+void MapReturn(sal_uInt32 ret0, sal_uInt32 ret1, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn, sal_uInt32 *pRegisterReturn)
+{
+ register float fret asm("fr4");
+ register double dret asm("fr4");
+
+ switch (pReturnTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pRegisterReturn[1] = ret1;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ pRegisterReturn[0] = ret0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = fret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = dret;
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ if (bRegisterReturn)
+ {
+ pRegisterReturn[0] = ret0;
+ pRegisterReturn[1] = ret1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+//Moved callVirtual into this .cxx so that I can do this and get gcc to not
+//touch r28 without having to learn any more pa-risc assembly than is
+//strictly necessary
+register sal_uInt32 r28 __asm__("%r28");
+
+void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn,
+ sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR) __attribute__((noinline));
+
+void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn,
+ sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR)
+{
+ register sal_uInt32* sp __asm__("%r30");
+
+ sal_uInt32 pMethod = *((sal_uInt32*)pThis);
+ pMethod += 4 * nVtableIndex;
+ pMethod = *((sal_uInt32 *)pMethod);
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "this is %p\n", pGPR[0]);
+ for (int i = 0; i < hppa::MAX_GPR_REGS ; ++i)
+ fprintf(stderr, "normal reg %d is %d %x\n", i, pGPR[i], pGPR[i]);
+
+ for (int i = 0; i < hppa::MAX_SSE_REGS ; ++i)
+ fprintf(stderr, "float reg %d is %x\n", i, pFPR[i]);
+
+ for (int i = 0; i < nStack; ++i)
+ fprintf(stderr, "stack bytes are %x\n", pStack[i]);
+#endif
+
+ //Always reserve 4 slots, and align to 8 bytes
+ sal_uInt32 nStackBytes = ( ( nStack + 4 + 1 ) >> 1 ) * 8;
+ __builtin_alloca(nStackBytes);
+ sal_uInt32 *stack = sp-8;
+ int o = -5;
+ for (sal_uInt32 i = 0; i < nStack; ++i, --o)
+ stack[o] = pStack[i];
+
+ typedef int (* FunctionCall )( sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32 );
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ asm volatile("fldd %0, %%fr4" : : "m"(pFPR[0]) : "fr4");
+ asm volatile("fldd %0, %%fr5" : : "m"(pFPR[1]) : "fr5");
+ asm volatile("fldd %0, %%fr6" : : "m"(pFPR[2]) : "fr6");
+ asm volatile("fldd %0, %%fr7" : : "m"(pFPR[3]) : "fr7");
+ asm volatile("ldw %0, %%r28" : : "m"(pRegisterReturn) : "r28");
+ (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3]);
+
+ register sal_uInt32 r29 __asm__("%r29");
+ MapReturn(r28, r29, pReturnTypeDescr, bRegisterReturn, (sal_uInt32*)pRegisterReturn);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx
new file mode 100644
index 0000000000..7e8524d1c7
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx
@@ -0,0 +1,720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+
+#include <dlfcn.h>
+
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+ static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ long r8, void ** gpreg, double *fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ void ** startovrflw = ovrflw;
+ int nregs = 0; //number of words passed in registers
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "cpp2uno_call\n");
+#endif
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+ void * pCppReturn = 0;
+
+ if (pReturnTypeDescr)
+ {
+ if (hppa::isRegisterReturn(pReturnTypeRef))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple return\n");
+#endif
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex return via r8\n");
+#endif
+ pCppReturn = (void *)r8;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ gpreg++;
+ fpreg++;
+ nregs++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion
+ // cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr =
+ (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+ bool bOverflowUsed = false;
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_DOUBLE:
+ if (nregs < hppa::MAX_WORDS_IN_REGS && (nregs & 1))
+ {
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ if (nregs < hppa::MAX_WORDS_IN_REGS-1)
+ {
+ fpreg++;
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg;
+ gpreg+=2;
+ fpreg+=2;
+ nregs+=2;
+ }
+ else
+ {
+ if ((startovrflw-ovrflw) & 1)
+ ovrflw--;
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw - 4);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw-=2;
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (nregs < hppa::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw--;
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (nregs < hppa::MAX_WORDS_IN_REGS && (nregs & 1))
+ {
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ if (nregs < hppa::MAX_WORDS_IN_REGS-1)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg+=2;
+ fpreg+=2;
+ nregs+=2;
+ }
+ else
+ {
+ if ((startovrflw-ovrflw) & 1)
+ ovrflw--;
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw - 4);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw-=2;
+ break;
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ if (nregs < hppa::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)gpreg + 3);
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw+3);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw--;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (nregs < hppa::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)gpreg+2);
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw+2);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw--;
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ default:
+ if (nregs < hppa::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw--;
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ void *pCppStack;
+
+ if (nregs < hppa::MAX_WORDS_IN_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg;
+ gpreg++;
+ fpreg++;
+ nregs++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw--;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "before dispatch\n");
+#endif
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "after dispatch\n");
+#endif
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex],
+ ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
+ pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr =
+ ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
+ cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn,
+ pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to eax
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet =
+ (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, double* fpreg,
+ long sp, long r8,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+
+ {
+ void ** ovrflw = (void**)(sp);
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "cpp_mediate with\n");
+ fprintf(stderr, "%x %x\n", nFunctionIndex, nVtableOffset);
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[0]), (long)(ovrflw[-1]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-2]), (long)(ovrflw[-3]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-4]), (long)(ovrflw[-5]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-6]), (long)(ovrflw[-7]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-8]), (long)(ovrflw[-9]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-10]), (long)(ovrflw[-11]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-12]), (long)(ovrflw[-13]));
+ fprintf(stderr, "and %x %x\n", (long)(ovrflw[-14]), (long)(ovrflw[-15]));
+#endif
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[1]\n");
+#endif
+ }
+ else
+ {
+ pThis = gpreg[0];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[0]\n");
+#endif
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ assert(nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex);
+ sal_Int32 nMemberPos =
+ pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
+ nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET(&pTD,
+ reinterpret_cast<Type *>(gpreg[1])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( r8 ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = (void*)r8;
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+
+ return eRet;
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+
+sal_Int64 cpp_vtable_call( sal_uInt32 in0, sal_uInt32 in1, sal_uInt32 in2, sal_uInt32 in3, sal_uInt32 firstonstack )
+{
+ register sal_Int32 r21 asm("r21");
+ register sal_Int32 r22 asm("r22");
+ register sal_Int32 r28 asm("r28");
+ sal_Int32 functionIndex = r21;
+ sal_Int32 vtableOffset = r22;
+ sal_Int32 r8 = r28;
+
+ long sp = (long)&firstonstack;
+
+ sal_uInt32 gpreg[hppa::MAX_GPR_REGS];
+ gpreg[0] = in0;
+ gpreg[1] = in1;
+ gpreg[2] = in2;
+ gpreg[3] = in3;
+
+ float fpreg[hppa::MAX_SSE_REGS]; //todo
+ register float f0 asm("fr4"); fpreg[0] = f0;
+ register float f1 asm("fr5"); fpreg[1] = f1;
+ register float f2 asm("fr6"); fpreg[2] = f2;
+ register float f3 asm("fr7"); fpreg[3] = f3;
+
+ double dpreg[hppa::MAX_SSE_REGS]; //todo
+ register double d0 asm("fr4"); dpreg[0] = d0;
+ register double d1 asm("fr5"); dpreg[1] = d1;
+ register double d2 asm("fr6"); dpreg[2] = d2;
+ register double d3 asm("fr7"); dpreg[3] = d3;
+
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "got to cpp_vtable_call with %x %x\n", functionIndex, vtableOffset);
+ for (int i = 0; i < hppa::MAX_GPR_REGS; ++i)
+ fprintf(stderr, "reg %d is %d %x\n", i, gpreg[i], gpreg[i]);
+ for (int i = 0; i < hppa::MAX_SSE_REGS; ++i)
+ fprintf(stderr, "float reg %d is %f %x\n", i, fpreg[i], ((long*)fpreg)[i]);
+ for (int i = 0; i < 4; ++i)
+ fprintf(stderr, "double reg %d is %f %llx\n", i, dpreg[i], ((long long*)dpreg)[i]);
+#endif
+
+ sal_Int64 nRegReturn;
+
+ typelib_TypeClass aType =
+ cpp_mediate( functionIndex, vtableOffset, (void**)gpreg, dpreg, sp, r8, &nRegReturn);
+
+ switch( aType )
+ {
+ case typelib_TypeClass_FLOAT:
+ f0 = (*((float*)&nRegReturn));
+ break;
+ case typelib_TypeClass_DOUBLE:
+ d0 = (*((double*)&nRegReturn));
+ break;
+ default:
+ break;
+ }
+
+ return nRegReturn;
+}
+
+
+namespace
+{
+ const int codeSnippetSize = 44;
+
+# define unldil(v) (((v & 0x7c) << 14) | ((v & 0x180) << 7) | ((v & 0x3) << 12) | ((v & 0xffe00) >> 8) | ((v & 0x100000) >> 20))
+# define L21(v) unldil(((unsigned long)(v) >> 11) & 0x1fffff) //Left 21 bits
+# define R11(v) (((unsigned long)(v) & 0x7FF) << 1) //Right 11 bits
+
+ unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
+ sal_Int32 vtableOffset, bool bHasHiddenParam)
+ {
+ if (bHasHiddenParam)
+ functionIndex |= 0x80000000;
+
+ unsigned char * p = code;
+ *(unsigned long*)&p[0] = 0xeaa00000; // b,l 0x8,r21
+ *(unsigned long*)&p[4] = 0xd6a01c1e; // depwi 0,31,2,r21
+ *(unsigned long*)&p[8] = 0x4aa10040; // ldw 32(r21),r1
+
+ *(unsigned long*)&p[12] = 0x22A00000 | L21(functionIndex); // ldil L<functionIndex>,r21
+ *(unsigned long*)&p[16] = 0x36B50000 | R11(functionIndex); // ldo R<functionIndex>,r21
+
+ *(unsigned long*)&p[20] = 0x22C00000 | L21(vtableOffset); // ldil L<vtableOffset>,r22
+ *(unsigned long*)&p[24] = 0x36D60000 | R11(vtableOffset); // ldo R<vtableOffset>,r22
+
+ *(unsigned long*)&p[28] = 0x0c201094; // ldw 0(r1),r20
+ *(unsigned long*)&p[32] = 0xea80c000; // bv r0(r20)
+ *(unsigned long*)&p[36] = 0x0c281093; // ldw 4(r1),r19
+ *(unsigned long*)&p[40] = ((unsigned long)(cpp_vtable_call) & ~2);
+
+ return code + codeSnippetSize;
+ }
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ }
+ break;
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ break;
+ }
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *beg, unsigned char const *end)
+{
+ void *p = (void*)((size_t)beg & ~31);
+ size_t stride = 32;
+ while (p < end)
+ {
+ asm volatile("fdc (%0)\n\t"
+ "sync\n\t"
+ "fic,m %1(%%sr4, %0)\n\t"
+ "sync" : "+r"(p) : "r"(stride) : "memory");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/except.cxx b/bridges/source/cpp_uno/gcc3_linux_hppa/except.cxx
new file mode 100644
index 0000000000..b5339eb2b1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_hppa/except.cxx
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+extern sal_Int32 * pHack;
+extern sal_Int32 nHack;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ void dummy_can_throw_anything( char const * )
+ {
+ }
+
+ static OUString toUNOname( char const * p )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+ }
+
+ class RTTI
+ {
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+ public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI(typelib_CompoundTypeDescription *);
+ };
+
+ RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+ {
+ }
+
+ RTTI::~RTTI()
+ {
+ dlclose( m_hApp );
+ }
+
+
+ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+ {
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+ }
+
+
+ static void deleteException( void * pExc )
+ {
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+ }
+
+ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+ }
+
+ static void* getAdjustedPtr(__cxa_exception* header)
+ {
+ return header->adjustedPtr;
+ }
+
+ void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+ {
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE(
+ OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, getAdjustedPtr(header), pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/share.hxx b/bridges/source/cpp_uno/gcc3_linux_hppa/share.hxx
new file mode 100644
index 0000000000..ff5b63d795
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_hppa/share.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+
+namespace hppa
+{
+ enum hppalimits { MAX_WORDS_IN_REGS = 4, MAX_GPR_REGS = 4, MAX_SSE_REGS = 4 };
+
+ bool isRegisterReturn( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_hppa/uno2cpp.cxx
new file mode 100644
index 0000000000..43e9aabac8
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_hppa/uno2cpp.cxx
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "share.hxx"
+
+#include <exception>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+using namespace ::com::sun::star::uno;
+
+void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn,
+ sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR);
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow )\
+ if (nr < hppa::MAX_WORDS_IN_REGS) \
+ { \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ } \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow )\
+ if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
+ { \
+ ++nr; \
+ } \
+ if ( nr < hppa::MAX_WORDS_IN_REGS ) \
+ { \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
+ } \
+ else \
+ bOverflow = true; \
+ if ( bOverflow ) \
+ { \
+ if ( (pDS - pStart) % 2) \
+ ++pDS; \
+ *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
+ *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
+ }
+
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverflow ) \
+ if (nr < hppa::MAX_WORDS_IN_REGS) \
+ { \
+ sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr++]); \
+ pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ } \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverflow ) \
+ if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
+ { \
+ ++nr; \
+ } \
+ if ( nr < hppa::MAX_WORDS_IN_REGS ) \
+ { \
+ sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr+1]); \
+ pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ pDouble[1] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
+ nr+=2; \
+ } \
+ else \
+ bOverflow = true; \
+ if ( bOverflow ) \
+ { \
+ if ( (pDS - pStart) % 2) \
+ ++pDS; \
+ *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
+ *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
+ }
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < hppa::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < hppa::MAX_WORDS_IN_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+namespace hppa
+{
+ bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+ }
+
+ bool isRegisterReturn( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return true;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ /* If the struct is larger than 8 bytes, then there is a buffer at r8 to stick the return value into */
+ bool bRet = pTypeDescr->nSize <= 8 && !is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return false;
+ }
+}
+
+
+namespace {
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
+ sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
+ sal_uInt32 * pStackStart = pStack;
+
+ sal_uInt32 pGPR[hppa::MAX_GPR_REGS];
+ double pFPR[hppa::MAX_SSE_REGS];
+ sal_uInt32 nRegs=0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+ bool bOverflow = false;
+ bool bRegisterReturn = true;
+
+ if (pReturnTypeDescr)
+ {
+
+ bRegisterReturn = hppa::isRegisterReturn(pReturnTypeRef);
+ if (bRegisterReturn)
+ pCppReturn = pUnoReturn; // direct way for simple types
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? __builtin_alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ INSERT_INT32( &pAdjustedThisPtr, nRegs, pGPR, pStack, bOverflow );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "hyper is %llx\n", *((long long*)pCppArgs[nPos]));
+#endif
+ INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack, pStackStart, bOverflow );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
+#endif
+ INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack, pStackStart, bOverflow );
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT32( &(pCppArgs[nPos]), nRegs, pGPR, pStack, bOverflow );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr, bRegisterReturn,
+ pStackStart,
+ (pStack - pStackStart), pGPR, pFPR);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
+ (pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1;
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
+ (pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/call.s b/bridges/source/cpp_uno/gcc3_linux_ia64/call.s
new file mode 100644
index 0000000000..19b0b94b58
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_ia64/call.s
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+/* ia64 support code for OpenOffice C++/UNO bridging
+ * Caolan McNamara <caolanm@redhat.com>
+ */
+ .text
+ .align 16
+ .global privateSnippetExecutor#
+ .proc privateSnippetExecutor#
+privateSnippetExecutor:
+ adds r15 = 8, gp /* r15 now points to real gp value*/
+ ;;
+ ld8 r14 = [gp] /* load nOffsetAndIndex into a handy register */
+ ld8 gp = [r15] /* load real gp value into gp */
+ ;;
+ /* store the address where large structs are "returned" into a handy register */
+ mov r15 = r8
+ ;;
+ br cpp_vtable_call# /* call cpp_vtable_call which'll suck out r14 */
+ ;;
+ .endp privateSnippetExecutor#
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx
new file mode 100644
index 0000000000..0d8303861c
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx
@@ -0,0 +1,681 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+#include <stdio.h>
+#include <typeinfo>
+
+extern "C" { extern void (*privateSnippetExecutor)(); }
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams, long r8,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "as far as cpp2uno_call\n");
+#endif
+
+ int ng = 0; //number of gpr registers used
+ int nf = 0; //number of fpr registers used
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if ( ia64::return_in_hidden_param( pReturnTypeRef ) ) // complex return via ptr passed as hidden parameter reg (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ ng++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ else if ( ia64::return_via_r8_buffer( pReturnTypeRef ) ) // complex return via ptr passed in r8
+ {
+ pCppReturn = (void *)r8;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+
+ else
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ // pop this
+ gpreg++;
+ ng++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+ bool bOverflowUsed = false;
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "arg %d of %d\n", nPos, nParams);
+#endif
+
+ //I think it is impossible to get UNO to pass structs as parameters by copy
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple\n");
+#endif
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ if (nf < ia64::MAX_SSE_REGS && ng < ia64::MAX_GPR_REGS)
+ {
+ float tmp = (float) (*((double *)fpreg));
+ (*((float *) fpreg)) = tmp;
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nf++;
+ gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (nf < ia64::MAX_SSE_REGS && ng < ia64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nf++;
+ gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ default:
+ if (ng < ia64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex, ng is %d\n", ng);
+#endif
+ void *pCppStack; //temporary stack pointer
+
+ if (ng < ia64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of params\n");
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = ia64::return_via_r8_buffer(pReturnTypeRef) ? typelib_TypeClass_VOID : (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_uInt64 nOffsetAndIndex,
+ void ** gpreg, void ** fpreg, long sp, long r8,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int64)==sizeof(void *), "### unexpected!");
+
+ sal_Int32 nVtableOffset = (nOffsetAndIndex >> 32);
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+
+ void ** ovrflw = (void**)(sp);
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[1]\n");
+#endif
+ }
+ else
+ {
+ pThis = gpreg[0];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[0]\n");
+#endif
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is %p\n", pThis);
+#endif
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is now %p\n", pThis);
+#endif
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "indexes are %d %d\n", nFunctionIndex, pTypeDescr->nMapFunctionIndexToMemberIndex);
+#endif
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "members are %d %d\n", nMemberPos, pTypeDescr->nAllMembers);
+#endif
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ r8, gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "screwed\n");
+#endif
+
+ throw RuntimeException( "no member description found!", (XInterface *)pThis );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of cpp_mediate\n");
+#endif
+ return eRet;
+}
+}
+
+extern "C" ia64::RegReturn cpp_vtable_call(
+ long in0, long in1, long in2, long in3, long in4, long in5, long in6, long in7,
+ long firstonstack
+ )
+{
+ register long r15 asm("r15");
+ long r8 = r15;
+
+ register long r14 asm("r14");
+ long nOffsetAndIndex = r14;
+
+ long sp = (long)&firstonstack;
+
+ sal_uInt64 gpreg[ia64::MAX_GPR_REGS];
+ gpreg[0] = in0;
+ gpreg[1] = in1;
+ gpreg[2] = in2;
+ gpreg[3] = in3;
+ gpreg[4] = in4;
+ gpreg[5] = in5;
+ gpreg[6] = in6;
+ gpreg[7] = in7;
+
+ double fpreg[ia64::MAX_SSE_REGS];
+ register double f8 asm("f8"); fpreg[0] = f8;
+ register double f9 asm("f9"); fpreg[1] = f9;
+ register double f10 asm("f10"); fpreg[2] = f10;
+ register double f11 asm("f11"); fpreg[3] = f11;
+ register double f12 asm("f12"); fpreg[4] = f12;
+ register double f13 asm("f13"); fpreg[5] = f13;
+ register double f14 asm("f14"); fpreg[6] = f14;
+ register double f15 asm("f15"); fpreg[7] = f15;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "cpp_vtable_call called with %lx\n", nOffsetAndIndex);
+ fprintf(stderr, "adump is %lx %lx %lx %lx %lx %lx %lx %lx\n", in0, in1, in2, in3, in4, in5, in6, in7);
+ fprintf(stderr, "bdump is %f %f %f %f %f %f %f %f\n", f8, f9, f10, f11, f12, f13, f14, f15);
+#endif
+
+ volatile long nRegReturn[4] = { 0 };
+
+ typelib_TypeClass aType =
+ cpp_mediate( nOffsetAndIndex, (void**)gpreg, (void**)fpreg, sp, r8, (sal_Int64*)&nRegReturn[0]);
+
+ ia64::RegReturn ret;
+ switch( aType )
+ {
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_HYPER:
+ ret.r8 = nRegReturn[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ asm volatile("ldfs f8=%0" : : "m"((*((float*)&nRegReturn))) : "f8");
+ break;
+ case typelib_TypeClass_DOUBLE:
+ asm volatile("ldfd f8=%0" : : "m"((*((double*)&nRegReturn))) : "f8");
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ ret.r8 = nRegReturn[0];
+ ret.r9 = nRegReturn[1];
+ ret.r10 = nRegReturn[2];
+ ret.r11 = nRegReturn[3];
+ break;
+ }
+ default:
+ break;
+ }
+ return ret;
+}
+
+namespace
+{
+const int codeSnippetSize = 40;
+
+bridges::cpp_uno::shared::VtableFactory::Slot codeSnippet( unsigned char * code, sal_PtrDiff writetoexecdiff, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ bool bHasHiddenParam )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "size is %d\n", codeSnippetSize);
+ fprintf(stderr,"in codeSnippet functionIndex is %x\n", nFunctionIndex);
+ fprintf(stderr,"in codeSnippet vtableOffset is %x\n", nVtableOffset);
+#endif
+
+ sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
+
+ if ( bHasHiddenParam )
+ nOffsetAndIndex |= 0x80000000;
+
+ long *raw = (long *)code;
+
+ bridges::cpp_uno::shared::VtableFactory::Slot* destination = (bridges::cpp_uno::shared::VtableFactory::Slot*)cpp_vtable_call;
+
+ raw[0] = (long)&privateSnippetExecutor;
+ raw[1] = (long)&raw[2];
+ raw[2] = nOffsetAndIndex;
+ raw[3] = destination->gp_value;
+
+ return *(bridges::cpp_uno::shared::VtableFactory::Slot*)(code+writetoexecdiff);
+}
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, unsigned char const *)
+{
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 1;
+}
+
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot* bridges::cpp_uno::shared::VtableFactory::initializeBlock(void * block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-1] = {0,reinterpret_cast<sal_uInt64>(&typeid(ProxyRtti))};
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** in_slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*in_slots) -= functionCount;
+ Slot * slots = *in_slots;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ *slots++ = codeSnippet(
+ code, writetoexecdiff, functionOffset++, vtableOffset,
+ ia64::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+ code += codeSnippetSize;
+
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ *slots++ = codeSnippet(code, writetoexecdiff, functionOffset++, vtableOffset, false);
+ code += codeSnippetSize;
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ *slots++ = codeSnippet(
+ code, writetoexecdiff, functionOffset++, vtableOffset,
+ ia64::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ code += codeSnippetSize;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_ia64/except.cxx
new file mode 100644
index 0000000000..1241aa02e1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_ia64/except.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ if (! pTypeDescr)
+ terminate();
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ if (! rtti)
+ terminate();
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ terminate();
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (! pExcTypeDescr)
+ terminate();
+
+ // construct uno exception any
+ ::uno_any_constructAndConvert( pExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ ::typelib_typedescription_release( pExcTypeDescr );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_ia64/share.hxx
new file mode 100644
index 0000000000..5b9ae8c47f
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_ia64/share.hxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+#include "vtablefactory.hxx"
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+namespace ia64
+{
+ enum ia64limits { MAX_GPR_REGS = 8, MAX_SSE_REGS = 8, MAX_REG_SLOTS = 8 };
+
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+ bool return_via_r8_buffer( typelib_TypeDescriptionReference *pTypeRef );
+
+ struct RegReturn
+ {
+ long r8;
+ long r9;
+ long r10;
+ long r11;
+ };
+}
+
+namespace bridges
+{
+ namespace cpp_uno
+ {
+ namespace shared
+ {
+ /*
+ http://www.swag.uwaterloo.ca/asx/ABI.html
+ On Itanium, function pointers are pairs: the function address followed
+ by the global pointer value that should be used when calling the
+ function (code address, gp value)
+ */
+ struct VtableFactory::Slot
+ {
+ sal_uInt64 code_address;
+ sal_uInt64 gp_value;
+ };
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_ia64/uno2cpp.cxx
new file mode 100644
index 0000000000..0c3e90b571
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_ia64/uno2cpp.cxx
@@ -0,0 +1,694 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+
+using namespace ::com::sun::star::uno;
+
+void MapReturn(const ia64::RegReturn &rRet, double dret, typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn, sal_uInt64 *pRegisterReturn)
+{
+ switch (pReturnTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *pRegisterReturn = rRet.r8;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *pRegisterReturn = (unsigned short)rRet.r8;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *pRegisterReturn = (unsigned char)rRet.r8;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *reinterpret_cast<float *>( pRegisterReturn ) = dret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double *>( pRegisterReturn ) = dret;
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ sal_uInt32 nRetSize = pReturnTypeDescr->nSize;
+ if (bSimpleReturn && nRetSize <= 32 && nRetSize > 0)
+ memcpy(pRegisterReturn, (void*)&rRet, nRetSize);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+namespace ia64
+{
+ bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+ }
+
+ bool is_complex_struct( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ bool bRet = is_complex_struct( pTypeDescr );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+
+ return bRet;
+ }
+ return false;
+ }
+
+ bool return_via_r8_buffer( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ if (is_complex_struct( pTypeRef )) return false;
+
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ /* If the struct is larger than 32 bytes, then there is a buffer at r8 to stick the return value into */
+ bool bRet = pTypeDescr->nSize > 32;
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return false;
+ }
+
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ return is_complex_struct( pTypeRef );
+ return true;
+ }
+
+
+}
+
+namespace
+{
+
+static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
+ sal_uInt64 *pStack, sal_uInt32 nStack,
+ sal_uInt64 *pGPR, sal_uInt32 nGPR,
+ double *pFPR, sal_uInt32 nFPR)
+{
+ // Stack, if used, must be 16-bytes aligned
+ if ( nStack )
+ nStack = ( nStack + 1 ) & ~1;
+
+ // Should not happen, but...
+ if ( nFPR > ia64::MAX_SSE_REGS )
+ nFPR = ia64::MAX_SSE_REGS;
+ if ( nGPR > ia64::MAX_GPR_REGS )
+ nGPR = ia64::MAX_GPR_REGS;
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
+ for ( unsigned int i = 0; i < nGPR; ++i )
+ fprintf( stderr, "0x%lx, ", pGPR[i] );
+ fprintf( stderr, "\nFPR's (%d): ", nFPR );
+ for ( unsigned int i = 0; i < nFPR; ++i )
+ fprintf( stderr, "0x%lx (%f), ", pFPR[i], pFPR[i] );
+ fprintf( stderr, "\nStack (%d): ", nStack );
+ for ( unsigned int i = 0; i < nStack; ++i )
+ fprintf( stderr, "0x%lx, ", pStack[i] );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
+ }
+#endif
+
+ // Load parameters to stack, if necessary
+ sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca( nStack * 8 );
+ memcpy( stack, pStack, nStack * 8 );
+
+ // To get pointer to method
+ // a) get the address of the vtable
+ sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
+ // b) get the address from the vtable entry at offset, each entry is 16bytes,
+ // 8 for function pointer, and 8 for global pointer
+ pMethod += 16 * nVtableIndex;
+
+ typedef void (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 );
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ switch (nFPR) //deliberate fall through
+ {
+ case 8:
+ asm volatile("ldfd f15=%0" : : "m"(pFPR[7]) : "f15");
+ case 7:
+ asm volatile("ldfd f14=%0" : : "m"(pFPR[6]) : "f14");
+ case 6:
+ asm volatile("ldfd f13=%0" : : "m"(pFPR[5]) : "f13");
+ case 5:
+ asm volatile("ldfd f12=%0" : : "m"(pFPR[4]) : "f12");
+ case 4:
+ asm volatile("ldfd f11=%0" : : "m"(pFPR[3]) : "f11");
+ case 3:
+ asm volatile("ldfd f10=%0" : : "m"(pFPR[2]) : "f10");
+ case 2:
+ asm volatile("ldfd f9=%0" : : "m"(pFPR[1]) : "f9");
+ case 1:
+ asm volatile("ldfd f8=%0" : : "m"(pFPR[0]) : "f8");
+ default:
+ break;
+ }
+
+ //stick the return area into r8 for big struct returning
+ asm volatile("ld8 r8=%0" : : "m"(pRegisterReturn) : "r8");
+
+ (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3], pGPR[4], pGPR[5], pGPR[6], pGPR[7]);
+
+ register double f8 asm("f8");
+ ia64::RegReturn ret;
+ {
+ register long r8 asm("r8"); ret.r8 = r8;
+ register long r9 asm("r9"); ret.r9 = r9;
+ register long r10 asm("r10"); ret.r10 = r10;
+ register long r11 asm("r11"); ret.r11 = r11;
+ }
+
+ MapReturn(ret, f8, pReturnTypeDescr, bSimpleReturn, (sal_uInt64*)pRegisterReturn);
+}
+
+// Macros for easier insertion of values to registers or stack
+// pSV - pointer to the source
+// nr - order of the value [will be increased if stored to register]
+// pFPR, pGPR - pointer to the registers
+// pDS - pointer to the stack [will be increased if stored here]
+
+// The value in %xmm register is already prepared to be retrieved as a float,
+// thus we treat float and double the same
+#define INSERT_FLOAT( pSV, nfr, pFPR, ngr, pGPR, pDS, bOverflow ) \
+ if ( nfr < ia64::MAX_SSE_REGS && ngr < ia64::MAX_GPR_REGS ) \
+ pFPR[nfr++] = *reinterpret_cast<float *>( pSV ); \
+ if ( ngr < ia64::MAX_GPR_REGS ) \
+ pGPR[ngr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_DOUBLE( pSV, nfr, pFPR, ngr, pGPR, pDS, bOverflow ) \
+ if ( nfr < ia64::MAX_SSE_REGS && ngr < ia64::MAX_GPR_REGS ) \
+ pFPR[nfr++] = *reinterpret_cast<double *>( pSV ); \
+ if ( ngr < ia64::MAX_GPR_REGS ) \
+ pGPR[ngr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ia64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ia64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ia64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ia64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+3) * sizeof(sal_Int64) );
+ sal_uInt64 * pStackStart = pStack;
+
+ sal_uInt64 pGPR[ia64::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ double pFPR[ia64::MAX_SSE_REGS];
+ sal_uInt32 nFPR = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ bool bOverflow = false;
+
+ bool bSimpleReturn = true;
+ if (pReturnTypeDescr)
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "return type is %d\n", pReturnTypeDescr->eTypeClass);
+#endif
+ if ( ia64::return_in_hidden_param(pReturnTypeRef) || ia64::return_via_r8_buffer(pReturnTypeRef) )
+ bSimpleReturn = false;
+
+ if ( bSimpleReturn )
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple return\n");
+#endif
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize ) : pUnoReturn);
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pCppReturn/pUnoReturn is %lx/%lx", pCppReturn, pUnoReturn);
+#endif
+ if (!ia64::return_via_r8_buffer(pReturnTypeRef))
+ INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack, bOverflow );
+ }
+ }
+ // push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "this pointer is %p\n", pAdjustedThisPtr);
+#endif
+ INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack, bOverflow );
+
+ // Args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "n params is %d\n", nParams);
+#endif
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "param %d is %d %d %d\n", nPos, rParam.bOut, bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ),
+ pParamTypeDescr->eTypeClass);
+#endif
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+// uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "hyper is %lx\n", *(unsigned long*)(pCppArgs[nPos]));
+#endif
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "long is %lx\n", *(unsigned int*)(pCppArgs[nPos]));
+#endif
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "short is %x\n", *(unsigned short*)(pCppArgs[nPos]));
+#endif
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "byte is %x\n", *(unsigned char*)(pCppArgs[nPos]));
+#endif
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_FLOAT:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "a float is %f\n", *(float*)(pCppArgs[nPos]));
+ fprintf(stderr, "b float is %f\n", *(double*)(pCppArgs[nPos]));
+#endif
+ INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR, nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_DOUBLE:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "double is %f\n", *(double*)(pCppArgs[nPos]));
+#endif
+ INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, nGPR, pGPR, pStack, bOverflow );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex type again %d\n", rParam.bIn);
+#endif
+ if (! rParam.bIn) // is pure out
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex size is %d\n", pParamTypeDescr->nSize );
+#endif
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "this one\n");
+#endif
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "that one, passing %lx through\n", pUnoArgs[nPos]);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack, bOverflow );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr, bSimpleReturn,
+ pStackStart, ( pStack - pStackStart ),
+ pGPR, nGPR,
+ pFPR, nFPR );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/call.hxx b/bridges/source/cpp_uno/gcc3_linux_intel/call.hxx
new file mode 100644
index 0000000000..2051be13df
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/call.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+extern "C" void cpp_vtable_call(
+ int nFunctionIndex, int nVtableOffset, void ** pCallStack,
+ void * pRegisterReturn);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/call.s b/bridges/source/cpp_uno/gcc3_linux_intel/call.s
new file mode 100644
index 0000000000..0a5870defc
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/call.s
@@ -0,0 +1,308 @@
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .text
+
+.globl privateSnippetExecutorGeneral
+ .type privateSnippetExecutorGeneral,@function
+privateSnippetExecutorGeneral:
+.LFBg:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFIg0:
+ movl %esp,%ebp
+.LCFIg1:
+ subl $0x8,%esp # 32bit returnValue, and preserve potential 128bit
+ # stack alignment
+ pushl %esp # 32bit &returnValue
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ movl 16(%esp),%eax # 32bit returnValue
+ leave
+ ret
+.LFEg:
+ .size privateSnippetExecutorGeneral,.-privateSnippetExecutorGeneral
+
+.globl privateSnippetExecutorVoid
+ .type privateSnippetExecutorVoid,@function
+privateSnippetExecutorVoid:
+.LFBv:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFIv0:
+ movl %esp,%ebp
+.LCFIv1:
+ andl $0xFFFFFFF0,%esp # preserve potential 128bit stack alignment
+ pushl $0 # 32bit null pointer (returnValue not used)
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ leave
+ ret
+.LFEv:
+ .size privateSnippetExecutorVoid,.-privateSnippetExecutorVoid
+
+.globl privateSnippetExecutorHyper
+ .type privateSnippetExecutorHyper,@function
+privateSnippetExecutorHyper:
+.LFBh:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFIh0:
+ movl %esp,%ebp
+.LCFIh1:
+ subl $0x8,%esp # 64bit returnValue (preserves potential 128bit
+ # stack alignment)
+ pushl %esp # 32bit &returnValue
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ movl 16(%esp),%eax # 64bit returnValue, lower half
+ movl 20(%esp),%edx # 64bit returnValue, upper half
+ leave
+ ret
+.LFEh:
+ .size privateSnippetExecutorHyper,.-privateSnippetExecutorHyper
+
+.globl privateSnippetExecutorFloat
+ .type privateSnippetExecutorFloat,@function
+privateSnippetExecutorFloat:
+.LFBf:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFIf0:
+ movl %esp,%ebp
+.LCFIf1:
+ subl $0x8,%esp # 32bit returnValue, and preserve potential 128bit
+ # stack alignment
+ pushl %esp # 32bit &returnValue
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ flds 16(%esp) # 32bit returnValue
+ leave
+ ret
+.LFEf:
+ .size privateSnippetExecutorFloat,.-privateSnippetExecutorFloat
+
+.globl privateSnippetExecutorDouble
+ .type privateSnippetExecutorDouble,@function
+privateSnippetExecutorDouble:
+.LFBd:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFId0:
+ movl %esp,%ebp
+.LCFId1:
+ subl $0x8,%esp # 64bit returnValue (preserves potential 128bit
+ # stack alignment)
+ pushl %esp # 32bit &returnValue
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ fldl 16(%esp) # 64bit returnValue
+ leave
+ ret
+.LFEd:
+ .size privateSnippetExecutorDouble,.-privateSnippetExecutorDouble
+
+.globl privateSnippetExecutorClass
+ .type privateSnippetExecutorClass,@function
+privateSnippetExecutorClass:
+.LFBc:
+ movl %esp,%ecx
+ pushl %ebp # proper stack frame needed for exception handling
+.LCFIc0:
+ movl %esp,%ebp
+.LCFIc1:
+ subl $0x8,%esp # 32bit returnValue, and preserve potential 128bit
+ # stack alignment
+ pushl %esp # 32bit &returnValue
+ pushl %ecx # 32bit pCallStack
+ pushl %edx # 32bit nVtableOffset
+ pushl %eax # 32bit nFunctionIndex
+ call cpp_vtable_call
+ movl 16(%esp),%eax # 32bit returnValue
+ leave
+ ret $4
+.LFEc:
+ .size privateSnippetExecutorClass,.-privateSnippetExecutorClass
+
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1 # length
+.LSCIE1:
+ .long 0 # CIE_ID
+ .byte 1 # version
+ .string "zR" # augmentation
+ .uleb128 1 # code_alignment_factor
+ .sleb128 -4 # data_alignment_factor
+ .byte 8 # return_address_register
+ .uleb128 1 # augmentation size 1:
+ .byte 0x1B # FDE Encoding (pcrel sdata4)
+ # initial_instructions:
+ .byte 0x0C # DW_CFA_def_cfa %esp, 4
+ .uleb128 4
+ .uleb128 4
+ .byte 0x88 # DW_CFA_offset ret, 1
+ .uleb128 1
+ .align 4
+.LECIE1:
+.LSFDEg:
+ .long .LEFDEg-.LASFDEg # length
+.LASFDEg:
+ .long .LASFDEg-.Lframe1 # CIE_pointer
+ .long .LFBg-. # initial_location
+ .long .LFEg-.LFBg # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIg0-.LFBg
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIg1-.LCFIg0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEg:
+.LSFDEv:
+ .long .LEFDEv-.LASFDEv # length
+.LASFDEv:
+ .long .LASFDEv-.Lframe1 # CIE_pointer
+ .long .LFBv-. # initial_location
+ .long .LFEv-.LFBv # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIv0-.LFBv
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIv1-.LCFIv0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEv:
+.LSFDEh:
+ .long .LEFDEh-.LASFDEh # length
+.LASFDEh:
+ .long .LASFDEh-.Lframe1 # CIE_pointer
+ .long .LFBh-. # initial_location
+ .long .LFEh-.LFBh # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIh0-.LFBh
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIh1-.LCFIh0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEh:
+.LSFDEf:
+ .long .LEFDEf-.LASFDEf # length
+.LASFDEf:
+ .long .LASFDEf-.Lframe1 # CIE_pointer
+ .long .LFBf-. # initial_location
+ .long .LFEf-.LFBf # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIf0-.LFBf
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIf1-.LCFIf0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEf:
+.LSFDEd:
+ .long .LEFDEd-.LASFDEd # length
+.LASFDEd:
+ .long .LASFDEd-.Lframe1 # CIE_pointer
+ .long .LFBd-. # initial_location
+ .long .LFEd-.LFBd # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFId0-.LFBd
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFId1-.LCFId0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEd:
+.LSFDEc:
+ .long .LEFDEc-.LASFDEc # length
+.LASFDEc:
+ .long .LASFDEc-.Lframe1 # CIE_pointer
+ .long .LFBc-. # initial_location
+ .long .LFEc-.LFBc # address_range
+ .uleb128 0 # augmentation size 0
+ # instructions:
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIc0-.LFBc
+ .byte 0x0E # DW_CFA_def_cfa_offset 8
+ .uleb128 8
+ .byte 0x85 # DW_CFA_offset %ebp, 2
+ .uleb128 2
+ .byte 0x04 # DW_CFA_advance_loc4
+ .long .LCFIc1-.LCFIc0
+ .byte 0x0D # DW_CFA_def_cfa_register %ebp
+ .uleb128 5
+ .align 4
+.LEFDEc:
+ .section .note.GNU-stack,"",@progbits
+ .section .note.gnu.property,"a"
+ .p2align 2
+ .long 1f - 0f
+ .long 4f - 1f
+ .long 5
+0:
+ .string "GNU"
+1:
+ .p2align 2
+ .long 0xc0000002
+ .long 3f - 2f
+2:
+ .long 0x3
+3:
+ .p2align 2
+4:
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.cxx
new file mode 100644
index 0000000000..b0b160b24b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+#include "callvirtualmethod.hxx"
+#include "share.hxx"
+
+// The call instruction within the asm block of callVirtualMethod may throw
+// exceptions. At least GCC 4.7.0 with -O0 would create (unnecessary)
+// .gcc_exception_table call-site table entries around all other calls in this
+// function that can throw, leading to std::terminate if the asm call throws an
+// exception and the unwinding C++ personality routine finds the unexpected hole
+// in the .gcc_exception_table. Therefore, make sure this function explicitly
+// only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
+// .gcc_exception_table section at all for this function). For some reason,
+// this also needs to be in a source file of its own.
+//
+// Also, this file should be compiled with -fnon-call-exceptions, and ideally
+// there would be a way to tell the compiler that the asm block contains calls
+// to functions that can potentially throw; see the mail thread starting at
+// <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
+// asm block can call function that can throw?"
+
+void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
+ sal_Int32 * pStackLongs, sal_Int32 nStackLongs)
+{
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ assert(pStackLongs && pAdjustedThisPtr);
+ assert(sizeof (void *) == 4 && sizeof (sal_Int32) == 4);
+ // unexpected size of int
+ assert(nStackLongs && pStackLongs); // no stack
+
+#if defined __clang__
+ if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+#endif
+
+ long edx, eax; // for register returns
+ void * stackptr;
+ asm volatile (
+ "mov %%esp, %2\n\t"
+ // preserve potential 128bit stack alignment
+ "and $0xfffffff0, %%esp\n\t"
+ "mov %3, %%eax\n\t"
+ "lea -4(,%%eax,4), %%eax\n\t"
+ "and $0xf, %%eax\n\t"
+ "sub $0xc, %%eax\n\t"
+ "add %%eax, %%esp\n\t"
+ // copy values
+ "mov %3, %%eax\n\t"
+ "mov %%eax, %%edx\n\t"
+ "dec %%edx\n\t"
+ "shl $2, %%edx\n\t"
+ "add %4, %%edx\n"
+ "Lcopy:\n\t"
+ "pushl 0(%%edx)\n\t"
+ "sub $4, %%edx\n\t"
+ "dec %%eax\n\t"
+ "jne Lcopy\n\t"
+ // do the actual call
+ "mov %5, %%edx\n\t"
+ "mov 0(%%edx), %%edx\n\t"
+ "mov %6, %%eax\n\t"
+ "shl $2, %%eax\n\t"
+ "add %%eax, %%edx\n\t"
+ "mov 0(%%edx), %%edx\n\t"
+ "call *%%edx\n\t"
+ // save return registers
+ "mov %%eax, %0\n\t"
+ "mov %%edx, %1\n\t"
+ // cleanup stack
+ "mov %2, %%esp\n\t"
+ : "=m"(eax), "=m"(edx), "=m"(stackptr)
+ : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), "m"(nVtableIndex)
+ : "eax", "ecx", "edx" );
+ switch( pReturnTypeDescr->eTypeClass )
+ {
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ static_cast<long*>(pRegisterReturn)[1] = edx;
+ [[fallthrough]];
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ static_cast<long*>(pRegisterReturn)[0] = eax;
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<unsigned short*>(pRegisterReturn) = eax;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *static_cast<unsigned char*>(pRegisterReturn) = eax;
+ break;
+ case typelib_TypeClass_FLOAT:
+ asm ( "fstps %0" : : "m"(*static_cast<char *>(pRegisterReturn)) );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ asm ( "fstpl %0\n\t" : : "m"(*static_cast<char *>(pRegisterReturn)) );
+ break;
+ default:
+ {
+#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
+ defined(DRAGONFLY)
+ sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
+ if (bSimpleReturn && nRetSize <= 8 && nRetSize > 0)
+ {
+ if (nRetSize > 4)
+ static_cast<long *>(pRegisterReturn)[1] = edx;
+ static_cast<long *>(pRegisterReturn)[0] = eax;
+ }
+#else
+ (void)bSimpleReturn;
+#endif
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.hxx b/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.hxx
new file mode 100644
index 0000000000..4eafe8edc5
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/callvirtualmethod.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+void callVirtualMethod(
+ void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
+ sal_Int32 * pStackLongs, sal_Int32 nStackLongs);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx
new file mode 100644
index 0000000000..5dd6e1aa90
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "call.hxx"
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+void cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** pCallStack,
+ void * pReturnValue )
+{
+ // pCallStack: ret, [return ptr], this, params
+ char * pCppStack = reinterpret_cast<char *>(pCallStack +1);
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = nullptr;
+ void * pCppReturn = nullptr; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (x86::isSimpleReturnType( pReturnTypeDescr ))
+ {
+ pUnoReturn = pReturnValue; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *reinterpret_cast<void **>(pCppStack);
+ pCppStack += sizeof(void *);
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut
+ && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ // value
+ {
+ pCppArgs[nPos] = pCppStack;
+ pUnoArgs[nPos] = pCppStack;
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *reinterpret_cast<void **>(pCppStack), pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], nullptr );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException(
+ &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, nullptr );
+ }
+ // complex return ptr is set to eax
+ *static_cast< void ** >(pReturnValue) = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+ }
+}
+
+
+extern "C" void cpp_vtable_call(
+ int nFunctionIndex, int nVtableOffset, void** pCallStack,
+ void * pReturnValue )
+{
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+ // pCallStack: ret adr, [ret *], this, params
+ void * pThis;
+ if( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = pCallStack[2];
+ }
+ else
+ {
+ pThis = pCallStack[1];
+ }
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ static_cast<XInterface *>(pThis));
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pCallStack, pReturnValue );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ nullptr, // indicates void return
+ 1, &aParam,
+ pCallStack, pReturnValue );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pCallStack[3] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = nullptr;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&pInterface), pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pCallStack[1] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *static_cast< void ** >(pReturnValue) = pCallStack[1];
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pParams,
+ pCallStack, pReturnValue );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", static_cast<XInterface *>(pThis) );
+ }
+ }
+}
+
+extern "C" typedef void (*PrivateSnippetExecutor)();
+
+int const codeSnippetSize = 16;
+
+#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
+ defined(DRAGONFLY)
+namespace
+{
+ PrivateSnippetExecutor returnsInRegister(typelib_TypeDescriptionReference * pReturnTypeRef)
+ {
+ //These archs apparently are returning small structs in registers, while Linux
+ //doesn't
+ PrivateSnippetExecutor exec=NULL;
+
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ const bool bSimpleReturnStruct = x86::isSimpleReturnType(pReturnTypeDescr);
+ const sal_Int32 nRetSize = pReturnTypeDescr->nSize;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ if (bSimpleReturnStruct)
+ {
+ exec = privateSnippetExecutorGeneral; // fills eax
+ if (nRetSize > 4)
+ exec = privateSnippetExecutorHyper; // fills eax/edx
+ }
+ return exec;
+ }
+}
+#endif
+
+unsigned char * codeSnippet(
+ unsigned char * code, sal_PtrDiff writetoexecdiff, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ typelib_TypeDescriptionReference * pReturnTypeRef)
+{
+ PrivateSnippetExecutor exec;
+ typelib_TypeClass eReturnClass = pReturnTypeRef ? pReturnTypeRef->eTypeClass : typelib_TypeClass_VOID;
+ switch (eReturnClass)
+ {
+ case typelib_TypeClass_VOID:
+ exec = privateSnippetExecutorVoid;
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ exec = privateSnippetExecutorHyper;
+ break;
+ case typelib_TypeClass_FLOAT:
+ exec = privateSnippetExecutorFloat;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ exec = privateSnippetExecutorDouble;
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+#if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
+ defined(DRAGONFLY)
+ exec = returnsInRegister(pReturnTypeRef);
+ if (!exec)
+ {
+ exec = privateSnippetExecutorClass;
+ functionIndex |= 0x80000000;
+ }
+ break;
+#endif
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ exec = privateSnippetExecutorClass;
+ functionIndex |= 0x80000000;
+ break;
+ default:
+ exec = privateSnippetExecutorGeneral;
+ break;
+ }
+ unsigned char * p = code;
+ assert(sizeof (sal_Int32) == 4);
+ // mov function_index, %eax:
+ *p++ = 0xB8;
+ *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
+ p += sizeof (sal_Int32);
+ // mov vtable_offset, %edx:
+ *p++ = 0xBA;
+ *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
+ p += sizeof (sal_Int32);
+ // jmp privateSnippetExecutor:
+ *p++ = 0xE9;
+ *reinterpret_cast< sal_Int32 * >(p)
+ = reinterpret_cast<unsigned char *>(exec) - p - sizeof (sal_Int32) - writetoexecdiff;
+ p += sizeof (sal_Int32);
+ assert(p - code <= codeSnippetSize);
+ return code + codeSnippetSize;
+}
+
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::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 * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = nullptr;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != nullptr);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, writetoexecdiff, functionOffset++, vtableOffset,
+ reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef);
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, writetoexecdiff, functionOffset++, vtableOffset,
+ nullptr);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, writetoexecdiff, functionOffset++, vtableOffset,
+ reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *, unsigned char const *)
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/except.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/except.cxx
new file mode 100644
index 0000000000..79a37803b3
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/except.cxx
@@ -0,0 +1,302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cstdio>
+#include <cstring>
+#include <dlfcn.h>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <typelib/typedescription.hxx>
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+#if !defined ANDROID
+ void * m_hApp;
+#endif
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+#if !defined ANDROID
+ : m_hApp( dlopen(nullptr, RTLD_LAZY) )
+#endif
+{
+}
+
+RTTI::~RTTI()
+{
+#if !defined ANDROID
+ dlclose( m_hApp );
+#endif
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = OUString::unacquired(&pTypeDescr->aBase.pTypeName);
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+#if !defined ANDROID
+ rtti = static_cast<type_info *>(dlsym( m_hApp, symName.getStr() ));
+#else
+ rtti = static_cast<type_info *>(dlsym( RTLD_DEFAULT, symName.getStr() ));
+#endif
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second, "bridges", "### inserting new rtti failed?!" );
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ pTypeDescr->pBaseTypeDescription);
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), static_cast<__class_type_info *>(base_rtti) );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second, "bridges", "### inserting new generated rtti failed?!" );
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+extern "C" {
+static void _GLIBCXX_CDTOR_CALLABI deleteException( void * pExc )
+{
+ __cxa_exception const * header = static_cast<__cxa_exception const *>(pExc) - 1;
+ typelib_TypeDescription * pTD = nullptr;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ "cannot get typedescription for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxxabiv1::__cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = rtti_data.getRTTI(reinterpret_cast<typelib_CompoundTypeDescription*>(pTypeDescr));
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ "no rtti for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxxabiv1::__cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = reinterpret_cast<CPPU_CURRENT_NAMESPACE::__cxa_eh_globals*>(
+ __cxxabiv1::__cxa_get_globals())->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxxabiv1::__cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = nullptr;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (nullptr == pExcTypeDescr)
+ {
+ RuntimeException aRE( "exception type not found: " + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx b/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx
new file mode 100644
index 0000000000..39325c84e7
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/share.hxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+#include <cxxabi.h>
+#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h
+#define _GLIBCXX_CDTOR_CALLABI
+#endif
+#include <unwind.h>
+
+#include <config_cxxabi.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#if !HAVE_CXXABI_H_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __class_type_info: public std::type_info {
+public:
+ explicit __class_type_info(char const * n): type_info(n) {}
+ ~__class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __si_class_type_info: public __class_type_info {
+public:
+ __class_type_info const * __base_type;
+ explicit __si_class_type_info(
+ char const * n, __class_type_info const *base):
+ __class_type_info(n), __base_type(base) {}
+ ~__si_class_type_info() override;
+};
+}
+#endif
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * );
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+}
+
+// __cxa_get_globals is exported from libstdc++ since GCC 3.4.0 (CXXABI_1.3),
+// but it is only declared in cxxabi.h (in namespace __cxxabiv1) since
+// GCC 4.7.0. It returns a pointer to a struct __cxa_eh_globals, but that
+// struct is only incompletely declared even in the GCC 4.7.0 cxxabi.h.
+// Therefore, provide a declaration here for old GCC (libstdc++, really) version
+// that returns a void pointer, and in the code calling it always cast to the
+// above fake definition of CPPU_CURRENT_NAMESPACE::__cxa_eh_globals (which
+// hopefully keeps matching the real definition in libstdc++); similarly for
+// __cxa_allocate_exception and __cxa_throw, though they do not have the
+// additional problem of an incompletely declared return type:
+
+#if !HAVE_CXXABI_H_CXA_GET_GLOBALS
+namespace __cxxabiv1 { extern "C" void * __cxa_get_globals() throw(); }
+#endif
+
+#if !HAVE_CXXABI_H_CXA_CURRENT_EXCEPTION_TYPE
+namespace __cxxabiv1 {
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_ALLOCATE_EXCEPTION
+namespace __cxxabiv1 {
+extern "C" void * __cxa_allocate_exception(std::size_t thrown_size) throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_THROW
+namespace __cxxabiv1 {
+extern "C" void __cxa_throw(
+ void * thrown_exception, void * tinfo, void (* dest)(void *))
+ __attribute__((noreturn));
+}
+#endif
+
+extern "C" void privateSnippetExecutorGeneral();
+extern "C" void privateSnippetExecutorVoid();
+extern "C" void privateSnippetExecutorHyper();
+extern "C" void privateSnippetExecutorFloat();
+extern "C" void privateSnippetExecutorDouble();
+extern "C" void privateSnippetExecutorClass();
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+}
+
+namespace x86
+{
+ bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive = false);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx
new file mode 100644
index 0000000000..8d532b7749
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_intel/uno2cpp.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <typeinfo>
+
+#include <sal/alloca.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "callvirtualmethod.hxx"
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ char * pCppStack =
+ static_cast<char *>(alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ));
+ char * pCppStackStart = pCppStack;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion
+ bool bSimpleReturn = true;
+
+ if (pReturnTypeDescr)
+ {
+ bSimpleReturn = x86::isSimpleReturnType(pReturnTypeDescr);
+ if (bSimpleReturn)
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = *reinterpret_cast<void **>(pCppStack)
+ = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ pCppStack += sizeof(void *);
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ *reinterpret_cast<void **>(pCppStack) = pAdjustedThisPtr;
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut
+ && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ *reinterpret_cast<void **>(pCppStack) = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ *reinterpret_cast<void **>(pCppStack) = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ *reinterpret_cast<void **>(pCppStack) = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ try
+ {
+ assert( !( (pCppStack - pCppStackStart ) & 3) && "UNALIGNED STACK !!! (Please DO panic)" );
+ try {
+ CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr, bSimpleReturn,
+ reinterpret_cast<sal_Int32 *>(pCppStackStart), (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace x86
+{
+ bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pTD ))
+ return true;
+#if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \
+ defined(MACOSX) || defined(DRAGONFLY)
+ // Only structs of exactly 1, 2, 4, or 8 bytes are returned through
+ // registers, see <http://developer.apple.com/documentation/DeveloperTools/
+ // Conceptual/LowLevelABI/Articles/IA32.html>:
+ if (pTD->eTypeClass == typelib_TypeClass_STRUCT &&
+ (recursive || pTD->nSize <= 2 || pTD->nSize == 4 || pTD->nSize == 8))
+ {
+ typelib_CompoundTypeDescription *const pCompTD =
+ (typelib_CompoundTypeDescription *) pTD;
+ for ( sal_Int32 pos = pCompTD->nMembers; pos--; ) {
+ typelib_TypeDescription * pMemberTD = 0;
+ TYPELIB_DANGER_GET( &pMemberTD, pCompTD->ppTypeRefs[pos] );
+ bool const b = isSimpleReturnType(pMemberTD, true);
+ TYPELIB_DANGER_RELEASE( pMemberTD );
+ if (! b)
+ return false;
+ }
+ return true;
+ }
+#else
+ (void)recursive;
+#endif
+ return false;
+ }
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.cxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.cxx
new file mode 100644
index 0000000000..f9eb095173
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.cxx
@@ -0,0 +1,163 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "abi.hxx"
+
+int loongarch64::flatten_struct(typelib_TypeDescription* pTypeDescr, Registers& regs)
+{
+ const typelib_CompoundTypeDescription* p
+ = reinterpret_cast<const typelib_CompoundTypeDescription*>(pTypeDescr);
+ int sum = p->nMembers;
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ typelib_TypeDescriptionReference* pTypeInStruct = p->ppTypeRefs[i];
+
+ switch (pTypeInStruct->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription* t = 0;
+ TYPELIB_DANGER_GET(&t, pTypeInStruct);
+ sum--;
+ sum += flatten_struct(t, regs);
+ TYPELIB_DANGER_RELEASE(t);
+ }
+ break;
+ case typelib_TypeClass_CHAR:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ regs.nr_int++;
+ if (!regs.priorInt && !regs.priorFp)
+ regs.priorInt = true;
+ break;
+ case typelib_TypeClass_FLOAT:
+ regs.complex_float = true;
+ [[fallthrough]];
+ case typelib_TypeClass_DOUBLE:
+ regs.nr_fp++;
+ if (!regs.priorInt && !regs.priorFp)
+ regs.priorFp = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return sum;
+}
+
+loongarch64::ReturnKind loongarch64::getReturnKind(typelib_TypeDescriptionReference* pTypeRef)
+{
+ switch (pTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ return ReturnKind::RegistersInt;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ return ReturnKind::RegistersFp;
+ case typelib_TypeClass_STRUCT:
+ {
+ Registers regs = { false, false, false, 0, 0 };
+ typelib_TypeDescription* pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET(&pTypeDescr, pTypeRef);
+ int sum = flatten_struct(pTypeDescr, regs);
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ if ((sum == 1 || sum == 2) && sum == regs.nr_fp)
+ {
+ if (regs.complex_float && pTypeRef->pType->nSize == 8)
+ return ReturnKind::RegistersTwoFloat;
+ return ReturnKind::RegistersFp;
+ }
+ if (sum == 2 && regs.nr_fp == regs.nr_int)
+ {
+ if (regs.priorInt)
+ {
+ if (regs.complex_float && pTypeRef->pType->nSize == 8)
+ return ReturnKind::RegistersIntFloat;
+ return ReturnKind::RegistersIntFp;
+ }
+ if (regs.priorFp)
+ {
+ if (regs.complex_float && pTypeRef->pType->nSize == 8)
+ return ReturnKind::RegistersFloatInt;
+ return ReturnKind::RegistersFpInt;
+ }
+ }
+ }
+ [[fallthrough]];
+ default:
+ return ReturnKind::RegistersInt;
+ }
+}
+
+void loongarch64::fillReturn(typelib_TypeDescriptionReference* pTypeRef, sal_Int64* gret,
+ double* fret, void* pRegisterReturn)
+{
+ ReturnKind returnKind = getReturnKind(pTypeRef);
+ switch (returnKind)
+ {
+ case ReturnKind::RegistersFp:
+ reinterpret_cast<double*>(pRegisterReturn)[0] = fret[0];
+ reinterpret_cast<double*>(pRegisterReturn)[1] = fret[1];
+ break;
+ case ReturnKind::RegistersTwoFloat:
+ memcpy(reinterpret_cast<char*>(pRegisterReturn), &(fret[0]), 4);
+ memcpy(reinterpret_cast<char*>(pRegisterReturn) + 4, &(fret[1]), 4);
+ break;
+ case ReturnKind::RegistersFpInt:
+ reinterpret_cast<double*>(pRegisterReturn)[0] = fret[0];
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[1] = gret[0];
+ break;
+ case ReturnKind::RegistersFloatInt:
+ memcpy(reinterpret_cast<char*>(pRegisterReturn), fret, 4);
+ memcpy(reinterpret_cast<char*>(pRegisterReturn) + 4, gret, 4);
+ break;
+ case ReturnKind::RegistersIntFp:
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[0] = gret[0];
+ reinterpret_cast<double*>(pRegisterReturn)[1] = fret[0];
+ break;
+ case ReturnKind::RegistersIntFloat:
+ memcpy(reinterpret_cast<char*>(pRegisterReturn), gret, 4);
+ memcpy(reinterpret_cast<char*>(pRegisterReturn) + 4, fret, 4);
+ break;
+ default:
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[0] = gret[0];
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[1] = gret[1];
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.hxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.hxx
new file mode 100644
index 0000000000..1fe9e9b588
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/abi.hxx
@@ -0,0 +1,55 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <typelib/typedescription.hxx>
+
+#define MAX_GP_REGS 8
+#define MAX_FP_REGS 8
+
+namespace loongarch64
+{
+enum class ReturnKind
+{
+ RegistersInt,
+ RegistersFp,
+ RegistersTwoFloat,
+ RegistersFpInt,
+ RegistersFloatInt,
+ RegistersIntFp,
+ RegistersIntFloat
+};
+typedef struct Registers
+{
+ bool complex_float;
+ bool priorInt;
+ bool priorFp;
+ int nr_fp;
+ int nr_int;
+} Registers;
+int flatten_struct(typelib_TypeDescription* pTypeDescr, Registers& regs);
+
+ReturnKind getReturnKind(typelib_TypeDescriptionReference* type);
+
+void fillReturn(typelib_TypeDescriptionReference* pTypeRef, sal_Int64* gret, double* fret,
+ void* pRegisterReturn);
+} // namespace loongarch64
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.hxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.hxx
new file mode 100644
index 0000000000..ee8daa9ad0
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+namespace
+{
+extern "C" int cpp_vtable_call(sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, void** gpreg,
+ void** fpreg, void** ovrflw,
+ sal_uInt64* pRegisterReturn /* space for register return */);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.s b/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.s
new file mode 100644
index 0000000000..d27b5bd8a5
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/call.s
@@ -0,0 +1,138 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .text
+ .globl privateSnippetExecutor
+.LFB0 = .
+ .cfi_startproc
+ .cfi_personality 0x80,DW.ref.__gxx_personality_v0
+ .cfi_lsda 0,.LLSDA0
+ .type privateSnippetExecutor, @function
+privateSnippetExecutor:
+ addi.d $sp,$sp,-160
+ .cfi_def_cfa_offset 160
+ st.d $ra,$sp,152
+ .cfi_offset 1, -8
+.LEHB0 = .
+ // Clear return value space
+ st.d $zero,$sp,0
+ st.d $zero,$sp,8
+ // Save the float point registers
+ fst.d $f0,$sp,80
+ fst.d $f1,$sp,88
+ fst.d $f2,$sp,96
+ fst.d $f3,$sp,104
+ fst.d $f4,$sp,112
+ fst.d $f5,$sp,120
+ fst.d $f6,$sp,128
+ fst.d $f7,$sp,136
+ // Save the general purpose registers
+ st.d $a0,$sp,16
+ st.d $a1,$sp,24
+ st.d $a2,$sp,32
+ st.d $a3,$sp,40
+ st.d $a4,$sp,48
+ st.d $a5,$sp,56
+ st.d $a6,$sp,64
+ st.d $a7,$sp,72
+ // Load arguments
+ // a0=index
+ move $a0,$t6
+ // a1=offset
+ move $a1,$t7
+ // a2=gpregptr
+ addi.d $a2,$sp,16
+ // a3=fpregptr
+ addi.d $a3,$sp,80
+ // a4=ovrflw
+ addi.d $a4,$sp,160
+ // a5=retregptr
+ move $a5,$sp
+
+ // Call cpp_vtable_call
+ jirl $ra,$t5,0
+
+.LEHE0 = .
+ // Perform return value
+ beq $a0,$zero,.Lintfp
+ blt $zero,$a0,.Lfpint
+ fld.d $f0,$sp,0
+ fld.d $f1,$sp,8
+ ld.d $a0,$sp,0
+ ld.d $a1,$sp,8
+ b .Lfinish
+.Lintfp:
+ ld.d $a0,$sp,0
+ fld.d $f0,$sp,8
+ b .Lfinish
+.Lfpint:
+ fld.d $f0,$sp,0
+ ld.d $a0,$sp,8
+.Lfinish:
+ ld.d $ra,$sp,152
+ .cfi_restore 1
+ addi.d $sp,$sp,160
+ .cfi_def_cfa_offset 0
+ jr $ra
+ .cfi_endproc
+
+.LFE0:
+ .globl __gxx_personality_v0
+ .section .gcc_except_table,"aw",@progbits
+ .align 3
+.LLSDA0:
+ .byte 0xff
+ .byte 0x80
+ .uleb128 .LLSDATT0-.LLSDATTD0
+.LLSDATTD0:
+ .byte 0x1
+ .uleb128 .LLSDACSE0-.LLSDACSB0
+.LLSDACSB0:
+ .uleb128 .LEHB0-.LFB0
+ .uleb128 .LEHE0-.LEHB0
+ .uleb128 0
+ .uleb128 0
+.LLSDACSE0:
+ .byte 0x7f
+ .byte 0
+ .align 3
+ .8byte DW.ref._ZTIi
+.LLSDATT0:
+ .byte 0x1
+ .byte 0
+ .text
+ .size privateSnippetExecutor, .-privateSnippetExecutor
+ .hidden DW.ref._ZTIi
+ .weak DW.ref._ZTIi
+ .section .data.DW.ref._ZTIi,"awG",@progbits,DW.ref._ZTIi,comdat
+ .align 3
+ .type DW.ref._ZTIi, @object
+ .size DW.ref._ZTIi, 8
+DW.ref._ZTIi:
+ .dword _ZTIi
+ .hidden DW.ref.__gxx_personality_v0
+ .weak DW.ref.__gxx_personality_v0
+ .section .data.DW.ref.__gxx_personality_v0,"awG",@progbits,DW.ref.__gxx_personality_v0,comdat
+ .align 3
+ .type DW.ref.__gxx_personality_v0, @object
+ .size DW.ref.__gxx_personality_v0, 8
+DW.ref.__gxx_personality_v0:
+ .dword __gxx_personality_v0
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx
new file mode 100644
index 0000000000..1a0c42b0da
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx
@@ -0,0 +1,564 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include <osl/endian.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "call.hxx"
+#include "share.hxx"
+#include "abi.hxx"
+
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+using namespace com::sun::star::uno;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+bool is_complex_struct(const typelib_TypeDescription* type)
+{
+ const typelib_CompoundTypeDescription* p
+ = reinterpret_cast<const typelib_CompoundTypeDescription*>(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT
+ || p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription* t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b)
+ {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+}
+
+bool return_in_hidden_param(typelib_TypeDescriptionReference* pTypeRef)
+{
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT
+ || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription* pTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pTypeDescr, pTypeRef);
+
+ //A Composite Type not larger than 16 bytes is returned in up to two GPRs
+ bool bRet = pTypeDescr->nSize > 16 || is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ return bRet;
+ }
+ return true;
+}
+}
+
+namespace
+{
+static int cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription* pMemberTypeDescr,
+ typelib_TypeDescriptionReference* pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter* pParams, void** gpreg,
+ void** fpreg, void** ovrflw,
+ sal_uInt64* pRegisterReturn /* space for register return */)
+{
+ sal_Int32 gCount = 0;
+ sal_Int32 fCount = 0;
+ sal_Int32 sp = 0;
+
+ // return
+ typelib_TypeDescription* pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET(&pReturnTypeDescr, pReturnTypeRef);
+ loongarch64::ReturnKind returnKind
+ = (pReturnTypeRef == nullptr || pReturnTypeRef->eTypeClass == typelib_TypeClass_VOID)
+ ? loongarch64::ReturnKind::RegistersInt
+ : loongarch64::getReturnKind(pReturnTypeRef);
+
+ void* pUnoReturn = 0;
+ void* pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param(pReturnTypeRef))
+ {
+ pCppReturn = gpreg[gCount++]; // complex return via ptr (pCppReturn)
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr)
+ ? alloca(pReturnTypeDescr->nSize)
+ : pCppReturn); // direct way
+ }
+ else
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ }
+
+ // pop this
+ gCount++;
+
+ // stack space
+ static_assert(sizeof(void*) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void** pUnoArgs = (void**)alloca(4 * sizeof(void*) * nParams);
+ void** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32* pTempIndices = (sal_Int32*)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription** ppTempParamTypeDescr
+ = (typelib_TypeDescription**)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for (sal_Int32 nPos = 0; nPos < nParams; ++nPos)
+ {
+ const typelib_MethodParameter& rParam = pParams[nPos];
+
+ typelib_TypeDescription* pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pParamTypeDescr, rParam.pTypeRef);
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTypeDescr)) // value
+ {
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ pCppArgs[nPos]
+ = fCount != MAX_FP_REGS
+ ? &(fpreg[fCount++])
+ : (gCount != MAX_GP_REGS ? &(gpreg[gCount++]) : &(ovrflw[sp++]));
+ pUnoArgs[nPos] = pCppArgs[nPos];
+ break;
+ default:
+ pCppArgs[nPos] = gCount == MAX_GP_REGS ? &(ovrflw[sp++]) : &(gpreg[gCount++]);
+ pUnoArgs[nPos] = pCppArgs[nPos];
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ else // ptr to complex value | ref
+ {
+ void* pCppStack;
+ pCppStack = gCount == MAX_GP_REGS ? ovrflw[sp++] : gpreg[gCount++];
+ pCppArgs[nPos] = pCppStack;
+ if (!rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca(pParamTypeDescr->nSize);
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTypeDescr))
+ {
+ uno_copyAndConvertData(pUnoArgs[nPos] = alloca(pParamTypeDescr->nSize), pCppStack,
+ pParamTypeDescr, pThis->getBridge()->getCpp2Uno());
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ }
+ }
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any* pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs,
+ &pUnoExc);
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData(pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0);
+ TYPELIB_DANGER_RELEASE(ppTempParamTypeDescr[nTempIndices]);
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+
+ CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp());
+ // has to destruct the any
+ // is here for dummy
+ return -1;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription* pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData(pCppArgs[nIndex], pParamTypeDescr, cpp_release);
+ uno_copyAndConvertData(pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+ }
+ // destroy temp uno param
+ uno_destructData(pUnoArgs[nIndex], pParamTypeDescr, 0);
+
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData(pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+ // destroy temp uno return
+ uno_destructData(pUnoReturn, pReturnTypeDescr, 0);
+ }
+ // complex return ptr is set to return reg
+ *(void**)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+ }
+ switch (returnKind)
+ {
+ case loongarch64::ReturnKind::RegistersIntFloat:
+ memcpy(pRegisterReturn + 1, static_cast<char*>(pUnoReturn) + 4, 4);
+ [[fallthrough]];
+ case loongarch64::ReturnKind::RegistersIntFp:
+ return 0;
+ case loongarch64::ReturnKind::RegistersFloatInt:
+ memcpy(pRegisterReturn + 1, static_cast<char*>(pUnoReturn) + 4, 4);
+ [[fallthrough]];
+ case loongarch64::ReturnKind::RegistersFpInt:
+ return 1;
+ case loongarch64::ReturnKind::RegistersTwoFloat:
+ memcpy(pRegisterReturn + 1, static_cast<char*>(pUnoReturn) + 4, 4);
+ [[fallthrough]];
+ default:
+ return -1;
+ }
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+int cpp_vtable_call(sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, void** gpreg, void** fpreg,
+ void** ovrflw, sal_uInt64* pRegisterReturn /* space for register return */)
+{
+ static_assert(sizeof(sal_Int64) == sizeof(void*), "### unexpected!");
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+ void* pThis;
+ if (nFunctionIndex & 0x80000000)
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+ pThis = static_cast<char*>(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy* pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis);
+ typelib_InterfaceTypeDescription* pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN("bridges", "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface*)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr(pTypeDescr->ppAllMembers[nMemberPos]);
+
+ int eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference* pAttrTypeRef
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
+ ->pAttributeTypeRef;
+
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pAttrTypeRef, 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn);
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam, gpreg, fpreg, ovrflw, pRegisterReturn);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = -1;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = -1;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription* pTD = 0;
+ TYPELIB_DANGER_GET(&pTD, reinterpret_cast<Type*>(gpreg[2])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface* pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(), (void**)&pInterface,
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD));
+
+ if (pInterface)
+ {
+ ::uno_any_construct(reinterpret_cast<uno_Any*>(gpreg[0]), &pInterface,
+ pTD, cpp_acquire);
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE(pTD);
+
+ reinterpret_cast<void**>(pRegisterReturn)[0] = gpreg[0];
+ eRet = -1;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pTD);
+ }
+ } // else perform queryInterface()
+ [[fallthrough]];
+ default:
+ typelib_InterfaceMethodTypeDescription* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
+ aMemberDescr.get());
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams, pMethodTD->pParams, gpreg, fpreg,
+ ovrflw, pRegisterReturn);
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException("no member description found!", (XInterface*)pThis);
+ }
+ }
+
+ return eRet;
+}
+
+extern "C" void privateSnippetExecutor(...);
+
+int const codeSnippetSize = 0x34;
+
+unsigned char* codeSnippet(unsigned char* code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool bHasHiddenParam)
+{
+ if (bHasHiddenParam)
+ functionIndex |= 0x80000000;
+
+ unsigned int* p = (unsigned int*)code;
+
+ assert((((unsigned long)code) & 0x3) == 0); //aligned to 4 otherwise a mistake
+
+ /* generate this code */
+ /*
+ # index
+ 0: 14000012 lu12i.w $t6,0x0
+ 4: 34420000 ori $t6,$t6,0x0
+ # privateSnippetExecutor
+ 8: 14000014 lu12i.w $t8,0x0
+ c: 03800294 ori $t8,$t8,0x0
+ 10: 16000014 lu32i.d $t8,0x0
+ 14: 03000294 lu52i.d $t8,$t8,0x0
+ # cpp_vtable_call
+ 18: 14000011 lu12i.w $t5,0x0
+ 1c: 03800231 ori $t5,$t5,0x0
+ 20: 16000011 lu32i.d $t5,0x0
+ 24: 03000231 lu52i.d $t5,$t5,0x0
+ # offset
+ 28: 14000013 lu12i.w $t7,0x0
+ 2c: 03800273 ori $t7,$t7,0x0
+ 30: 4c000280 jr $t8
+ */
+
+ *p++ = 0x14000012 | (((functionIndex >> 12) & 0x000fffff) << 5);
+ *p++ = 0x03800252 | ((functionIndex & 0x00000fff) << 10);
+ *p++ = 0x14000014 | (((((unsigned long)privateSnippetExecutor) >> 12) & 0x000fffff) << 5);
+ *p++ = 0x03800294 | ((((unsigned long)privateSnippetExecutor) & 0x00000fff) << 10);
+ *p++ = 0x16000014 | (((((unsigned long)privateSnippetExecutor) >> 32) & 0x000fffff) << 5);
+ *p++ = 0x03000294 | (((((unsigned long)privateSnippetExecutor) >> 52) & 0x00000fff) << 10);
+ *p++ = 0x14000011 | (((((unsigned long)cpp_vtable_call) >> 12) & 0x000fffff) << 5);
+ *p++ = 0x03800231 | ((((unsigned long)cpp_vtable_call) & 0x00000fff) << 10);
+ *p++ = 0x16000011 | (((((unsigned long)cpp_vtable_call) >> 32) & 0x000fffff) << 5);
+ *p++ = 0x03000231 | (((((unsigned long)cpp_vtable_call) >> 52) & 0x00000fff) << 10);
+ *p++ = 0x14000013 | (((vtableOffset >> 12) & 0x000fffff) << 5);
+ *p++ = 0x03800273 | ((vtableOffset & 0x00000fff) << 10);
+ *p++ = 0x4c000280;
+ return (code + codeSnippetSize);
+}
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const* bptr,
+ unsigned char const* eptr)
+{
+ asm volatile("ibar 0" :::);
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot
+{
+ void const* fn;
+};
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block)
+{
+ return static_cast<Slot*>(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof(Slot) + slotCount * codeSnippetSize;
+}
+
+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
+{
+};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
+ sal_Int32,
+ typelib_InterfaceTypeDescription*)
+{
+ Slot* slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char* bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot** slots, unsigned char* code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const* type, sal_Int32 functionOffset, sal_Int32 functionCount,
+ sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot* s = *slots;
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription* member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(member)
+ ->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(member)
+ ->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(member)
+ ->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/except.cxx
new file mode 100644
index 0000000000..b69c52b1f4
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/except.cxx
@@ -0,0 +1,251 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything(char const*) {}
+
+static OUString toUNOname(char const* p)
+{
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf(64);
+ assert('N' == *p);
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii(p, n);
+ p += n;
+ if ('E' != *p)
+ buf.append('.');
+ }
+
+ return buf.makeStringAndClear();
+}
+
+class RTTI
+{
+ typedef std::unordered_map<OUString, type_info*> t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void* m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info* getRTTI(typelib_CompoundTypeDescription*);
+};
+
+RTTI::RTTI()
+ : m_hApp(dlopen(0, RTLD_LAZY))
+{
+}
+
+RTTI::~RTTI() { dlclose(m_hApp); }
+
+type_info* RTTI::getRTTI(typelib_CompoundTypeDescription* pTypeDescr)
+{
+ type_info* rtti;
+
+ OUString const& unoName = *(OUString const*)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard(m_mutex);
+ t_rtti_map::const_iterator iRttiFind(m_rttis.find(unoName));
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf(64);
+ buf.append("_ZTIN");
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token(unoName.getToken(0, '.', index));
+ buf.append(token.getLength());
+ OString c_token(OUStringToOString(token, RTL_TEXTENCODING_ASCII_US));
+ buf.append(c_token);
+ } while (index >= 0);
+ buf.append('E');
+
+ OString symName(buf.makeStringAndClear());
+ rtti = (type_info*)dlsym(m_hApp, symName.getStr());
+
+ if (rtti)
+ {
+ pair<t_rtti_map::iterator, bool> insertion(
+ m_rttis.insert(t_rtti_map::value_type(unoName, rtti)));
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind(m_generatedRttis.find(unoName));
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const* rttiName = symName.getStr() + 4;
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info* base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription*)pTypeDescr->pBaseTypeDescription);
+ rtti
+ = new __si_class_type_info(strdup(rttiName), (__class_type_info*)base_rtti);
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info(strdup(rttiName));
+ }
+
+ pair<t_rtti_map::iterator, bool> insertion(
+ m_generatedRttis.insert(t_rtti_map::value_type(unoName, rtti)));
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+static void deleteException(void* pExc)
+{
+ __cxa_exception const* header = ((__cxa_exception const*)pExc - 1);
+ typelib_TypeDescription* pTD = 0;
+ OUString unoName(toUNOname(header->exceptionType->name()));
+ ::typelib_typedescription_getByName(&pTD, unoName.pData);
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData(pExc, pTD, cpp_release);
+ ::typelib_typedescription_release(pTD);
+ }
+}
+
+void raiseException(uno_Any* pUnoExc, uno_Mapping* pUno2Cpp)
+{
+ void* pCppExc;
+ type_info* rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription* pTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pTypeDescr, pUnoExc->pType);
+ assert(pTypeDescr);
+ if (!pTypeDescr)
+ {
+ throw RuntimeException(OUString("cannot get typedescription for type ")
+ + OUString::unacquired(&pUnoExc->pType->pTypeName));
+ }
+
+ pCppExc = __cxa_allocate_exception(pTypeDescr->nSize);
+ ::uno_copyAndConvertData(pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp);
+
+ // destruct uno exception
+ ::uno_any_destruct(pUnoExc, 0);
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ assert(rtti && "### no rtti for throwing exception!");
+ if (!rtti)
+ {
+ throw RuntimeException(OUString("no rtti for type ")
+ + OUString::unacquired(&pUnoExc->pType->pTypeName));
+ }
+ }
+
+ __cxa_throw(pCppExc, rtti, deleteException);
+}
+
+void fillUnoException(uno_Any* pUnoExc, uno_Mapping* pCpp2Uno)
+{
+ __cxa_exception* header = __cxa_get_globals()->caughtExceptions;
+ if (!header)
+ {
+ RuntimeException aRE("no exception header!");
+ Type const& rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert(pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno);
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info* exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription* pExcTypeDescr = 0;
+ OUString unoName(toUNOname(exceptionType->name()));
+ typelib_typedescription_getByName(&pExcTypeDescr, unoName.pData);
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE(OUString("exception type not found: ") + unoName);
+ Type const& rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert(pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno);
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert(pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno);
+ typelib_typedescription_release(pExcTypeDescr);
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/share.hxx
new file mode 100644
index 0000000000..258aac64a7
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/share.hxx
@@ -0,0 +1,82 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything(char const*);
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void* exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info* exceptionType;
+ void (*exceptionDestructor)(void*);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception* nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char* actionRecord;
+ const unsigned char* languageSpecificData;
+ void* catchTemp;
+ void* adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void* __cxa_allocate_exception(std::size_t thrown_size) throw();
+extern "C" void __cxa_throw(void* thrown_exception, std::type_info* tinfo, void (*dest)(void*))
+ __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception* caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals* __cxa_get_globals() throw();
+extern "C" std::type_info* __cxa_current_exception_type() throw();
+
+void raiseException(uno_Any* pUnoExc, uno_Mapping* pUno2Cpp);
+
+void fillUnoException(uno_Any*, uno_Mapping* pCpp2Uno);
+
+bool return_in_hidden_param(typelib_TypeDescriptionReference* pTypeRef);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/uno2cpp.cxx
new file mode 100644
index 0000000000..c4e7815e0a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/uno2cpp.cxx
@@ -0,0 +1,479 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <cstring>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+#include "abi.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+void pushArgs(unsigned long value, unsigned long* const stack, sal_Int32* const sp,
+ unsigned long* const regs, sal_Int32* const nregs)
+{
+ (*nregs != 8 ? regs[(*nregs)++] : stack[(*sp)++]) = value;
+}
+
+static void callVirtualMethod(void* pAdjustedThisPtr, sal_Int32 nVtableIndex, void* pRegisterReturn,
+ typelib_TypeDescriptionReference* pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64* pStack, sal_uInt32 nStack, sal_uInt64* pGPR, double* pFPR)
+{
+ // Get pointer to method
+ sal_uInt64 pMethod = *((sal_uInt64*)pAdjustedThisPtr);
+ pMethod += 8 * nVtableIndex;
+ void* mfunc = (void*)*((sal_uInt64*)pMethod);
+ // Load parameters to stack, if necessary
+ sal_uInt64* pCallStack = NULL;
+ if (nStack)
+ {
+ // 16-bytes aligned
+ sal_uInt32 nStackBytes = ((nStack + 1) >> 1) * 16;
+ pCallStack = (sal_uInt64*)__builtin_alloca(nStackBytes);
+ std::memcpy(pCallStack, pStack, nStackBytes);
+ }
+
+ sal_Int64 gret[2];
+ double fret[2];
+ asm volatile(
+ // Fill the general purpose registers
+ "ld.d $r4,%[gpr],0 \n\t"
+ "ld.d $r5,%[gpr],8 \n\t"
+ "ld.d $r6,%[gpr],16 \n\t"
+ "ld.d $r7,%[gpr],24 \n\t"
+ "ld.d $r8,%[gpr],32 \n\t"
+ "ld.d $r9,%[gpr],40 \n\t"
+ "ld.d $r10,%[gpr],48 \n\t"
+ "ld.d $r11,%[gpr],56 \n\t"
+ // Fill the floating pointer registers
+ "fld.d $f0,%[fpr],0 \n\t"
+ "fld.d $f1,%[fpr],8 \n\t"
+ "fld.d $f2,%[fpr],16 \n\t"
+ "fld.d $f3,%[fpr],24 \n\t"
+ "fld.d $f4,%[fpr],32 \n\t"
+ "fld.d $f5,%[fpr],40 \n\t"
+ "fld.d $f6,%[fpr],48 \n\t"
+ "fld.d $f7,%[fpr],56 \n\t"
+ // Perform the call
+ "jirl $ra,%[mfunc],0 \n\t"
+ // Fill the return values
+ "move %[gret1], $a0 \n\t"
+ "move %[gret2], $a1 \n\t"
+ "fmov.d %[fret1], $f0 \n\t"
+ "fmov.d %[fret2], $f1 \n\t"
+ : [gret1] "=r"(gret[0]), [gret2] "=r"(gret[1]), [fret1] "=f"(fret[0]), [fret2] "=f"(fret[1])
+ : [gpr] "r"(pGPR), [fpr] "r"(pFPR), [mfunc] "r"(mfunc),
+ [stack] "m"(
+ pCallStack) // dummy input to prevent the compiler from optimizing the alloca out
+ : "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r1", "$f0", "$f1", "$f2",
+ "$f3", "$f4", "$f5", "$f6", "$f7", "memory");
+
+ switch (pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<sal_Int64*>(pRegisterReturn) = gret[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double*>(pRegisterReturn) = fret[0];
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+ if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+ {
+ loongarch64::fillReturn(pReturnTypeRef, gret, fret, pRegisterReturn);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy* pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference* pReturnTypeRef, sal_Int32 nParams,
+ typelib_MethodParameter* pParams, void* pUnoReturn, void* pUnoArgs[],
+ uno_Any** ppUnoExc)
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64* pStack = (sal_uInt64*)__builtin_alloca(((nParams + 3) * sizeof(sal_Int64)));
+ sal_uInt64* pStackStart = pStack;
+ sal_Int32 sp = 0;
+
+ sal_uInt64 pGPR[MAX_GP_REGS];
+ sal_Int32 gCount = 0;
+ double pFPR[MAX_FP_REGS];
+ sal_Int32 fCount = 0;
+
+ // return
+ typelib_TypeDescription* pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pReturnTypeDescr, pReturnTypeRef);
+ assert(pReturnTypeDescr);
+
+ void* pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ bool bSimpleReturn = true;
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param(pReturnTypeRef))
+ {
+ bSimpleReturn = false;
+ // complex return via ptr
+ pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr)
+ ? __builtin_alloca(pReturnTypeDescr->nSize)
+ : pUnoReturn;
+ pGPR[gCount++] = reinterpret_cast<unsigned long>(pCppReturn);
+ }
+ else
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ }
+
+ // push this
+ void* pAdjustedThisPtr = reinterpret_cast<void**>(pThis->getCppI()) + aVtableSlot.offset;
+ pGPR[gCount++] = reinterpret_cast<unsigned long>(pAdjustedThisPtr);
+
+ // args
+ void** pCppArgs = (void**)alloca(3 * sizeof(void*) * nParams);
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32* pTempIndices = (sal_Int32*)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription** ppTempParamTypeDescr
+ = (typelib_TypeDescription**)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for (sal_Int32 nPos = 0; nPos < nParams; ++nPos)
+ {
+ const typelib_MethodParameter& rParam = pParams[nPos];
+ typelib_TypeDescription* pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pParamTypeDescr, rParam.pTypeRef);
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTypeDescr))
+ {
+ uno_copyAndConvertData(pCppArgs[nPos] = alloca(8), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_ENUM:
+ pushArgs(*static_cast<sal_Int32*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pushArgs(*static_cast<sal_uInt32*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_CHAR:
+ pushArgs(*static_cast<sal_Unicode*>(pCppArgs[nPos]), pStack, &sp, pGPR,
+ &gCount);
+ break;
+ case typelib_TypeClass_SHORT:
+ pushArgs(*static_cast<sal_Int16*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pushArgs(*static_cast<sal_uInt16*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pushArgs(static_cast<unsigned long>(*static_cast<sal_Bool*>(pCppArgs[nPos])),
+ pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_BYTE:
+ pushArgs(*static_cast<sal_Int8*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (fCount != MAX_FP_REGS)
+ {
+ pFPR[fCount++] = *static_cast<double*>(pCppArgs[nPos]);
+ }
+ else if (gCount != MAX_GP_REGS)
+ {
+ pGPR[gCount++] = *static_cast<unsigned long*>(pCppArgs[nPos]);
+ }
+ else
+ {
+ pStack[sp++] = *static_cast<unsigned long*>(pCppArgs[nPos]);
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ pushArgs(*static_cast<sal_Int64*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pushArgs(*static_cast<sal_uInt64*>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ else // ptr to complex value | ref
+ {
+ if (!rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(pCppArgs[nPos] = alloca(pParamTypeDescr->nSize), pParamTypeDescr);
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTypeDescr))
+ {
+ uno_copyAndConvertData(pCppArgs[nPos] = alloca(pParamTypeDescr->nSize),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ pushArgs(reinterpret_cast<unsigned long>(pCppArgs[nPos]), pStack, &sp, pGPR, &gCount);
+ }
+ }
+
+ try
+ {
+ try
+ {
+ callVirtualMethod(pAdjustedThisPtr, aVtableSlot.index, pCppReturn, pReturnTypeRef,
+ bSimpleReturn, pStackStart, sp, pGPR, pFPR);
+ }
+ catch (css::uno::Exception&)
+ {
+ throw;
+ }
+ catch (std::exception& e)
+ {
+ throw css::uno::RuntimeException("C++ code threw "
+ + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ }
+ catch (...)
+ {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription* pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData(pUnoArgs[nIndex], pParamTypeDescr, 0); // destroy uno value
+ uno_copyAndConvertData(pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData(pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData(pCppArgs[nIndex], pParamTypeDescr, cpp_release);
+
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData(pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ uno_destructData(pCppReturn, pReturnTypeDescr, cpp_release);
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData(pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release);
+ TYPELIB_DANGER_RELEASE(ppTempParamTypeDescr[nTempIndices]);
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared
+{
+void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const typelib_TypeDescription* pMemberDescr,
+ void* pReturn, void* pArgs[], uno_Any** ppException)
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy* pThis
+ = static_cast<bridges::cpp_uno::shared::UnoInterfaceProxy*>(pUnoI);
+ //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const*>(pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription*)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException);
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef
+ = ((typelib_InterfaceAttributeTypeDescription*)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference* pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(&pReturnTypeRef, typelib_TypeClass_VOID,
+ aVoidName.pData);
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(pThis, aVtableSlot, pReturnTypeRef, 1, &aParam, pReturn, pArgs,
+ ppException);
+
+ typelib_typedescriptionreference_release(pReturnTypeRef);
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)(pUnoI);
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)(pUnoI);
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription* pTD = 0;
+ TYPELIB_DANGER_GET(&pTD, reinterpret_cast<Type*>(pArgs[0])->getTypeLibType());
+ if (pTD)
+ {
+ uno_Interface* pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(), (void**)&pInterface, pThis->oid.pData,
+ (typelib_InterfaceTypeDescription*)pTD);
+
+ if (pInterface)
+ {
+ ::uno_any_construct(reinterpret_cast<uno_Any*>(pReturn), &pInterface,
+ pTD, 0);
+ (*pInterface->release)(pInterface);
+ TYPELIB_DANGER_RELEASE(pTD);
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pTD);
+ }
+ } // else perform queryInterface()
+ [[fallthrough]];
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->pParams, pReturn,
+ pArgs, ppException);
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface>());
+
+ Type const& rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), 0);
+ }
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx
new file mode 100644
index 0000000000..ac375e052b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx
@@ -0,0 +1,528 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+
+#include <dlfcn.h>
+
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+ static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ long r8, void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ // pCallStack: ret, [return ptr], this, params
+ char * pTopStack = (char *)(pCallStack + 0);
+ char * pCppStack = pTopStack;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "cpp2uno_call\n");
+#endif
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+ void * pCppReturn = 0;
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple return\n");
+#endif
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex return\n");
+#endif
+ pCppReturn = (void *)r8;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert( sizeof(void *) == sizeof(sal_Int32),
+ "### unexpected size!" );
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion
+ // cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr =
+ (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut &&
+ bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ pCppArgs[nPos] = pCppStack + 3;
+ pUnoArgs[nPos] = pCppStack + 3;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pCppArgs[nPos] = pCppStack + 2;
+ pUnoArgs[nPos] = pCppStack + 2;
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ pCppArgs[nPos] = pCppStack;
+ pUnoArgs[nPos] = pCppStack;
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ pCppArgs[nPos] = pCppStack;
+ pUnoArgs[nPos] = pCppStack;
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *(void **)pCppStack;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *(void **)pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *(void **)pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "before dispatch\n");
+#endif
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "after dispatch\n");
+#endif
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex],
+ ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
+ pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr =
+ ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
+ cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn,
+ pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet =
+ (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ long sp, long r8,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ void ** pCallStack = (void**)(sp);
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "cpp_mediate with\n");
+ fprintf(stderr, "%x %x\n", nFunctionIndex, nVtableOffset);
+ fprintf(stderr, "and %x %x\n", pCallStack, pRegisterReturn);
+ fprintf(stderr, "and %x %x\n", pCallStack[0], pCallStack[1]);
+#endif
+ static_assert( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
+
+ void *pThis = pCallStack[0];
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ assert(nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex);
+ sal_Int32 nMemberPos =
+ pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
+ nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ r8, pCallStack, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ r8, pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET(&pTD,
+ reinterpret_cast<Type *>(pCallStack[1])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( r8 ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = (void*)r8;
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ r8, pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+
+ return eRet;
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+
+extern "C" sal_Int64 cpp_vtable_call( long firstonstack )
+{
+ register long d0 asm("d0");
+ long functionIndex = d0;
+
+ register long a1 asm("a1");
+ long r8 = a1;
+
+ register long d1 asm("d1");
+ long vtableOffset = d1;
+
+ long sp = (long)&firstonstack;
+
+ sal_Int64 nRegReturn;
+ cpp_mediate( functionIndex, vtableOffset, sp, r8, &nRegReturn );
+ return nRegReturn;
+}
+
+namespace
+{
+ const int codeSnippetSize = 20;
+
+ //some m68k info: http://www2.biglobe.ne.jp/~inaba/trampolines.html
+
+ unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
+ sal_Int32 vtableOffset)
+ {
+ unsigned char * p = code;
+ *(short *)&p[0] = 0x203C; //movel functionIndex,d0
+ *(long *)&p[2] = functionIndex;
+ *(short *)&p[6] = 0x223C; //movel functionIndex,d1
+ *(long *)&p[8] = vtableOffset;
+ *(short *)&p[12] = 0x4EF9; //jmp cpp_vtable_call
+ *(long *)&p[14] = (long)&cpp_vtable_call;
+ *(short *)&p[18] = 0x4E71; //nop
+ return code + codeSnippetSize;
+ }
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset);
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset);
+ }
+ break;
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ (s++)->fn = code + writetoexecdiff;
+
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(member);
+
+ code = codeSnippet(code, functionOffset++, vtableOffset);
+ break;
+ }
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const * /*beg*/, unsigned char const * /*end*/)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_m68k/except.cxx b/bridges/source/cpp_uno/gcc3_linux_m68k/except.cxx
new file mode 100644
index 0000000000..047022f245
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_m68k/except.cxx
@@ -0,0 +1,297 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+extern sal_Int32 * pHack;
+extern sal_Int32 nHack;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ void dummy_can_throw_anything( char const * )
+ {
+ }
+
+ static OUString toUNOname( char const * p )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+ }
+
+ class RTTI
+ {
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+ public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI(typelib_CompoundTypeDescription *);
+ };
+
+ RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+ {
+ }
+
+ RTTI::~RTTI()
+ {
+ dlclose( m_hApp );
+ }
+
+
+ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+ {
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+ }
+
+
+ static void deleteException( void * pExc )
+ {
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+ }
+
+ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+ }
+
+ static void* getAdjustedPtr(__cxa_exception* header)
+ {
+ return header->adjustedPtr;
+ }
+
+ void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+ {
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE( OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, getAdjustedPtr(header), pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_m68k/share.hxx b/bridges/source/cpp_uno/gcc3_linux_m68k/share.hxx
new file mode 100644
index 0000000000..55bc7e9185
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_m68k/share.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_m68k/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_m68k/uno2cpp.cxx
new file mode 100644
index 0000000000..de3aaf1985
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_m68k/uno2cpp.cxx
@@ -0,0 +1,497 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "share.hxx"
+
+#include <exception>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+using namespace ::com::sun::star::uno;
+
+void MapReturn(long d0, long d1, typelib_TypeClass eReturnType, long *pRegisterReturn)
+{
+ register float fret asm("fp0");
+ register double dret asm("fp0");
+
+ switch( eReturnType )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pRegisterReturn[1] = d1;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ pRegisterReturn[0] = d0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = fret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = dret;
+ break;
+ default:
+ break;
+ }
+}
+
+namespace
+{
+
+void callVirtualMethod(
+ void * pThis,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+ sal_uInt32 *pStack,
+ sal_uInt32 nStack) __attribute__((noinline));
+
+void callVirtualMethod(
+ void * pThis,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+ sal_uInt32 *pStack,
+ sal_uInt32 nStack)
+{
+ // never called
+ if (! pThis)
+ CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+ if ( nStack )
+ {
+ // m68k stack is either 2 or 4 bytes aligned, doesn't really matter as
+ // we deal in 4 byte units anyway
+ sal_uInt32 nStackBytes = nStack * sizeof(sal_uInt32);
+ sal_uInt32 *stack = (sal_uInt32 *) __builtin_alloca( nStackBytes );
+ memcpy( stack, pStack, nStackBytes );
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "\nStack (%d): ", nStack );
+ for ( unsigned int i = 0; i < nStack; ++i )
+ fprintf( stderr, "0x%lx, ", pStack[i] );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
+ }
+#endif
+
+ sal_uInt32 pMethod = *((sal_uInt32*)pThis);
+ pMethod += 4 * nVtableIndex;
+ pMethod = *((sal_uInt32 *)pMethod);
+
+ typedef long (*FunctionCall )();
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ //stick the return area into r8 for big struct returning
+ asm volatile("movel %0,%%a1" : : "m"(pRegisterReturn) : );
+
+ long d0 = (*pFunc)();
+
+ register long d1 asm("d1");
+
+ MapReturn(d0, d1, eReturnType, (long*)pRegisterReturn);
+}
+}
+
+#define INSERT_INT32( pSV, pDS )\
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT64( pSV, pDS )\
+ INSERT_INT32( pSV, pDS ) \
+ INSERT_INT32( ((sal_uInt32*)pSV)+1, pDS )
+
+#define INSERT_FLOAT( pSV, pDS ) \
+ INSERT_INT32( pSV, pDS )
+
+#define INSERT_DOUBLE( pSV, pDS ) \
+ INSERT_INT64( pSV, pDS )
+
+#define INSERT_INT16( pSV, pDS ) \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, pDS ) \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+namespace {
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
+ sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
+ sal_uInt32 * pStackStart = pStack;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? __builtin_alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+
+// INSERT_INT32( &pCppReturn, pStack );
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ INSERT_INT32( &pAdjustedThisPtr, pStack );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+// uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos],
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
+ pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "hyper is %lx\n", pCppArgs[nPos]);
+#endif
+ INSERT_INT64( pCppArgs[nPos], pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
+#endif
+ INSERT_INT32( pCppArgs[nPos], pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], pStack );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], pStack );
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT32( &(pCppArgs[nPos]), pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr->eTypeClass,
+ pStackStart,
+ (pStack - pStackStart));
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
+ (pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1;
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // determine vtable call index
+ sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
+ (pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx
new file mode 100644
index 0000000000..21ec313942
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx
@@ -0,0 +1,813 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include <osl/endian.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+using namespace com::sun::star::uno;
+
+//#define BRDEBUG
+
+#ifdef BRDEBUG
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+using namespace ::std;
+using namespace ::osl;
+using namespace ::rtl;
+#endif
+
+#ifndef ANDROID
+#include <sys/sysmips.h>
+#endif
+
+#ifdef ANDROID
+#include <unistd.h>
+#endif
+
+#ifdef OSL_BIGENDIAN
+#define IS_BIG_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 0
+#endif
+
+namespace
+{
+
+ static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** /*fpreg*/, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ /* Most MIPS ABIs view the arguments as a struct, of which the
+ first N words go in registers and the rest go on the stack. If I < N, the
+ Ith word might go in Ith integer argument register or the Ith
+ floating-point one. For these ABIs, we only need to remember the number
+ of words passed so far. We are interested only in o32 ABI,so it is the
+ case.
+ */
+ int nw = 0; // number of words used by arguments
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call1\n");
+#endif
+
+ /* C++ has [ret *] or this as the first arguments, so no arguments will
+ * be passed in floating-point registers?
+ */
+ //int int_seen = 0; // have we seen integer arguments?
+
+ void ** pCppStack; //temporary stack pointer
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:simplereturn\n");
+#endif
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ nw++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:complexreturn\n");
+#endif
+ }
+ }
+
+ // pop this
+ gpreg++;
+ nw++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:nParams=%d\n",nParams);
+#endif
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ // value
+ {
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:hyper=%d,%p\n",pParamTypeDescr->eTypeClass,gpreg[0]);
+#endif
+ if (nw < 3) {
+ if (nw & 1) {
+ nw++;
+ gpreg++;
+ }
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:gpreg=%p,%p\n",gpreg[0],gpreg[1]);
+#endif
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ nw += 2;
+ gpreg += 2;
+ } else {
+ if (((long)ovrflw) & 4) ovrflw++;
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:overflw=%p,%p\n",ovrflw[0],ovrflw[1]);
+#endif
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw += 2;
+ }
+ break;
+
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:byte=%p,%p\n",gpreg[0],ovrflw[0]);
+#endif
+ if (nw < 4) {
+ pCppArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
+ pUnoArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
+ nw++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
+ pUnoArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
+ ovrflw++;
+ }
+ break;
+
+
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:char=%p,%p\n",gpreg[0],ovrflw[0]);
+#endif
+ if (nw < 4) {
+ pCppArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
+ pUnoArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
+ nw++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
+ pUnoArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
+ ovrflw++;
+ }
+ break;
+
+
+ default:
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:def=%p,%p\n",gpreg[0],ovrflw[0]);
+#endif
+ if (nw < 4) {
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ nw++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:ptr|ref\n");
+#endif
+ if (nw < 4) {
+ pCppArgs[nPos] = *(void **)gpreg;
+ pCppStack = gpreg;
+ nw++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = *(void **)ovrflw;
+ pCppStack = ovrflw;
+ ovrflw++;
+ }
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:pCppStack=%p\n",pCppStack);
+#endif
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *(void **)pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",*(void**)pCppStack,pParamTypeDescr->nSize,nPos,pUnoArgs[nPos]);
+#endif
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *(void **)pCppStack;
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:direct,pUnoArgs[%d]=%p\n",nPos,pUnoArgs[nPos]);
+#endif
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call2,%p,unoargs=%p\n",pThis->getUnoI()->pDispatcher,pUnoArgs);
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call2,after dispatch\n");
+#endif
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+ {
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate1 gp=%p,fp=%p,ov=%p\n",gpreg,fpreg,ovrflw);
+ fprintf(stderr,"gp=%p,%p,%p,%p\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
+#endif
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate12,pThis=%p, nFunctionIndex=%d,nVtableOffset=%d\n",pThis,nFunctionIndex,nVtableOffset);
+#endif
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate13,pCppI=%p\n",pCppI);
+#endif
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate2\n");
+#endif
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate3\n");
+ OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
+#endif
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate4\n");
+#endif
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate5\n");
+#endif
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate51\n");
+#endif
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate52\n");
+#endif
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp_mediate6\n");
+#endif
+ throw RuntimeException( "no member description found!", (XInterface *)pThis );
+ }
+ }
+
+ return eRet;
+ }
+
+ /**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+// static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw)
+// static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** ovrflw)
+ static void cpp_vtable_call()
+ {
+ int nFunctionIndex;
+ int vTableOffset;
+ void** pCallStack;
+ void** ovrflw;
+
+ sal_Int32 gpreg[4];
+ double fpreg[2];
+
+ //memcpy( fpreg, fpregptr, 16);
+
+ volatile long nRegReturn[2];
+
+ __asm__( "sw $4, %0\n\t"
+ "sw $5, %1\n\t"
+ "sw $6, %2\n\t"
+ "sw $7, %3\n\t"
+ ::"m"(nFunctionIndex), "m"(vTableOffset), "m"(pCallStack), "m"(ovrflw) );
+
+ memcpy( gpreg, pCallStack, 16);
+
+#ifdef BRDEBUG
+ fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %d\n",nFunctionIndex);
+ fprintf(stderr,"in cpp_vtable_call nVtableOffset is %d\n",vTableOffset);
+ fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
+#endif
+
+ //sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False;
+
+ typelib_TypeClass aType =
+ cpp_mediate( nFunctionIndex, vTableOffset, (void**)gpreg, (void**)fpreg, ovrflw, (sal_Int64*)nRegReturn );
+
+ switch( aType )
+ {
+
+ // move return value into register space
+ // (will be loaded by machine code snippet)
+
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ __asm__( "lbu $2,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ __asm__( "lhu $2,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+
+ case typelib_TypeClass_SHORT:
+ __asm__( "lh $2,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+
+
+ case typelib_TypeClass_FLOAT:
+ __asm__( "lwc1 $f0,%0\n\t" : :
+ "m" (*((float*)nRegReturn)) );
+ break;
+
+ case typelib_TypeClass_DOUBLE:
+ { register double dret asm("$f0");
+ dret = (*((double*)nRegReturn));
+ (void) dret;
+ }
+ break;
+
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ __asm__( "lw $3,%0\n\t" : :
+ "m"(nRegReturn[1]) ); // fall through
+
+ default:
+ __asm__( "lw $2,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+ }
+ }
+
+
+ int const codeSnippetSize = 56;
+
+ unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool simpleRetType)
+ {
+
+#ifdef BRDEBUG
+ fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex);
+ fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset);
+ fflush(stderr);
+#endif
+
+ if (! simpleRetType )
+ functionIndex |= 0x80000000;
+
+ unsigned long * p = (unsigned long *) code;
+
+ // static_assert( sizeof (long) == 4 );
+ assert((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake
+
+ /* generate this code */
+ /*
+ #save regs into argument space required by mips abi
+ c: afa40000 sw a0,0(sp)
+ 10: afa50004 sw a1,4(sp)
+ 14: afa60008 sw a2,8(sp)
+ 18: afa7000c sw a3,12(sp)
+ #a0=index
+ 1c: 3c040000 lui a0,0x0
+ 20: 34840000 ori a0,a0,0x0
+ #a1=offset
+ 24: 3c050000 lui a1,0x0
+ 28: 34a50000 ori a1,a1,0x0
+ #a2=gpregptr
+ 2c: 27a60000 addiu a2,sp,0
+ #a3=ovrflw
+ 30: 27a70010 addiu a3,sp,16
+ #load cpp_vtable_call addr
+ 34: 3c190000 lui t9,0x0
+ 38: 37390000 ori t9,t9,0
+ #jmp to the function,note: we don't use jalr, that will destroy $ra
+ #but be sure to use t9! gp calculation depends on it
+ 3c: 03200008 jr t9
+ 40: 00000000 nop
+
+ be careful, we use the argument space reserved by the caller to
+ write down regs. This can avoid the need to make use of arbitrary far away
+ stack space or to allocate a function frame for this code snippet itself.
+ Since only functions with variable arguments will overwrite the space,
+ cpp_vtable_call should be safe.
+ ??? gcc seems change this behavior! cpp_vtable_call overwrite the space!
+ */
+
+ * p++ = 0xafa40000;
+ * p++ = 0xafa50004;
+ * p++ = 0xafa60008;
+ * p++ = 0xafa7000c;
+ * p++ = 0x3c040000 | ((functionIndex>>16) & 0x0000ffff);
+ * p++ = 0x34840000 | (functionIndex & 0x0000ffff);
+ * p++ = 0x3c050000 | ((vtableOffset>>16) & 0x0000ffff);
+ * p++ = 0x34a50000 | (vtableOffset & 0x0000ffff);
+ * p++ = 0x27a60000;
+ * p++ = 0x27a70010;
+ * p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff);
+ * p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF);
+ * p++ = 0x03200008;
+ * p++ = 0x00000000;
+ return (code + codeSnippetSize);
+
+ }
+
+
+}
+
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *bptr, unsigned char const *eptr)
+{
+#ifndef ANDROID
+ (void) bptr;
+ (void) eptr;
+ sysmips(FLUSH_CACHE,0,0,0);
+#else
+ cacheflush((long) bptr, (long) eptr, 0);
+#endif
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+#ifdef BRDEBUG
+ fprintf(stderr, "in addLocalFunctions functionOffset is %d\n",functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n",vtableOffset);
+ fprintf(stderr, "nMembers=%d\n",type->nMembers);
+ fflush(stderr);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, true);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx
new file mode 100644
index 0000000000..68e4e25f69
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips/except.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if defined BRIDGES_DEBUG
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if defined BRIDGES_DEBUG
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if defined BRIDGES_DEBUG
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if defined BRIDGES_DEBUG
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE( OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx b/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx
new file mode 100644
index 0000000000..55bc7e9185
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips/share.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx
new file mode 100644
index 0000000000..532e9d0d69
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx
@@ -0,0 +1,602 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+//#define BRDEBUG
+#ifdef BRDEBUG
+#include <stdio.h>
+#endif
+
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+
+ static void callVirtualMethod(
+ void * pAdjustedThisPtr,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+ char * pPT,
+ sal_Int32 * pStackLongs,
+ sal_Int32 /*nStackLongs*/)
+ {
+
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ unsigned long * mfunc; // actual function to be invoked
+ void (*ptr)();
+ int gpr[4]; // storage for gpregisters, map to a0-a3
+ int off; // offset used to find function
+ int nw; // number of words mapped
+ long *p; // pointer to parameter overflow area
+ int iret, iret2; // temporary function return values
+
+ // never called
+ if (! pAdjustedThisPtr ) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+#ifdef BRDEBUG
+ fprintf(stderr,"in CallVirtualMethod\n");
+#endif
+
+ // Because of the MIPS O32 calling conventions we could be passing
+ // parameters in both register types and on the stack. To create the
+ // stack parameter area we need we now simply allocate local
+ // variable storage param[] that is at least the size of the parameter stack
+ // (more than enough space) which we can overwrite the parameters into.
+
+ /* p = sp - 512; new sp will be p - 16, but we don't change sp
+ * at this time to avoid breaking ABI--not sure whether changing sp will break
+ * references to local variables. For the same reason, we use absolute value.
+ */
+ __asm__ __volatile__ (
+ "addiu $2,$29,-512\n\t"
+ "move %0,$2\n\t"
+ :"=r"(p): : "$2","$29" );
+
+#ifdef BRDEBUG
+ if (nStackLongs * 4 > 512 )
+ fprintf(stderr,"too many arguments");
+#endif
+
+ // now begin to load the C++ function arguments into storage
+ nw = 0;
+
+ // now we need to parse the entire signature string */
+ // until we get the END indicator */
+
+ // treat complex return pointer like any other parameter
+
+#ifdef BRDEBUG
+ fprintf(stderr,"overflow area pointer p=%p\n",p);
+
+ /* Let's figure out what is really going on here*/
+ fprintf(stderr,"callVirtualMethod parameters string is %s\n",pPT);
+ int k = nStackLongs;
+ long * q = (long *)pStackLongs;
+ while (k > 0) {
+ fprintf(stderr,"uno stack is: %x\n",(unsigned int)*q);
+ k--;
+ q++;
+ }
+#endif
+
+ /* parse the argument list up to the ending ) */
+ while (*pPT != 'X') {
+ int c = *pPT; // character of parameter type being decoded
+ switch (c) {
+ case 'D': /* type is double */
+ /* treat the same as long long */
+ case 'H': /* type is long long */
+ if (nw & 1) nw++; /* note even elements gpr[] will map to
+ odd registers*/
+ if (nw < 4) {
+ gpr[nw++] = *pStackLongs;
+ gpr[nw++] = *(pStackLongs+1);
+ } else {
+ if (((long) p) & 4)
+ p++;
+ *p++ = *pStackLongs;
+ *p++ = *(pStackLongs+1);
+ }
+ pStackLongs += 2;
+ break;
+
+ case 'S':
+ if (nw < 4) {
+ gpr[nw++] = *((unsigned short*)pStackLongs);
+ } else {
+ *p++ = *((unsigned short *)pStackLongs);
+ }
+ pStackLongs += 1;
+ break;
+
+ case 'B':
+ if (nw < 4) {
+ gpr[nw++] = *((char *)pStackLongs);
+ } else {
+ *p++ = *((char *)pStackLongs);
+ }
+ pStackLongs += 1;
+ break;
+
+ default:
+ if (nw < 4) {
+ gpr[nw++] = *pStackLongs;
+ } else {
+ *p++ = *pStackLongs;
+ }
+ pStackLongs += 1;
+ break;
+ }
+ pPT++;
+ }
+
+ /* figure out the address of the function we need to invoke */
+ off = nVtableIndex;
+ off = off * 4; // 4 bytes per slot
+ mfunc = *((unsigned long **)pAdjustedThisPtr); // get the address of the vtable
+ mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset
+ mfunc = *((unsigned long **)mfunc); // the function is stored at the address
+ ptr = (void (*)())mfunc;
+
+#ifdef BRDEBUG
+ fprintf(stderr,"calling function %p\n",mfunc);
+#endif
+
+ /* Set up the machine registers and invoke the function */
+
+ __asm__ __volatile__ (
+ "lw $4, 0(%0)\n\t"
+ "lw $5, 4(%0)\n\t"
+ "lw $6, 8(%0)\n\t"
+ "lw $7, 12(%0)\n\t"
+ : : "r" (gpr)
+ : "$4", "$5", "$6", "$7"
+ );
+
+ __asm__ __volatile__ ("addiu $29,$29,-528\r\n":::"$29");
+
+ (*ptr)();
+
+ __asm__ __volatile__ ("addiu $29,$29,528\r\n":::"$29");
+
+ __asm__ __volatile__ (
+ "sw $2,%0 \n\t"
+ "sw $3,%1 \n\t"
+ : "=m" (iret), "=m" (iret2) : );
+ register float fret asm("$f0");
+ register double dret asm("$f0");
+
+ switch( eReturnType )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ ((long*)pRegisterReturn)[1] = iret2; // fall through
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ ((long*)pRegisterReturn)[0] = iret;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)iret;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)iret;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = fret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = dret;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+ {
+ // max space for: [complex ret ptr], values|ptr ...
+ char * pCppStack =
+ (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
+ char * pCppStackStart = pCppStack;
+
+ // need to know parameter types for callVirtualMethod so generate a signature string
+ char * pParamType = (char *) alloca(nParams+2);
+ char * pPT = pParamType;
+
+#ifdef BRDEBUG
+ fprintf(stderr,"in cpp_call\n");
+#endif
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ // assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = *(void **)pCppStack =
+ (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way
+ *pPT++ = 'I'; //signify that a complex return type on stack
+ pCppStack += sizeof(void *);
+ }
+ }
+ // push this
+ void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset;
+ *(void**)pCppStack = pAdjustedThisPtr;
+ pCppStack += sizeof( void* );
+ *pPT++ = 'I';
+
+ // stack space
+ // static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+
+ // we need to know type of each param so that we know whether to use
+ // gpr or fpr to pass in parameters:
+ // Key: I - int, long, pointer, etc means pass in gpr
+ // B - byte value passed in gpr
+ // S - short value passed in gpr
+ // F - float value pass in fpr
+ // D - double value pass in fpr
+ // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
+ // X - indicates end of parameter description string
+
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *pPT++ = 'I';
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *pPT++ = 'S';
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *pPT++ = 'B';
+ break;
+ case typelib_TypeClass_FLOAT:
+ *pPT++ = 'F';
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *pPT++ = 'D';
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *pPT++ = 'H';
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // KBH: FIXME: is this the right way to pass these
+ *pPT++='I';
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // terminate the signature string
+ *pPT++='X';
+ *pPT=0;
+
+ try
+ {
+ assert( !( (pCppStack - pCppStackStart ) & 3) && "UNALIGNED STACK !!! (Please DO panic)" );
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr->eTypeClass, pParamType,
+ (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+ }
+
+}
+
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+ //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+#ifdef BRDEBUG
+ fprintf(stderr,"in dispatch\n");
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/call.hxx b/bridges/source/cpp_uno/gcc3_linux_mips64/call.hxx
new file mode 100644
index 0000000000..dc84d56b88
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/call.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+namespace {
+
+ extern "C" typelib_TypeClass cpp_vtable_call(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/call.s b/bridges/source/cpp_uno/gcc3_linux_mips64/call.s
new file mode 100644
index 0000000000..eb83eef463
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/call.s
@@ -0,0 +1,134 @@
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .text
+ .globl privateSnippetExecutor
+.LFB0 = .
+ .cfi_startproc
+ .cfi_personality 0x80,DW.ref.__gxx_personality_v0
+ .cfi_lsda 0,.LLSDA0
+ .ent privateSnippetExecutor
+ .type privateSnippetExecutor, @function
+privateSnippetExecutor:
+ .set noreorder
+ daddiu $sp,$sp,-160
+ .cfi_def_cfa_offset 160
+ sd $ra,152($sp)
+ .cfi_offset 31, -8
+.LEHB0 = .
+ // Save the float point registers
+ sdc1 $f12,80($sp)
+ sdc1 $f13,88($sp)
+ sdc1 $f14,96($sp)
+ sdc1 $f15,104($sp)
+ sdc1 $f16,112($sp)
+ sdc1 $f17,120($sp)
+ sdc1 $f18,128($sp)
+ sdc1 $f19,136($sp)
+ // Save the general purpose registers
+ sd $a0,16($sp)
+ sd $a1,24($sp)
+ sd $a2,32($sp)
+ sd $a3,40($sp)
+ sd $a4,48($sp)
+ sd $a5,56($sp)
+ sd $a6,64($sp)
+ sd $a7,72($sp)
+ // Load arguments
+ // a0=index
+ move $a0,$v0
+ // a1=offset
+ move $a1,$v1
+ // a2=gpregptr
+ daddiu $a2,$sp,16
+ // a3=fpregptr
+ daddiu $a3,$sp,80
+ // a4=ovrflw
+ daddiu $a4,$sp,160
+ // Call cpp_vtable_call
+ jalr $t9
+ // a5=retregptr
+ move $a5,$sp
+
+.LEHE0 = .
+ // Perform return value
+ li $v1,10
+ beq $v0,$v1,.Lfloat
+ li $v1,11
+ beq $v0,$v1,.Lfloat
+ ldc1 $f0,0($sp)
+ ldc1 $f2,8($sp)
+ ld $v0,0($sp)
+ b .Lfinish
+ ld $v1,8($sp)
+.Lfloat:
+ ldc1 $f0,0($sp)
+ ldc1 $f2,8($sp)
+
+.Lfinish:
+ ld $ra,152($sp)
+ .cfi_restore 31
+ jr $ra
+ daddiu $sp,$sp,160
+ .cfi_def_cfa_offset 0
+
+ .set reorder
+ .end privateSnippetExecutor
+ .cfi_endproc
+.LFE0:
+ .globl __gxx_personality_v0
+ .section .gcc_except_table,"aw",@progbits
+ .align 3
+.LLSDA0:
+ .byte 0xff
+ .byte 0x80
+ .uleb128 .LLSDATT0-.LLSDATTD0
+.LLSDATTD0:
+ .byte 0x1
+ .uleb128 .LLSDACSE0-.LLSDACSB0
+.LLSDACSB0:
+ .uleb128 .LEHB0-.LFB0
+ .uleb128 .LEHE0-.LEHB0
+ .uleb128 0
+ .uleb128 0
+.LLSDACSE0:
+ .byte 0x7f
+ .byte 0
+ .align 3
+ .8byte DW.ref._ZTIi
+.LLSDATT0:
+ .byte 0x1
+ .byte 0
+ .text
+ .size privateSnippetExecutor, .-privateSnippetExecutor
+ .hidden DW.ref._ZTIi
+ .weak DW.ref._ZTIi
+ .section .data.DW.ref._ZTIi,"awG",@progbits,DW.ref._ZTIi,comdat
+ .align 3
+ .type DW.ref._ZTIi, @object
+ .size DW.ref._ZTIi, 8
+DW.ref._ZTIi:
+ .dword _ZTIi
+ .hidden DW.ref.__gxx_personality_v0
+ .weak DW.ref.__gxx_personality_v0
+ .section .data.DW.ref.__gxx_personality_v0,"awG",@progbits,DW.ref.__gxx_personality_v0,comdat
+ .align 3
+ .type DW.ref.__gxx_personality_v0, @object
+ .size DW.ref.__gxx_personality_v0, 8
+DW.ref.__gxx_personality_v0:
+ .dword __gxx_personality_v0
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx
new file mode 100644
index 0000000000..7dbf0022e9
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx
@@ -0,0 +1,711 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include <osl/endian.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "call.hxx"
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+using namespace com::sun::star::uno;
+
+//#define BRDEBUG
+
+#ifdef BRDEBUG
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+using namespace ::std;
+using namespace ::osl;
+using namespace ::rtl;
+#endif
+
+#ifndef ANDROID
+#include <sys/sysmips.h>
+#endif
+
+#ifdef ANDROID
+#include <unistd.h>
+#endif
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+ }
+
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT ||
+ pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ //A Composite Type not larger than 16 bytes is returned in up to two GPRs
+ bool bRet = pTypeDescr->nSize > 16 || is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return true;
+ }
+}
+
+namespace
+{
+
+ static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+ {
+ /* Most MIPS ABIs view the arguments as a struct, of which the
+ first N words go in registers and the rest go on the stack. If I < N, the
+ With word might go in With integer argument register or the With
+ floating-point one. For these ABIs, we only need to remember the number
+ of words passed so far. We are interested only in n64 ABI,so it is the
+ case.
+ */
+ unsigned int nREG = 0;
+
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:begin\n");
+#endif
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) )
+ {
+ pCppReturn = gpreg[nREG]; // complex return via ptr (pCppReturn)
+ nREG++;
+
+ pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:complexreturn\n");
+#endif
+ }
+ else
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:simplereturn\n");
+#endif
+ }
+ }
+
+ // pop this
+ nREG++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:nParams=%d\n", nParams);
+#endif
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
+ {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:Param %u, type %u\n", nPos, pParamTypeDescr->eTypeClass);
+#endif
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nREG < MAX_FP_REGS) {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:fpr=%p\n", fpreg[nREG]);
+#endif
+ pCppArgs[nPos] = &(fpreg[nREG]);
+ pUnoArgs[nPos] = &(fpreg[nREG]);
+ } else {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:fpr=%p\n", ovrflw[nREG - MAX_FP_REGS]);
+#endif
+ pCppArgs[nPos] = &(ovrflw[nREG - MAX_FP_REGS]);
+ pUnoArgs[nPos] = &(ovrflw[nREG - MAX_FP_REGS]);
+ }
+ nREG++;
+ break;
+
+
+ default:
+ if (nREG < MAX_GP_REGS) {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:gpr=%p\n", gpreg[nREG]);
+#endif
+ pCppArgs[nPos] = &(gpreg[nREG]);
+ pUnoArgs[nPos] = &(gpreg[nREG]);
+ } else {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:gpr=%p\n", ovrflw[nREG - MAX_GP_REGS]);
+#endif
+ pCppArgs[nPos] = &(ovrflw[nREG - MAX_GP_REGS]);
+ pUnoArgs[nPos] = &(ovrflw[nREG - MAX_GP_REGS]);
+ }
+ nREG++;
+ break;
+
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+#ifdef BRDEBUG
+ fprintf(stderr,"cpp2uno_call:ptr|ref\n");
+#endif
+ void *pCppStack;
+ if (nREG < MAX_GP_REGS) {
+ pCppArgs[nPos] = pCppStack = gpreg[nREG];
+ } else {
+ pCppArgs[nPos] = pCppStack = ovrflw[nREG - MAX_GP_REGS];
+ }
+ nREG++;
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:pCppStack=%p\n", pCppStack);
+#endif
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",
+ pCppStack, pParamTypeDescr->nSize, nPos, pUnoArgs[nPos]);
+#endif
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call:direct,pUnoArgs[%d]=%p\n", nPos, pUnoArgs[nPos]);
+#endif
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call2,%p,unoargs=%p\n", pThis->getUnoI()->pDispatcher, pUnoArgs);
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp2uno_call2,after dispatch\n");
+#endif
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+ }
+
+
+ /**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+ typelib_TypeClass cpp_vtable_call(
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+ {
+ static_assert( sizeof(sal_Int64)==sizeof(void *), "### unexpected!" );
+
+#ifdef BRDEBUG
+ fprintf(stderr, "in cpp_vtable_call nFunctionIndex is %d\n", nFunctionIndex);
+ fprintf(stderr, "in cpp_vtable_call nVtableOffset is %d\n", nVtableOffset);
+ fprintf(stderr, "in cpp_vtable_call gp=%p, fp=%p, ov=%p\n", gpreg, fpreg, ovrflw);
+#endif
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call, pThis=%p, nFunctionIndex=%d, nVtableOffset=%d\n",
+ pThis, nFunctionIndex, nVtableOffset);
+#endif
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call, pCppI=%p\n", pCppI);
+#endif
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+#ifdef BRDEBUG
+ OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf(stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
+#endif
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call interface attribute\n");
+#endif
+ typelib_TypeDescriptionReference *pAttrTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
+
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call interface method\n");
+#endif
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call method acquire\n");
+#endif
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call method release\n");
+#endif
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call method query interface opt\n");
+#endif
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
+ ( pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface,
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct( reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call method query interface\n");
+#endif
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams,
+ pMethodTD->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+#ifdef BRDEBUG
+ fprintf(stderr, "cpp_vtable_call no member\n");
+#endif
+ throw RuntimeException( "no member description found!", (XInterface *)pThis );
+ }
+ }
+
+ return eRet;
+ }
+
+ extern "C" void privateSnippetExecutor( ... );
+
+ int const codeSnippetSize = 0x44;
+
+ unsigned char * codeSnippet( unsigned char * code,
+ sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool bHasHiddenParam )
+ {
+#ifdef BRDEBUG
+ fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex);
+ fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset);
+ fflush(stderr);
+#endif
+
+ if ( bHasHiddenParam )
+ functionIndex |= 0x80000000;
+
+ unsigned int * p = (unsigned int *) code;
+
+ assert((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake
+
+ /* generate this code */
+ /*
+ # index
+ 0: 3c020000 lui v0,0x0
+ 4: 34420000 ori v0,v0,0x0
+ # privateSnippetExecutor
+ 8: 3c0c0000 lui t0,0x0
+ c: 358c0000 ori t0,t0,0x0
+ 10: 000c6438 dsll t0,t0,0x10
+ 14: 358c0000 ori t0,t0,0x0
+ 18: 000c6438 dsll t0,t0,0x10
+ 1c: 358c0000 ori t0,t0,0x0
+ # cpp_vtable_call
+ 20: 3c190000 lui t9,0x0
+ 24: 37390000 ori t9,t9,0x0
+ 28: 0019cc38 dsll t9,t9,0x10
+ 2c: 37390000 ori t9,t9,0x0
+ 30: 0019cc38 dsll t9,t9,0x10
+ 34: 37390000 ori t9,t9,0x0
+ # offset
+ 38: 3c030000 lui v1,0x0
+ 3c: 01800008 jr t0
+ 40: 34630000 ori v1,v1,0x0
+ */
+
+ * p++ = 0x3c020000 | ((functionIndex>>16) & 0x0000ffff);
+ * p++ = 0x34420000 | (functionIndex & 0x0000ffff);
+ * p++ = 0x3c0c0000 | ((((unsigned long)privateSnippetExecutor) >> 48) & 0x0000ffff);
+ * p++ = 0x358c0000 | ((((unsigned long)privateSnippetExecutor) >> 32) & 0x0000ffff);
+ * p++ = 0x000c6438;
+ * p++ = 0x358c0000 | ((((unsigned long)privateSnippetExecutor) >> 16) & 0x0000ffff);
+ * p++ = 0x000c6438;
+ * p++ = 0x358c0000 | (((unsigned long)privateSnippetExecutor) & 0x0000ffff);
+ * p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 48) & 0x0000ffff);
+ * p++ = 0x37390000 | ((((unsigned long)cpp_vtable_call) >> 32) & 0x0000ffff);
+ * p++ = 0x0019cc38;
+ * p++ = 0x37390000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff);
+ * p++ = 0x0019cc38;
+ * p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000ffff);
+ * p++ = 0x3c030000 | ((vtableOffset>>16) & 0x0000ffff);
+ * p++ = 0x01800008;
+ * p++ = 0x34630000 | (vtableOffset & 0x0000ffff);
+ return (code + codeSnippetSize);
+
+ }
+
+}
+
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *bptr, unsigned char const *eptr)
+{
+#ifndef ANDROID
+ (void) bptr;
+ (void) eptr;
+ sysmips(FLUSH_CACHE, 0, 0, 0);
+#else
+ cacheflush((long) bptr, (long) eptr, 0);
+#endif
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+
+#ifdef BRDEBUG
+ fprintf(stderr, "in addLocalFunctions functionOffset is %d\n", functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n", vtableOffset);
+ fprintf(stderr, "nMembers=%d\n", type->nMembers);
+ fflush(stderr);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_mips64/except.cxx
new file mode 100644
index 0000000000..4e8ab0f2e4
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/except.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if defined BRIDGES_DEBUG
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if defined BRIDGES_DEBUG
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+ SAL_INFO("bridges", "generated rtti for " << rttiName);
+
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if defined BRIDGES_DEBUG
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE( OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_mips64/share.hxx
new file mode 100644
index 0000000000..ee2235e4fc
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/share.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+#define MAX_GP_REGS (8)
+#define MAX_FP_REGS (8)
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_mips64/uno2cpp.cxx
new file mode 100644
index 0000000000..cb0661e7fd
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_mips64/uno2cpp.cxx
@@ -0,0 +1,592 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <cstring>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+//#define BRDEBUG
+#ifdef BRDEBUG
+#include <stdio.h>
+#endif
+
+#define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
+ if ( nr < MAX_FP_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+ if ( nr < MAX_GP_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int64 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ if ( nr < MAX_GP_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int32 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < MAX_GP_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int16 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int16 *>( pSV );
+
+#define INSERT_UINT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < MAX_GP_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+ if ( nr < MAX_GP_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int8 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int8 *>( pSV );
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+ bool isReturnInFPR(const typelib_TypeDescription * pTypeDescr, sal_uInt32 & nSize)
+ {
+ const typelib_CompoundTypeDescription *p =
+ reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
+
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ typelib_TypeDescriptionReference *pTypeInStruct = p->ppTypeRefs[ i ];
+
+ switch (pTypeInStruct->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, pTypeInStruct);
+ bool isFPR = isReturnInFPR(t, nSize);
+ TYPELIB_DANGER_RELEASE(t);
+ if (!isFPR)
+ return false;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nSize >= 16)
+ return false;
+ nSize += 8;
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void fillReturn(const typelib_TypeDescription * pTypeDescr,
+ sal_Int64 * gret, double * fret, void * pRegisterReturn)
+ {
+ sal_uInt32 nSize = 0;
+ if (isReturnInFPR(pTypeDescr, nSize))
+ {
+ reinterpret_cast<double *>( pRegisterReturn )[0] = fret[0];
+ reinterpret_cast<double *>( pRegisterReturn )[1] = fret[1];
+ }
+ else
+ {
+ reinterpret_cast<sal_Int64 *>( pRegisterReturn )[0] = gret[0];
+ reinterpret_cast<sal_Int64 *>( pRegisterReturn )[1] = gret[1];
+ }
+ }
+
+ static void callVirtualMethod(
+ void * pAdjustedThisPtr,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ bool bSimpleReturn,
+ sal_uInt64 *pStack,
+ sal_uInt32 nStack,
+ sal_uInt64 *pGPR,
+ double *pFPR,
+ sal_uInt32 nREG)
+ {
+ // Should not happen, but...
+ static_assert(MAX_GP_REGS == MAX_FP_REGS, "must be the same size");
+ if ( nREG > MAX_GP_REGS )
+ nREG = MAX_GP_REGS;
+
+ // Get pointer to method
+ sal_uInt64 pMethod = *((sal_uInt64 *)pAdjustedThisPtr);
+ pMethod += 8 * nVtableIndex;
+ void *mfunc = (void *) *((sal_uInt64 *)pMethod);
+#ifdef BRDEBUG
+ fprintf(stderr, "calling function %p\n", mfunc);
+#endif
+
+ // Load parameters to stack, if necessary
+ sal_uInt64* pCallStack = NULL;
+ if ( nStack )
+ {
+ // 16-bytes aligned
+ sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16;
+ pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes );
+ std::memcpy( pCallStack, pStack, nStackBytes );
+ }
+
+ sal_Int64 gret[2];
+ double fret[2];
+ asm volatile (
+ ".set push \n\t"
+ ".set mips64 \n\t"
+ // Fill the general purpose registers
+ "ld $4, 0(%[gpr]) \n\t"
+ "ld $5, 8(%[gpr]) \n\t"
+ "ld $6, 16(%[gpr]) \n\t"
+ "ld $7, 24(%[gpr]) \n\t"
+ "ld $8, 32(%[gpr]) \n\t"
+ "ld $9, 40(%[gpr]) \n\t"
+ "ld $10, 48(%[gpr]) \n\t"
+ "ld $11, 56(%[gpr]) \n\t"
+ // Fill the floating pointer registers
+ "ldc1 $f12, 0(%[fpr]) \n\t"
+ "ldc1 $f13, 8(%[fpr]) \n\t"
+ "ldc1 $f14, 16(%[fpr]) \n\t"
+ "ldc1 $f15, 24(%[fpr]) \n\t"
+ "ldc1 $f16, 32(%[fpr]) \n\t"
+ "ldc1 $f17, 40(%[fpr]) \n\t"
+ "ldc1 $f18, 48(%[fpr]) \n\t"
+ "ldc1 $f19, 56(%[fpr]) \n\t"
+ // Perform the call
+ "jalr %[mfunc] \n\t"
+ // Fill the return values
+ "move %[gret1], $2 \n\t"
+ "move %[gret2], $3 \n\t"
+ "mov.d %[fret1], $f0 \n\t"
+ "mov.d %[fret2], $f2 \n\t"
+ ".set pop \n\t"
+ :[gret1]"=r"(gret[0]), [gret2]"=r"(gret[1]),
+ [fret1]"=f"(fret[0]), [fret2]"=f"(fret[1])
+ :[gpr]"r"(pGPR), [fpr]"r"(pFPR), [mfunc]"c"(mfunc),
+ [stack]"m"(pCallStack) // dummy input to prevent the compiler from optimizing the alloca out
+ :"$2", "$3", "$4", "$5", "$6", "$7", "$8",
+ "$9", "$10", "$11", "$31",
+ "$f0", "$f2", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "memory"
+ );
+
+ switch (pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<sal_Int64 *>( pRegisterReturn ) = gret[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double *>( pRegisterReturn ) = fret[0];
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+ if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pReturnTypeRef );
+ fillReturn(pTypeDescr, gret, fret, pRegisterReturn);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ }
+ default:
+#ifdef BRDEBUG
+ fprintf(stderr,"unhandled return type %u\n", pReturnTypeRef->eTypeClass);
+#endif
+ break;
+ }
+ }
+
+
+ static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+ {
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( ((nParams+3) * sizeof(sal_Int64)) );
+ sal_uInt64 *pStackStart = pStack;
+
+ sal_uInt64 pGPR[MAX_GP_REGS];
+ double pFPR[MAX_FP_REGS];
+ sal_uInt32 nREG = 0;
+
+#ifdef BRDEBUG
+ fprintf(stderr, "in cpp_call\n");
+#endif
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ bool bSimpleReturn = true;
+ if (pReturnTypeDescr)
+ {
+ if ( CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) )
+ {
+ bSimpleReturn = false;
+ // complex return via ptr
+ pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
+ __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
+ INSERT_INT64( &pCppReturn, nREG, pGPR, pStack );
+ }
+ else
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ }
+
+ // push this
+ void* pAdjustedThisPtr = reinterpret_cast< void **>( pThis->getCppI() ) + aVtableSlot.offset;
+ INSERT_INT64( &pAdjustedThisPtr, nREG, pGPR, pStack );
+
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nREG, pGPR, pStack );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nREG, pGPR, pStack );
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_UINT16( pCppArgs[nPos], nREG, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nREG, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nREG, pFPR, pStack );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nREG, pGPR, pStack );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nREG, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeRef, bSimpleReturn,
+ pStackStart, ( pStack - pStackStart ),
+ pGPR, pFPR, nREG);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+ }
+
+}
+
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+ //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+#ifdef BRDEBUG
+ fprintf(stderr, "in dispatch\n");
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx
new file mode 100644
index 0000000000..328fb7a17e
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx
@@ -0,0 +1,792 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ int ng = 0; //number of gpr registers used
+#ifndef __NO_FPRS__
+ int nf = 0; //number of fpr registers used
+#endif
+ void ** pCppStack; //temporary stack pointer
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ ng++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ gpreg++;
+ ng++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ // value
+ {
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+
+ case typelib_TypeClass_DOUBLE:
+#ifndef __NO_FPRS__
+ if (nf < 8) {
+ pCppArgs[nPos] = fpreg;
+ pUnoArgs[nPos] = fpreg;
+ nf++;
+ fpreg += 2;
+#else
+ if (ng & 1) {
+ ng++;
+ gpreg++;
+ }
+ if (ng < 8) {
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ ng += 2;
+ gpreg += 2;
+#endif
+ } else {
+ if (((long)ovrflw) & 4) ovrflw++;
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw += 2;
+ }
+ break;
+
+ case typelib_TypeClass_FLOAT:
+ // fpreg are all double values so need to
+ // modify fpreg to be a single word float value
+#ifndef __NO_FPRS__
+ if (nf < 8) {
+ float tmp = (float) (*((double *)fpreg));
+ (*((float *) fpreg)) = tmp;
+ pCppArgs[nPos] = fpreg;
+ pUnoArgs[nPos] = fpreg;
+ nf++;
+ fpreg += 2;
+#else
+ if (ng < 8) {
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ ng++;
+ gpreg++;
+#endif
+ } else {
+#if 0 /* abi is not being followed correctly */
+ if (((long)ovrflw) & 4) ovrflw++;
+ float tmp = (float) (*((double *)ovrflw));
+ (*((float *) ovrflw)) = tmp;
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw += 2;
+#else
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw += 1;
+#endif
+ }
+ break;
+
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (ng & 1) {
+ ng++;
+ gpreg++;
+ }
+ if (ng < 8) {
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ ng += 2;
+ gpreg += 2;
+ } else {
+ if (((long)ovrflw) & 4) ovrflw++;
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw += 2;
+ }
+ break;
+
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ if (ng < 8) {
+ pCppArgs[nPos] = (((char *)gpreg) + 3);
+ pUnoArgs[nPos] = (((char *)gpreg) + 3);
+ ng++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = (((char *)ovrflw) + 3);
+ pUnoArgs[nPos] = (((char *)ovrflw) + 3);
+ ovrflw++;
+ }
+ break;
+
+
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (ng < 8) {
+ pCppArgs[nPos] = (((char *)gpreg)+ 2);
+ pUnoArgs[nPos] = (((char *)gpreg)+ 2);
+ ng++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = (((char *)ovrflw) + 2);
+ pUnoArgs[nPos] = (((char *)ovrflw) + 2);
+ ovrflw++;
+ }
+ break;
+
+
+ default:
+ if (ng < 8) {
+ pCppArgs[nPos] = gpreg;
+ pUnoArgs[nPos] = gpreg;
+ ng++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = ovrflw;
+ pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+
+ if (ng < 8) {
+ pCppArgs[nPos] = *(void **)gpreg;
+ pCppStack = gpreg;
+ ng++;
+ gpreg++;
+ } else {
+ pCppArgs[nPos] = *(void **)ovrflw;
+ pCppStack = ovrflw;
+ ovrflw++;
+ }
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *(void **)pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *(void **)pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pThis );
+ }
+ }
+
+ return eRet;
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw)
+{
+ sal_Int32 gpreg[8];
+ memcpy( gpreg, gpregptr, 32);
+
+#ifndef __NO_FPRS__
+ double fpreg[8];
+ memcpy( fpreg, fpregptr, 64);
+#endif
+
+ volatile long nRegReturn[2];
+
+ // fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %x\n",nFunctionIndex);
+ // fprintf(stderr,"in cpp_vtable_call nVtableOffset is %x\n",nVtableOffset);
+ // fflush(stderr);
+
+ typelib_TypeClass aType =
+ cpp_mediate( nFunctionIndex, nVtableOffset, (void**)gpreg,
+#ifndef __NO_FPRS__
+ (void**)fpreg,
+#else
+ NULL,
+#endif
+ ovrflw, (sal_Int64*)nRegReturn );
+
+ switch( aType )
+ {
+
+ // move return value into register space
+ // (will be loaded by machine code snippet)
+
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ __asm__( "lbz 3,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ __asm__( "lhz 3,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+
+ case typelib_TypeClass_FLOAT:
+#ifndef __NO_FPRS__
+ __asm__( "lfs 1,%0\n\t" : :
+ "m" (*((float*)nRegReturn)) );
+ #else
+ __asm__( "lwz 3,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+#endif
+ break;
+
+ case typelib_TypeClass_DOUBLE:
+#ifndef __NO_FPRS__
+ __asm__( "lfd 1,%0\n\t" : :
+ "m" (*((double*)nRegReturn)) );
+#else
+ __asm__( "lwz 3,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ __asm__( "lwz 4,%0\n\t" : :
+ "m"(nRegReturn[1]) );
+#endif
+ break;
+
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ __asm__( "lwz 4,%0\n\t" : :
+ "m"(nRegReturn[1]) ); // fall through
+
+ default:
+ __asm__( "lwz 3,%0\n\t" : :
+ "m"(nRegReturn[0]) );
+ break;
+ }
+}
+
+
+int const codeSnippetSize = 108;
+
+unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool simpleRetType)
+{
+
+ // fprintf(stderr,"in codeSnippet functionIndex is %x\n", functionIndex);
+ // fprintf(stderr,"in codeSnippet vtableOffset is %x\n", vtableOffset);
+ // fflush(stderr);
+
+ if (! simpleRetType )
+ functionIndex |= 0x80000000;
+
+ unsigned long * p = (unsigned long *) code;
+
+ // static_assert( sizeof (long) == 4 );
+ assert((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake
+
+ /* generate this code */
+ // # so first save gpr 3 to gpr 10 (aligned to 4)
+ // stw r3,-2048(r1)
+ // stw r4,-2044(r1)
+ // stw r5,-2040(r1)
+ // stw r6,-2036(r1)
+ // stw r7,-2032(r1)
+ // stw r8,-2028(r1)
+ // stw r9,-2024(r1)
+ // stw r10,-2020(r1)
+
+
+ // # next save fpr 1 to fpr 8 (aligned to 8)
+ // if dedicated floating point registers are used
+ // stfd f1,-2016(r1)
+ // stfd f2,-2008(r1)
+ // stfd f3,-2000(r1)
+ // stfd f4,-1992(r1)
+ // stfd f5,-1984(r1)
+ // stfd f6,-1976(r1)
+ // stfd f7,-1968(r1)
+ // stfd f8,-1960(r1)
+
+ // # now here is where cpp_vtable_call must go
+ // lis r3,-8531
+ // ori r3,r3,48879
+ // mtctr r3
+
+ // # now load up the functionIndex
+ // lis r3,-8531
+ // ori r3,r3,48879
+
+ // # now load up the vtableOffset
+ // lis r4,-8531
+ // ori r4,r4,48879
+
+ // #now load up the pointer to the saved gpr registers
+ // addi r5,r1,-2048
+
+ // #now load up the pointer to the saved fpr registers
+ // addi r6,r1,-2016
+ // if no dedicated floating point registers are used then we have NULL
+ // pointer there
+ // li r6, 0
+
+ // #now load up the pointer to the overflow call stack
+ // addi r7,r1,8
+ // bctr
+
+ * p++ = 0x9061f800;
+ * p++ = 0x9081f804;
+ * p++ = 0x90a1f808;
+ * p++ = 0x90c1f80c;
+ * p++ = 0x90e1f810;
+ * p++ = 0x9101f814;
+ * p++ = 0x9121f818;
+ * p++ = 0x9141f81c;
+#ifndef __NO_FPRS__
+ * p++ = 0xd821f820;
+ * p++ = 0xd841f828;
+ * p++ = 0xd861f830;
+ * p++ = 0xd881f838;
+ * p++ = 0xd8a1f840;
+ * p++ = 0xd8c1f848;
+ * p++ = 0xd8e1f850;
+ * p++ = 0xd901f858;
+#else
+ /* these nops could be replaced with a smaller codeSnippetSize - 8 * 4 */
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+ * p++ = 0x60000000;
+#endif
+ * p++ = 0x3c600000 | (((unsigned long)cpp_vtable_call) >> 16);
+ * p++ = 0x60630000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF);
+ * p++ = 0x7c6903a6;
+ * p++ = 0x3c600000 | (((unsigned long)functionIndex) >> 16);
+ * p++ = 0x60630000 | (((unsigned long)functionIndex) & 0x0000FFFF);
+ * p++ = 0x3c800000 | (((unsigned long)vtableOffset) >> 16);
+ * p++ = 0x60840000 | (((unsigned long)vtableOffset) & 0x0000FFFF);
+ * p++ = 0x38a1f800;
+#ifndef __NO_FPRS__
+ * p++ = 0x38c1f820;
+#else
+ * p++ = 0x38c00000;
+#endif
+ * p++ = 0x38e10008;
+ * p++ = 0x4e800420;
+ return (code + codeSnippetSize);
+
+}
+
+
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bptr, unsigned char const * eptr)
+{
+ int const lineSize = 32;
+ for (unsigned char const * p = bptr; p < eptr + lineSize; p += lineSize) {
+ __asm__ volatile ("dcbst 0, %0" : : "r"(p) : "memory");
+ }
+ __asm__ volatile ("sync" : : : "memory");
+ for (unsigned char const * p = bptr; p < eptr + lineSize; p += lineSize) {
+ __asm__ volatile ("icbi 0, %0" : : "r"(p) : "memory");
+ }
+ __asm__ volatile ("isync" : : : "memory");
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ // fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
+ // fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
+ // fflush(stderr);
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, true);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc/except.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc/except.cxx
new file mode 100644
index 0000000000..ec26bc4969
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc/except.cxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ terminate();
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ if (! rtti)
+ terminate();
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ terminate();
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (! pExcTypeDescr)
+ terminate();
+
+ // construct uno exception any
+ ::uno_any_constructAndConvert( pExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ ::typelib_typedescription_release( pExcTypeDescr );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc/share.hxx b/bridges/source/cpp_uno/gcc3_linux_powerpc/share.hxx
new file mode 100644
index 0000000000..55bc7e9185
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc/share.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc/uno2cpp.cxx
new file mode 100644
index 0000000000..cce78ba95a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc/uno2cpp.cxx
@@ -0,0 +1,686 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+
+static void callVirtualMethod(
+ void * pAdjustedThisPtr,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+ char * pPT,
+ sal_Int32 * pStackLongs,
+ sal_Int32 nStackLongs)
+{
+
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ // the basic idea here is to use gpr[8] as a storage area for
+ // the future values of registers r3 to r10 needed for the call,
+ // and similarly fpr[8] as a storage area for the future values
+ // of floating point registers f1 to f8
+
+ unsigned long * mfunc; // actual function to be invoked
+ int gpr[8]; // storage for gpregisters, map to r3-r10
+ int off; // offset used to find function
+#ifndef __NO_FPRS__
+ double fpr[8]; // storage for fpregisters, map to f1-f8
+ int f; // number of fprs mapped so far
+ double dret; // temporary function return values
+#endif
+ int n; // number of gprs mapped so far
+ long *p; // pointer to parameter overflow area
+ int c; // character of parameter type being decoded
+ int iret, iret2;
+
+ // Because of the Power PC calling conventions we could be passing
+ // parameters in both register types and on the stack. To create the
+ // stack parameter area we need we now simply allocate local
+ // variable storage param[] that is at least the size of the parameter stack
+ // (more than enough space) which we can overwrite the parameters into.
+
+ // Note: This keeps us from having to decode the signature twice and
+ // prevents problems with later local variables.
+
+ // Note: could require up to 2*nStackLongs words of parameter stack area
+ // if the call has many float parameters (i.e. floats take up only 1
+ // word on the stack but double takes 2 words in parameter area in the
+ // stack frame.
+
+ // Update! Floats on the outgoing parameter stack only take up 1 word
+ // (stfs is used) which is not correct according to the ABI but we
+ // will match what the compiler does until this is figured out
+
+ // this grows the current stack to the appropriate size
+ // and sets the outgoing stack pointer p to the right place
+ __asm__ __volatile__ (
+ "rlwinm %0,%0,3,3,28\n\t"
+ "addi %0,%0,22\n\t"
+ "rlwinm %0,%0,0,4,28\n\t"
+ "lwz 0,0(1)\n\t"
+ "subf 1,%0,1\n\t"
+ "stw 0,0(1)\n\t"
+ : : "r" (nStackLongs) : "0" );
+
+ __asm__ __volatile__ ( "addi %0,1,8" : "=r" (p) : );
+
+ // never called
+ // if (! pAdjustedThisPtr ) dummy_can_throw_anything("xxx"); // address something
+
+
+ // now begin to load the C++ function arguments into storage
+ n = 0;
+#ifndef __NO_FPRS__
+ f = 0;
+#endif
+
+ // now we need to parse the entire signature string */
+ // until we get the END indicator */
+
+ // treat complex return pointer like any other parameter
+
+#if 0
+ /* Let's figure out what is really going on here*/
+ fprintf(stderr,"callVirtualMethod parameters string is %s\n",pPT);
+ int k = nStackLongs;
+ long * q = (long *)pStackLongs;
+ while (k > 0) {
+ fprintf(stderr,"uno stack is: %x\n",*q);
+ k--;
+ q++;
+ }
+#endif
+
+ /* parse the argument list up to the ending ) */
+ while (*pPT != 'X') {
+ c = *pPT;
+ switch (c) {
+ case 'D': /* type is double */
+#ifndef __NO_FPRS__
+ if (f < 8) {
+ fpr[f++] = *((double *)pStackLongs); /* store in register */
+#else
+ if (n & 1)
+ n++;
+ if (n < 8) {
+ gpr[n++] = *pStackLongs;
+ gpr[n++] = *(pStackLongs+1);
+#endif
+ } else {
+ if (((long) p) & 4)
+ p++;
+ *p++ = *pStackLongs; /* or on the parameter stack */
+ *p++ = *(pStackLongs + 1);
+ }
+ pStackLongs += 2;
+ break;
+
+ case 'F': /* type is float */
+ /* this assumes that floats are stored as 1 32 bit word on param
+ stack and that if passed in parameter stack to C, should be
+ as double word.
+
+ Whoops: the abi is not actually followed by gcc, need to
+ store floats as a *single* word on outgoing parameter stack
+ to match what gcc actually does
+ */
+#ifndef __NO_FPRS__
+ if (f < 8) {
+ fpr[f++] = *((float *)pStackLongs);
+#else
+ if (n < 8) {
+ gpr[n++] = *pStackLongs;
+#endif
+ } else {
+#if 0 /* if abi were followed */
+ if (((long) p) & 4)
+ p++;
+ *((double *)p) = *((float *)pStackLongs);
+ p += 2;
+#else
+ *((float *)p) = *((float *)pStackLongs);
+ p += 1;
+#endif
+ }
+ pStackLongs += 1;
+ break;
+
+ case 'H': /* type is long long */
+ if (n & 1) n++; /* note even elements gpr[] will map to
+ odd registers*/
+ if (n <= 6) {
+ gpr[n++] = *pStackLongs;
+ gpr[n++] = *(pStackLongs+1);
+ } else {
+ if (((long) p) & 4)
+ p++;
+ *p++ = *pStackLongs;
+ *p++ = *(pStackLongs+1);
+ }
+ pStackLongs += 2;
+ break;
+
+ case 'S':
+ if (n < 8) {
+ gpr[n++] = *((unsigned short*)pStackLongs);
+ } else {
+ *p++ = *((unsigned short *)pStackLongs);
+ }
+ pStackLongs += 1;
+ break;
+
+ case 'B':
+ if (n < 8) {
+ gpr[n++] = *((char *)pStackLongs);
+ } else {
+ *p++ = *((char *)pStackLongs);
+ }
+ pStackLongs += 1;
+ break;
+
+ default:
+ if (n < 8) {
+ gpr[n++] = *pStackLongs;
+ } else {
+ *p++ = *pStackLongs;
+ }
+ pStackLongs += 1;
+ break;
+ }
+ pPT++;
+ }
+
+ /* figure out the address of the function we need to invoke */
+ off = nVtableIndex;
+ off = off * 4; // 4 bytes per slot
+ mfunc = *((unsigned long **)pAdjustedThisPtr); // get the address of the vtable
+ mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset
+ mfunc = *((unsigned long **)mfunc); // the function is stored at the address
+ typedef void (*FunctionCall)(sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32);
+ FunctionCall ptr = (FunctionCall)mfunc;
+
+ /* Set up the machine registers and invoke the function */
+
+ __asm__ __volatile__ (
+ "lwz 3, 0(%0)\n\t"
+ "lwz 4, 4(%0)\n\t"
+ "lwz 5, 8(%0)\n\t"
+ "lwz 6, 12(%0)\n\t"
+ "lwz 7, 16(%0)\n\t"
+ "lwz 8, 20(%0)\n\t"
+ "lwz 9, 24(%0)\n\t"
+ "lwz 10, 28(%0)\n\t"
+#ifndef __NO_FPRS__
+ "lfd 1, 0(%1)\n\t"
+ "lfd 2, 8(%1)\n\t"
+ "lfd 3, 16(%1)\n\t"
+ "lfd 4, 24(%1)\n\t"
+ "lfd 5, 32(%1)\n\t"
+ "lfd 6, 40(%1)\n\t"
+ "lfd 7, 48(%1)\n\t"
+ "lfd 8, 56(%1)\n\t"
+ : : "r" (gpr), "r" (fpr)
+#else
+ : : "r" (gpr)
+#endif
+ : "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"
+ );
+
+ // tell gcc that r3 to r10 are not available to it for doing the TOC and exception munge on the func call
+ register sal_uInt32 r3 __asm__("r3");
+ register sal_uInt32 r4 __asm__("r4");
+ register sal_uInt32 r5 __asm__("r5");
+ register sal_uInt32 r6 __asm__("r6");
+ register sal_uInt32 r7 __asm__("r7");
+ register sal_uInt32 r8 __asm__("r8");
+ register sal_uInt32 r9 __asm__("r9");
+ register sal_uInt32 r10 __asm__("r10");
+
+ (*ptr)(r3, r4, r5, r6, r7, r8, r9, r10);
+
+ __asm__ __volatile__ (
+ "mr %0, 3\n\t"
+ "mr %1, 4\n\t"
+#ifndef __NO_FPRS__
+ "fmr %2, 1\n\t"
+ : "=r" (iret), "=r" (iret2), "=f" (dret)
+#else
+ : "=r" (iret), "=r" (iret2)
+#endif
+ : );
+
+ switch( eReturnType )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ ((long*)pRegisterReturn)[0] = iret;
+ ((long*)pRegisterReturn)[1] = iret2;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ ((long*)pRegisterReturn)[0] = iret;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)iret;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)iret;
+ break;
+ case typelib_TypeClass_FLOAT:
+#ifndef __NO_FPRS__
+ *(float*)pRegisterReturn = (float)dret;
+#else
+ ((unsigned int*)pRegisterReturn)[0] = iret;
+#endif
+ break;
+ case typelib_TypeClass_DOUBLE:
+#ifndef __NO_FPRS__
+ *(double*)pRegisterReturn = dret;
+#else
+ ((unsigned int*)pRegisterReturn)[0] = iret;
+ ((unsigned int*)pRegisterReturn)[1] = iret2;
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ char * pCppStack =
+ (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
+ char * pCppStackStart = pCppStack;
+
+ // need to know parameter types for callVirtualMethod so generate a signature string
+ char * pParamType = (char *) alloca(nParams+2);
+ char * pPT = pParamType;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ // assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = *(void **)pCppStack =
+ (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way
+ *pPT++ = 'I'; //signify that a complex return type on stack
+ pCppStack += sizeof(void *);
+ }
+ }
+ // push this
+ void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset;
+ *(void**)pCppStack = pAdjustedThisPtr;
+ pCppStack += sizeof( void* );
+ *pPT++ = 'I';
+
+ // stack space
+ // static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+
+ // we need to know type of each param so that we know whether to use
+ // gpr or fpr to pass in parameters:
+ // Key: I - int, long, pointer, etc means pass in gpr
+ // B - byte value passed in gpr
+ // S - short value passed in gpr
+ // F - float value pass in fpr
+ // D - double value pass in fpr
+ // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
+ // X - indicates end of parameter description string
+
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *pPT++ = 'I';
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *pPT++ = 'S';
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *pPT++ = 'B';
+ break;
+ case typelib_TypeClass_FLOAT:
+ *pPT++ = 'F';
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *pPT++ = 'D';
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *pPT++ = 'H';
+ pCppStack += sizeof(sal_Int32); // extra long
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // KBH: FIXME: is this the right way to pass these
+ *pPT++='I';
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // terminate the signature string
+ *pPT++='X';
+ *pPT=0;
+
+ try
+ {
+ assert( !( (pCppStack - pCppStackStart ) & 3) && "UNALIGNED STACK !!! (Please DO panic)");
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr->eTypeClass, pParamType,
+ (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx
new file mode 100644
index 0000000000..d1a5ee6f4e
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx
@@ -0,0 +1,755 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+#include <osl/endian.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+#ifdef OSL_BIGENDIAN
+#define IS_BIG_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 0
+#endif
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "as far as cpp2uno_call\n");
+#endif
+
+ int ng = 0; //number of gpr registers used
+ int nf = 0; //number of fpr registers used
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (!ppc64::return_in_hidden_param(pReturnTypeRef))
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ ng++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ gpreg++;
+ ng++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+ bool bOverflowUsed = false;
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "arg %d of %d\n", nPos, nParams);
+#endif
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple\n");
+#endif
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nf < ppc64::MAX_SSE_REGS)
+ {
+ if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+ {
+ float tmp = (float) (*((double *)fpreg));
+ (*((float *) fpreg)) = tmp;
+ }
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nf++;
+
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ ng++;
+ gpreg++;
+ }
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + 7*IS_BIG_ENDIAN);
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + 7*IS_BIG_ENDIAN);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + 6*IS_BIG_ENDIAN);
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + 6*IS_BIG_ENDIAN);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + 4*IS_BIG_ENDIAN);
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + 4*IS_BIG_ENDIAN);
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ default:
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex, ng is %d\n", ng);
+#endif
+ void *pCppStack; //temporary stack pointer
+
+ if (ng < ppc64::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw;
+ bOverflowUsed = true;
+ }
+ if (bOverflowUsed) ovrflw++;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of params\n");
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+# define PARAMSAVE 32
+#else
+# define PARAMSAVE 48
+#endif
+
+static typelib_TypeClass cpp_mediate(
+ sal_uInt64 nOffsetAndIndex,
+ void ** gpreg, void ** fpreg, long sp,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int64)==sizeof(void *), "### unexpected!");
+
+ sal_Int32 nVtableOffset = (nOffsetAndIndex >> 32);
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+
+ long sf = *(long*)sp;
+ void ** ovrflw = (void**)(sf + PARAMSAVE + 64);
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ void * pThis;
+ if (nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[1]\n");
+#endif
+ }
+ else
+ {
+ pThis = gpreg[0];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is gpreg[0]\n");
+#endif
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is %lx\n", pThis);
+#endif
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pThis is now %lx\n", pThis);
+#endif
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "indexes are %d %d\n", nFunctionIndex, pTypeDescr->nMapFunctionIndexToMemberIndex);
+#endif
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "members are %d %d\n", nMemberPos, pTypeDescr->nAllMembers);
+#endif
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "screwed\n");
+#endif
+
+ throw RuntimeException( "no member description found!", (XInterface *)pThis );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of cpp_mediate\n");
+#endif
+ return eRet;
+}
+
+extern "C" void privateSnippetExecutor( ... )
+{
+ sal_uInt64 gpreg[ppc64::MAX_GPR_REGS];
+
+ register long r3 asm("r3"); gpreg[0] = r3;
+ register long r4 asm("r4"); gpreg[1] = r4;
+ register long r5 asm("r5"); gpreg[2] = r5;
+ register long r6 asm("r6"); gpreg[3] = r6;
+ register long r7 asm("r7"); gpreg[4] = r7;
+ register long r8 asm("r8"); gpreg[5] = r8;
+ register long r9 asm("r9"); gpreg[6] = r9;
+ register long r10 asm("r10"); gpreg[7] = r10;
+
+ double fpreg[ppc64::MAX_SSE_REGS];
+
+ __asm__ __volatile__ (
+ "stfd 1, 0(%0)\t\n"
+ "stfd 2, 8(%0)\t\n"
+ "stfd 3, 16(%0)\t\n"
+ "stfd 4, 24(%0)\t\n"
+ "stfd 5, 32(%0)\t\n"
+ "stfd 6, 40(%0)\t\n"
+ "stfd 7, 48(%0)\t\n"
+ "stfd 8, 56(%0)\t\n"
+ "stfd 9, 64(%0)\t\n"
+ "stfd 10, 72(%0)\t\n"
+ "stfd 11, 80(%0)\t\n"
+ "stfd 12, 88(%0)\t\n"
+ "stfd 13, 96(%0)\t\n"
+ : : "r" (fpreg)
+ : "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9",
+ "fr10", "fr11", "fr12", "fr13"
+ );
+
+ register long r11 asm("r11");
+ const long nOffsetAndIndex = r11;
+
+ register long r1 asm("r1");
+ const long sp = r1;
+
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ volatile long nRegReturn[2];
+#else
+ volatile long nRegReturn[1];
+#endif
+
+ typelib_TypeClass aType =
+ cpp_mediate( nOffsetAndIndex, (void**)gpreg, (void**)fpreg, sp, (sal_Int64*)nRegReturn);
+
+ switch( aType )
+ {
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ __asm__( "lbz 3,%0\n\t"
+ : : "m" (nRegReturn[0]) );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ __asm__( "lhz 3,%0\n\t"
+ : : "m" (nRegReturn[0]) );
+ break;
+ case typelib_TypeClass_SHORT:
+ __asm__( "lha 3,%0\n\t"
+ : : "m" (nRegReturn[0]) );
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ __asm__( "lwz 3,%0\n\t"
+ : : "m"(nRegReturn[0]) );
+ break;
+ case typelib_TypeClass_LONG:
+ __asm__( "lwa 3,%0\n\t"
+ : : "m"(nRegReturn[0]) );
+ break;
+ case typelib_TypeClass_FLOAT:
+ __asm__( "lfs 1,%0\n\t"
+ : : "m" (*((float*)nRegReturn)) );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ __asm__( "lfd 1,%0\n\t"
+ : : "m" (*((double*)nRegReturn)) );
+ break;
+ default:
+ __asm__( "ld 3,%0\n\t"
+ : : "m" (nRegReturn[0]) );
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ __asm__( "ld 4,%0\n\t"
+ : : "m" (nRegReturn[1]) );
+#endif
+ break;
+ }
+}
+
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+const int codeSnippetSize = 32;
+#else
+const int codeSnippetSize = 24;
+#endif
+
+unsigned char * codeSnippet( unsigned char * code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ bool bHasHiddenParam)
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr,"in codeSnippet functionIndex is %x\n", nFunctionIndex);
+ fprintf(stderr,"in codeSnippet vtableOffset is %x\n", nVtableOffset);
+#endif
+
+ sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
+
+ if ( bHasHiddenParam )
+ nOffsetAndIndex |= 0x80000000;
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ unsigned int *raw = (unsigned int *)&code[0];
+
+ raw[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
+ raw[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
+ raw[2] = 0x7d8903a6; /* mtctr 12 */
+ raw[3] = 0x4e800420; /* bctr */
+ /* 1: .quad function_addr */
+ /* 2: .quad context */
+ *(void **)&raw[4] = (void *)privateSnippetExecutor;
+ *(void **)&raw[6] = (void*)nOffsetAndIndex;
+#else
+ void ** raw = (void **)&code[0];
+ memcpy(raw, (char*) privateSnippetExecutor, 16);
+ raw[2] = (void*) nOffsetAndIndex;
+#endif
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "in: offset/index is %x %x %d, %lx\n",
+ nFunctionIndex, nVtableOffset, bHasHiddenParam, raw[2]);
+#endif
+ return (code + codeSnippetSize);
+}
+
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bptr, unsigned char const * eptr)
+{
+ int const lineSize = 32;
+ for (unsigned char const * p = bptr; p < eptr + lineSize; p += lineSize) {
+ __asm__ volatile ("dcbst 0, %0" : : "r"(p) : "memory");
+ }
+ __asm__ volatile ("sync" : : : "memory");
+ for (unsigned char const * p = bptr; p < eptr + lineSize; p += lineSize) {
+ __asm__ volatile ("icbi 0, %0" : : "r"(p) : "memory");
+ }
+ __asm__ volatile ("isync" : : : "memory");
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ ppc64::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ ppc64::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc64/except.cxx
new file mode 100644
index 0000000000..1241aa02e1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc64/except.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ if (! pTypeDescr)
+ terminate();
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ if (! rtti)
+ terminate();
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ terminate();
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (! pExcTypeDescr)
+ terminate();
+
+ // construct uno exception any
+ ::uno_any_constructAndConvert( pExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ ::typelib_typedescription_release( pExcTypeDescr );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_powerpc64/share.hxx
new file mode 100644
index 0000000000..8286a878a1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc64/share.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+namespace ppc64
+{
+ enum ppclimits { MAX_GPR_REGS = 8, MAX_SSE_REGS = 13 };
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc64/uno2cpp.cxx
new file mode 100644
index 0000000000..37d75659fd
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_powerpc64/uno2cpp.cxx
@@ -0,0 +1,712 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+
+using namespace ::com::sun::star::uno;
+
+namespace ppc64
+{
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+ }
+#endif
+
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ //A Composite Type not larger than 16 bytes is returned in up to two GPRs
+ bool bRet = pTypeDescr->nSize > 16 || is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+#endif
+ return true;
+ }
+}
+
+void MapReturn(long r3, long r4, double dret, typelib_TypeDescriptionReference* pReturnType, void *pRegisterReturn)
+{
+ switch (pReturnType->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = r3;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = r3;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = (unsigned short)r3;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = (unsigned char)r3;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *reinterpret_cast<float *>( pRegisterReturn ) = dret;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double *>( pRegisterReturn ) = dret;
+ break;
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (!ppc64::return_in_hidden_param(pReturnType))
+ {
+ sal_uInt64 *pRegisters = reinterpret_cast<sal_uInt64*>(pRegisterReturn);
+ pRegisters[0] = r3;
+ if (pReturnType->pType->nSize > 8)
+ pRegisters[1] = r4;
+ }
+#else
+ (void)r4;
+#endif
+ default:
+ break;
+ }
+}
+
+namespace
+{
+
+static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr,
+ sal_uInt64 *pStack, sal_uInt32 nStack,
+ sal_uInt64 *pGPR, sal_uInt32 nGPR,
+ double *pFPR, sal_uInt32 nFPR)
+{
+ // Stack, if used, must be 16-bytes aligned
+ if ( nStack )
+ nStack = ( nStack + 1 ) & ~1;
+
+ // Should not happen, but...
+ if ( nFPR > ppc64::MAX_SSE_REGS )
+ nFPR = ppc64::MAX_SSE_REGS;
+ if ( nGPR > ppc64::MAX_GPR_REGS )
+ nGPR = ppc64::MAX_GPR_REGS;
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
+ for ( sal_uInt32 i = 0; i < nGPR; ++i )
+ fprintf( stderr, "0x%lx, ", pGPR[i] );
+ fprintf( stderr, "\nFPR's (%d): ", nFPR );
+ for ( sal_uInt32 i = 0; i < nFPR; ++i )
+ fprintf( stderr, "0x%lx (%lf), ", (sal_Int64)pFPR[i], pFPR[i] );
+ fprintf( stderr, "\nStack (%d): ", nStack );
+ for ( sal_uInt32 i = 0; i < nStack; ++i )
+ fprintf( stderr, "0x%lx, ", pStack[i] );
+ fprintf( stderr, "\n" );
+ }
+#endif
+
+ // Load parameters to stack, if necessary
+ sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca( nStack * 8 );
+ memcpy( stack, pStack, nStack * 8 );
+
+ // Get pointer to method
+ sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
+ pMethod += 8 * nVtableIndex;
+ pMethod = *((sal_uInt64 *)pMethod);
+
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ typedef void (* FunctionCall )(...);
+#else
+ typedef void (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 );
+#endif
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ volatile double dret;
+
+ // fill registers
+ __asm__ __volatile__ (
+ "lfd 1, 0(%0)\n\t"
+ "lfd 2, 8(%0)\n\t"
+ "lfd 3, 16(%0)\n\t"
+ "lfd 4, 24(%0)\n\t"
+ "lfd 5, 32(%0)\n\t"
+ "lfd 6, 40(%0)\n\t"
+ "lfd 7, 48(%0)\n\t"
+ "lfd 8, 56(%0)\n\t"
+ "lfd 9, 64(%0)\n\t"
+ "lfd 10, 72(%0)\n\t"
+ "lfd 11, 80(%0)\n\t"
+ "lfd 12, 88(%0)\n\t"
+ "lfd 13, 96(%0)\n\t"
+ : : "r" (pFPR)
+ : "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9",
+ "fr10", "fr11", "fr12", "fr13"
+ );
+
+ // tell gcc that r3 to r11 are not available to it for doing the TOC and exception munge on the func call
+ register sal_uInt64 r3 asm("r3");
+ register sal_uInt64 r4 asm("r4");
+
+ (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3], pGPR[4], pGPR[5], pGPR[6], pGPR[7]);
+
+ // get return value
+ __asm__ __volatile__ (
+ "mr %1, 3\n\t"
+ "mr %2, 4\n\t"
+ "fmr %0, 1\n\t"
+ : "=f" (dret), "=r" (r3), "=r" (r4) : );
+
+ MapReturn(r3, r4, dret, reinterpret_cast<typelib_TypeDescriptionReference *>(pReturnTypeDescr), pRegisterReturn);
+}
+
+// Macros for easier insertion of values to registers or stack
+// pSV - pointer to the source
+// nr - order of the value [will be increased if stored to register]
+// pFPR, pGPR - pointer to the registers
+// pDS - pointer to the stack [will be increased if stored here]
+
+// The value in %xmm register is already prepared to be retrieved as a float,
+// thus we treat float and double the same
+#define INSERT_FLOAT( pSV, nr, pFPR, nGPR, pDS, bOverflow ) \
+ if ( nGPR < ppc64::MAX_GPR_REGS ) \
+ ++nGPR; \
+ if ( nr < ppc64::MAX_SSE_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<float *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, nGPR, pDS, bOverflow ) \
+ if ( nGPR < ppc64::MAX_GPR_REGS ) \
+ ++nGPR; \
+ if ( nr < ppc64::MAX_SSE_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int64 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_Int64 *>( pSV );
+
+#define INSERT_UINT64( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int32 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_Int32 *>( pSV );
+
+#define INSERT_UINT32( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int16 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_Int16 *>( pSV );
+
+#define INSERT_UINT16( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int8 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_Int8 *>( pSV );
+
+#define INSERT_UINT8( pSV, nr, pGPR, pDS, bOverflow ) \
+ if ( nr < ppc64::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ bOverflow = true; \
+ if (bOverflow) \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "= cpp_call() =\n" );
+#endif
+
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+3) * sizeof(sal_Int64) );
+ sal_uInt64 * pStackStart = pStack;
+
+ sal_uInt64 pGPR[ppc64::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ double pFPR[ppc64::MAX_SSE_REGS];
+ sal_uInt32 nFPR = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ bool bOverflow = false;
+
+ if (pReturnTypeDescr)
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "return type is %d\n", pReturnTypeDescr->eTypeClass);
+#endif
+ bool bSimpleReturn =!ppc64::return_in_hidden_param(pReturnTypeRef);
+
+ if (bSimpleReturn)
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple return\n");
+#endif
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize ) : pUnoReturn);
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "pCppReturn/pUnoReturn is %p/%p\n", pCppReturn, pUnoReturn);
+#endif
+ INSERT_UINT64( &pCppReturn, nGPR, pGPR, pStack, bOverflow );
+ }
+ }
+ // push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "this pointer is %p\n", pAdjustedThisPtr);
+#endif
+ INSERT_UINT64( &pAdjustedThisPtr, nGPR, pGPR, pStack, bOverflow );
+
+ // Args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "n params is %d\n", nParams);
+#endif
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "param %d is %d %d %d\n", nPos, rParam.bOut, bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ),
+ pParamTypeDescr->eTypeClass);
+#endif
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "hyper is 0x%lx\n", *(sal_Int64 *)pCppArgs[nPos]);
+#endif
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "uhyper is 0x%lx\n", *(sal_Int64 *)pCppArgs[nPos]);
+#endif
+ INSERT_UINT64( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_ENUM:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "long is 0x%x\n", *(sal_Int32 *)pCppArgs[nPos]);
+#endif
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "ulong is 0x%x\n", *(sal_Int32 *)pCppArgs[nPos]);
+#endif
+ INSERT_UINT32( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_UINT16( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ INSERT_UINT8( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR, nGPR, pStack, bOverflow );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, nGPR, pStack, bOverflow );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex type again %d\n", rParam.bIn);
+#endif
+ if (! rParam.bIn) // is pure out
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex size is %d\n", pParamTypeDescr->nSize );
+#endif
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "this one\n");
+#endif
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "that one, passing %p through\n", pUnoArgs[nPos]);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_UINT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack, bOverflow );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr,
+ pStackStart, ( pStack - pStackStart ),
+ pGPR, nGPR,
+ pFPR, nFPR );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.cxx
new file mode 100644
index 0000000000..b090953efd
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.cxx
@@ -0,0 +1,95 @@
+/* -*- 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/.
+ */
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+#include "types.hxx"
+#include "abi.hxx"
+#include <stdio.h>
+#include <cstring>
+
+//#define BRIDGE_DEBUG
+
+namespace abi_riscv64
+{
+void countnGreg(sal_Int32& nGreg, sal_Int32& nFreg,
+ const typelib_CompoundTypeDescription* pTypeDescr)
+{
+ for (int i = 0; i < pTypeDescr->nMembers; i++)
+ {
+ typelib_TypeDescriptionReference* pTypeInStruct = pTypeDescr->ppTypeRefs[i];
+ switch (pTypeInStruct->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription* childTypeDescr = nullptr;
+ TYPELIB_DANGER_GET(&childTypeDescr, pTypeInStruct);
+ countnGreg(
+ nGreg, nFreg,
+ reinterpret_cast<typelib_CompoundTypeDescription const*>(childTypeDescr));
+ TYPELIB_DANGER_RELEASE(childTypeDescr);
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ nFreg++;
+ break;
+ default:
+ nGreg++;
+ break;
+ }
+ }
+}
+
+void fillStruct(const typelib_TypeDescription* pTypeDescr, sal_Int64* gret, double* fret,
+ void* pRegisterReturn)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In fillStruct, pTypeDescr = %p, gret = %p, fret = %p, pRegisterReturn = %p\n",
+ pTypeDescr, gret, fret, pRegisterReturn);
+#endif
+ sal_Int32 nGreg = 0;
+ sal_Int32 nFreg = 0;
+ countnGreg(nGreg, nFreg, reinterpret_cast<typelib_CompoundTypeDescription const*>(pTypeDescr));
+ char* pAdjust = reinterpret_cast<char*>(pRegisterReturn);
+ if (nGreg == 0 && nFreg <= 2)
+ {
+ if (pTypeDescr->nSize <= 8 && nFreg == 2)
+ {
+ std::memcpy(pAdjust, fret, 4);
+ std::memcpy(pAdjust + 4, fret + 1, 4);
+ }
+ else
+ {
+ std::memcpy(pAdjust, fret, 16);
+ }
+ }
+ else if (nFreg == 1 && nGreg == 1)
+ {
+ if (pTypeDescr->nSize > 8)
+ {
+ std::memcpy(pAdjust, gret, 8);
+ std::memcpy(pAdjust + 8, fret, 8);
+ }
+ else
+ {
+ std::memcpy(pAdjust, gret, 4);
+ std::memcpy(pAdjust + 4, fret, 4);
+ }
+ }
+ else
+ {
+ std::memcpy(pAdjust, gret, 16);
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.hxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.hxx
new file mode 100644
index 0000000000..081e578150
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/abi.hxx
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//#pragma once
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+namespace abi_riscv64
+{
+void countnGreg(sal_Int32& nGreg, sal_Int32& nFreg,
+ const typelib_CompoundTypeDescription* pTypeDescr);
+
+void fillStruct(const typelib_TypeDescription* pTypeDescr, sal_Int64* gret, double* fret,
+ void* pRegisterReturn);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx
new file mode 100644
index 0000000000..4b58f24c4b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+namespace
+{
+extern "C" sal_Int32 cpp_vtable_call(sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void** gpreg, void** fpreg, void** ovrflw,
+ sal_uInt64* pRegisterReturn /* space for register return */);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s
new file mode 100644
index 0000000000..4eab63b7eb
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/call.s
@@ -0,0 +1,81 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .text
+ .align 2
+ .global privateSnippetExecutor
+ .hidden privateSnippetExecutor
+ .type privateSnippetExecutor, %function
+privateSnippetExecutor:
+ .cfi_startproc
+ addi sp,sp,-160
+ .cfi_def_cfa_offset 160
+ sd ra,152(sp)
+ .cfi_offset 1, -8
+ fsd fa0,80(sp)
+ fsd fa1,88(sp)
+ fsd fa2,96(sp)
+ fsd fa3,104(sp)
+ fsd fa4,112(sp)
+ fsd fa5,120(sp)
+ fsd fa6,128(sp)
+ fsd fa7,136(sp)
+ sd a0,16(sp)
+ sd a1,24(sp)
+ sd a2,32(sp)
+ sd a3,40(sp)
+ sd a4,48(sp)
+ sd a5,56(sp)
+ sd a6,64(sp)
+ sd a7,72(sp)
+ // a0 = functionIndex
+ // a1 = vtableOffset
+ // a2 = gpreg
+ // a3 = fpreg
+ // a4 = overflw
+ // a5 = pRegisterReturn
+ add a0,t4,zero
+ add a1,t5,zero
+ addi a2,sp,16
+ addi a3,sp,80
+ addi a4,sp,160
+ add a5,sp,zero
+ // jump to cpp_vtable_call
+ jalr ra,t6,0
+
+ bne a0,zero,.OneFloatOneInt
+ ld a0,0(sp)
+ ld a1,8(sp)
+ fld fa0,0(sp)
+ fld fa1,8(sp)
+ jal zero,.EndProgram
+.OneFloatOneInt:
+ ld a0,0(sp)
+ fld fa0,8(sp)
+.EndProgram:
+ ld ra,152(sp)
+ .cfi_restore 1
+ addi sp,sp,160
+ .cfi_def_cfa_offset 0
+ jalr zero,ra,0
+ .cfi_endproc
+ .size privateSnippetExecutor, .-privateSnippetExecutor
+ .section .note.GNU-stack, "", @progbits
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx
new file mode 100644
index 0000000000..99965c5700
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx
@@ -0,0 +1,825 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include <osl/endian.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "call.hxx"
+#include "share.hxx"
+#include "abi.hxx"
+
+#include <stdio.h>
+//#include <string.h>
+#include <cstring>
+#include <typeinfo>
+
+using namespace com::sun::star::uno;
+
+//#define BRIDGE_DEBUG
+
+#ifdef BRIDGE_DEBUG
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+using namespace ::std;
+using namespace ::osl;
+using namespace ::rtl;
+#endif
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+bool is_complex_struct(const typelib_TypeDescription* type)
+{
+ const typelib_CompoundTypeDescription* p
+ = reinterpret_cast<const typelib_CompoundTypeDescription*>(type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT
+ || p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription* t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b)
+ {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ if (p->pBaseTypeDescription != 0)
+ return is_complex_struct(&p->pBaseTypeDescription->aBase);
+ return false;
+}
+
+bool return_in_hidden_param(typelib_TypeDescriptionReference* pTypeRef)
+{
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT
+ || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription* pTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pTypeDescr, pTypeRef);
+
+ //A Composite Type not larger than 16 bytes is returned in up to two GPRs
+ bool bRet = pTypeDescr->nSize > 16 || is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ return bRet;
+ }
+ return true;
+}
+}
+
+namespace
+{
+static sal_Int32
+cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription* pMemberTypeDescr,
+ typelib_TypeDescriptionReference* pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter* pParams, void** gpreg, void** fpreg,
+ void** ovrflw, sal_uInt64* pRegisterReturn /* space for register return */)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In cpp2uno_call, pThis = %p, pMemberTypeDescr = %p, pReturnTypeRef = %p\n", pThis,
+ pMemberTypeDescr, pReturnTypeRef);
+ printf("In cpp2uno_call, nParams = %d, pParams = %p, pRegisterReturn = %p\n", nParams, pParams,
+ pRegisterReturn);
+ printf("In cpp2uno_call, gpreg = %p, fpreg = %p, ovrflw = %p\n", gpreg, fpreg, ovrflw);
+#endif
+ unsigned int nr_gpr = 0;
+ unsigned int nr_fpr = 0;
+
+ char* gpreg_t = reinterpret_cast<char*>(gpreg);
+ char* fpreg_t = reinterpret_cast<char*>(fpreg);
+
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:begin\n");
+#endif
+ // return
+ typelib_TypeDescription* pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET(&pReturnTypeDescr, pReturnTypeRef);
+
+ void* pUnoReturn = 0;
+ void* pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param(pReturnTypeRef))
+ {
+ pCppReturn = *gpreg++; // complex return via ptr (pCppReturn)
+ nr_gpr++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr)
+ ? alloca(pReturnTypeDescr->nSize)
+ : pCppReturn); // direct way
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:complexreturn\n");
+#endif
+ }
+ else
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:simplereturn\n");
+#endif
+ }
+ }
+
+ // pop this
+ gpreg++;
+ nr_gpr++;
+
+ // stack space
+ static_assert(sizeof(void*) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void** pUnoArgs = (void**)alloca(4 * sizeof(void*) * nParams);
+ void** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32* pTempIndices = (sal_Int32*)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription** ppTempParamTypeDescr
+ = (typelib_TypeDescription**)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:nParams=%d\n", nParams);
+#endif
+ for (sal_Int32 nPos = 0; nPos < nParams; ++nPos)
+ {
+ const typelib_MethodParameter& rParam = pParams[nPos];
+
+ typelib_TypeDescription* pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pParamTypeDescr, rParam.pTypeRef);
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTypeDescr)) // value
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:Param %u, type %u\n", nPos, pParamTypeDescr->eTypeClass);
+#endif
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nr_fpr < MAX_FP_REGS)
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:fpr=%p\n", *fpreg);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nr_fpr++;
+ }
+ else if (nr_gpr < MAX_GP_REGS)
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:fpr=%p\n", *gpreg);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ nr_gpr++;
+ }
+ else
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:fpr=%p\n", *ovrflw);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+
+ break;
+
+ default:
+ if (nr_gpr < MAX_GP_REGS)
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:gpr=%p\n", *gpreg);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ nr_gpr++;
+ }
+ else
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:gpr=%p\n", *ovrflw);
+#endif
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ else // ptr to complex value | ref
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:ptr|ref\n");
+#endif
+ void* pCppStack;
+ if (nr_gpr < MAX_GP_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ nr_gpr++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw++;
+ }
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:pCppStack=%p\n", pCppStack);
+#endif
+
+ if (!rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca(pParamTypeDescr->nSize);
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTypeDescr))
+ {
+ uno_copyAndConvertData(pUnoArgs[nPos] = alloca(pParamTypeDescr->nSize), pCppStack,
+ pParamTypeDescr, pThis->getBridge()->getCpp2Uno());
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",
+ pCppStack, pParamTypeDescr->nSize, nPos, pUnoArgs[nPos]);
+#endif
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call:direct,pUnoArgs[%d]=%p\n", nPos, pUnoArgs[nPos]);
+#endif
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ }
+ }
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call2,%p,unoargs=%p\n", pThis->getUnoI()->pDispatcher, pUnoArgs);
+ printf("pMemberTypeDescr=%p,pUnoReturn=%p\n", pMemberTypeDescr, pUnoReturn);
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any* pUnoExc = &aUnoExc;
+#ifdef BRIDGE_DEBUG
+ printf("pThis=%p,pThis->getUnoI()=%p,pMemberTypeDescr=%p\npUnoReturn=%p,pUnoArgs=%p", pThis,
+ pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs);
+#endif
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs,
+ &pUnoExc);
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp2uno_call2,after dispatch\n");
+#endif
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ fflush(stdout);
+ // destruct temporary in/inout params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData(pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0);
+ TYPELIB_DANGER_RELEASE(ppTempParamTypeDescr[nTempIndices]);
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+
+ CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp());
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription* pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData(pCppArgs[nIndex], pParamTypeDescr, cpp_release);
+ uno_copyAndConvertData(pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+ }
+ // destroy temp uno param
+ uno_destructData(pUnoArgs[nIndex], pParamTypeDescr, 0);
+
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ void* retout = nullptr; // avoid false -Werror=maybe-uninitialized
+ // return
+ sal_Int32 returnType = 0;
+ if (pReturnTypeDescr)
+ {
+ char* pReturn = reinterpret_cast<char*>(pRegisterReturn);
+ if (!bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr))
+ {
+ switch (pReturnTypeDescr == nullptr ? typelib_TypeClass_VOID
+ : pReturnTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ std::memcpy(pReturn, pUnoReturn, 8);
+ break;
+ // Sometimes we need to return a 32 bit integer into a 64 bit integer.
+ // For example, in pyuno.cxx:PyUNO_bool(), an int(32bit) is returned
+ // in type Py_ssize_t(64bit)
+ // We assume that this 32bit int was put in low 32 bit of register a0.
+ // The bridge may return with high 32 bit uncleaned and compiler might
+ // directly bind this register to 64 bit variable.
+ //
+ // This bug occurs when build pyuno with gcc-12 with -O2.
+ // https://bugs.documentfoundation.org/show_bug.cgi?id=155937
+ //
+ // So we need to clean the high 32 bit in bridge.
+ case typelib_TypeClass_UNSIGNED_LONG:
+ std::memset(pReturn + 4, 0x0, 4);
+ std::memcpy(pReturn, pUnoReturn, 4);
+ break;
+ case typelib_TypeClass_LONG:
+ if (*reinterpret_cast<sal_uInt32*>(pUnoReturn) & 0x80000000)
+ std::memset(pReturn + 4, 0xFF, 4);
+ else
+ std::memset(pReturn + 4, 0x0, 4);
+ std::memcpy(pReturn, pUnoReturn, 4);
+ break;
+ case typelib_TypeClass_FLOAT:
+ std::memcpy(pReturn, pUnoReturn, 4);
+ std::memset(pReturn + 4, 0xFF, 4);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(pReturn, pUnoReturn, 8);
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ std::memcpy(pReturn, pUnoReturn, 16);
+ sal_Int32 nGreg = 0;
+ sal_Int32 nFreg = 0;
+ abi_riscv64::countnGreg(
+ nGreg, nFreg,
+ reinterpret_cast<typelib_CompoundTypeDescription const*>(
+ pReturnTypeDescr));
+ if (pReturnTypeDescr->nSize <= 8 && nFreg == 2 && nGreg == 0)
+ {
+ std::memcpy(pReturn + 8, pReturn + 4, 4);
+ std::memset(pReturn + 4, 0xFF, 4);
+ std::memset(pReturn + 12, 0xFF, 4);
+ }
+ else if (nGreg == 1 && nFreg == 1)
+ {
+ returnType = 1;
+ if (pReturnTypeDescr->nSize <= 8)
+ {
+ std::memcpy(pReturn + 8, pReturn + 4, 4);
+ std::memset(pReturn + 12, 0xFF, 4);
+ }
+ }
+ }
+ break;
+ case typelib_TypeClass_VOID:
+ break;
+ default:
+ if (pUnoReturn)
+ {
+ std::memcpy(pRegisterReturn, pUnoReturn, 16);
+ }
+#ifdef BRIDGE_DEBUG
+ printf("Unhandled Type: %d\n", pReturnTypeDescr->eTypeClass);
+#endif
+ }
+ }
+ else
+ {
+ uno_copyAndConvertData(pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+ // destroy temp uno return
+ uno_destructData(pUnoReturn, pReturnTypeDescr, 0);
+ // complex return ptr is set to return reg
+ *(void**)pRegisterReturn = pCppReturn;
+ }
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+ }
+ return returnType;
+ }
+}
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+sal_Int32 cpp_vtable_call(sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, void** gpreg,
+ void** fpreg, void** ovrflw,
+ sal_uInt64* pRegisterReturn /* space for register return */)
+{
+ static_assert(sizeof(sal_Int64) == sizeof(void*), "### unexpected!");
+
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "in cpp_vtable_call nFunctionIndex is %d\n", nFunctionIndex);
+ fprintf(stdout, "in cpp_vtable_call nVtableOffset is %d\n", nVtableOffset);
+ fprintf(stdout, "in cpp_vtable_call gp=%p, fp=%p, ov=%p\n", gpreg, fpreg, ovrflw);
+#endif
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+ void* pThis;
+ if (nFunctionIndex & 0x80000000)
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call, pThis=%p, nFunctionIndex=%d, nVtableOffset=%d\n", pThis,
+ nFunctionIndex, nVtableOffset);
+#endif
+
+ pThis = static_cast<char*>(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy* pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis);
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call, pCppI=%p\n", pCppI);
+#endif
+
+ typelib_InterfaceTypeDescription* pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN("bridges", "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface*)pThis);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr(pTypeDescr->ppAllMembers[nMemberPos]);
+
+#ifdef BRIDGE_DEBUG
+ //OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ //fprintf(stdout, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
+#endif
+ sal_Int32 eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call interface attribute\n");
+#endif
+ typelib_TypeDescriptionReference* pAttrTypeRef
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
+ ->pAttributeTypeRef;
+
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pAttrTypeRef, 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn);
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam, gpreg, fpreg, ovrflw, pRegisterReturn);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call interface method\n");
+#endif
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call method acquire\n");
+#endif
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 2: // release()
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call method release\n");
+#endif
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call method query interface opt\n");
+#endif
+ typelib_TypeDescription* pTD = 0;
+ TYPELIB_DANGER_GET(&pTD, reinterpret_cast<Type*>(gpreg[2])->getTypeLibType());
+ if (pTD)
+ {
+ XInterface* pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(), (void**)&pInterface,
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD));
+
+ if (pInterface)
+ {
+ ::uno_any_construct(reinterpret_cast<uno_Any*>(gpreg[0]), &pInterface,
+ pTD, cpp_acquire);
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE(pTD);
+
+ reinterpret_cast<void**>(pRegisterReturn)[0] = gpreg[0];
+ eRet = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pTD);
+ }
+ } // else perform queryInterface()
+ default:
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call method query interface\n");
+#endif
+ typelib_InterfaceMethodTypeDescription* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
+ aMemberDescr.get());
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams, pMethodTD->pParams, gpreg, fpreg,
+ ovrflw, pRegisterReturn);
+ }
+ break;
+ }
+ default:
+ {
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "cpp_vtable_call no member\n");
+#endif
+ throw RuntimeException("no member description found!", (XInterface*)pThis);
+ }
+ }
+
+ return eRet;
+}
+
+extern "C" void privateSnippetExecutor(...);
+
+int const codeSnippetSize = 0x6c;
+
+unsigned char* codeSnippet(unsigned char* code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool bHasHiddenParam)
+{
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "in codeSnippet functionIndex is %d\n", functionIndex);
+ fprintf(stdout, "in codeSnippet vtableOffset is %d\n", vtableOffset);
+ fprintf(stdout, "in codeSnippet privateSnippetExecutor is %lx\n",
+ (unsigned long)privateSnippetExecutor);
+ fprintf(stdout, "in codeSnippet cpp_vtable_call is %lx\n", (unsigned long)cpp_vtable_call);
+
+ fflush(stdout);
+#endif
+
+ if (bHasHiddenParam)
+ functionIndex |= 0x80000000;
+
+ unsigned int* p = (unsigned int*)code;
+
+ assert((((unsigned long)code) & 0x3) == 0); //aligned to 4 otherwise a mistake
+
+ /* generate this code */
+ /*
+ It is complex to load a 64bit address because you cannot load
+ an unsigned number to register on RISC-V.
+ # load functionIndex to t4
+ 00000eb7 lui t4,0x0
+ 000eee93 ori t4,t4,0x0
+ # load privateSnippetExecutor to t0
+ 000002b7 lui t0,0x0
+ 02429293 slli t0,t0,36
+ 00000337 lui t1,0x0
+ 01431313 slli t1,t1,20
+ 0062e2b3 or t0,t0,t1
+ 00000337 lui t1,0x0
+ 00431313 slli t1,t1,4
+ 0062e2b3 or t0,t0,t1
+ 00000337 lui t1,0x0
+ 00c35313 srli t1,t1,12
+ 0062e2b3 or t0,t0,t1
+ # load cpp_vtable_call to t6
+ 00000fb7 lui t6,0x0
+ 024f9f93 slli t6,t6,36
+ 00000337 lui t1,0x0
+ 01431313 slli t1,t1,20
+ 006fefb3 or t6,t6,t1
+ 00000337 lui t1,0x0
+ 00431313 slli t1,t1,4
+ 006fefb3 or t6,t6,t1
+ 00000337 lui t1,0x0
+ 00c35313 srli t1,t1,12
+ 006fefb3 or t6,t6,t1
+ # load vtableOffset to t5
+ 00000f37 lui t5,0x0
+ 000f6f13 ori t5,t5,0x0
+ # jump to privateSnippetExecutor
+ 00028067 jalr zero,t0,0x0
+ */
+
+ *p++ = 0x00000eb7 | ((functionIndex)&0xfffff000);
+ *p++ = 0x000eee93 | ((functionIndex << 20) & 0xfff00000);
+
+ // load privateSnippetExecutor to t0
+ unsigned long functionEntry = ((unsigned long)privateSnippetExecutor);
+ *p++ = 0x000002b7 | ((functionEntry >> 36) & 0x000000000ffff000);
+ *p++ = 0x02429293;
+ *p++ = 0x00000337 | ((functionEntry >> 20) & 0x000000000ffff000);
+ *p++ = 0x01431313;
+ *p++ = 0x0062e2b3;
+ *p++ = 0x00000337 | ((functionEntry >> 4) & 0x000000000ffff000);
+ *p++ = 0x00431313;
+ *p++ = 0x0062e2b3;
+ *p++ = 0x00000337 | ((functionEntry << 12) & 0x000000000ffff000);
+ *p++ = 0x00c35313;
+ *p++ = 0x0062e2b3;
+ // load cpp_vtable_call to t6
+ functionEntry = (unsigned long)cpp_vtable_call;
+ *p++ = 0x00000fb7 | ((functionEntry >> 36) & 0x000000000ffff000);
+ *p++ = 0x024f9f93;
+ *p++ = 0x00000337 | ((functionEntry >> 20) & 0x000000000ffff000);
+ *p++ = 0x01431313;
+ *p++ = 0x006fefb3;
+ *p++ = 0x00000337 | ((functionEntry >> 4) & 0x000000000ffff000);
+ *p++ = 0x00431313;
+ *p++ = 0x006fefb3;
+ *p++ = 0x00000337 | ((functionEntry << 12) & 0x000000000ffff000);
+ *p++ = 0x00c35313;
+ *p++ = 0x006fefb3;
+ // load vtableOffset to t5
+ *p++ = 0x00000f37 | ((vtableOffset)&0xfffff000);
+ *p++ = 0x000f6f13 | ((vtableOffset << 20) & 0xfff00000);
+ // jump to privateSnippetExecutor
+ *p++ = 0x00028067;
+ return (code + codeSnippetSize);
+}
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const* bptr,
+ unsigned char const* eptr)
+{
+ asm volatile("fence" :::);
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot
+{
+ void const* fn;
+};
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block)
+{
+ return static_cast<Slot*>(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof(Slot) + slotCount * codeSnippetSize;
+}
+
+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
+{
+};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
+ sal_Int32,
+ typelib_InterfaceTypeDescription*)
+{
+ Slot* slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char* bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot** slots, unsigned char* code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const* type, sal_Int32 functionOffset, sal_Int32 functionCount,
+ sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot* s = *slots;
+
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "in addLocalFunctions functionOffset is %d\n", functionOffset);
+ fprintf(stdout, "in addLocalFunctions vtableOffset is %d\n", vtableOffset);
+ fprintf(stdout, "nMembers=%d\n", type->nMembers);
+ fflush(stdout);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i)
+ {
+ typelib_TypeDescription* member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(member)
+ ->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(member)
+ ->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, false);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(member)
+ ->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx
new file mode 100644
index 0000000000..f95da42526
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/except.cxx
@@ -0,0 +1,282 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+//#define BRIDGE_DEBUG
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything(char const*) {}
+
+static OUString toUNOname(char const* p)
+{
+#if defined BRIDGE_DEBUG
+ char const* start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf(64);
+ assert('N' == *p);
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii(p, n);
+ p += n;
+ if ('E' != *p)
+ buf.append('.');
+ }
+
+#if defined BRIDGE_DEBUG
+ OUString ret(buf.makeStringAndClear());
+ OString c_ret(OUStringToOString(ret, RTL_TEXTENCODING_ASCII_US));
+ fprintf(stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr());
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map<OUString, type_info*> t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void* m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info* getRTTI(typelib_CompoundTypeDescription*);
+};
+
+RTTI::RTTI()
+ : m_hApp(dlopen(0, RTLD_LAZY))
+{
+}
+
+RTTI::~RTTI() { dlclose(m_hApp); }
+
+type_info* RTTI::getRTTI(typelib_CompoundTypeDescription* pTypeDescr)
+{
+ type_info* rtti;
+
+ OUString const& unoName = *(OUString const*)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard(m_mutex);
+ t_rtti_map::const_iterator iRttiFind(m_rttis.find(unoName));
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf(64);
+ buf.append("_ZTIN");
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token(unoName.getToken(0, '.', index));
+ buf.append(token.getLength());
+ OString c_token(OUStringToOString(token, RTL_TEXTENCODING_ASCII_US));
+ buf.append(c_token);
+ } while (index >= 0);
+ buf.append('E');
+
+ OString symName(buf.makeStringAndClear());
+ rtti = (type_info*)dlsym(m_hApp, symName.getStr());
+
+ if (rtti)
+ {
+ pair<t_rtti_map::iterator, bool> insertion(
+ m_rttis.insert(t_rtti_map::value_type(unoName, rtti)));
+ assert(insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind(m_generatedRttis.find(unoName));
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const* rttiName = symName.getStr() + 4;
+#if defined BRIDGE_DEBUG
+ fprintf(stderr, "generated rtti for %s\n", rttiName);
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info* base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription*)pTypeDescr->pBaseTypeDescription);
+ rtti
+ = new __si_class_type_info(strdup(rttiName), (__class_type_info*)base_rtti);
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info(strdup(rttiName));
+ }
+
+ pair<t_rtti_map::iterator, bool> insertion(
+ m_generatedRttis.insert(t_rtti_map::value_type(unoName, rtti)));
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+static void deleteException(void* pExc)
+{
+#if defined BRIDGE_DEBUG
+ fprintf(stderr, "in deleteException: pExc = %p\n", pExc);
+#endif
+ __cxa_exception const* header = ((__cxa_exception const*)pExc - 1);
+ typelib_TypeDescription* pTD = 0;
+ OUString unoName(toUNOname(header->exceptionType->name()));
+ ::typelib_typedescription_getByName(&pTD, unoName.pData);
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData(pExc, pTD, cpp_release);
+ ::typelib_typedescription_release(pTD);
+ }
+}
+
+//extern "C" {
+// void __cxa_throw(void* ex, void* info, void (*dest)(void*)) { ::abort(); }
+//}
+
+void raiseException(uno_Any* pUnoExc, uno_Mapping* pUno2Cpp)
+{
+#if defined BRIDGE_DEBUG
+ OString cstr(OUStringToOString(OUString::unacquired(&pUnoExc->pType->pTypeName),
+ RTL_TEXTENCODING_ASCII_US));
+ fprintf(stderr, "> uno exception occurred: %s\n", cstr.getStr());
+#endif
+ void* pCppExc;
+ type_info* rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription* pTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pTypeDescr, pUnoExc->pType);
+ assert(pTypeDescr);
+ if (!pTypeDescr)
+ {
+ throw RuntimeException(OUString("cannot get typedescription for type ")
+ + OUString::unacquired(&pUnoExc->pType->pTypeName));
+ }
+
+ pCppExc = __cxa_allocate_exception(pTypeDescr->nSize);
+ ::uno_copyAndConvertData(pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp);
+
+ // destruct uno exception
+ ::uno_any_destruct(pUnoExc, 0);
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ assert(rtti && "### no rtti for throwing exception!");
+ if (!rtti)
+ {
+ throw RuntimeException(OUString("no rtti for type ")
+ + OUString::unacquired(&pUnoExc->pType->pTypeName));
+ }
+ }
+ __cxa_throw(pCppExc, rtti, deleteException);
+}
+
+void fillUnoException(uno_Any* pUnoExc, uno_Mapping* pCpp2Uno)
+{
+ __cxa_exception* header = __cxa_get_globals()->caughtExceptions;
+ if (!header)
+ {
+ RuntimeException aRE("no exception header!");
+ Type const& rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert(pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno);
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info* exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription* pExcTypeDescr = 0;
+ OUString unoName(toUNOname(exceptionType->name()));
+#if defined BRIDGE_DEBUG
+ OString cstr_unoName(OUStringToOString(unoName, RTL_TEXTENCODING_ASCII_US));
+ fprintf(stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr());
+#endif
+ typelib_typedescription_getByName(&pExcTypeDescr, unoName.pData);
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE(OUString("exception type not found: ") + unoName);
+ Type const& rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert(pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno);
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert(pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno);
+ typelib_typedescription_release(pExcTypeDescr);
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx
new file mode 100644
index 0000000000..331ed789e3
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/share.hxx
@@ -0,0 +1,85 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+#define MAX_GP_REGS (8)
+#define MAX_FP_REGS (8)
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything(char const*);
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void* exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info* exceptionType;
+ void (*exceptionDestructor)(void*);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception* nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char* actionRecord;
+ const unsigned char* languageSpecificData;
+ void* catchTemp;
+ void* adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void* __cxa_allocate_exception(std::size_t thrown_size) throw();
+extern "C" void __cxa_throw(void* thrown_exception, std::type_info* tinfo, void (*dest)(void*))
+ __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception* caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+
+extern "C" __cxa_eh_globals* __cxa_get_globals() throw();
+extern "C" std::type_info* __cxa_current_exception_type() throw();
+
+void raiseException(uno_Any* pUnoExc, uno_Mapping* pUno2Cpp);
+
+void fillUnoException(uno_Any*, uno_Mapping* pCpp2Uno);
+
+bool return_in_hidden_param(typelib_TypeDescriptionReference* pTypeRef);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx
new file mode 100644
index 0000000000..a23bcc3e8c
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/uno2cpp.cxx
@@ -0,0 +1,616 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <cstring>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+#include "abi.hxx"
+
+//#define BRIDGE_DEBUG
+#ifdef BRIDGE_DEBUG
+#include <stdio.h>
+#endif
+
+// FP reg -> GP reg -> stack
+#define INSERT_FLOAT_DOUBLE(pSV, nfr, pFPR, ngr, pGPR, pDS) \
+ if (nfr < MAX_FP_REGS) \
+ pFPR[nfr++] = *reinterpret_cast<double*>(pSV); \
+ else if (ngr < MAX_FP_REGS) \
+ pGPR[ngr++] = *reinterpret_cast<sal_Int64*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64*>(pSV); // verbatim!
+
+#define INSERT_INT64(pSV, nr, pGPR, pDS) \
+ if (nr < MAX_GP_REGS) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int64*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int64*>(pSV);
+
+#define INSERT_INT32(pSV, nr, pGPR, pDS) \
+ if (nr < MAX_GP_REGS) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int32*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int32*>(pSV);
+
+#define INSERT_INT16(pSV, nr, pGPR, pDS) \
+ if (nr < MAX_GP_REGS) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int16*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int16*>(pSV);
+
+#define INSERT_UINT16(pSV, nr, pGPR, pDS) \
+ if (nr < MAX_GP_REGS) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt16*>(pSV);
+
+#define INSERT_INT8(pSV, nr, pGPR, pDS) \
+ if (nr < MAX_GP_REGS) \
+ pGPR[nr++] = *reinterpret_cast<sal_Int8*>(pSV); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_Int8*>(pSV);
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+bool isReturnInFPR(const typelib_TypeDescription* pTypeDescr, sal_uInt32& nSize)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In isReturnInFPR, pTypeDescr = %p, nSize = %d\n", pTypeDescr, nSize);
+#endif
+ const typelib_CompoundTypeDescription* p
+ = reinterpret_cast<const typelib_CompoundTypeDescription*>(pTypeDescr);
+
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ typelib_TypeDescriptionReference* pTypeInStruct = p->ppTypeRefs[i];
+
+ switch (pTypeInStruct->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription* t = 0;
+ TYPELIB_DANGER_GET(&t, pTypeInStruct);
+ bool isFPR = isReturnInFPR(t, nSize);
+ TYPELIB_DANGER_RELEASE(t);
+ if (!isFPR)
+ return false;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nSize >= 16)
+ return false;
+ nSize += 8;
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+void fillReturn(const typelib_TypeDescription* pTypeDescr, sal_Int64* gret, double* fret,
+ void* pRegisterReturn)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In fillReturn, pTypeDescr = %p, gret = %p, fret = %p, pRegisterReturn = %p\n",
+ pTypeDescr, gret, fret, pRegisterReturn);
+#endif
+ sal_uInt32 nSize = 0;
+ if (isReturnInFPR(pTypeDescr, nSize))
+ {
+ reinterpret_cast<double*>(pRegisterReturn)[0] = fret[0];
+ reinterpret_cast<double*>(pRegisterReturn)[1] = fret[1];
+ }
+ else
+ {
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[0] = gret[0];
+ reinterpret_cast<sal_Int64*>(pRegisterReturn)[1] = gret[1];
+ }
+}
+
+static void callVirtualMethod(void* pAdjustedThisPtr, sal_Int32 nVtableIndex, void* pRegisterReturn,
+ typelib_TypeDescriptionReference* pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64* pStack, sal_uInt32 nStack, sal_uInt64* pGPR, double* pFPR,
+ typelib_TypeDescription* pReturnTypeDescr)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In callVirtualMethod:\n");
+ printf("pAdjustedThisPtr = %p, nVtableIndex = %d, pRegisterReturn = %p, pReturnTypeRef = %p\n",
+ pAdjustedThisPtr, nVtableIndex, pRegisterReturn, pReturnTypeRef);
+ printf("bSimpleReturn = %d, pStack = %p, nStack = %d, pGPR = %p, pFPR = %p, pReturnTypeDescr = "
+ "%p\n",
+ bSimpleReturn, pStack, nStack, pGPR, pFPR, pReturnTypeDescr);
+#endif
+ // Get pointer to method
+ sal_uInt64 pMethod = *((sal_uInt64*)pAdjustedThisPtr);
+ pMethod += 8 * nVtableIndex;
+ void* mfunc = (void*)*((sal_uInt64*)pMethod);
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "calling function %p\n", mfunc);
+#endif
+
+ // Load parameters to stack, if necessary
+ sal_uInt64* pCallStack = NULL;
+ if (nStack)
+ {
+ // 16-bytes aligned
+ sal_uInt32 nStackBytes = ((nStack + 1) >> 1) * 16;
+ pCallStack = (sal_uInt64*)__builtin_alloca(nStackBytes);
+ std::memcpy(pCallStack, pStack, nStackBytes);
+ }
+
+ sal_Int64* gret = (sal_Int64*)malloc(2 * sizeof(sal_Int64));
+ sal_Int64* gret1 = gret;
+ sal_Int64* gret2 = gret + 1;
+ double* fret = (double*)malloc(2 * sizeof(double));
+ double* fret1 = fret;
+ double* fret2 = fret + 1;
+ asm volatile(
+ //".set push \n\t"
+ //".set riscv64 \n\t"
+ // Fill the general purpose registers
+ "ld a0, 0(%[gpr]) \n\t"
+ "ld a1, 8(%[gpr]) \n\t"
+ "ld a2, 16(%[gpr]) \n\t"
+ "ld a3, 24(%[gpr]) \n\t"
+ "ld a4, 32(%[gpr]) \n\t"
+ "ld a5, 40(%[gpr]) \n\t"
+ "ld a6, 48(%[gpr]) \n\t"
+ "ld a7, 56(%[gpr]) \n\t"
+ // Fill the floating pointer registers
+ "fld fa0, 0(%[fpr]) \n\t"
+ "fld fa1, 8(%[fpr]) \n\t"
+ "fld fa2, 16(%[fpr]) \n\t"
+ "fld fa3, 24(%[fpr]) \n\t"
+ "fld fa4, 32(%[fpr]) \n\t"
+ "fld fa5, 40(%[fpr]) \n\t"
+ "fld fa6, 48(%[fpr]) \n\t"
+ "fld fa7, 56(%[fpr]) \n\t"
+ // Perform the call
+ "jalr ra,%[mfunc],0 \n\t"
+ // Fill the return values
+ "add %[gret1], a0,zero \n\t"
+ "add %[gret2], a1,zero \n\t"
+ "fmv.d %[fret1], fa0 \n\t"
+ "fmv.d %[fret2], fa1 \n\t"
+ //".set pop \n\t"
+ : [gret1] "=&r"(*gret1), [gret2] "=&r"(*gret2), [fret1] "=&f"(*fret1), [fret2] "=&f"(*fret2)
+ : [gpr] "r"(pGPR), [fpr] "r"(pFPR), [mfunc] "r"(mfunc),
+ [stack] "m"(
+ pCallStack) // dummy input to prevent the compiler from optimizing the alloca out
+ : "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "ra", "fa0", "fa1", "fa2", "fa3", "fa4",
+ "fa5", "fa6", "fa7", "memory");
+#ifdef BRIDGE_DEBUG
+ printf("In callVirtualMethod, fret = %p, gret = %p\n", fret, gret);
+#endif
+
+ switch (pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<sal_Int64*>(pRegisterReturn) = gret[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double*>(pRegisterReturn) = fret[0];
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+#ifdef BRIDGE_DEBUG
+ printf("nRetSize = %d\n", nRetSize);
+#endif
+ if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+ {
+ typelib_TypeDescription* pTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pTypeDescr, pReturnTypeRef);
+ abi_riscv64::fillStruct(pTypeDescr, gret, fret, pRegisterReturn);
+ TYPELIB_DANGER_RELEASE(pTypeDescr);
+ }
+ break;
+ }
+ default:
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "unhandled return type %u\n", pReturnTypeRef->eTypeClass);
+#endif
+ break;
+ }
+}
+
+static void cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy* pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference* pReturnTypeRef, sal_Int32 nParams,
+ typelib_MethodParameter* pParams, void* pUnoReturn, void* pUnoArgs[],
+ uno_Any** ppUnoExc)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In cpp_call\n");
+ printf("pThis = %p, aVtableSlot = %p, pReturnTypeRef = %p, nParams = %d\n", pThis, aVtableSlot,
+ pReturnTypeRef, nParams);
+ printf("pParams = %p , pUnoReturn = %p, pUnoArgs = %p\n", pParams, pUnoReturn, pUnoArgs);
+#endif
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64* pStack = (sal_uInt64*)__builtin_alloca(((nParams + 3) * sizeof(sal_Int64)));
+ sal_uInt64* pStackStart = pStack;
+
+ sal_uInt64 pGPR[MAX_GP_REGS];
+ sal_uInt64 nREG = 0;
+
+ double pFPR[MAX_FP_REGS];
+ sal_uInt32 nFPR = 0;
+#ifdef BRIDGE_DEBUG
+ printf("pGPR = %p, pFPR = %p\n", pGPR, pFPR);
+#endif
+
+ // return
+ typelib_TypeDescription* pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pReturnTypeDescr, pReturnTypeRef);
+ assert(pReturnTypeDescr);
+
+ void* pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ bool bSimpleReturn = true;
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param(pReturnTypeRef))
+ {
+ bSimpleReturn = false;
+ // complex return via ptr
+ pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr)
+ ? __builtin_alloca(pReturnTypeDescr->nSize)
+ : pUnoReturn;
+ INSERT_INT64(&pCppReturn, nREG, pGPR, pStack);
+ }
+ else
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ }
+
+ // push this
+ void* pAdjustedThisPtr = reinterpret_cast<void**>(pThis->getCppI()) + aVtableSlot.offset;
+ INSERT_INT64(&pAdjustedThisPtr, nREG, pGPR, pStack);
+
+ // args
+ void** pCppArgs = (void**)alloca(3 * sizeof(void*) * nParams);
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32* pTempIndices = (sal_Int32*)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription** ppTempParamTypeDescr
+ = (typelib_TypeDescription**)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+#ifdef BRIDGE_DEBUG
+ printf("In cpp_call, nParams = %d\n", nParams);
+ printf("pCppArgs = %p, pStack = %p\n", pCppArgs, pStack);
+#endif
+ for (sal_Int32 nPos = 0; nPos < nParams; ++nPos)
+ {
+#ifdef BRIDGE_DEBUG
+ printf("In cpp_call, nPos = %d\n", nPos);
+#endif
+ const typelib_MethodParameter& rParam = pParams[nPos];
+ typelib_TypeDescription* pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET(&pParamTypeDescr, rParam.pTypeRef);
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTypeDescr))
+ {
+#ifdef BRIDGE_DEBUG
+ printf("Before uno_copyAndConvertData and tons of switch.\n");
+#endif
+ uno_copyAndConvertData(pCppArgs[nPos] = alloca(8), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+#ifdef BRIDGE_DEBUG
+ printf("Type = %d, Param = 0x%lx\n", pParamTypeDescr->eTypeClass,
+ *reinterpret_cast<sal_uInt64*>(pCppArgs[nPos]));
+#endif
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32(pCppArgs[nPos], nREG, pGPR, pStack);
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ INSERT_INT16(pCppArgs[nPos], nREG, pGPR, pStack);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_UINT16(pCppArgs[nPos], nREG, pGPR, pStack);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8(pCppArgs[nPos], nREG, pGPR, pStack);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ INSERT_FLOAT_DOUBLE(pCppArgs[nPos], nFPR, pFPR, nREG, pGPR, pStack);
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64(pCppArgs[nPos], nREG, pGPR, pStack);
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ else // ptr to complex value | ref
+ {
+ if (!rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(pCppArgs[nPos] = alloca(pParamTypeDescr->nSize), pParamTypeDescr);
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTypeDescr))
+ {
+ uno_copyAndConvertData(pCppArgs[nPos] = alloca(pParamTypeDescr->nSize),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp());
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ INSERT_INT64(&(pCppArgs[nPos]), nREG, pGPR, pStack);
+ }
+ }
+
+ try
+ {
+ try
+ {
+ callVirtualMethod(pAdjustedThisPtr, aVtableSlot.index, pCppReturn, pReturnTypeRef,
+ bSimpleReturn, pStackStart, (pStack - pStackStart), pGPR, pFPR,
+ pReturnTypeDescr);
+ }
+ catch (css::uno::Exception&)
+ {
+ throw;
+ }
+ catch (std::exception& e)
+ {
+ throw css::uno::RuntimeException("C++ code threw "
+ + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ }
+ catch (...)
+ {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription* pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData(pUnoArgs[nIndex], pParamTypeDescr, 0); // destroy uno value
+ uno_copyAndConvertData(pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData(pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData(pCppArgs[nIndex], pParamTypeDescr, cpp_release);
+
+ TYPELIB_DANGER_RELEASE(pParamTypeDescr);
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData(pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno());
+ uno_destructData(pCppReturn, pReturnTypeDescr, cpp_release);
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for (; nTempIndices--;)
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData(pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release);
+ TYPELIB_DANGER_RELEASE(ppTempParamTypeDescr[nTempIndices]);
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE(pReturnTypeDescr);
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared
+{
+void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const typelib_TypeDescription* pMemberDescr,
+ void* pReturn, void* pArgs[], uno_Any** ppException)
+{
+#ifdef BRIDGE_DEBUG
+ printf("In unoInterfaceProxyDispatch:\n");
+ printf("pMemberDescr = %p, pReturn = %p, pArgs = %p, ppExeption = %p\n", pMemberDescr, pReturn,
+ pArgs, ppException);
+#endif
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy* pThis
+ = static_cast<bridges::cpp_uno::shared::UnoInterfaceProxy*>(pUnoI);
+ //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+#ifdef BRIDGE_DEBUG
+ fprintf(stdout, "in dispatch\n");
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(getVtableSlot(
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const*>(pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription*)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException);
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef
+ = ((typelib_InterfaceAttributeTypeDescription*)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference* pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(&pReturnTypeRef, typelib_TypeClass_VOID,
+ aVoidName.pData);
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(pThis, aVtableSlot, pReturnTypeRef, 1, &aParam, pReturn, pArgs,
+ ppException);
+
+ typelib_typedescriptionreference_release(pReturnTypeRef);
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)(pUnoI);
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)(pUnoI);
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription* pTD = 0;
+ TYPELIB_DANGER_GET(&pTD, reinterpret_cast<Type*>(pArgs[0])->getTypeLibType());
+ if (pTD)
+ {
+ uno_Interface* pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(), (void**)&pInterface, pThis->oid.pData,
+ (typelib_InterfaceTypeDescription*)pTD);
+
+ if (pInterface)
+ {
+ ::uno_any_construct(reinterpret_cast<uno_Any*>(pReturn), &pInterface,
+ pTD, 0);
+ (*pInterface->release)(pInterface);
+ TYPELIB_DANGER_RELEASE(pTD);
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pTD);
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription*)pMemberDescr)->pParams, pReturn,
+ pArgs, ppException);
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface>());
+
+ Type const& rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), 0);
+ }
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx
new file mode 100644
index 0000000000..285d1241a2
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx
@@ -0,0 +1,656 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include "share.hxx"
+#include <stdio.h>
+#include <typeinfo>
+
+using namespace ::com::sun::star::uno;
+
+namespace
+{
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "as far as cpp2uno_call\n");
+#endif
+ int ng = 0; //number of gpr registers used
+ int nf = 0; //number of fpr registers used
+
+ // gpreg: [ret *], this, [gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void **)gpreg;
+ gpreg++;
+ ng++;
+
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ }
+ }
+ // pop this
+ gpreg++;
+ ng++;
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "arg %d of %d\n", nPos, nParams);
+#endif
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "simple\n");
+#endif
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ if (nf < s390x::MAX_SSE_REGS)
+ {
+ if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
+ {
+ float tmp = (float) (*((double *)fpreg));
+ (*((float *) fpreg)) = tmp;
+ }
+
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nf++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_BOOLEAN:
+ if (ng < s390x::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + (sizeof(void*)-1));
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + (sizeof(void*)-1));
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (ng < s390x::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + (sizeof(void*)-2));
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + (sizeof(void*)-2));
+ ovrflw++;
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (ng < s390x::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)gpreg) + (sizeof(void*)-4));
+ ng++;
+ gpreg++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = (((char *)ovrflw) + (sizeof(void*)-4));
+ ovrflw++;
+ }
+ break;
+ default:
+ if (ng < s390x::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
+ ovrflw++;
+ }
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "complex, ng is %d\n", ng);
+#endif
+
+ void *pCppStack; //temporary stack pointer
+
+ if (ng < s390x::MAX_GPR_REGS)
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ ng++;
+ }
+ else
+ {
+ pCppArgs[nPos] = pCppStack = *ovrflw;
+ ovrflw++;
+ }
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of params\n");
+#endif
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to return reg
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_uInt64 nOffsetAndIndex,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int64)==sizeof(void *), "### unexpected!");
+
+ sal_Int32 nVtableOffset = (nOffsetAndIndex >> 32);
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "nVTableOffset, nFunctionIndex are %x %x\n", nVtableOffset, nFunctionIndex);
+#endif
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= cpp_mediate () =\nGPR's (%d): ", 5 );
+ for ( unsigned int i = 0; i < 5; ++i )
+ fprintf( stderr, "0x%lx, ", gpreg[i] );
+ fprintf( stderr, "\n");
+ fprintf( stderr, "\nFPR's (%d): ", 4 );
+ for ( unsigned int i = 0; i < 4; ++i )
+ fprintf( stderr, "0x%lx (%f), ", fpreg[i], fpreg[i] );
+ fprintf( stderr, "\n");
+ }
+#endif
+
+
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+
+ // _this_ ptr is patched cppu_XInterfaceProxy object
+ void * pThis;
+ if( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ pThis);
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData,
+ (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = gpreg[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+
+ return eRet;
+}
+
+long privateSnippetExecutor(long r2, long r3, long r4, long r5, long r6, long firstonstack)
+{
+ register long r0 asm("r0");
+ sal_uInt64 nOffsetAndIndex = r0;
+
+ long sp = (long)&firstonstack;
+
+ sal_uInt64 gpreg[s390x::MAX_GPR_REGS];
+ gpreg[0] = r2;
+ gpreg[1] = r3;
+ gpreg[2] = r4;
+ gpreg[3] = r5;
+ gpreg[4] = r6;
+
+ double fpreg[s390x::MAX_SSE_REGS];
+ register double f0 asm("f0"); fpreg[0] = f0;
+ register double f2 asm("f2"); fpreg[1] = f2;
+ register double f4 asm("f4"); fpreg[2] = f4;
+ register double f6 asm("f6"); fpreg[3] = f6;
+
+ volatile long nRegReturn[1];
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "before mediate with %lx\n",nOffsetAndIndex);
+ fprintf(stderr, "doubles are %f %f %f %f\n", fpreg[0], fpreg[1], fpreg[2], fpreg[3]);
+#endif
+ typelib_TypeClass aType =
+ cpp_mediate( nOffsetAndIndex, (void**)gpreg, (void**)fpreg, (void**)sp,
+ (sal_Int64*)nRegReturn );
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "after mediate ret is %lx %ld\n", nRegReturn[0], nRegReturn[0]);
+#endif
+
+ switch( aType )
+ {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ nRegReturn[0] = (unsigned long)(*(unsigned char *)nRegReturn);
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_SHORT:
+ nRegReturn[0] = (unsigned long)(*(unsigned short *)nRegReturn);
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_LONG:
+ nRegReturn[0] = (unsigned long)(*(unsigned int *)nRegReturn);
+ break;
+ case typelib_TypeClass_VOID:
+ default:
+ break;
+ case typelib_TypeClass_FLOAT:
+ {
+ double tmp = (double) (*((float *)nRegReturn));
+ (*((double *) nRegReturn)) = tmp;
+ }
+ //deliberate fall through
+ case typelib_TypeClass_DOUBLE:
+ __asm__ ( "ld 0,%0\n\t"
+ : : "m" (*((double*)nRegReturn)) );
+ break;
+ }
+ return nRegReturn[0];
+}
+
+const int codeSnippetSize = 32;
+
+unsigned char *codeSnippet( unsigned char * code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool simple_ret_type )
+{
+ sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_Int64) nFunctionIndex );
+
+ if (! simple_ret_type)
+ nOffsetAndIndex |= 0x80000000;
+
+ unsigned char * p = code;
+ *(short *)&p[0] = 0x0d10; /* basr %r1,0 */
+ *(short *)&p[2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
+ *(short *)&p[4] = 0x100e;
+ *(short *)&p[6] = 0x0004;
+ *(short *)&p[8] = 0x07f1; /* br %r1 */
+ *(long *)&p[16] = (long)nOffsetAndIndex;
+ *(long *)&p[24] = (long)&privateSnippetExecutor;
+ return (code + codeSnippetSize);
+}
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, unsigned char const *)
+{
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0;
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
+ fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
+#endif
+
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vtableOffset, true);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vtableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_s390x/except.cxx b/bridges/source/cpp_uno/gcc3_linux_s390x/except.cxx
new file mode 100644
index 0000000000..386069b9fb
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_s390x/except.cxx
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iRttiFind( m_rttis.find( unoName ) );
+ if (iRttiFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert( insertion.second && "### inserting new rtti failed?!");
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) );
+ if (iFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second && "### inserting new generated rtti failed?!");
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iRttiFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ terminate();
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ if (! rtti)
+ terminate();
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ terminate();
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (! pExcTypeDescr)
+ terminate();
+
+ // construct uno exception any
+ ::uno_any_constructAndConvert( pExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ ::typelib_typedescription_release( pExcTypeDescr );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_s390x/share.hxx b/bridges/source/cpp_uno/gcc3_linux_s390x/share.hxx
new file mode 100644
index 0000000000..383c1da1ab
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_s390x/share.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+ void dummy_can_throw_anything( char const * );
+
+
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+namespace s390x
+{
+ enum s390xlimits { MAX_GPR_REGS = 5, MAX_SSE_REGS = 4 };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_s390x/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_s390x/uno2cpp.cxx
new file mode 100644
index 0000000000..e2078ec6ca
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_s390x/uno2cpp.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+
+using namespace ::com::sun::star::uno;
+
+void MapReturn(long r2, double f0, typelib_TypeClass eTypeClass, sal_uInt64* pRegisterReturn)
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr,"Mapping Return with %lx %ld %f\n", r2, r2, f0);
+#endif
+ switch (eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *pRegisterReturn = r2;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *(unsigned int*)pRegisterReturn = (unsigned int)r2;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)r2;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)r2;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *reinterpret_cast<float *>( pRegisterReturn ) = f0;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *reinterpret_cast<double *>( pRegisterReturn ) = f0;
+ break;
+ default:
+ break;
+ }
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "end of MapReturn with %x\n", pRegisterReturn ? *pRegisterReturn : 0);
+#endif
+}
+
+#define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
+ { \
+ if ( nr < s390x::MAX_SSE_REGS ) \
+ { \
+ pFPR[nr++] = *reinterpret_cast<float *>( pSV ); \
+ } \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ }
+
+#define INSERT_DOUBLE( pSV, nr, pFPR, pDS ) \
+ if ( nr < s390x::MAX_SSE_REGS ) \
+ pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+ if ( nr < s390x::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+ if ( nr < s390x::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+ if ( nr < s390x::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+ if ( nr < s390x::MAX_GPR_REGS ) \
+ pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+ else \
+ *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+namespace
+{
+
+void callVirtualMethod(
+ void * pThis, sal_Int32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr,
+ sal_uInt64 *pStack, sal_uInt32 nStack,
+ sal_uInt64 *pGPR, sal_uInt32 nGPR,
+ double *pFPR, sal_uInt32 nFPR)
+{
+ // Should not happen, but...
+ if ( nFPR > s390x::MAX_SSE_REGS )
+ nFPR = s390x::MAX_SSE_REGS;
+ if ( nGPR > s390x::MAX_GPR_REGS )
+ nGPR = s390x::MAX_GPR_REGS;
+
+#if OSL_DEBUG_LEVEL > 2
+ // Let's figure out what is really going on here
+ {
+ fprintf( stderr, "= nStack is %d\n", nStack );
+ fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
+ for ( unsigned int i = 0; i < nGPR; ++i )
+ fprintf( stderr, "0x%lx, ", pGPR[i] );
+ fprintf( stderr, "\nFPR's (%d): ", nFPR );
+ for ( unsigned int i = 0; i < nFPR; ++i )
+ fprintf( stderr, "0x%lx (%f), ", pFPR[i], pFPR[i] );
+ fprintf( stderr, "\nStack (%d): ", nStack );
+ for ( unsigned int i = 0; i < nStack; ++i )
+ fprintf( stderr, "0x%lx, ", pStack[i] );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
+ }
+#endif
+
+ // Load parameters to stack, if necessary
+ // Stack, if used, must be 8-bytes aligned
+ sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca( nStack * 8 );
+ memcpy( stack, pStack, nStack * 8 );
+
+ // To get pointer to method
+ // a) get the address of the vtable
+ sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
+ // b) get the address from the vtable entry at offset
+ pMethod += 8 * nVtableIndex;
+ pMethod = *((sal_uInt64 *)pMethod);
+
+ typedef void (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 );
+ FunctionCall pFunc = (FunctionCall)pMethod;
+
+ switch (nFPR) //deliberate fall through
+ {
+ case 4:
+ asm volatile("ld 6,%0" :: "m"(pFPR[3]) : "16");
+ case 3:
+ asm volatile("ld 4,%0" :: "m"(pFPR[2]) : "16");
+ case 2:
+ asm volatile("ld 2,%0" :: "m"(pFPR[1]) : "16");
+ case 1:
+ asm volatile("ld 0,%0" :: "m"(pFPR[0]) : "16");
+ default:
+ break;
+ }
+
+ volatile long r2;
+ volatile double f0;
+
+ (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3], pGPR[4]);
+
+ __asm__ __volatile__ (
+ "lgr %0,2\n\t"
+ "ldr %1,0\n\t"
+ : "=r" (r2), "=f" (f0)
+ : :
+ );
+
+ MapReturn(r2, f0, pReturnTypeDescr->eTypeClass, (sal_uInt64*)pRegisterReturn);
+}
+
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+3) * sizeof(sal_Int64) );
+ sal_uInt64 * pStackStart = pStack;
+
+ sal_uInt64 pGPR[s390x::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ double pFPR[s390x::MAX_SSE_REGS];
+ sal_uInt32 nFPR = 0;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
+ }
+ }
+ // push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+
+ INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeDescr,
+ pStackStart, (pStack - pStackStart),
+ pGPR, nGPR,
+ pFPR, nFPR );
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "unoInterfaceProxyDispatch\n");
+#endif
+
+
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; //get then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/call.s b/bridges/source/cpp_uno/gcc3_linux_sparc/call.s
new file mode 100644
index 0000000000..c5dba78689
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc/call.s
@@ -0,0 +1,28 @@
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+.global doFlushCode
+doFlushCode:
+.L: flush %o0
+ deccc %o1
+ bne .L
+ add %o0, 8, %o0
+ retl
+ nop
+.size doFlushCode,(.-doFlushCode)
+.align 8
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx
new file mode 100644
index 0000000000..950d644df1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "share.hxx"
+
+using namespace com::sun::star::uno;
+
+namespace
+{
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ // pCallStack: [ret ptr], this, params
+ char * pCppStack = (char *)pCallStack;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ else // complex return via ptr (pCppReturn)
+ {
+ pCppReturn = *(void**)pCppStack;
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ pCppStack += sizeof( void* );
+ }
+ }
+ // pop this
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = CPPU_CURRENT_NAMESPACE::adjustPointer(pCppStack, pParamTypeDescr);
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ {
+ if ((reinterpret_cast< long >(pCppStack) & 7) != 0)
+ {
+ static_assert(sizeof (double) == sizeof (sal_Int64), "boo");
+ void * pDest = alloca( sizeof (sal_Int64) );
+ *reinterpret_cast< sal_Int32 * >(pDest) =
+ *reinterpret_cast< sal_Int32 const * >(pCppStack);
+ *(reinterpret_cast< sal_Int32 * >(pDest) + 1) =
+ *(reinterpret_cast< sal_Int32 const * >(pCppStack) + 1);
+ pCppArgs[nPos] = pUnoArgs[nPos] = pDest;
+ }
+ pCppStack += sizeof (sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *(void **)pCppStack;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *(void **)pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *(void **)pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to eax
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
+
+ // pCallStack: this, params
+ // eventual [ret*] lies at pCallStack -1
+ // so count down pCallStack by one to keep it simple
+ // pCallStack: this, params
+ // eventual [ret*] lies at pCallStack -1
+ // so count down pCallStack by one to keep it simple
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ static_cast< char * >(*pCallStack) - nVtableOffset);
+ if ((nFunctionIndex & 0x80000000) != 0) {
+ nFunctionIndex &= 0x7FFFFFFF;
+ --pCallStack;
+ }
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+#if defined BRIDGES_DEBUG
+ OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
+#endif
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ pCallStack, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pCallStack[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = pCallStack[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+ return eRet;
+}
+
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+static void cpp_vtable_call()
+{
+ sal_Int64 nRegReturn;
+ int nFunctionIndex;
+ void** pCallStack;
+ int vTableOffset;
+
+void * pRegReturn = &nRegReturn;
+
+ __asm__( "st %%i0, %0\n\t"
+ "st %%i1, %1\n\t"
+ "st %%i2, %2\n\t"
+ : : "m"(nFunctionIndex), "m"(pCallStack), "m"(vTableOffset) );
+
+// fprintf(stderr,"cpp_mediate nFunctionIndex=%x\n",nFunctionIndex);
+// fflush(stderr);
+
+ const sal_Bool bComplex = (nFunctionIndex & 0x80000000) ? sal_True : sal_False;
+ typelib_TypeClass aType =
+ cpp_mediate( nFunctionIndex, vTableOffset, pCallStack+17, (sal_Int64*)&nRegReturn );
+
+ switch( aType )
+ {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ __asm__( "ld %0, %%l0\n\t"
+ "ldsb [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ __asm__( "ld %0, %%l0\n\t"
+ "ldsh [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ __asm__( "ld %0, %%l0\n\t"
+ "ld [%%l0], %%i0\n\t"
+ "add %%l0, 4, %%l0\n\t"
+ "ld [%%l0], %%i1\n\t"
+ : : "m"(pRegReturn) );
+
+ break;
+ case typelib_TypeClass_FLOAT:
+ __asm__( "ld %0, %%l0\n\t"
+ "ld [%%l0], %%f0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ __asm__( "ld %0, %%l0\n\t"
+ "ldd [%%l0], %%f0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_VOID:
+ break;
+ default:
+ __asm__( "ld %0, %%l0\n\t"
+ "ld [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ }
+
+ if( bComplex )
+ {
+ __asm__( "add %i7, 4, %i7\n\t" );
+ // after call to complex return valued function there is an unimp instruction
+ }
+
+}
+
+
+int const codeSnippetSize = 56;
+unsigned char * codeSnippet(
+ unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool simpleRetType)
+{
+ sal_uInt32 index = functionIndex;
+ if (!simpleRetType) {
+ index |= 0x80000000;
+ }
+ unsigned int * p = reinterpret_cast< unsigned int * >(code);
+ static_assert(sizeof (unsigned int) == 4, "boo");
+ // st %o0, [%sp+68]:
+ *p++ = 0xD023A044;
+ // st %o1, [%sp+72]:
+ *p++ = 0xD223A048;
+ // st %o2, [%sp+76]:
+ *p++ = 0xD423A04C;
+ // st %o3, [%sp+80]:
+ *p++ = 0xD623A050;
+ // st %o4, [%sp+84]:
+ *p++ = 0xD823A054;
+ // st %o5, [%sp+88]:
+ *p++ = 0xDA23A058;
+ // sethi %hi(index), %o0:
+ *p++ = 0x11000000 | (index >> 10);
+ // or %o0, %lo(index), %o0:
+ *p++ = 0x90122000 | (index & 0x3FF);
+ // sethi %hi(vtableOffset), %o2:
+ *p++ = 0x15000000 | (vtableOffset >> 10);
+ // or %o2, %lo(vtableOffset), %o2:
+ *p++ = 0x9412A000 | (vtableOffset & 0x3FF);
+ // sethi %hi(cpp_vtable_call), %o3:
+ *p++ = 0x17000000 | (reinterpret_cast< unsigned int >(cpp_vtable_call) >> 10);
+ // or %o3, %lo(cpp_vtable_call), %o3:
+ *p++ = 0x9612E000 | (reinterpret_cast< unsigned int >(cpp_vtable_call) & 0x3FF);
+ // jmpl %o3, %g0:
+ *p++ = 0x81C2C000;
+ // mov %sp, %o1:
+ *p++ = 0x9210000E;
+ assert(reinterpret_cast< unsigned char * >(p) - code <= codeSnippetSize);
+ return code + codeSnippetSize;
+}
+
+} //end of namespace
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vTableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vTableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef));
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vTableOffset, true);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vTableOffset,
+ bridges::cpp_uno::shared::isSimpleType(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+// use flush code from cc50_solaris_sparc
+
+extern "C" void doFlushCode(unsigned long address, unsigned long count);
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const * begin, unsigned char const * end)
+{
+ unsigned long n = end - begin;
+ if (n != 0) {
+ unsigned long adr = reinterpret_cast< unsigned long >(begin);
+ unsigned long off = adr & 7;
+ doFlushCode(adr - off, (n + off + 7) >> 3);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/except.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc/except.cxx
new file mode 100644
index 0000000000..a87eeac162
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc/except.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if defined BRIDGES_DEBUG
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if defined BRIDGES_DEBUG
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second);
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iiFind( m_generatedRttis.find( unoName ) );
+ if (iiFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if defined BRIDGES_DEBUG
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second);
+ }
+ else // taking already generated rtti
+ {
+ rtti = iiFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti);
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName )
+ );
+ }
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if defined BRIDGES_DEBUG
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE( OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/share.hxx b/bridges/source/cpp_uno/gcc3_linux_sparc/share.hxx
new file mode 100644
index 0000000000..675a909d0c
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc/share.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything( char const * );
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+inline char* adjustPointer( char* pIn, typelib_TypeDescription* pType )
+{
+ switch( pType->nSize )
+ {
+ case 1: return pIn + 3;
+ case 2: return pIn + 2;
+ case 3: return pIn + 1;
+ // Huh ? perhaps a char[3] ? Though that would be a pointer
+ // well, we have it anyway for symmetry
+ }
+ return pIn;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc/uno2cpp.cxx
new file mode 100644
index 0000000000..efc9ded564
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc/uno2cpp.cxx
@@ -0,0 +1,609 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+using namespace com::sun::star::uno;
+
+namespace
+{
+// The call instruction within the asm section of callVirtualMethod may throw
+// exceptions. So that the compiler handles this correctly, it is important
+// that (a) callVirtualMethod might call dummy_can_throw_anything (although this
+// never happens at runtime), which in turn can throw exceptions, and (b)
+// callVirtualMethod is not inlined at its call site (so that any exceptions are
+// caught which are thrown from the instruction calling callVirtualMethod):
+
+void callVirtualMethod( void * pAdjustedThisPtr,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+ sal_Int32 * pStackLongs,
+ sal_Int32 nStackLongs ) __attribute__((noinline));
+
+void callVirtualMethod( void * pAdjustedThisPtr,
+ sal_Int32 /* nVtableIndex */,
+ void * pRegisterReturn,
+ typelib_TypeClass eReturnType,
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 * pStackLongs,
+ sal_Int32 nStackLongs)
+#else
+ sal_Int32 * /*pStackLongs*/,
+ sal_Int32 /*nStackLongs*/)
+#endif
+{
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ assert(pStackLongs && pAdjustedThisPtr);
+ static_assert( (sizeof(void *) == 4) &&
+ (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
+ assert(nStackLongs && pStackLongs && "### no stack in callVirtualMethod !");
+
+ // never called
+ if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+ long o0, o1; // for register returns
+ double f0d;
+ float f0f;
+ volatile long long saveReg[7];
+
+ __asm__ (
+ // save registers
+ "std %%l0, [%4]\n\t"
+ "mov %4, %%l0\n\t"
+ "mov %%l0, %%l1\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%l2, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%l4, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%o0, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%o2, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%o4, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "std %%l6, [%%l0]\n\t"
+ "mov %%l1, %%l7\n\t"
+
+ // increase our own stackframe if necessary
+ "mov %%sp, %%l3\n\t" // save stack ptr for readjustment
+
+ "subcc %%i5, 7, %%l0\n\t"
+ "ble .LmoveOn\n\t"
+ "nop\n\t"
+
+ "sll %%l0, 2, %%l0\n\t"
+ "add %%l0, 96, %%l0\n\t"
+ "mov %%sp, %%l1\n\t" // old stack ptr
+ "sub %%sp, %%l0, %%l0\n\t" // future stack ptr
+ "andcc %%l0, 7, %%g0\n\t" // align stack to 8
+ "be .LisAligned\n\t"
+ "nop\n\t"
+ "sub %%l0, 4, %%l0\n"
+ ".LisAligned:\n\t"
+ "mov %%l0, %%o5\n\t" // save newly computed stack ptr
+ "add %%g0, 16, %%o4\n"
+
+ // now copy longs down to save register window
+ // and local variables
+ ".LcopyDown:\n\t"
+ "ld [%%l1], %%l2\n\t"
+ "st %%l2,[%%l0]\n\t"
+ "add %%l0, 4, %%l0\n\t"
+ "add %%l1, 4, %%l1\n\t"
+ "subcc %%o4, 1, %%o4\n\t"
+ "bne .LcopyDown\n\t"
+
+ "mov %%o5, %%sp\n\t" // move new stack ptr (hopefully) atomically
+ // while register window is valid in both spaces
+ // (scheduling might hit in copyDown loop)
+
+ "sub %%i5, 7, %%l0\n\t" // copy parameters past the sixth to stack
+ "add %%i4, 28, %%l1\n\t"
+ "add %%sp, 92, %%l2\n"
+ ".LcopyLong:\n\t"
+ "ld [%%l1], %%o0\n\t"
+ "st %%o0, [%%l2]\n\t"
+ "add %%l1, 4, %%l1\n\t"
+ "add %%l2, 4, %%l2\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "bne .LcopyLong\n\t"
+ "nop\n"
+
+ ".LmoveOn:\n\t"
+ "mov %%i5, %%l0\n\t" // prepare out registers
+ "mov %%i4, %%l1\n\t"
+
+ "ld [%%l1], %%o0\n\t" // prepare complex return ptr
+ "st %%o0, [%%sp+64]\n\t"
+ "sub %%l0, 1, %%l0\n\t"
+ "add %%l1, 4, %%l1\n\t"
+
+ "ld [%%l1], %%o0\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 4, %%l1\n\t"
+ "ld [%%l1], %%o1\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 4, %%l1\n\t"
+ "ld [%%l1], %%o2\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 4, %%l1\n\t"
+ "ld [%%l1], %%o3\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 4, %%l1\n\t"
+ "ld [%%l1], %%o4\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 4, %%l1\n\t"
+ "ld [%%l1], %%o5\n"
+
+ ".LdoCall:\n\t"
+ "ld [%%i0], %%l0\n\t" // get vtable ptr
+
+"sll %%i1, 2, %%l6\n\t"
+// "add %%l6, 8, %%l6\n\t"
+ "add %%l6, %%l0, %%l0\n\t"
+// // vtable has 8byte wide entries,
+// // upper half contains 2 half words, of which the first
+// // is the this ptr patch !
+// // first entry is (or __tf)
+
+// "ldsh [%%l0], %%l6\n\t" // load this ptr patch
+// "add %%l6, %%o0, %%o0\n\t" // patch this ptr
+
+// "add %%l0, 4, %%l0\n\t" // get virtual function ptr
+ "ld [%%l0], %%l0\n\t"
+
+ "ld [%%i4], %%l2\n\t"
+ "subcc %%l2, %%g0, %%l2\n\t"
+ "bne .LcomplexCall\n\t"
+ "nop\n\t"
+ "call %%l0\n\t"
+ "nop\n\t"
+ "ba .LcallReturned\n\t"
+ "nop\n"
+ ".LcomplexCall:\n\t"
+ "call %%l0\n\t"
+ "nop\n\t"
+ "unimp\n"
+
+ ".LcallReturned:\n\t"
+ "mov %%l3, %%sp\n\t" // readjust stack so that our locals are where they belong
+ "st %%o0, %0\n\t" // save possible return registers into our locals
+ "st %%o1, %1\n\t"
+ "std %%f0, %2\n\t"
+ "st %%f0, %3\n\t"
+
+ // restore registers
+ "ldd [%%l7], %%l0\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%l2\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%l4\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%o0\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%o2\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%o4\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldd [%%l7], %%l6\n\t"
+ :
+ "=m"(o0),
+ "=m"(o1),
+ "=m"(f0d),
+ "=m"(f0f)
+ :
+ "r"(&saveReg[0])
+ :
+ "memory"
+ );
+ switch( eReturnType )
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ ((long*)pRegisterReturn)[1] = o1;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ ((long*)pRegisterReturn)[0] = o0;
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)o0;
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)o0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = f0f;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = f0d;
+ break;
+ default:
+ break;
+ }
+}
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: complex ret ptr, this, values|ptr ...
+ char * pCppStack =
+ (char *)alloca( (nParams+2) * sizeof(sal_Int64) );
+ char * pCppStackStart = pCppStack;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ *(void**)pCppStack = NULL;
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = *(void **)pCppStack = (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ }
+ pCppStack += sizeof(void*);
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ *(void**)pCppStack = pAdjustedThisPtr;
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ pCppArgs[ nPos ] = CPPU_CURRENT_NAMESPACE::adjustPointer(pCppStack, pParamTypeDescr );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ static_assert(sizeof (double) == sizeof (sal_Int64), "boo");
+ *reinterpret_cast< sal_Int32 * >(pCppStack) =
+ *reinterpret_cast< sal_Int32 const * >(pUnoArgs[ nPos ]);
+ pCppStack += sizeof (sal_Int32);
+ *reinterpret_cast< sal_Int32 * >(pCppStack) =
+ *(reinterpret_cast< sal_Int32 const * >(pUnoArgs[ nPos ] ) + 1);
+ break;
+ default:
+ uno_copyAndConvertData(
+ pCppArgs[nPos], pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ try
+ {
+ int nStackLongs = (pCppStack - pCppStackStart)/sizeof(sal_Int32);
+ assert( !( (pCppStack - pCppStackStart ) & 3) && "UNALIGNED STACK !!! (Please DO panic" );
+
+ if( nStackLongs & 1 )
+ // stack has to be 8 byte aligned
+ nStackLongs++;
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr,
+ aVtableSlot.index,
+ pCppReturn,
+ pReturnTypeDescr->eTypeClass,
+ (sal_Int32 *)pCppStackStart,
+ nStackLongs);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch( ... )
+ {
+ // get exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr( OUStringToOString( pMemberDescr->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "received dispatch( %s )\n", cstr.getStr() );
+#endif
+
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+// typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/call.s b/bridges/source/cpp_uno/gcc3_linux_sparc64/call.s
new file mode 100644
index 0000000000..7aed24c7a4
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/call.s
@@ -0,0 +1,77 @@
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+.global doFlushCode
+doFlushCode:
+.L: flush %o0
+ deccc %o1
+ bne .L
+ add %o0, 8, %o0
+ retl
+ nop
+.size doFlushCode,(.-doFlushCode)
+.align 8
+
+// %{o->i}0: index
+// %{o->i}1: pCallStack = %{s->f}p+2047
+// %{o->i}2: vtableOffset
+// %{o->i}3: cpp_vtable_call
+// %{o->i}4: frameSize (negative)
+// [%{s->f}p+2047+128]: param 0 ...
+ .file "call.s"
+ .text
+ .align 4
+ .global privateSnippetExecutor
+ .type privateSnippetExecutor, #function
+privateSnippetExecutor:
+.LFB0:
+ //// Already done by codeSnippet
+ .cfi_startproc
+ save %sp, -176, %sp
+ .cfi_window_save
+ // Register 8 (%o0) saved to register 24 (%i0)
+ .cfi_register 8, 24
+ // Register 9 (%o1) saved to register 25 (%i1)
+ .cfi_register 9, 25
+ // Register 10 (%o2) saved to register 26 (%i2)
+ .cfi_register 10, 26
+ // Register 11 (%o3) saved to register 27 (%i3)
+ .cfi_register 11, 27
+ // Register 12 (%o4) saved to register 28 (%i4)
+ .cfi_register 12, 28
+ // Register 15 (%o7) saved to register 31 (%i7)
+ .cfi_register 15, 31
+ // Use register 30 (%i6 - saved stack pointer) for Call Frame Address
+ .cfi_def_cfa_register 30
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ jmpl %i3, %o7
+ nop
+ mov %o0, %i0
+ mov %o1, %i1
+ mov %o2, %i2
+ mov %o3, %i3
+ ret
+ restore
+ .cfi_endproc
+.LFE0:
+ .size privateSnippetExecutor,(.-privateSnippetExecutor)
+ .section .note.GNU-stack,"",@progbits
+
+.align 8
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx
new file mode 100644
index 0000000000..986be00c6f
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx
@@ -0,0 +1,751 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+#include "share.hxx"
+
+#define GET_FP(n, p) \
+ __asm__( "ldx %0, %%l0\n\t" \
+ "std %%f" #n ", [%%l0]\n" \
+ : : "m"(p) );
+
+using namespace com::sun::star::uno;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+ bool is_complex_struct(const typelib_TypeDescription * type)
+ {
+ for (const typelib_CompoundTypeDescription * p
+ = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
+ p != NULL; p = p->pBaseTypeDescription)
+ {
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
+ p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * t = 0;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = is_complex_struct(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
+ return false;
+ else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT ||
+ pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ //A Composite Type not larger than 32 bytes is returned in up to two GPRs
+ bool bRet = pTypeDescr->nSize > 32 || is_complex_struct(pTypeDescr);
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return bRet;
+ }
+ return true;
+ }
+}
+
+
+namespace
+{
+
+static typelib_TypeClass cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ // pCallStack: [ret ptr], this, params
+ char * pCppStack = (char *)pCallStack;
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+ void * pUnoReturn = 0;
+ void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ int paramsOffset;
+ if (pReturnTypeDescr)
+ {
+ if (CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) )
+ {
+ pCppReturn = *(void**)pCppStack; // complex return via ptr (pCppReturn)
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn); // direct way
+ pCppStack += sizeof( void* );
+ paramsOffset = 2;
+ }
+ else
+ {
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ paramsOffset = 1;
+ }
+ }
+ else
+ {
+ paramsOffset = 1;
+ }
+ // pop this
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // parameters
+ void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = CPPU_CURRENT_NAMESPACE::adjustPointer(pCppStack, pParamTypeDescr);
+ switch (pParamTypeDescr->eTypeClass) {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ {
+ int paramArrayIdx = nPos + paramsOffset;
+ assert(paramArrayIdx < nParams + paramsOffset);
+ switch (paramArrayIdx) {
+ // Cannot be 0 - paramsOffset >= 1
+ case 1:
+ GET_FP(2, pCppStack);
+ break;
+ case 2:
+ GET_FP(4, pCppStack);
+ break;
+ case 3:
+ GET_FP(6, pCppStack);
+ break;
+ case 4:
+ GET_FP(8, pCppStack);
+ break;
+ case 5:
+ GET_FP(10, pCppStack);
+ break;
+ case 6:
+ GET_FP(12, pCppStack);
+ break;
+ case 7:
+ GET_FP(14, pCppStack);
+ break;
+ case 8:
+ GET_FP(16, pCppStack);
+ break;
+ case 9:
+ GET_FP(18, pCppStack);
+ break;
+ case 10:
+ GET_FP(20, pCppStack);
+ break;
+ case 11:
+ GET_FP(22, pCppStack);
+ break;
+ case 12:
+ GET_FP(24, pCppStack);
+ break;
+ case 13:
+ GET_FP(26, pCppStack);
+ break;
+ case 14:
+ GET_FP(28, pCppStack);
+ break;
+ case 15:
+ GET_FP(30, pCppStack);
+ break;
+ // Anything larger is passed on the stack
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *(void **)pCppStack;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ *(void **)pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *(void **)pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int64); // standard parameter length
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)(pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp() );
+ // has to destruct the any
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
+ }
+ // complex return ptr is set to eax
+ *(void **)pRegisterReturn = pCppReturn;
+ }
+ if (pReturnTypeDescr)
+ {
+ typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ return eRet;
+ }
+ else
+ return typelib_TypeClass_VOID;
+ }
+}
+
+
+static typelib_TypeClass cpp_mediate(
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
+ void ** pCallStack,
+ sal_Int64 * pRegisterReturn /* space for register return */ )
+{
+ static_assert(sizeof(sal_Int64)==sizeof(void *), "### unexpected!");
+
+ // pCallStack: [ret*], this, params
+ void * pThis;
+ if (nFunctionIndex & 0x80000000)
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = pCallStack[1];
+ }
+ else
+ {
+ pThis = pCallStack[0];
+ }
+
+ pThis = static_cast< char * >(pThis) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ (XInterface *)pCppI);
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ typelib_TypeClass eRet;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ {
+ // is GET method
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
+ 0, 0, // no params
+ pCallStack, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ 0, // indicates void return
+ 1, &aParam,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[2] )->getTypeLibType() );
+ if (pTD)
+ {
+ XInterface * pInterface = 0;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
+ pCppI->getBridge()->getCppEnv(),
+ (void **)&pInterface, pCppI->getOid().pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pCallStack[0] ),
+ &pInterface, pTD, cpp_acquire );
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+ *(void **)pRegisterReturn = pCallStack[0];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ eRet = cpp2uno_call(
+ pCppI, aMemberDescr.get(),
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
+ pCallStack, pRegisterReturn );
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException( "no member description found!", (XInterface *)pCppI );
+ }
+ }
+ return eRet;
+}
+
+
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+static void cpp_vtable_call(int nFunctionIndex, void** pCallStack, int vTableOffset)
+{
+ sal_Int64 nRegReturn[4] = { 0 };
+ void * pRegReturn = &nRegReturn[0];
+
+ //__asm__( "st %%i0, %0\n\t"
+ // "stx %%i1, %1\n\t"
+ // "st %%i2, %2\n\t"
+ // : : "m"(nFunctionIndex), "m"(pCallStack), "m"(vTableOffset) );
+
+// fprintf(stderr,"cpp_mediate nFunctionIndex=%x\n",nFunctionIndex);
+// fflush(stderr);
+
+ //const sal_Bool bComplex = (nFunctionIndex & 0x80000000) ? sal_True : sal_False;
+ typelib_TypeClass aType =
+ cpp_mediate( nFunctionIndex, vTableOffset, pCallStack+16, (sal_Int64*)&nRegReturn );
+
+ switch( aType )
+ {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ldsb [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ldsh [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ld [%%l0], %%i0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ldx [%%l0], %%i0\n\t"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_FLOAT:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ld [%%l0], %%f0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ldd [%%l0], %%f0\n"
+ : : "m"(pRegReturn) );
+ break;
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ __asm__( "ldx %0, %%l0\n\t"
+ "ldx [%%l0 ], %%i0\n\t"
+ "ldx [%%l0+ 8], %%i1\n\t"
+ "ldx [%%l0+16], %%i2\n\t"
+ "ldx [%%l0+24], %%i3\n\t"
+ "ldd [%%l0 ], %%f0\n\t"
+ "ldd [%%l0+ 8], %%f2\n\t"
+ "ldd [%%l0+16], %%f4\n\t"
+ "ldd [%%l0+24], %%f6\n\t"
+ : : "m"(pRegReturn) );
+ break;
+ default:
+ break;
+ }
+
+ //if( bComplex )
+ //{
+ // __asm__( "add %i7, 4, %i7\n\t" );
+ // // after call to complex return valued function there is an unimp instruction
+ //}
+
+}
+
+extern "C" void privateSnippetExecutor(...);
+
+int const codeSnippetSize = 120;
+unsigned char * codeSnippet(
+ unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ bool bHasHiddenParam, sal_Int32 nParams)
+{
+ sal_uInt32 index = functionIndex;
+ if (bHasHiddenParam) {
+ index |= 0x80000000;
+ }
+ unsigned int * p = reinterpret_cast< unsigned int * >(code);
+ static_assert(sizeof (unsigned int) == 4, "boo");
+ static_assert(sizeof (unsigned long long) == 8, "boo");
+ ++nParams; // implicit this ptr
+ if (bHasHiddenParam) {
+ ++nParams;
+ }
+ long long frameSize;
+ if (nParams > 6) {
+ frameSize = 128 + nParams * 8;
+ } else {
+ frameSize = 176;
+ }
+ assert(frameSize <= 4096);
+ frameSize = -frameSize;
+ switch (nParams) {
+ default:
+ assert(nParams >= 6);
+ // stx %o5, [%sp+168+2047]:
+ *p++ = 0xDA73A8A7;
+ case 5:
+ // stx %o4, [%sp+160+2047]:
+ *p++ = 0xD873A89F;
+ case 4:
+ // stx %o3, [%sp+152+2047]:
+ *p++ = 0xD673A897;
+ case 3:
+ // stx %o2, [%sp+144+2047]:
+ *p++ = 0xD473A88F;
+ case 2:
+ // stx %o1, [%sp+136+2047]:
+ *p++ = 0xD273A887;
+ case 1:
+ // stx %o0, [%sp+128+2047]:
+ *p++ = 0xD073A87F;
+ case 0:
+ break;
+ }
+ // sethi %hi(index), %o0:
+ *p++ = 0x11000000 | (index >> 10);
+ // or %o0, %lo(index), %o0:
+ *p++ = 0x90122000 | (index & 0x3FF);
+ // sethi %hh(cpp_vtable_call), %o3:
+ *p++ = 0x17000000 | (reinterpret_cast< unsigned long long >(cpp_vtable_call) >> 42);
+ // or %o3, %hm(cpp_vtable_call), %o3:
+ *p++ = 0x9612E000 | ((reinterpret_cast< unsigned long long >(cpp_vtable_call) >> 32) & 0x3FF);
+ // sllx %o3, 32, %o3
+ *p++ = 0x972AF020;
+ // sethi %lm(cpp_vtable_call), %o2:
+ *p++ = 0x15000000 | ((reinterpret_cast< unsigned long long >(cpp_vtable_call) >> 10) & 0x3FFFFF);
+ // or %o2, %lo(cpp_vtable_call), %o2:
+ *p++ = 0x9412A000 | (reinterpret_cast< unsigned long long >(cpp_vtable_call) & 0x3FF);
+ // or %o2, %o3, %o3:
+ *p++ = 0x9612800B;
+ // sethi %hh(privateSnippetExecutor), %o1:
+ *p++ = 0x13000000 | (reinterpret_cast< unsigned long long >(privateSnippetExecutor) >> 42);
+ // or %o1, %hm(privateSnippetExecutor), %o1:
+ *p++ = 0x92126000 | ((reinterpret_cast< unsigned long long >(privateSnippetExecutor) >> 32) & 0x3FF);
+ // sllx %o1, 32, %o1:
+ *p++ = 0x932a7020;
+ // sethi %lm(privateSnippetExecutor), %o2:
+ *p++ = 0x15000000 | ((reinterpret_cast< unsigned long long >(privateSnippetExecutor) >> 10) & 0x3FFFFF);
+ // or %o2, %lo(privateSnippetExecutor), %o2:
+ *p++ = 0x9412A000 | (reinterpret_cast< unsigned long long >(privateSnippetExecutor) & 0x3FF);
+ // or %o2, %o1, %o1:
+ *p++ = 0x92128009;
+ // sethi %hh(frameSize), %o4:
+ *p++ = 0x19000000 | (*reinterpret_cast< unsigned long long * >(&frameSize) >> 42);
+ // or %o4, %hm(frameSize), %o4:
+ *p++ = 0x98132000 | ((*reinterpret_cast< unsigned long long * >(&frameSize) >> 32) & 0x3FF);
+ // sllx %o4, 32, %o4
+ *p++ = 0x992B3020;
+ // sethi %lm(frameSize), %o2:
+ *p++ = 0x15000000 | ((*reinterpret_cast< unsigned long long * >(&frameSize) >> 10) & 0x3FFFFF);
+ // or %o2, %lo(frameSize), %o2:
+ *p++ = 0x9412A000 | (*reinterpret_cast< unsigned long long * >(&frameSize) & 0x3FF);
+ // or %o2, %o4, %o4:
+ *p++ = 0x9812800C;
+ // sethi %hi(vtableOffset), %o2:
+ *p++ = 0x15000000 | (vtableOffset >> 10);
+ // or %o2, %lo(vtableOffset), %o2:
+ *p++ = 0x9412A000 | (vtableOffset & 0x3FF);
+ // save %sp, -frameSize, %sp
+ //*p++ = 0x9DE3A000 | (*reinterpret_cast< unsigned int * >(&frameSize) & 0x1FFF);
+ // jmpl %o1, %g0:
+ *p++ = 0x81C24000;
+ // add %sp, 2047, %o1:
+ *p++ = 0x9203A7FF;
+ assert(reinterpret_cast< unsigned char * >(p) - code <= codeSnippetSize);
+ return code + codeSnippetSize;
+}
+
+} //end of namespace
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = 0; //null
+ slots[-1].fn = &typeid(ProxyRtti);
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vTableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < type->nMembers; ++i) {
+ typelib_TypeDescription * member = 0;
+ TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
+ assert(member != 0);
+ switch (member->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vTableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->pAttributeTypeRef), 0);
+ // Setter:
+ if (!reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member)->bReadOnly)
+ {
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(code, functionOffset++, vTableOffset, false, 1);
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet(
+ code, functionOffset++, vTableOffset,
+ CPPU_CURRENT_NAMESPACE::return_in_hidden_param(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->pReturnTypeRef),
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member)->nParams);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(member);
+ }
+ return code;
+}
+
+// use flush code from cc50_solaris_sparc
+
+extern "C" void doFlushCode(unsigned long address, unsigned long count);
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const * begin, unsigned char const * end)
+{
+ unsigned long n = end - begin;
+ if (n != 0) {
+ unsigned long adr = reinterpret_cast< unsigned long >(begin);
+ unsigned long off = adr & 7;
+ doFlushCode(adr - off, (n + off + 7) >> 3);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc64/except.cxx
new file mode 100644
index 0000000000..a87eeac162
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/except.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+static OUString toUNOname( char const * p )
+{
+#if defined BRIDGES_DEBUG
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = (*p++ - '0');
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if defined BRIDGES_DEBUG
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+RTTI::RTTI()
+ : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ type_info * rtti;
+
+ OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
+
+ if (rtti)
+ {
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second);
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iiFind( m_generatedRttis.find( unoName ) );
+ if (iiFind == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+#if defined BRIDGES_DEBUG
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ type_info * base_rtti = getRTTI(
+ (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
+ rtti = new __si_class_type_info(
+ strdup( rttiName ), (__class_type_info *)base_rtti );
+ }
+ else
+ {
+ // this class has no base class
+ rtti = new __class_type_info( strdup( rttiName ) );
+ }
+
+ pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ assert(insertion.second);
+ }
+ else // taking already generated rtti
+ {
+ rtti = iiFind->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
+ typelib_TypeDescription * pTD = 0;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ OUString("cannot get typedescription for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = (type_info*)rtti_data.getRTTI((typelib_CompoundTypeDescription*)pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti);
+ if (! rtti)
+ {
+ throw RuntimeException(
+ OUString("no rtti for type ") +
+ OUString::unacquired( &pUnoExc->pType->pTypeName )
+ );
+ }
+ }
+
+ __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ std::type_info *exceptionType = __cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if defined BRIDGES_DEBUG
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (0 == pExcTypeDescr)
+ {
+ RuntimeException aRE( OUString("exception type not found: ") + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_sparc64/share.hxx
new file mode 100644
index 0000000000..2299f95d6b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/share.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "uno/mapping.h"
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+namespace CPPU_CURRENT_NAMESPACE
+{
+void dummy_can_throw_anything( char const * );
+// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
+
+struct _Unwind_Exception
+{
+ unsigned exception_class __attribute__((__mode__(__DI__)));
+ void * exception_cleanup;
+ unsigned private_1 __attribute__((__mode__(__word__)));
+ unsigned private_2 __attribute__((__mode__(__word__)));
+} __attribute__((__aligned__));
+
+struct __cxa_exception
+{
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+
+ _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+ std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+ void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) __attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+
+inline char* adjustPointer( char* pIn, typelib_TypeDescription* pType )
+{
+ switch( pType->nSize )
+ {
+ case 1: return pIn + 7;
+ case 2: return pIn + 6;
+ case 3: return pIn + 5;
+ case 4: return pIn + 4;
+ case 5: return pIn + 3;
+ case 6: return pIn + 2;
+ case 7: return pIn + 1;
+ // Huh ? perhaps a char[3] ? Though that would be a pointer
+ // well, we have it anyway for symmetry
+ }
+ return pIn;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc64/uno2cpp.cxx
new file mode 100644
index 0000000000..ed498d8586
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/uno2cpp.cxx
@@ -0,0 +1,853 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <exception>
+#include <malloc.h>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include "bridge.hxx"
+#include "types.hxx"
+#include "unointerfaceproxy.hxx"
+#include "vtables.hxx"
+
+#include "share.hxx"
+
+#define SET_FP(n, p) \
+ __asm__( "ldx %0, %%l0\n\t" \
+ "ldd [%%l0], %%f" #n "\n" \
+ : : "m"(p) );
+
+using namespace com::sun::star::uno;
+
+namespace
+{
+ void fillReturn(const typelib_TypeDescription * pTypeDescr,
+ long long * oret, float * fret, double * dret, void * pRegisterReturn)
+ {
+ for (const typelib_CompoundTypeDescription *p =
+ reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
+ p != NULL; p = p->pBaseTypeDescription)
+ {
+
+ for (sal_Int32 i = 0; i < p->nMembers; ++i)
+ {
+ typelib_TypeDescriptionReference *pTypeInStruct = p->ppTypeRefs[ i ];
+
+ sal_Int32 nOff = p->pMemberOffsets[ i ];
+
+ switch (pTypeInStruct->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *(long*)((char *)pRegisterReturn + nOff) = *(long*)((char *)oret + nOff);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *(int*)((char *)pRegisterReturn + nOff) = *(int*)((char *)oret + nOff);
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)((char *)pRegisterReturn + nOff) = *(unsigned short*)((char *)oret + nOff);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)((char *)pRegisterReturn + nOff) = *(unsigned char*)((char *)oret + nOff);
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)((char *)pRegisterReturn + nOff) = *(float*)((char *)fret + nOff);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)((char *)pRegisterReturn + nOff) = *(double*)((char *)dret + nOff);
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * td = NULL;
+ TYPELIB_DANGER_GET(&td, pTypeInStruct);
+ fillReturn(td,
+ (long long *)((char *)oret + nOff),
+ (float *)((char *)fret + nOff),
+ (double *)((char *)dret + nOff),
+ (char *)pRegisterReturn + nOff);
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+// The call instruction within the asm section of callVirtualMethod may throw
+// exceptions. So that the compiler handles this correctly, it is important
+// that (a) callVirtualMethod might call dummy_can_throw_anything (although this
+// never happens at runtime), which in turn can throw exceptions, and (b)
+// callVirtualMethod is not inlined at its call site (so that any exceptions are
+// caught which are thrown from the instruction calling callVirtualMethod):
+
+void callVirtualMethod( void * pAdjustedThisPtr,
+ sal_Int32 nVtableIndex,
+ void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int64 * pStackHypers,
+ sal_Int32 nStackHypers,
+ typelib_MethodParameter * pParams, sal_Int32 nParams) __attribute__((noinline));
+
+void callVirtualMethod( void * pAdjustedThisPtr,
+ sal_Int32 /* nVtableIndex */,
+ void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int64 * pStackHypers,
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nStackHypers,
+#else
+// sal_Int64 * /*pStackHypers*/,
+ sal_Int32 /*nStackHypers*/,
+#endif
+ typelib_MethodParameter * pParams, sal_Int32 nParams)
+{
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ assert(pStackHypers && pAdjustedThisPtr);
+ static_assert( (sizeof(void *) == 8) &&
+ (sizeof(sal_Int64) == 8), "### unexpected size of int!" );
+ assert(nStackHypers && pStackHypers && "### no stack in callVirtualMethod !");
+
+ // never called
+ if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
+
+ long bSimpleReturn = !CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef );
+
+ int paramsOffset = bSimpleReturn ? 1 : 2;
+ for (sal_Int32 i = 0; i < nParams; ++i)
+ {
+ if (!pParams[i].bOut)
+ {
+ switch (pParams[i].pTypeRef->eTypeClass) {
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ {
+ int paramArrayIdx = i + paramsOffset;
+ assert(paramArrayIdx < nStackHypers);
+ void *p = &pStackHypers[paramArrayIdx];
+ switch (paramArrayIdx) {
+ // Cannot be 0 - paramsOffset >= 1
+ case 1:
+ SET_FP(2, p);
+ break;
+ case 2:
+ SET_FP(4, p);
+ break;
+ case 3:
+ SET_FP(6, p);
+ break;
+ case 4:
+ SET_FP(8, p);
+ break;
+ case 5:
+ SET_FP(10, p);
+ break;
+ case 6:
+ SET_FP(12, p);
+ break;
+ case 7:
+ SET_FP(14, p);
+ break;
+ case 8:
+ SET_FP(16, p);
+ break;
+ case 9:
+ SET_FP(18, p);
+ break;
+ case 10:
+ SET_FP(20, p);
+ break;
+ case 11:
+ SET_FP(22, p);
+ break;
+ case 12:
+ SET_FP(24, p);
+ break;
+ case 13:
+ SET_FP(26, p);
+ break;
+ case 14:
+ SET_FP(28, p);
+ break;
+ case 15:
+ SET_FP(30, p);
+ break;
+ // Anything larger is passed on the stack
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ //long o0;
+ //double f0d;
+ //float f0f;
+ volatile long long saveReg[14];
+
+ long long oret[4];
+ union {
+ float f[8];
+ double d[4];
+ } fdret;
+
+ __asm__ (
+ // save registers
+ "stx %%l0, [%[saveReg]]\n\t"
+ "stx %%l1, [%[saveReg]+8]\n\t"
+ "mov %[saveReg], %%l1\n\t"
+ "add %%l1, 16, %%l0\n\t"
+ "stx %%l2, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%l3, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%l4, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%l5, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o0, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o1, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o2, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o3, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o4, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%o5, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%l6, [%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "stx %%l7, [%%l0]\n\t"
+ "mov %%l1, %%l7\n\t"
+
+ // increase our own stackframe if necessary
+ "mov %%sp, %%l3\n\t" // save stack ptr for readjustment
+
+ "subcc %%i5, 6, %%l0\n\t"
+ "ble .LmoveOn\n\t"
+ "nop\n\t"
+
+ "sllx %%l0, 3, %%l0\n\t"
+ "add %%l0, 192, %%l0\n\t"
+ "add %%sp, 2047, %%l1\n\t" // old stack ptr
+ "sub %%l1, %%l0, %%l0\n\t" // future stack ptr
+ "andcc %%l0, 15, %%g0\n\t" // align stack to 16
+ "be .LisAligned\n\t"
+ "nop\n\t"
+ "sub %%l0, 8, %%l0\n"
+ ".LisAligned:\n\t"
+ "mov %%l0, %%o5\n\t" // save newly computed stack ptr
+ "add %%g0, 16, %%o4\n"
+
+ // now copy hypers down to save register window
+ // and local variables
+ ".LcopyDown:\n\t"
+ "ldx [%%l1], %%l2\n\t"
+ "stx %%l2,[%%l0]\n\t"
+ "add %%l0, 8, %%l0\n\t"
+ "add %%l1, 8, %%l1\n\t"
+ "subcc %%o4, 1, %%o4\n\t"
+ "bne .LcopyDown\n\t"
+ "nop\n\t"
+
+ "sub %%o5, 2047, %%sp\n\t" // move new stack ptr (hopefully) atomically - with bias
+ // while register window is valid in both spaces
+ // (scheduling might hit in copyDown loop)
+
+ "sub %%i5, 6, %%l0\n\t" // copy parameters past the sixth to stack
+ "add %%i4, 48, %%l1\n\t"
+ "add %%sp, 2223, %%l2\n" // 2047+176
+ ".LcopyLong:\n\t"
+ "ldx [%%l1], %%o0\n\t"
+ "stx %%o0, [%%l2]\n\t"
+ "add %%l1, 8, %%l1\n\t"
+ "add %%l2, 8, %%l2\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "bne .LcopyLong\n\t"
+ "nop\n"
+
+ ".LmoveOn:\n\t"
+ "mov %%i5, %%l0\n\t" // prepare out registers
+ "mov %%i4, %%l1\n\t"
+
+ "ldx [%%l1], %%o0\n\t"// // prepare complex return ptr
+ //"ldd [%%l1], %%f0\n\t"
+ //"stx %%o0, [%%sp+2047+128]\n\t"
+ "sub %%l0, 1, %%l0\n\t"
+ "add %%l1, 8, %%l1\n\t"
+ //"subxcc %%o0, %%g0, %%o0\n\t"
+ //"bne .LhadComplexReturn\n\t"
+ //"nop\n\t"
+
+ // No complex return ptr - this (next on stack) goes in %o0
+
+ //"ldx [%%l1], %%o0\n\t"
+ //"subcc %%l0, 1, %%l0\n\t"
+ //"be .LdoCall\n\t"
+ //"nop\n\t"
+ //"add %%l1, 8, %%l1\n\t"
+
+ //".LhadComplexReturn:\n\t"
+ "ldx [%%l1], %%o1\n\t"
+ //"ldd [%%l1], %%f2\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 8, %%l1\n\t"
+ "ldx [%%l1], %%o2\n\t"
+ //"ldd [%%l1], %%f4\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 8, %%l1\n\t"
+ "ldx [%%l1], %%o3\n\t"
+ //"ldd [%%l1], %%f6\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 8, %%l1\n\t"
+ "ldx [%%l1], %%o4\n\t"
+ //"ldd [%%l1], %%f8\n\t"
+ "subcc %%l0, 1, %%l0\n\t"
+ "be .LdoCall\n\t"
+ "nop\n\t"
+
+ "add %%l1, 8, %%l1\n\t"
+ "ldx [%%l1], %%o5\n"
+ //"ldd [%%l1], %%f10\n\t"
+
+ ".LdoCall:\n\t"
+ "ldx [%%i0], %%l0\n\t" // get vtable ptr
+
+"sllx %%i1, 3, %%l6\n\t"
+// "add %%l6, 8, %%l6\n\t"
+ "add %%l6, %%l0, %%l0\n\t"
+// // vtable has 8byte wide entries,
+// // upper half contains 2 half words, of which the first
+// // is the this ptr patch !
+// // first entry is (or __tf)
+
+// "ldsh [%%l0], %%l6\n\t" // load this ptr patch
+// "add %%l6, %%o0, %%o0\n\t" // patch this ptr
+
+// "add %%l0, 4, %%l0\n\t" // get virtual function ptr
+ "ldx [%%l0], %%l0\n\t"
+
+// "ldx %0, %%l2\n\t"
+// "subcc %%l2, %%g0, %%l2\n\t"
+// "be .LcomplexCall\n\t"
+// "nop\n\t"
+ "call %%l0\n\t"
+ "nop\n\t"
+// "ba .LcallReturned\n\t"
+// "nop\n"
+// ".LcomplexCall:\n\t"
+// "call %%l0\n\t"
+// "nop\n\t"
+// "unimp\n"
+
+// ".LcallReturned:\n\t"
+ "subcc %%l3, %%sp, %%g0\n\t"
+ "be .LcopiedUp\n\t"
+ "nop\n\t"
+ // Copy register save area back up
+ // Note: copy in reverse order (top down) in case areas overlap
+ "add %%sp, 2167, %%l0\n\t" // 2047+120
+ "add %%l3, 2167, %%l1\n\t"
+ "add %%g0, 16, %%o4\n\t"
+ ".LcopyUp:\n\t"
+ "ldx [%%l0], %%l2\n\t"
+ "stx %%l2, [%%l1]\n\t"
+ "sub %%l0, 8, %%l0\n\t"
+ "sub %%l1, 8, %%l1\n\t"
+ "subcc %%o4, 1, %%o4\n\t"
+ "bne .LcopyUp\n\t"
+ "nop\n\t"
+
+ ".LcopiedUp:\n\t"
+ "mov %%l3, %%sp\n\t" // readjust stack so that our locals are where they belong
+
+ // save possible return registers into our locals
+ "stx %%o0, %[oret0]\n\t"
+ "stx %%o1, %[oret1]\n\t"
+ "stx %%o2, %[oret2]\n\t"
+ "stx %%o3, %[oret3]\n\t"
+ "std %%f0, %[dret0]\n\t"
+ "std %%f2, %[dret1]\n\t"
+ "std %%f4, %[dret2]\n\t"
+ "std %%f6, %[dret3]\n\t"
+ //"st %%f0, %3\n\t"
+
+ // restore registers
+ "ldx [%%l7], %%l0\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l1\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l2\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l3\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l4\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l5\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o0\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o1\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o2\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o3\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o4\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%o5\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l6\n\t"
+ "add %%l7, 8, %%l7\n\t"
+ "ldx [%%l7], %%l7\n\t"
+ :
+ //"=m"(bSimpleReturn),
+ [oret0]"=m"(oret[0]), [oret1]"=m"(oret[1]), [oret2]"=m"(oret[2]), [oret3]"=m"(oret[3]),
+ [dret0]"=m"(fdret.d[0]), [dret1]"=m"(fdret.d[1]), [dret2]"=m"(fdret.d[2]), [dret3]"=m"(fdret.d[3])
+ //"=m"(f0f)
+ :
+ [saveReg]"r"(&saveReg[0])
+ :
+ "memory"
+ );
+ switch(pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *(long*)pRegisterReturn = oret[0];
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *(int*)pRegisterReturn = (int)oret[0];
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(unsigned short*)pRegisterReturn = (unsigned short)oret[0];
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(unsigned char*)pRegisterReturn = (unsigned char)oret[0];
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float*)pRegisterReturn = fdret.f[0];
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double*)pRegisterReturn = fdret.d[0];
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+ if (bSimpleReturn && nRetSize <= 32 && nRetSize > 0)
+ {
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pReturnTypeRef );
+ fillReturn(pTypeDescr, oret, fdret.f, fdret.d, pRegisterReturn);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // max space for: complex ret ptr, this, values|ptr ...
+ char * pCppStack =
+ (char *)alloca( (nParams+2) * sizeof(sal_Int64) );
+ char * pCppStackStart = pCppStack;
+
+ //fprintf(stderr, "pCppStack: %p, pCppStackStart: %p\n", pCppStack, pCppStackStart);
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTypeDescr)
+ {
+ if ( CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) )
+ {
+ // complex return via ptr
+ pCppReturn = *(void **)pCppStack = (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pUnoReturn); // direct way
+ pCppStack += sizeof(void*);
+ }
+ else
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ }
+ // push this
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
+ + aVtableSlot.offset;
+ *(void**)pCppStack = pAdjustedThisPtr;
+ pCppStack += sizeof( void* );
+
+ // stack space
+ static_assert(sizeof(void *) == sizeof(sal_Int64), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_LONG:
+ *(sal_Int64 *)pCppStack = *(sal_Int32 *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *(sal_Int64 *)pCppStack = *(sal_uInt32 *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ *(sal_Int64 *)pCppStack = *(sal_Int16 *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *(sal_Int64 *)pCppStack = *(sal_uInt16 *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *(sal_Int64 *)pCppStack = *(sal_Int8 *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_FLOAT:
+ *(float *)(pCppStack+4) = *(float *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *(double *)pCppStack = *(double *)pCppArgs[nPos];
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *(sal_Int64 *)pCppStack = *(sal_Int64 *)pCppArgs[nPos];
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ pCppStack += sizeof(sal_Int64); // standard parameter length
+ }
+
+ try
+ {
+ int nStackHypers = (pCppStack - pCppStackStart)/sizeof(sal_Int64);
+ assert( !( (pCppStack - pCppStackStart ) & 7) && "UNALIGNED STACK !!! (Please DO panic" );
+
+ //fprintf( stderr, "callVirtualMethod: %p, %lld, %p, %p, %p, %lld\n",
+ // pAdjustedThisPtr,
+ // (long long)aVtableSlot.index,
+ // pCppReturn,
+ // pReturnTypeRef,
+ // pCppStackStart,
+ // (long long)nStackHypers);
+ try {
+ callVirtualMethod(
+ pAdjustedThisPtr,
+ aVtableSlot.index,
+ pCppReturn,
+ pReturnTypeRef,
+ (sal_Int64 *)pCppStackStart,
+ nStackHypers,
+ pParams,
+ nParams);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
+ + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw css::uno::RuntimeException("C++ code threw unknown exception");
+ }
+ // NO exception occurred...
+ *ppUnoExc = 0;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch( ... )
+ {
+ // get exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+#if defined BRIDGES_DEBUG
+ OString cstr( OUStringToOString( pMemberDescr->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "received dispatch( %s )\n", cstr.getStr() );
+#endif
+
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+// typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
+ 0, 0, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = 0;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = 0;
+ (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
+ pThis->pBridge->getUnoEnv(),
+ (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ reinterpret_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, 0 );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ } // else perform queryInterface()
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
+ ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.cxx
new file mode 100644
index 0000000000..243e42d057
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// This is an implementation of the x86-64 ABI as described in 'System V
+// Application Binary Interface, AMD64 Architecture Processor Supplement'
+// (http://www.x86-64.org/documentation/abi-0.95.pdf)
+//
+// The code in this file is a modification of src/x86/ffi64.c from libffi
+// (http://sources.redhat.com/libffi/) which is under the following license:
+
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
+
+ x86-64 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#include <sal/config.h>
+
+#include "abi.hxx"
+
+#include <o3tl/unreachable.hxx>
+#include <sal/log.hxx>
+
+using namespace x86_64;
+
+namespace {
+
+/* Register class used for passing given 64bit part of the argument.
+ These represent classes as documented by the PS ABI, with the exception
+ of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+ use SF or DFmode move instead of DImode to avoid reformatting penalties.
+
+ Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
+ whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+{
+ X86_64_NO_CLASS,
+ X86_64_INTEGER_CLASS,
+ X86_64_INTEGERSI_CLASS,
+ X86_64_SSE_CLASS,
+ X86_64_SSESF_CLASS,
+ X86_64_MEMORY_CLASS
+};
+
+}
+
+#define MAX_CLASSES 4
+
+/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
+ of this code is to classify each 8bytes of incoming argument by the register
+ class and assign registers accordingly. */
+
+/* Return the union class of CLASS1 and CLASS2.
+ See the x86-64 PS ABI for details. */
+
+static enum x86_64_reg_class
+merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
+ noexcept
+{
+ /* Rule #1: If both classes are equal, this is the resulting class. */
+ if (class1 == class2)
+ return class1;
+
+ /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+ the other class. */
+ if (class1 == X86_64_NO_CLASS)
+ return class2;
+ if (class2 == X86_64_NO_CLASS)
+ return class1;
+
+ /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
+ if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+ return X86_64_MEMORY_CLASS;
+
+ /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
+ if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+ || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+ return X86_64_INTEGERSI_CLASS;
+ if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+ || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+ return X86_64_INTEGER_CLASS;
+
+ /* Rule #6: Otherwise class SSE is used. */
+ return X86_64_SSE_CLASS;
+}
+
+/* Classify a parameter/return type.
+ CLASSES will be filled by the register class used to pass each word
+ of the operand. The number of words is returned. In case the operand
+ should be passed in memory, 0 is returned.
+
+ See the x86-64 PS ABI for details.
+*/
+static int
+classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) noexcept
+{
+ switch ( pTypeRef->eTypeClass )
+ {
+ case typelib_TypeClass_CHAR:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
+ classes[0] = X86_64_INTEGERSI_CLASS;
+ else
+ classes[0] = X86_64_INTEGER_CLASS;
+ return 1;
+ case typelib_TypeClass_FLOAT:
+ if ( ( byteOffset % 8 ) == 0 )
+ classes[0] = X86_64_SSESF_CLASS;
+ else
+ classes[0] = X86_64_SSE_CLASS;
+ return 1;
+ case typelib_TypeClass_DOUBLE:
+ classes[0] = X86_64_SSE_CLASS;
+ return 1;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ return 0;
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ const int UNITS_PER_WORD = 8;
+ int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
+ enum x86_64_reg_class subclasses[MAX_CLASSES];
+
+ /* If the struct is larger than 16 bytes, pass it on the stack. */
+ if ( pTypeDescr->nSize > 16 )
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+
+ for ( int i = 0; i < words; i++ )
+ classes[i] = X86_64_NO_CLASS;
+
+ const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
+
+ /* Merge the fields of structure. */
+ for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
+ {
+ typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
+ int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
+
+ int num = classify_argument( pTypeInStruct, subclasses, offset );
+
+ if ( num == 0 )
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+
+ for ( int i = 0; i < num; i++ )
+ {
+ int pos = offset / 8;
+ classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
+ if (classes[i + pos] == X86_64_MEMORY_CLASS) {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+ }
+ }
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+
+ return words;
+ }
+
+ default:
+ O3TL_UNREACHABLE;
+ }
+}
+
+/* Examine the argument and return set number of register required in each
+ class. Return 0 iff parameter should be passed in memory. */
+bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE ) noexcept
+{
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ // coverity[uninit_use_in_call : FALSE]
+ int n = classify_argument( pTypeRef, classes, 0 );
+
+ if ( n == 0 )
+ return false;
+
+ nUsedGPR = 0;
+ nUsedSSE = 0;
+ for ( n--; n >= 0; n-- )
+ switch ( classes[n] )
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ nUsedGPR++;
+ break;
+ case X86_64_SSE_CLASS:
+ case X86_64_SSESF_CLASS:
+ nUsedSSE++;
+ break;
+ default:
+ O3TL_UNREACHABLE;
+ }
+ return true;
+}
+
+bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) noexcept
+{
+ if (pTypeRef->eTypeClass == typelib_TypeClass_VOID) {
+ return false;
+ }
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ // coverity[uninit_use_in_call : FALSE]
+ return classify_argument(pTypeRef, classes, 0) == 0;
+}
+
+x86_64::ReturnKind x86_64::getReturnKind(typelib_TypeDescriptionReference * type) noexcept {
+ x86_64_reg_class classes[MAX_CLASSES];
+ // coverity[uninit_use_in_call : FALSE]
+ auto const n = classify_argument(type, classes, 0);
+ if (n == 0) {
+ return ReturnKind::Memory;
+ }
+ if (n == 2 && (classes[0] == X86_64_SSE_CLASS || classes[0] == X86_64_SSESF_CLASS)
+ && (classes[1] == X86_64_INTEGER_CLASS || classes[1] == X86_64_INTEGERSI_CLASS))
+ {
+ return ReturnKind::RegistersFpInt;
+ }
+ if (n == 2 && (classes[0] == X86_64_INTEGER_CLASS || classes[0] == X86_64_INTEGERSI_CLASS)
+ && (classes[1] == X86_64_SSE_CLASS || classes[1] == X86_64_SSESF_CLASS))
+ {
+ return ReturnKind::RegistersIntFp;
+ }
+ return ReturnKind::RegistersGeneral;
+}
+
+void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) noexcept
+{
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ // coverity[uninit_use_in_call : FALSE]
+ int n = classify_argument( pTypeRef, classes, 0 );
+
+ sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
+ for ( int i = 0; i != n; ++i )
+ switch ( classes[i] )
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ *pStructAlign++ = *pGPR++;
+ break;
+ case X86_64_SSE_CLASS:
+ case X86_64_SSESF_CLASS:
+ *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
+ break;
+ default:
+ O3TL_UNREACHABLE;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.hxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.hxx
new file mode 100644
index 0000000000..3ef80543ac
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/abi.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// This is an implementation of the x86-64 ABI as described in 'System V
+// Application Binary Interface, AMD64 Architecture Processor Supplement'
+// (http://www.x86-64.org/documentation/abi-0.95.pdf)
+
+#include <typelib/typedescription.hxx>
+
+namespace x86_64
+{
+
+/* 6 general purpose registers are used for parameter passing */
+const sal_uInt32 MAX_GPR_REGS = 6;
+
+/* 8 SSE registers are used for parameter passing */
+const sal_uInt32 MAX_SSE_REGS = 8;
+
+/* Count number of required registers.
+
+ Examine the argument and return set number of register required in each
+ class.
+
+ Return false iff parameter should be passed in memory.
+*/
+bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE ) noexcept;
+
+/** Does function that returns this type use a hidden parameter, or registers?
+
+ The value can be returned either in a hidden 1st parameter (which is a
+ pointer to a structure allocated by the caller), or in registers (rax, rdx
+ for the integers, xmm0, xmm1 for the floating point numbers).
+*/
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) noexcept;
+
+enum class ReturnKind {
+ Memory,
+ RegistersGeneral,
+ RegistersFpInt,
+ RegistersIntFp
+};
+
+ReturnKind getReturnKind(typelib_TypeDescriptionReference * type) noexcept;
+
+void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64* pGPR, const double* pSSE, void *pStruct ) noexcept;
+
+} // namespace x86_64
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/call.hxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/call.hxx
new file mode 100644
index 0000000000..08b19f06bb
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/call.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+extern "C" int cpp_vtable_call(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/call.s b/bridges/source/cpp_uno/gcc3_linux_x86-64/call.s
new file mode 100644
index 0000000000..e7ff106244
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/call.s
@@ -0,0 +1,142 @@
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .text
+ .align 2
+.globl privateSnippetExecutor
+ .type privateSnippetExecutor, @function
+privateSnippetExecutor:
+.LFB3:
+#if defined(END_BRANCH_INS_SUPPORT)
+ endbr64
+#endif
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ subq $160, %rsp
+.LCFI2:
+ movq %r10, -152(%rbp) # Save (nVtableOffset << 32) + nFunctionIndex
+
+ movq %rdi, -112(%rbp) # Save GP registers
+ movq %rsi, -104(%rbp)
+ movq %rdx, -96(%rbp)
+ movq %rcx, -88(%rbp)
+ movq %r8 , -80(%rbp)
+ movq %r9 , -72(%rbp)
+
+ movsd %xmm0, -64(%rbp) # Save FP registers
+ movsd %xmm1, -56(%rbp)
+ movsd %xmm2, -48(%rbp)
+ movsd %xmm3, -40(%rbp)
+ movsd %xmm4, -32(%rbp)
+ movsd %xmm5, -24(%rbp)
+ movsd %xmm6, -16(%rbp)
+ movsd %xmm7, -8(%rbp)
+
+ leaq -144(%rbp), %r9 # 6th param: sal_uInt64 * pRegisterReturn
+ leaq 16(%rbp), %r8 # 5rd param: void ** ovrflw
+ leaq -64(%rbp), %rcx # 4th param: void ** fpreg
+ leaq -112(%rbp), %rdx # 3rd param: void ** gpreg
+ movl -148(%rbp), %esi # 2nd param: sal_int32 nVtableOffset
+ movl -152(%rbp), %edi # 1st param: sal_int32 nFunctionIndex
+
+ call cpp_vtable_call
+
+ testl %eax, %eax
+ je .Lfpint
+ jg .Lintfp
+
+ movq -144(%rbp), %rax # Potential return value (general case)
+ movq -136(%rbp), %rdx # Potential return value (general case)
+ movq -144(%rbp), %xmm0 # Potential return value (general case)
+ movq -136(%rbp), %xmm1 # Potential return value (general case)
+ jmp .Lfinish
+.Lfpint:
+ movq -144(%rbp), %xmm0 # Return value (special fp and integer case)
+ movq -136(%rbp), %rax # Return value (special fp and integer case)
+ jmp .Lfinish
+.Lintfp:
+ movq -144(%rbp), %rax # Return value (special integer and fp case)
+ movq -136(%rbp), %xmm0 # Return value (special integer and fp case)
+
+.Lfinish:
+ leave
+ ret
+.LFE3:
+ .size privateSnippetExecutor, .-privateSnippetExecutor
+ # see http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+ # for details of the .eh_frame, the "Common Information Entry" and "Frame Description Entry" formats
+ # and http://mentorembedded.github.io/cxx-abi/exceptions.pdf for more info
+ .section .eh_frame,"a",@unwind
+.Lframe1:
+ .long .LECIE1-.LSCIE1 # CIE Length
+.LSCIE1:
+ .long 0x0 # CIE ID
+ .byte 0x1 # CIE Version
+ .string "zR" # CIE Augmentation String
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 -8 # CIE Data Alignment Factor
+ .byte 0x10 # CIE Return Address Register: pseudo "Return Address RA"
+ .uleb128 0x1 # CIE Augmentation Data Length
+ .byte 0x1b # CIE Augmentation Data
+ # CIE Initial Instructions:
+ .byte 0xc # DW_CFA_def_cfa %rsp +8
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90 # DW_CFA_offset (pseudo "Return Address RA") +1 (i.e., -8)
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1 # FDE Length
+.LASFDE1:
+ .long .LASFDE1-.Lframe1 # FDE CIE Pointer
+ .long .LFB3-. # FDE PC Begin
+ .long .LFE3-.LFB3 # FDE PC Range
+ .uleb128 0x0 # FDE Augmentation Data Length
+ # FDE Call Frame Instructions:
+ .byte 0x4 # DW_CFA_advance_loc4 .LCFI0
+ .long .LCFI0-.LFB3
+ .byte 0xe # DW_CFA_def_cfa_offset +16
+ .uleb128 0x10
+ .byte 0x86 # DW_CFA_offset %rbp +2 (i.e., -16)
+ .uleb128 0x2
+ .byte 0x4 # DW_CFA_advance_loc4 .LCFI1
+ .long .LCFI1-.LCFI0
+ .byte 0xd # DW_CFA_def_cfa_register %rbp
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+ .section .note.GNU-stack,"",@progbits
+ .section .note.gnu.property,"a"
+ .p2align 3
+ .long 1f - 0f
+ .long 4f - 1f
+ .long 5
+0:
+ .string "GNU"
+1:
+ .p2align 3
+ .long 0xc0000002
+ .long 3f - 2f
+2:
+ .long 0x3
+3:
+ .p2align 3
+4:
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.cxx
new file mode 100644
index 0000000000..04dd2dc6a5
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+#include "abi.hxx"
+#include "callvirtualmethod.hxx"
+
+// The call instruction within the asm block of callVirtualMethod may throw
+// exceptions. At least GCC 4.7.0 with -O0 would create (unnecessary)
+// .gcc_exception_table call-site table entries around all other calls in this
+// function that can throw, leading to std::terminate if the asm call throws an
+// exception and the unwinding C++ personality routine finds the unexpected hole
+// in the .gcc_exception_table. Therefore, make sure this function explicitly
+// only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
+// .gcc_exception_table section at all for this function). For some reason,
+// this also needs to be in a source file of its own.
+//
+// Also, this file should be compiled with -fnon-call-exceptions, and ideally
+// there would be a way to tell the compiler that the asm block contains calls
+// to functions that can potentially throw; see the mail thread starting at
+// <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
+// asm block can call function that can throw?"
+
+void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, double * pFPR)
+{
+ // Work around Clang -fsanitize=address "inline assembly requires more
+ // registers than available" error:
+ struct Data {
+ sal_uInt64 pMethod;
+ sal_uInt64 * pStack;
+ sal_uInt32 nStack;
+ sal_uInt64 * pGPR;
+ double * pFPR;
+ // Return values:
+ sal_uInt64 rax;
+ sal_uInt64 rdx;
+ double xmm0;
+ double xmm1;
+ } data;
+ data.pStack = pStack;
+ data.nStack = nStack;
+ data.pGPR = pGPR;
+ data.pFPR = pFPR;
+
+ // Get pointer to method
+ sal_uInt64 pMethod = *static_cast<sal_uInt64 *>(pThis);
+ pMethod += 8 * nVtableIndex;
+ data.pMethod = *reinterpret_cast<sal_uInt64 *>(pMethod);
+
+ asm volatile (
+ // Push arguments to stack
+ "movq %%rsp, %%r12\n\t"
+ "movl 16%0, %%ecx\n\t"
+ "jrcxz .Lpushed\n\t"
+ "xor %%rax, %%rax\n\t"
+ "leaq (%%rax, %%rcx, 8), %%rax\n\t"
+ "subq %%rax, %%rsp\n\t"
+ "andq $-9, %%rsp\n\t" // 16-bytes aligned
+ "movq 8%0, %%rsi\n\t"
+ "\n.Lpush:\n\t"
+ "decq %%rcx\n\t"
+ "movq (%%rsi, %%rcx, 8), %%rax\n\t"
+ "movq %%rax, (%%rsp, %%rcx, 8)\n\t"
+ "jnz .Lpush\n\t"
+ "\n.Lpushed:\n\t"
+
+ // Fill the xmm registers
+ "movq 32%0, %%rax\n\t"
+
+ "movsd (%%rax), %%xmm0\n\t"
+ "movsd 8(%%rax), %%xmm1\n\t"
+ "movsd 16(%%rax), %%xmm2\n\t"
+ "movsd 24(%%rax), %%xmm3\n\t"
+ "movsd 32(%%rax), %%xmm4\n\t"
+ "movsd 40(%%rax), %%xmm5\n\t"
+ "movsd 48(%%rax), %%xmm6\n\t"
+ "movsd 56(%%rax), %%xmm7\n\t"
+
+ // Fill the general purpose registers
+ "movq 24%0, %%rax\n\t"
+
+ "movq (%%rax), %%rdi\n\t"
+ "movq 8(%%rax), %%rsi\n\t"
+ "movq 16(%%rax), %%rdx\n\t"
+ "movq 24(%%rax), %%rcx\n\t"
+ "movq 32(%%rax), %%r8\n\t"
+ "movq 40(%%rax), %%r9\n\t"
+
+ // Perform the call
+ "movq 0%0, %%r11\n\t"
+ "call *%%r11\n\t"
+
+ // Fill the return values
+ "movq %%rax, 40%0\n\t"
+ "movq %%rdx, 48%0\n\t"
+ "movsd %%xmm0, 56%0\n\t"
+ "movsd %%xmm1, 64%0\n\t"
+
+ // Reset %rsp
+ "movq %%r12, %%rsp\n\t"
+ :: "o" (data)
+ : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", "r12",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+ "memory"
+ );
+
+ switch (pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_uInt64 *>( pRegisterReturn ) = data.rax;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *static_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32*>( &data.rax );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &data.rax );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &data.rax );
+ break;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(pRegisterReturn) = *reinterpret_cast<float *>(&data.xmm0);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>( pRegisterReturn ) = data.xmm0;
+ break;
+ default:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+ if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+ {
+ sal_uInt64 longs[2];
+ longs[0] = data.rax;
+ longs[1] = data.rdx;
+
+ double doubles[2];
+ doubles[0] = data.xmm0;
+ doubles[1] = data.xmm1;
+ x86_64::fill_struct( pReturnTypeRef, &longs[0], &doubles[0], pRegisterReturn);
+ }
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.hxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.hxx
new file mode 100644
index 0000000000..ac87c1c85b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/callvirtualmethod.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+void callVirtualMethod(
+ void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, double * pFPR);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx
new file mode 100644
index 0000000000..bd6d9e6179
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <config_options.h>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "abi.hxx"
+#include "call.hxx"
+#include "rtti.hxx"
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+// Perform the UNO call
+//
+// We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
+// arguments and call pThis->getUnoI()->pDispatcher.
+//
+// gpreg: [ret *], this, [gpr params]
+// fpreg: [fpr params]
+// ovrflw: [gpr or fpr params (properly aligned)]
+//
+// [ret *] is present when we are returning a structure bigger than 16 bytes
+// Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
+// Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
+//
+// The return value is the same as for cpp_vtable_call.
+static int cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+ unsigned int nr_gpr = 0; //number of gpr registers used
+ unsigned int nr_fpr = 0; //number of fpr registers used
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ x86_64::ReturnKind returnKind
+ = (pReturnTypeRef == nullptr || pReturnTypeRef->eTypeClass == typelib_TypeClass_VOID)
+ ? x86_64::ReturnKind::RegistersGeneral : x86_64::getReturnKind(pReturnTypeRef);
+
+ void * pUnoReturn = nullptr;
+ void * pCppReturn = nullptr; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if ( pReturnTypeDescr )
+ {
+ if ( returnKind == x86_64::ReturnKind::Memory )
+ {
+ pCppReturn = *gpreg++;
+ nr_gpr++;
+
+ pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn ); // direct way
+ }
+ else
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+
+ // pop this
+ gpreg++;
+ nr_gpr++;
+
+ // stack space
+ // parameters
+ void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+
+ if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
+ {
+ int nUsedGPR = 0;
+ int nUsedSSE = 0;
+ bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, nUsedGPR, nUsedSSE );
+
+ // Simple types must fit exactly one register on x86_64
+ assert( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); (void)bFitsRegisters;
+
+ if ( nUsedSSE == 1 )
+ {
+ if ( nr_fpr < x86_64::MAX_SSE_REGS )
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nr_fpr++;
+ }
+ else
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+ else if ( nUsedGPR == 1 )
+ {
+ if ( nr_gpr < x86_64::MAX_GPR_REGS )
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ nr_gpr++;
+ }
+ else
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+ }
+ else // ref
+ {
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ void *pCppStack;
+ if ( nr_gpr < x86_64::MAX_GPR_REGS )
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ nr_gpr++;
+ }
+ else
+ pCppArgs[nPos] = pCppStack = *ovrflw++;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
+ {
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ uno_copyAndConvertData( pUnoArgs[nPos],
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if ( pUnoExc )
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], nullptr );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return 0;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if ( pParams[nIndex].bOut ) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if ( pCppReturn ) // has complex return
+ {
+ if ( pUnoReturn != pCppReturn ) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, nullptr );
+ }
+ // complex return ptr is set to return reg
+ *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
+ }
+ if ( pReturnTypeDescr )
+ {
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+ switch (returnKind) {
+ case x86_64::ReturnKind::RegistersFpInt:
+ return 0;
+ case x86_64::ReturnKind::RegistersIntFp:
+ return 1;
+ default:
+ return -1;
+ }
+ }
+}
+
+// Returns -1 for the general case where potential return values from privateSnippetExecutor can be
+// copied from pRegisterReturn to both %rax and %rdx (in that order) and to %xmm0 and %xmm1 (in that
+// order)---each specific return type will only require a subset of that copy operations, but the
+// other copies to those non--callee-saved registers will be redundant and harmless. Returns 0 for
+// the special case where return values from privateSnippetExecutor must be copied from
+// pRegisterReturn to %xmm0 and %rax (in that order). Returns 1 for the special case where return
+// privateSnippetExecutor must be copied from pRegisterReturn to %rax and %xmm0 (in that order).
+int cpp_vtable_call(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+ void * pThis;
+ if ( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+ pThis = static_cast<char *>( pThis ) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ int eRet;
+ switch ( aMemberDescr.get()->eTypeClass )
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference *pAttrTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
+
+ if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
+ {
+ // is GET method
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
+ 0, nullptr, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ nullptr, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch ( nFunctionIndex )
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast<Type *>( gpreg[2] )->getTypeLibType() );
+ if ( pTD )
+ {
+ XInterface * pInterface = nullptr;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
+ ( pCppI->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&pInterface),
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
+
+ if ( pInterface )
+ {
+ ::uno_any_construct( static_cast<uno_Any *>( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
+ eRet = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ {
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams,
+ pMethodTD->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException("no member description found!",
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+ }
+
+ return eRet;
+}
+
+const int codeSnippetSize = 24;
+
+// Generate a trampoline that redirects method calls to
+// privateSnippetExecutor().
+//
+// privateSnippetExecutor() saves all the registers that are used for
+// parameter passing on x86_64, and calls the cpp_vtable_call().
+// When it returns, privateSnippetExecutor() sets the return value.
+//
+// Note: The code snippet we build here must not create a stack frame,
+// otherwise the UNO exceptions stop working thanks to non-existing
+// unwinding info.
+static unsigned char * codeSnippet( unsigned char * code,
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ bool bHasHiddenParam )
+{
+ sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>(nVtableOffset) << 32 ) | static_cast<sal_uInt64>(nFunctionIndex);
+
+ if ( bHasHiddenParam )
+ nOffsetAndIndex |= 0x80000000;
+
+ // movq $<nOffsetAndIndex>, %r10
+ *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
+ *reinterpret_cast<sal_uInt16 *>( code + 2 ) = nOffsetAndIndex & 0xFFFF;
+ *reinterpret_cast<sal_uInt32 *>( code + 4 ) = nOffsetAndIndex >> 16;
+ *reinterpret_cast<sal_uInt16 *>( code + 8 ) = nOffsetAndIndex >> 48;
+
+ // movq $<address of the privateSnippetExecutor>, %r11
+ *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
+ *reinterpret_cast<sal_uInt32 *>( code + 12 )
+ = reinterpret_cast<sal_uInt64>(privateSnippetExecutor);
+ *reinterpret_cast<sal_uInt32 *>( code + 16 )
+ = reinterpret_cast<sal_uInt64>(privateSnippetExecutor) >> 32;
+
+ // jmpq *%r11
+ *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
+
+ return code + codeSnippetSize;
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+#if ENABLE_RUNTIME_OPTIMIZATIONS
+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 {};
+}
+#endif
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32 vtableNumber,
+ typelib_InterfaceTypeDescription * type)
+{
+ Slot * slots = mapBlockToVtable(block);
+#if ENABLE_RUNTIME_OPTIMIZATIONS
+ slots[-2].fn = nullptr;
+ slots[-1].fn = &typeid(ProxyRtti);
+ (void)vtableNumber;
+ (void)type;
+#else
+ slots[-2].fn = reinterpret_cast<void *>(-(vtableNumber * sizeof (void *)));
+ slots[-1].fn = x86_64::getRtti(type->aBase);
+#endif
+ return slots + slotCount;
+}
+
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
+ sal_Int32 functionCount, sal_Int32 nVtableOffset )
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
+ {
+ typelib_TypeDescription * pTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
+ assert(pTD);
+
+ if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
+ {
+ typelib_InterfaceAttributeTypeDescription *pAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
+
+ // get method
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
+ x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
+
+ if ( ! pAttrTD->bReadOnly )
+ {
+ // set method
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
+ }
+ }
+ else if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
+ {
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
+
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
+ x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
+ }
+ else
+ assert(false);
+
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ SAL_UNUSED_PARAMETER unsigned char const *,
+ SAL_UNUSED_PARAMETER unsigned char const * )
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx
new file mode 100644
index 0000000000..daee12731e
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include "rtti.hxx"
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( *p == 'N' );
+ ++p; // skip N
+
+ while (*p != 'E')
+ {
+ // read chars count
+ int n = *p++ - '0';
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if (*p != 'E')
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+extern "C" {
+static void _GLIBCXX_CDTOR_CALLABI deleteException( void * pExc )
+{
+ __cxxabiv1::__cxa_exception const * header = static_cast<__cxxabiv1::__cxa_exception const *>(pExc) - 1;
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+ // First, the libcxxabi commit
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+ // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+ // LLVM 5.0 changed the size of __cxa_exception by adding
+ //
+ // __attribute__((aligned))
+ //
+ // to the final member unwindHeader, on x86-64 effectively adding a hole of
+ // size 8 in front of that member (changing its offset from 88 to 96,
+ // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+ // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
+ // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+ // point to this function (the use of __cxa_exception in fillUnoException is
+ // unaffected, as it only accesses members towards the start of the struct,
+ // through a pointer known to actually point at the start). The libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+ // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+ // removes the need for this hack, so the "header1" hack can be removed again once we can be
+ // sure that we only run against libcxxabi from LLVM >= 6.
+ //
+ // Second, the libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
+ // the layout of the start of __cxa_exception to
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
+ // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
+ // offset by 8. As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx), the "header2" hack (together with the
+ // "#if 0" in the definition of __cxa_exception and the corresponding hack in fillUnoException)
+ // can be dropped once we can be sure that we only run against new libcxxabi that has the
+ // reserve member.
+ if (header->exceptionDestructor != &deleteException) {
+ auto const header1 = reinterpret_cast<__cxa_exception const *>(
+ reinterpret_cast<char const *>(header) - 8);
+ if (header1->exceptionDestructor == &deleteException) {
+ header = header1;
+ } else {
+ auto const header2 = reinterpret_cast<__cxa_exception const *>(
+ reinterpret_cast<char const *>(header) + 8);
+ if (header2->exceptionDestructor == &deleteException) {
+ header = header2;
+ } else {
+ assert(false);
+ }
+ }
+ }
+#endif
+ assert(header->exceptionDestructor == &deleteException);
+ typelib_TypeDescription * pTD = nullptr;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ "cannot get typedescription for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxxabiv1::__cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ // avoiding locked counts
+ rtti = x86_64::getRtti(*pTypeDescr);
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ "no rtti for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxxabiv1::__cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxxabiv1::__cxa_exception * header = __cxxabiv1::__cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+ // Very bad HACK to find out whether we run against a libcxxabi that has a new
+ // __cxa_exception::reserved member at the start, introduced with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of the
+ // start of __cxa_exception is
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // where the (bad, hacky) assumption is that reserve (if present) is null
+ // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+ // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+ // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+ // __cxa_dependent_exception, the referenceCount member is rather
+ //
+ // 8 byte void* primaryException
+ //
+ // but which also will always be set to a non-null value in __cxa_rethrow_primary_exception).
+ // As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx), this hack (together with the "#if 0"
+ // there) can be dropped once we can be sure that we only run against new libcxxabi that has the
+ // reserve member:
+ if (*reinterpret_cast<void **>(header) == nullptr) {
+ header = reinterpret_cast<__cxxabiv1::__cxa_exception*>(reinterpret_cast<void **>(header) + 1);
+ }
+#endif
+
+ std::type_info *exceptionType = __cxxabiv1::__cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = nullptr;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (pExcTypeDescr == nullptr)
+ {
+ RuntimeException aRE( "exception type not found: " + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.cxx
new file mode 100644
index 0000000000..9bce77bc84
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.cxx
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <memory>
+#include <mutex>
+#include <typeinfo>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <dlfcn.h>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <typelib/typedescription.h>
+#include <o3tl/string_view.hxx>
+
+#include "rtti.hxx"
+#include "share.hxx"
+
+namespace {
+
+class Generated {
+public:
+ virtual ~Generated() {};
+
+ virtual std::type_info * get() const = 0;
+};
+
+class GeneratedPlain: public Generated {
+public:
+ GeneratedPlain(std::unique_ptr<std::type_info> && info): info_(std::move(info)) {};
+
+ std::type_info * get() const override { return info_.get(); }
+
+private:
+ std::unique_ptr<std::type_info> info_;
+};
+
+class GeneratedPad: public Generated {
+public:
+ GeneratedPad(std::unique_ptr<char[]> && pad): pad_(std::move(pad)) {};
+
+ ~GeneratedPad() override { get()->~type_info(); }
+
+ std::type_info * get() const override final
+ { return reinterpret_cast<std::type_info *>(pad_.get()); }
+
+private:
+ std::unique_ptr<char[]> pad_;
+};
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, std::type_info * > t_rtti_map;
+
+ t_rtti_map m_rttis;
+ std::vector<OString> m_rttiNames;
+ std::unordered_map<OUString, std::unique_ptr<Generated>> m_generatedRttis;
+
+#if !defined ANDROID
+ void * m_hApp;
+#endif
+
+public:
+ RTTI();
+ ~RTTI();
+
+ std::type_info * getRTTI(typelib_TypeDescription const &);
+};
+
+RTTI::RTTI()
+#if !defined ANDROID
+ : m_hApp( dlopen( nullptr, RTLD_LAZY ) )
+#endif
+{
+}
+
+RTTI::~RTTI()
+{
+#if !defined ANDROID
+ dlclose( m_hApp );
+#endif
+}
+
+std::type_info * RTTI::getRTTI(typelib_TypeDescription const & pTypeDescr)
+{
+ OUString const & unoName = OUString::unacquired(&pTypeDescr.pTypeName);
+
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind != m_rttis.end())
+ return iFind->second;
+
+ std::type_info * rtti;
+
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ std::u16string_view token( o3tl::getToken(unoName, 0, '.', index ) );
+ buf.append( static_cast<sal_Int32>(token.size()) );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+#if !defined ANDROID
+ rtti = static_cast<std::type_info *>(dlsym( m_hApp, symName.getStr() ));
+#else
+ rtti = static_cast<std::type_info *>(dlsym( RTLD_DEFAULT, symName.getStr() ));
+#endif
+
+ if (rtti)
+ {
+ std::pair< t_rtti_map::iterator, bool > insertion (
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second, "bridges", "key " << unoName << " already in rtti map" );
+ return rtti;
+ }
+
+ // try to lookup the symbol in the generated rtti map
+ auto iFind2( m_generatedRttis.find( unoName ) );
+ if (iFind2 != m_generatedRttis.end())
+ {
+ // taking already generated rtti
+ rtti = iFind2->second->get();
+ return rtti;
+ }
+
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char const * rttiName = symName.getStr() +4;
+
+ SAL_INFO("bridges", "Generated rtti for " << rttiName);
+
+ std::unique_ptr<Generated> newRtti;
+ switch (pTypeDescr.eTypeClass) {
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_CompoundTypeDescription const & ctd
+ = reinterpret_cast<
+ typelib_CompoundTypeDescription const &>(
+ pTypeDescr);
+ if (ctd.pBaseTypeDescription)
+ {
+ // ensure availability of base
+ std::type_info * base_rtti = getRTTI(
+ ctd.pBaseTypeDescription->aBase);
+ m_rttiNames.emplace_back(OString(rttiName));
+ std::unique_ptr<std::type_info> info(
+ new __cxxabiv1::__si_class_type_info(
+ m_rttiNames.back().getStr(), static_cast<__cxxabiv1::__class_type_info *>(base_rtti) ));
+ newRtti.reset(new GeneratedPlain(std::move(info)));
+ }
+ else
+ {
+ // this class has no base class
+ m_rttiNames.emplace_back(OString(rttiName));
+ std::unique_ptr<std::type_info> info(
+ new __cxxabiv1::__class_type_info(m_rttiNames.back().getStr()));
+ newRtti.reset(new GeneratedPlain(std::move(info)));
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ typelib_InterfaceTypeDescription const & itd
+ = reinterpret_cast<
+ typelib_InterfaceTypeDescription const &>(
+ pTypeDescr);
+ std::vector<std::type_info *> bases;
+ for (sal_Int32 i = 0; i != itd.nBaseTypes; ++i) {
+ bases.push_back(getRTTI(itd.ppBaseTypes[i]->aBase));
+ }
+ switch (itd.nBaseTypes) {
+ case 0:
+ {
+ m_rttiNames.emplace_back(OString(rttiName));
+ std::unique_ptr<std::type_info> info(
+ new __cxxabiv1::__class_type_info(
+ m_rttiNames.back().getStr()));
+ newRtti.reset(new GeneratedPlain(std::move(info)));
+ break;
+ }
+ case 1:
+ {
+ m_rttiNames.emplace_back(OString(rttiName));
+ std::unique_ptr<std::type_info> info(
+ new __cxxabiv1::__si_class_type_info(
+ m_rttiNames.back().getStr(),
+ static_cast<
+ __cxxabiv1::__class_type_info *>(
+ bases[0])));
+ newRtti.reset(new GeneratedPlain(std::move(info)));
+ break;
+ }
+ default:
+ {
+ m_rttiNames.emplace_back(OString(rttiName));
+ auto pad = std::make_unique<char[]>(
+ sizeof (__cxxabiv1::__vmi_class_type_info)
+ + ((itd.nBaseTypes - 1)
+ * sizeof (
+ __cxxabiv1::__base_class_type_info)));
+ __cxxabiv1::__vmi_class_type_info * info
+ = new(pad.get())
+ __cxxabiv1::__vmi_class_type_info(
+ m_rttiNames.back().getStr(),
+ __cxxabiv1::__vmi_class_type_info::__flags_unknown_mask);
+ info->__base_count = itd.nBaseTypes;
+ for (sal_Int32 i = 0; i != itd.nBaseTypes; ++i)
+ {
+ info->__base_info[i].__base_type
+ = static_cast<
+ __cxxabiv1::__class_type_info *>(
+ bases[i]);
+ info->__base_info[i].__offset_flags
+ = (__cxxabiv1::__base_class_type_info::__public_mask
+ | ((8 * i) << __cxxabiv1::__base_class_type_info::__offset_shift));
+ }
+ newRtti.reset(new GeneratedPad(std::move(pad)));
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ assert(false); // cannot happen
+ }
+ rtti = newRtti->get();
+
+ auto insertion(m_generatedRttis.emplace(unoName, std::move(newRtti)));
+ SAL_WARN_IF( !insertion.second, "bridges", "key " << unoName << " already in generated rtti map" );
+
+ return rtti;
+}
+
+}
+
+std::type_info * x86_64::getRtti(typelib_TypeDescription const & type) {
+ static RTTI theRttiFactory;
+ static std::mutex theMutex;
+ std::lock_guard aGuard(theMutex);
+ return theRttiFactory.getRTTI(type);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.hxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.hxx
new file mode 100644
index 0000000000..b056f2e640
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/rtti.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <typelib/typedescription.h>
+
+namespace x86_64
+{
+std::type_info* getRtti(typelib_TypeDescription const& type);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx
new file mode 100644
index 0000000000..d7657bcc04
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+#include <cxxabi.h>
+#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h
+#define _GLIBCXX_CDTOR_CALLABI
+#endif
+#include <unwind.h>
+
+#include <config_cxxabi.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#if !HAVE_CXXABI_H_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __class_type_info: public std::type_info {
+public:
+ explicit __class_type_info(char const * n): type_info(n) {}
+ ~__class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __si_class_type_info: public __class_type_info {
+public:
+ __class_type_info const * __base_type;
+ explicit __si_class_type_info(
+ char const * n, __class_type_info const *base):
+ __class_type_info(n), __base_type(base) {}
+ ~__si_class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_BASE_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+struct __base_class_type_info {
+ __class_type_info const * __base_type;
+#if defined _GLIBCXX_LLP64
+ long long __offset_flags;
+#else
+ long __offset_flags;
+#endif
+ enum __offset_flags_masks {
+ __virtual_mask = 0x1,
+ __public_mask = 0x2,
+ __offset_shift = 8
+ };
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_VMI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __vmi_class_type_info: public __class_type_info {
+public:
+ unsigned int __flags;
+ unsigned int __base_count;
+ __base_class_type_info __base_info[1];
+ enum __flags_masks {
+ __non_diamond_repeat_mask = 0x1,
+ __diamond_shaped_mask = 0x2,
+ __flags_unknown_mask = 0x10
+ };
+ explicit __vmi_class_type_info(char const * n, int flags):
+ __class_type_info(n), __flags(flags), __base_count(0) {}
+ ~__vmi_class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EXCEPTION
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>,
+// libcxxabi/src/cxa_exception.hpp:
+namespace __cxxabiv1 {
+struct __cxa_exception {
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+#if defined __LP64__ || LIBCXXABI_ARM_EHABI
+#if 0
+ // This is a new field added with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The HACK in
+ // fillUnoException (bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx) tries to find out at
+ // runtime whether a __cxa_exception has this member. Once we can be sure that we only run
+ // against new libcxxabi that has this member, we can drop the "#if 0" here and drop the hack
+ // in fillUnoException.
+
+ // Now _Unwind_Exception is marked with __attribute__((aligned)),
+ // which implies __cxa_exception is also aligned. Insert padding
+ // in the beginning of the struct, rather than before unwindHeader.
+ void *reserve;
+#endif
+ std::size_t referenceCount;
+#endif
+#endif
+ std::type_info * exceptionType;
+ void (* exceptionDestructor)(void *);
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+ __cxa_exception * nextException;
+ int handlerCount;
+ int handlerSwitchValue;
+ char const * actionRecord;
+ char const * languageSpecificData;
+ void * catchTemp;
+ void * adjustedPtr;
+ _Unwind_Exception unwindHeader;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EH_GLOBALS
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>:
+namespace __cxxabiv1 {
+struct __cxa_eh_globals {
+ __cxa_exception * caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_GET_GLOBALS
+namespace __cxxabiv1 {
+extern "C" __cxa_eh_globals * __cxa_get_globals() noexcept;
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_CURRENT_EXCEPTION_TYPE
+namespace __cxxabiv1 {
+extern "C" std::type_info *__cxa_current_exception_type() noexcept;
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_ALLOCATE_EXCEPTION
+namespace __cxxabiv1 {
+extern "C" void * __cxa_allocate_exception(std::size_t thrown_size) noexcept;
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_THROW
+namespace __cxxabiv1 {
+extern "C" void __cxa_throw(
+ void * thrown_exception, void * tinfo, void (* dest)(void *))
+ __attribute__((noreturn));
+}
+#endif
+
+extern "C" void privateSnippetExecutor( ... );
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/uno2cpp.cxx
new file mode 100644
index 0000000000..496702120a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/uno2cpp.cxx
@@ -0,0 +1,437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/alloca.h>
+
+#include <exception>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "abi.hxx"
+#include "callvirtualmethod.hxx"
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+// Functions for easier insertion of values to registers or stack
+// pSV - pointer to the source
+// nr - order of the value [will be increased if stored to register]
+// pFPR, pGPR - pointer to the registers
+// pDS - pointer to the stack [will be increased if stored here]
+
+// The value in %xmm register is already prepared to be retrieved as a float,
+// thus we treat float and double the same
+void INSERT_FLOAT_DOUBLE(
+ void const * pSV, sal_uInt32 & nr, double * pFPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_SSE_REGS )
+ pFPR[nr++] = *static_cast<double const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt64 const *>( pSV ); // verbatim!
+}
+
+void INSERT_INT64(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt64 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt64 const *>( pSV );
+}
+
+void INSERT_INT32(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt32 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt32 const *>( pSV );
+}
+
+void INSERT_INT16(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt16 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt16 const *>( pSV );
+}
+
+void INSERT_INT8(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt8 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt8 const *>( pSV );
+}
+
+}
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // Maximum space for [complex ret ptr], values | ptr ...
+ // (but will be used less - some of the values will be in pGPR and pFPR)
+ sal_uInt64 *pStack = static_cast<sal_uInt64 *>(__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ));
+ sal_uInt64 *pStackStart = pStack;
+
+ sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ double pFPR[x86_64::MAX_SSE_REGS];
+ sal_uInt32 nFPR = 0;
+
+ // Return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion (see below)
+
+ bool bSimpleReturn = true;
+ if ( pReturnTypeDescr )
+ {
+ if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
+ bSimpleReturn = false;
+
+ if ( bSimpleReturn )
+ pCppReturn = pUnoReturn; // direct way for simple types
+ else
+ {
+ // complex return via ptr
+ pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
+ __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
+ INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
+ }
+ }
+
+ // Push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+ INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+ // Args
+ void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
+ // Indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
+ // Type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ pCppArgs[nPos] = alloca( 8 );
+ uno_copyAndConvertData( pCppArgs[nPos], pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ uno_constructData( pCppArgs[nPos], pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ uno_copyAndConvertData(
+ pCppArgs[nPos], pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeRef, bSimpleReturn,
+ pStackStart, ( pStack - pStackStart ),
+ pGPR, pFPR );
+ } catch (const Exception &) {
+ throw;
+ } catch (const std::exception & e) {
+ throw RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name())
+ + ": " + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw RuntimeException("C++ code threw unknown exception");
+ }
+
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ assert(
+ (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)
+ ->nPosition)
+ < pThis->pTypeDescr->nAllMembers);
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ assert(
+ (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)
+ ->nPosition)
+ < pThis->pTypeDescr->nAllMembers);
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx
new file mode 100644
index 0000000000..8f6ca30957
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// This is an implementation of the x86-64 ABI as described in 'System V
+// Application Binary Interface, AMD64 Architecture Processor Supplement'
+// (http://www.x86-64.org/documentation/abi-0.95.pdf)
+//
+// The code in this file is a modification of src/x86/ffi64.c from libffi
+// (http://sources.redhat.com/libffi/) which is under the following license:
+
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
+
+ x86-64 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#include <sal/config.h>
+
+#include "abi.hxx"
+
+#include <o3tl/unreachable.hxx>
+#include <sal/log.hxx>
+
+using namespace x86_64;
+
+namespace {
+
+/* Register class used for passing given 64bit part of the argument.
+ These represent classes as documented by the PS ABI, with the exception
+ of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+ use SF or DFmode move instead of DImode to avoid reformatting penalties.
+
+ Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
+ whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+{
+ X86_64_NO_CLASS,
+ X86_64_INTEGER_CLASS,
+ X86_64_INTEGERSI_CLASS,
+ X86_64_SSE_CLASS,
+ X86_64_SSESF_CLASS,
+ X86_64_MEMORY_CLASS
+};
+
+}
+
+#define MAX_CLASSES 4
+
+/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
+ of this code is to classify each 8bytes of incoming argument by the register
+ class and assign registers accordingly. */
+
+/* Return the union class of CLASS1 and CLASS2.
+ See the x86-64 PS ABI for details. */
+
+static enum x86_64_reg_class
+merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
+ noexcept
+{
+ /* Rule #1: If both classes are equal, this is the resulting class. */
+ if (class1 == class2)
+ return class1;
+
+ /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+ the other class. */
+ if (class1 == X86_64_NO_CLASS)
+ return class2;
+ if (class2 == X86_64_NO_CLASS)
+ return class1;
+
+ /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
+ if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+ return X86_64_MEMORY_CLASS;
+
+ /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
+ if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+ || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+ return X86_64_INTEGERSI_CLASS;
+ if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+ || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+ return X86_64_INTEGER_CLASS;
+
+ /* Rule #6: Otherwise class SSE is used. */
+ return X86_64_SSE_CLASS;
+}
+
+/* Classify a parameter/return type.
+ CLASSES will be filled by the register class used to pass each word
+ of the operand. The number of words is returned. In case the operand
+ should be passed in memory, 0 is returned.
+
+ See the x86-64 PS ABI for details.
+*/
+static int
+classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) noexcept
+{
+ switch ( pTypeRef->eTypeClass )
+ {
+ case typelib_TypeClass_CHAR:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
+ classes[0] = X86_64_INTEGERSI_CLASS;
+ else
+ classes[0] = X86_64_INTEGER_CLASS;
+ return 1;
+ case typelib_TypeClass_FLOAT:
+ if ( ( byteOffset % 8 ) == 0 )
+ classes[0] = X86_64_SSESF_CLASS;
+ else
+ classes[0] = X86_64_SSE_CLASS;
+ return 1;
+ case typelib_TypeClass_DOUBLE:
+ classes[0] = X86_64_SSE_CLASS;
+ return 1;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ return 0;
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+ const int UNITS_PER_WORD = 8;
+ int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
+ enum x86_64_reg_class subclasses[MAX_CLASSES];
+
+ /* If the struct is larger than 16 bytes, pass it on the stack. */
+ if ( pTypeDescr->nSize > 16 )
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+
+ for ( int i = 0; i < words; i++ )
+ classes[i] = X86_64_NO_CLASS;
+
+ const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
+
+ /* Merge the fields of structure. */
+ for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
+ {
+ typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
+ int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
+
+ int num = classify_argument( pTypeInStruct, subclasses, offset );
+
+ if ( num == 0 )
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+
+ for ( int i = 0; i < num; i++ )
+ {
+ int pos = offset / 8;
+ classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
+ if (classes[i + pos] == X86_64_MEMORY_CLASS) {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ return 0;
+ }
+ }
+ }
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+
+ return words;
+ }
+
+ default:
+ O3TL_UNREACHABLE;
+ }
+}
+
+/* Examine the argument and return set number of register required in each
+ class. Return 0 iff parameter should be passed in memory. */
+bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE ) noexcept
+{
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ int n;
+
+ n = classify_argument( pTypeRef, classes, 0 );
+
+ if ( n == 0 )
+ return false;
+
+ nUsedGPR = 0;
+ nUsedSSE = 0;
+ for ( n--; n >= 0; n-- )
+ switch ( classes[n] )
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ nUsedGPR++;
+ break;
+ case X86_64_SSE_CLASS:
+ case X86_64_SSESF_CLASS:
+ nUsedSSE++;
+ break;
+ default:
+ O3TL_UNREACHABLE;
+ }
+ return true;
+}
+
+bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) noexcept
+{
+ if (pTypeRef->eTypeClass == typelib_TypeClass_VOID) {
+ return false;
+ }
+ x86_64_reg_class classes[MAX_CLASSES];
+ return classify_argument(pTypeRef, classes, 0) == 0;
+}
+
+x86_64::ReturnKind x86_64::getReturnKind(typelib_TypeDescriptionReference * type) noexcept {
+ x86_64_reg_class classes[MAX_CLASSES];
+ auto const n = classify_argument(type, classes, 0);
+ if (n == 0) {
+ return ReturnKind::Memory;
+ }
+ if (n == 2 && (classes[0] == X86_64_SSE_CLASS || classes[0] == X86_64_SSESF_CLASS)
+ && (classes[1] == X86_64_INTEGER_CLASS || classes[1] == X86_64_INTEGERSI_CLASS))
+ {
+ return ReturnKind::RegistersFpInt;
+ }
+ if (n == 2 && (classes[0] == X86_64_INTEGER_CLASS || classes[0] == X86_64_INTEGERSI_CLASS)
+ && (classes[1] == X86_64_SSE_CLASS || classes[1] == X86_64_SSESF_CLASS))
+ {
+ return ReturnKind::RegistersIntFp;
+ }
+ return ReturnKind::RegistersGeneral;
+}
+
+void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) noexcept
+{
+ enum x86_64_reg_class classes[MAX_CLASSES];
+ int n;
+
+ n = classify_argument( pTypeRef, classes, 0 );
+
+ sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
+ for ( int i = 0; i != n; ++i )
+ switch ( classes[i] )
+ {
+ case X86_64_INTEGER_CLASS:
+ case X86_64_INTEGERSI_CLASS:
+ *pStructAlign++ = *pGPR++;
+ break;
+ case X86_64_SSE_CLASS:
+ case X86_64_SSESF_CLASS:
+ *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
+ break;
+ default:
+ O3TL_UNREACHABLE;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx
new file mode 100644
index 0000000000..3ef80543ac
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// This is an implementation of the x86-64 ABI as described in 'System V
+// Application Binary Interface, AMD64 Architecture Processor Supplement'
+// (http://www.x86-64.org/documentation/abi-0.95.pdf)
+
+#include <typelib/typedescription.hxx>
+
+namespace x86_64
+{
+
+/* 6 general purpose registers are used for parameter passing */
+const sal_uInt32 MAX_GPR_REGS = 6;
+
+/* 8 SSE registers are used for parameter passing */
+const sal_uInt32 MAX_SSE_REGS = 8;
+
+/* Count number of required registers.
+
+ Examine the argument and return set number of register required in each
+ class.
+
+ Return false iff parameter should be passed in memory.
+*/
+bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE ) noexcept;
+
+/** Does function that returns this type use a hidden parameter, or registers?
+
+ The value can be returned either in a hidden 1st parameter (which is a
+ pointer to a structure allocated by the caller), or in registers (rax, rdx
+ for the integers, xmm0, xmm1 for the floating point numbers).
+*/
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) noexcept;
+
+enum class ReturnKind {
+ Memory,
+ RegistersGeneral,
+ RegistersFpInt,
+ RegistersIntFp
+};
+
+ReturnKind getReturnKind(typelib_TypeDescriptionReference * type) noexcept;
+
+void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64* pGPR, const double* pSSE, void *pStruct ) noexcept;
+
+} // namespace x86_64
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.cxx
new file mode 100644
index 0000000000..2c7332a16a
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "call.hxx"
+
+void privateSnippetExecutor()
+{
+ asm volatile
+ (
+ " subq $160, %rsp\n"
+
+ " movq %r10, -152(%rbp) # Save (nVtableOffset << 32) + nFunctionIndex\n"
+
+ " movq %rdi, -112(%rbp) # Save GP registers\n"
+ " movq %rsi, -104(%rbp)\n"
+ " movq %rdx, -96(%rbp)\n"
+ " movq %rcx, -88(%rbp)\n"
+ " movq %r8 , -80(%rbp)\n"
+ " movq %r9 , -72(%rbp)\n"
+
+ " movsd %xmm0, -64(%rbp) # Save FP registers\n"
+ " movsd %xmm1, -56(%rbp)\n"
+ " movsd %xmm2, -48(%rbp)\n"
+ " movsd %xmm3, -40(%rbp)\n"
+ " movsd %xmm4, -32(%rbp)\n"
+ " movsd %xmm5, -24(%rbp)\n"
+ " movsd %xmm6, -16(%rbp)\n"
+ " movsd %xmm7, -8(%rbp)\n"
+
+ " leaq -144(%rbp), %r9 # 6th param: sal_uInt64 * pRegisterReturn\n"
+ " leaq 16(%rbp), %r8 # 5rd param: void ** ovrflw\n"
+ " leaq -64(%rbp), %rcx # 4th param: void ** fpreg\n"
+ " leaq -112(%rbp), %rdx # 3rd param: void ** gpreg\n"
+ " movl -148(%rbp), %esi # 2nd param: sal_int32 nVtableOffset\n"
+ " movl -152(%rbp), %edi # 1st param: sal_int32 nFunctionIndex\n"
+
+ " call _cpp_vtable_call\n"
+
+ " testl %eax, %eax\n"
+ " je .Lfpint\n"
+ " jg .Lintfp\n"
+
+ " movq -144(%rbp), %rax # Potential return value (general case)\n"
+ " movq -136(%rbp), %rdx # Potential return value (general case)\n"
+ " movq -144(%rbp), %xmm0 # Potential return value (general case)\n"
+ " movq -136(%rbp), %xmm1 # Potential return value (general case)\n"
+ " jmp .Lfinish\n"
+
+ ".Lfpint:\n"
+ " movq -144(%rbp), %xmm0 # Return value (special fp and integer case)\n"
+ " movq -136(%rbp), %rax # Return value (special fp and integer case)\n"
+ " jmp .Lfinish\n"
+
+ ".Lintfp:\n"
+ " movq -144(%rbp), %rax # Return value (special integer and fp case)\n"
+ " movq -136(%rbp), %xmm0 # Return value (special integer and fp case)\n"
+
+ ".Lfinish:\n"
+ " addq $160, %rsp\n"
+ );
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.hxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.hxx
new file mode 100644
index 0000000000..efb5b95189
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+extern "C" int cpp_vtable_call(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ );
+
+extern "C" void privateSnippetExecutor();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx
new file mode 100644
index 0000000000..83a9ca81d8
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstring>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+#include "abi.hxx"
+#include "callvirtualmethod.hxx"
+
+// The call instruction within the asm block of callVirtualMethod may throw
+// exceptions. At least GCC 4.7.0 with -O0 would create (unnecessary)
+// .gcc_exception_table call-site table entries around all other calls in this
+// function that can throw, leading to std::terminate if the asm call throws an
+// exception and the unwinding C++ personality routine finds the unexpected hole
+// in the .gcc_exception_table. Therefore, make sure this function explicitly
+// only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
+// .gcc_exception_table section at all for this function). For some reason,
+// this also needs to be in a source file of its own.
+//
+// Also, this file should be compiled with -fnon-call-exceptions, and ideally
+// there would be a way to tell the compiler that the asm block contains calls
+// to functions that can potentially throw; see the mail thread starting at
+// <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
+// asm block can call function that can throw?"
+
+void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, double * pFPR)
+{
+ // Work around -fsanitize=address "inline assembly requires more registers
+ // than available" error:
+ struct Data {
+ sal_uInt64 pMethod;
+ sal_uInt64 * pStack;
+ sal_uInt32 nStack;
+ sal_uInt64 * pGPR;
+ double * pFPR;
+ // Return values:
+ sal_uInt64 rax;
+ sal_uInt64 rdx;
+ double xmm0;
+ double xmm1;
+ } data;
+ data.pStack = pStack;
+ data.nStack = nStack;
+ data.pGPR = pGPR;
+ data.pFPR = pFPR;
+
+ // Get pointer to method
+ sal_uInt64 pMethod = *static_cast<sal_uInt64 *>(pThis);
+ pMethod += 8 * nVtableIndex;
+ data.pMethod = *reinterpret_cast<sal_uInt64 *>(pMethod);
+
+ asm volatile (
+ // Push arguments to stack
+ "movq %%rsp, %%r12\n\t"
+ "movl 16%0, %%ecx\n\t"
+ "jrcxz Lpushed\n\t"
+ "xor %%rax, %%rax\n\t"
+ "leaq (%%rax, %%rcx, 8), %%rax\n\t"
+ "subq %%rax, %%rsp\n\t"
+ "andq $-9, %%rsp\n\t" // 16-bytes aligned
+ "movq 8%0, %%rsi\n\t"
+ "\nLpush:\n\t"
+ "decq %%rcx\n\t"
+ "movq (%%rsi, %%rcx, 8), %%rax\n\t"
+ "movq %%rax, (%%rsp, %%rcx, 8)\n\t"
+ "jnz Lpush\n\t"
+ "\nLpushed:\n\t"
+
+ // Fill the xmm registers
+ "movq 32%0, %%rax\n\t"
+
+ "movsd (%%rax), %%xmm0\n\t"
+ "movsd 8(%%rax), %%xmm1\n\t"
+ "movsd 16(%%rax), %%xmm2\n\t"
+ "movsd 24(%%rax), %%xmm3\n\t"
+ "movsd 32(%%rax), %%xmm4\n\t"
+ "movsd 40(%%rax), %%xmm5\n\t"
+ "movsd 48(%%rax), %%xmm6\n\t"
+ "movsd 56(%%rax), %%xmm7\n\t"
+
+ // Fill the general purpose registers
+ "movq 24%0, %%rax\n\t"
+
+ "movq (%%rax), %%rdi\n\t"
+ "movq 8(%%rax), %%rsi\n\t"
+ "movq 16(%%rax), %%rdx\n\t"
+ "movq 24(%%rax), %%rcx\n\t"
+ "movq 32(%%rax), %%r8\n\t"
+ "movq 40(%%rax), %%r9\n\t"
+
+ // Perform the call
+ "movq 0%0, %%r11\n\t"
+ "call *%%r11\n\t"
+
+ // Fill the return values
+ "movq %%rax, 40%0\n\t"
+ "movq %%rdx, 48%0\n\t"
+ "movsd %%xmm0, 56%0\n\t"
+ "movsd %%xmm1, 64%0\n\t"
+
+ // Reset %rsp
+ "movq %%r12, %%rsp\n\t"
+ :: "o" (data)
+ : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", "r12",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+ "memory"
+ );
+
+ switch (pReturnTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_uInt64 *>( pRegisterReturn ) = data.rax;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ *static_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32 *>( &data.rax );
+ break;
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16 *>( &data.rax );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8 *>( &data.rax );
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>( pRegisterReturn ) = data.xmm0;
+ break;
+ default:
+ {
+ sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+ if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+ {
+ sal_uInt64 longs[2];
+ longs[0] = data.rax;
+ longs[1] = data.rdx;
+
+ double doubles[2];
+ doubles[0] = data.xmm0;
+ doubles[1] = data.xmm1;
+ x86_64::fill_struct( pReturnTypeRef, &longs[0], &doubles[0], pRegisterReturn);
+ }
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx
new file mode 100644
index 0000000000..ac87c1c85b
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cppu/macros.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+void callVirtualMethod(
+ void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
+ typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+ sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, double * pFPR);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx
new file mode 100644
index 0000000000..11426e9475
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx
@@ -0,0 +1,543 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "abi.hxx"
+#include "call.hxx"
+#include "share.hxx"
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+
+// Perform the UNO call
+//
+// We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
+// arguments and call pThis->getUnoI()->pDispatcher.
+//
+// gpreg: [ret *], this, [gpr params]
+// fpreg: [fpr params]
+// ovrflw: [gpr or fpr params (properly aligned)]
+//
+// [ret *] is present when we are returning a structure bigger than 16 bytes
+// Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
+// Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
+//
+// The return value is the same as for cpp_vtable_call.
+static int cpp2uno_call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+ const typelib_TypeDescription * pMemberTypeDescr,
+ typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+ unsigned int nr_gpr = 0; //number of gpr registers used
+ unsigned int nr_fpr = 0; //number of fpr registers used
+
+ // return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ x86_64::ReturnKind returnKind
+ = (pReturnTypeRef == nullptr || pReturnTypeRef->eTypeClass == typelib_TypeClass_VOID)
+ ? x86_64::ReturnKind::RegistersGeneral : x86_64::getReturnKind(pReturnTypeRef);
+
+ void * pUnoReturn = nullptr;
+ void * pCppReturn = nullptr; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
+
+ if ( pReturnTypeDescr )
+ {
+ if ( returnKind == x86_64::ReturnKind::Memory )
+ {
+ pCppReturn = *gpreg++;
+ nr_gpr++;
+
+ pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+ ? alloca( pReturnTypeDescr->nSize )
+ : pCppReturn ); // direct way
+ }
+ else
+ pUnoReturn = pRegisterReturn; // direct way for simple types
+ }
+
+ // pop this
+ gpreg++;
+ nr_gpr++;
+
+ // stack space
+ // parameters
+ void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
+ void ** pCppArgs = pUnoArgs + nParams;
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+
+ if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
+ {
+ int nUsedGPR = 0;
+ int nUsedSSE = 0;
+#ifndef NDEBUG
+ bool bFitsRegisters =
+#endif
+ x86_64::examine_argument( rParam.pTypeRef, nUsedGPR, nUsedSSE );
+
+ // Simple types must fit exactly one register on x86_64
+ assert(bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ));
+
+ if ( nUsedSSE == 1 )
+ {
+ if ( nr_fpr < x86_64::MAX_SSE_REGS )
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
+ nr_fpr++;
+ }
+ else
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+ else if ( nUsedGPR == 1 )
+ {
+ if ( nr_gpr < x86_64::MAX_GPR_REGS )
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
+ nr_gpr++;
+ }
+ else
+ pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
+ }
+ }
+ else // ref
+ {
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ void *pCppStack;
+ if ( nr_gpr < x86_64::MAX_GPR_REGS )
+ {
+ pCppArgs[nPos] = pCppStack = *gpreg++;
+ nr_gpr++;
+ }
+ else
+ pCppArgs[nPos] = pCppStack = *ovrflw++;
+
+ if (! rParam.bIn) // is pure out
+ {
+ // uno out is unconstructed mem!
+ pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
+ pTempIndices[nTempIndices] = nPos;
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
+ {
+ uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pCppStack, pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = pCppStack;
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any * pUnoExc = &aUnoExc;
+
+ // invoke uno dispatch call
+ (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
+
+ // in case an exception occurred...
+ if ( pUnoExc )
+ {
+ // destruct temporary in/inout params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], nullptr );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+ CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+ // is here for dummy
+ return 0;
+ }
+ else // else no exception occurred...
+ {
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if ( pParams[nIndex].bOut ) // inout/out
+ {
+ // convert and assign
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+ uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ }
+ // destroy temp uno param
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return
+ if ( pCppReturn ) // has complex return
+ {
+ if ( pUnoReturn != pCppReturn ) // needs reconversion
+ {
+ uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+ // destroy temp uno return
+ uno_destructData( pUnoReturn, pReturnTypeDescr, nullptr );
+ }
+ // complex return ptr is set to return reg
+ *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
+ }
+ if ( pReturnTypeDescr )
+ {
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+ switch (returnKind) {
+ case x86_64::ReturnKind::RegistersFpInt:
+ return 0;
+ case x86_64::ReturnKind::RegistersIntFp:
+ return 1;
+ default:
+ return -1;
+ }
+ }
+}
+
+// Returns -1 for the general case where potential return values from privateSnippetExecutor can be
+// copied from pRegisterReturn to both %rax and %rdx (in that order) and to %xmm0 and %xmm1 (in that
+// order)---each specific return type will only require a subset of that copy operations, but the
+// other copies to those non--callee-saved registers will be redundant and harmless. Returns 0 for
+// the special case where return values from privateSnippetExecutor must be copied from
+// pRegisterReturn to %xmm0 and %rax (in that order). Returns 1 for the special case where return
+// privateSnippetExecutor must be copied from pRegisterReturn to %rax and %xmm0 (in that order).
+int cpp_vtable_call(
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ void ** gpreg, void ** fpreg, void ** ovrflw,
+ sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+ // gpreg: [ret *], this, [other gpr params]
+ // fpreg: [fpr params]
+ // ovrflw: [gpr or fpr params (properly aligned)]
+ void * pThis;
+ if ( nFunctionIndex & 0x80000000 )
+ {
+ nFunctionIndex &= 0x7fffffff;
+ pThis = gpreg[1];
+ }
+ else
+ {
+ pThis = gpreg[0];
+ }
+ pThis = static_cast<char *>( pThis ) - nVtableOffset;
+
+ bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+ bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+
+ typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+ if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
+ {
+ SAL_WARN(
+ "bridges",
+ "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ << " vtable index " << nFunctionIndex << "/"
+ << pTypeDescr->nMapFunctionIndexToMemberIndex);
+ throw RuntimeException(
+ ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+
+ TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+ int eRet;
+ switch ( aMemberDescr.get()->eTypeClass )
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference *pAttrTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
+
+ if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
+ {
+ // is GET method
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
+ 0, nullptr, // no params
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ else
+ {
+ // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ nullptr, // indicates void return
+ 1, &aParam,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch ( nFunctionIndex )
+ {
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast<Type *>( gpreg[2] )->getTypeLibType() );
+ if ( pTD )
+ {
+ XInterface * pInterface = nullptr;
+ (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
+ ( pCppI->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&pInterface),
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
+
+ if ( pInterface )
+ {
+ ::uno_any_construct( static_cast<uno_Any *>( gpreg[0] ),
+ &pInterface, pTD, cpp_acquire );
+
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
+ eRet = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ {
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
+
+ eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+ pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams,
+ pMethodTD->pParams,
+ gpreg, fpreg, ovrflw, pRegisterReturn );
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw RuntimeException("no member description found!",
+ reinterpret_cast<XInterface *>( pCppI ) );
+ }
+ }
+
+ return eRet;
+}
+
+const int codeSnippetSize = 24;
+
+// Generate a trampoline that redirects method calls to
+// privateSnippetExecutor().
+//
+// privateSnippetExecutor() saves all the registers that are used for
+// parameter passing on x86_64, and calls the cpp_vtable_call().
+// When it returns, privateSnippetExecutor() sets the return value.
+//
+// Note: The code snippet we build here must not create a stack frame,
+// otherwise the UNO exceptions stop working thanks to non-existing
+// unwinding info.
+static unsigned char * codeSnippet( unsigned char * code,
+ sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+ bool bHasHiddenParam )
+{
+ sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>(nVtableOffset) << 32 ) | static_cast<sal_uInt64>(nFunctionIndex);
+
+ if ( bHasHiddenParam )
+ nOffsetAndIndex |= 0x80000000;
+
+ // movq $<nOffsetAndIndex>, %r10
+ *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
+ *reinterpret_cast<sal_uInt16 *>( code + 2 ) = nOffsetAndIndex & 0xFFFF;
+ *reinterpret_cast<sal_uInt32 *>( code + 4 ) = nOffsetAndIndex >> 16;
+ *reinterpret_cast<sal_uInt16 *>( code + 8 ) = nOffsetAndIndex >> 48;
+
+ // movq $<address of the privateSnippetExecutor>, %r11
+ *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
+ *reinterpret_cast<sal_uInt32 *>( code + 12 )
+ = reinterpret_cast<sal_uInt64>(privateSnippetExecutor);
+ *reinterpret_cast<sal_uInt32 *>( code + 16 )
+ = reinterpret_cast<sal_uInt64>(privateSnippetExecutor) >> 32;
+
+ // jmpq *%r11
+ *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr,
+ "==> codeSnippet, functionIndex=%d%s, vtableOffset=%d\n",
+ nFunctionIndex, (bHasHiddenParam ? "|0x80000000":""), nVtableOffset);
+#endif
+
+ return code + codeSnippetSize;
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::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 * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+ typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
+ sal_Int32 functionCount, sal_Int32 nVtableOffset )
+{
+ const sal_PtrDiff writetoexecdiff = 0;
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
+ {
+ typelib_TypeDescription * pTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
+ assert(pTD);
+
+ if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
+ {
+ typelib_InterfaceAttributeTypeDescription *pAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
+
+ // get method
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
+ x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
+
+ if ( ! pAttrTD->bReadOnly )
+ {
+ // set method
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
+ }
+ }
+ else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
+ {
+ typelib_InterfaceMethodTypeDescription *pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
+
+ (s++)->fn = code + writetoexecdiff;
+ code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
+ x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
+ }
+ else
+ assert(false);
+
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ SAL_UNUSED_PARAMETER unsigned char const *,
+ SAL_UNUSED_PARAMETER unsigned char const * )
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx
new file mode 100644
index 0000000000..60f5f6e40e
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx
@@ -0,0 +1,407 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <new>
+#include <stdio.h>
+#include <string.h>
+#include <typeinfo>
+
+#include <cxxabi.h>
+#include <dlfcn.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <unordered_map>
+#include "share.hxx"
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+
+namespace CPPU_CURRENT_NAMESPACE {
+
+namespace {
+
+struct Fake_type_info {
+ virtual ~Fake_type_info() = delete;
+ char const * name;
+};
+
+struct Fake_class_type_info: Fake_type_info {
+ virtual ~Fake_class_type_info() override = delete;
+};
+
+struct Fake_si_class_type_info: Fake_class_type_info {
+ virtual ~Fake_si_class_type_info() override = delete;
+ void const * base;
+};
+
+struct Base {};
+struct Derived: Base {};
+
+std::type_info * createFake_class_type_info(char const * name) {
+ char * buf = new char[sizeof (Fake_class_type_info)];
+
+ *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+ &typeid(Base));
+ // copy __cxxabiv1::__class_type_info vtable into place
+ Fake_class_type_info * fake = reinterpret_cast<Fake_class_type_info *>(buf);
+ fake->name = name;
+ return reinterpret_cast<std::type_info *>(
+ static_cast<Fake_type_info *>(fake));
+}
+
+std::type_info * createFake_si_class_type_info(
+ char const * name, std::type_info const * base)
+{
+ char * buf = new char[sizeof (Fake_si_class_type_info)];
+
+ *reinterpret_cast<void **>(buf) = *reinterpret_cast<void * const *>(
+ &typeid(Derived));
+ // copy __cxxabiv1::__si_class_type_info vtable into place
+ Fake_si_class_type_info * fake
+ = reinterpret_cast<Fake_si_class_type_info *>(buf);
+ fake->name = name;
+ fake->base = base;
+ return reinterpret_cast<std::type_info *>(
+ static_cast<Fake_type_info *>(fake));
+}
+
+}
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+void dummy_can_throw_anything( char const * )
+{
+}
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static OUString toUNOname( char const * p )
+{
+#if OSL_DEBUG_LEVEL > 1
+ char const * start = p;
+#endif
+
+ // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+ OUStringBuffer buf( 64 );
+ assert( 'N' == *p );
+ ++p; // skip N
+
+ while ('E' != *p)
+ {
+ // read chars count
+ long n = *p++ - '0';
+ while ('0' <= *p && '9' >= *p)
+ {
+ n *= 10;
+ n += (*p++ - '0');
+ }
+ buf.appendAscii( p, n );
+ p += n;
+ if ('E' != *p)
+ buf.append( '.' );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString ret( buf.makeStringAndClear() );
+ OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+ return ret;
+#else
+ return buf.makeStringAndClear();
+#endif
+}
+
+namespace {
+
+class RTTI
+{
+ typedef std::unordered_map< OUString, std::type_info * > t_rtti_map;
+
+ Mutex m_mutex;
+ t_rtti_map m_rttis;
+ t_rtti_map m_generatedRttis;
+
+ void * m_hApp;
+
+public:
+ RTTI();
+ ~RTTI();
+
+ std::type_info * getRTTI( typelib_CompoundTypeDescription * );
+};
+
+}
+
+RTTI::RTTI()
+ : m_hApp( dlopen( nullptr, RTLD_LAZY ) )
+{
+}
+
+RTTI::~RTTI()
+{
+ dlclose( m_hApp );
+}
+
+
+std::type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
+{
+ std::type_info * rtti;
+
+ OUString const & unoName = OUString::unacquired(&pTypeDescr->aBase.pTypeName);
+
+ MutexGuard guard( m_mutex );
+ t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+ if (iFind == m_rttis.end())
+ {
+ // RTTI symbol
+ OStringBuffer buf( 64 );
+ buf.append( "_ZTIN" );
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( unoName.getToken( 0, '.', index ) );
+ buf.append( token.getLength() );
+ OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
+ buf.append( c_token );
+ }
+ while (index >= 0);
+ buf.append( 'E' );
+
+ OString symName( buf.makeStringAndClear() );
+ rtti = static_cast<std::type_info *>(dlsym( m_hApp, symName.getStr() ));
+
+ if (rtti)
+ {
+ std::pair< t_rtti_map::iterator, bool > insertion(
+ m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second,
+ "bridges",
+ "inserting new rtti failed" );
+ }
+ else
+ {
+ // try to lookup the symbol in the generated rtti map
+ t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
+ if (iFind2 == m_generatedRttis.end())
+ {
+ // we must generate it !
+ // symbol and rtti-name is nearly identical,
+ // the symbol is prefixed with _ZTI
+ char * rttiName = strdup(symName.getStr() + 4);
+ if (rttiName == nullptr) {
+ throw std::bad_alloc();
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"generated rtti for %s\n", rttiName );
+#endif
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // ensure availability of base
+ std::type_info * base_rtti = getRTTI(
+ pTypeDescr->pBaseTypeDescription );
+ rtti = createFake_si_class_type_info(rttiName, base_rtti);
+ }
+ else
+ {
+ rtti = createFake_class_type_info(rttiName);
+ }
+
+ std::pair< t_rtti_map::iterator, bool > insertion(
+ m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+ SAL_WARN_IF( !insertion.second,
+ "bridges",
+ "inserting new generated rtti failed" );
+ }
+ else // taking already generated rtti
+ {
+ rtti = iFind2->second;
+ }
+ }
+ }
+ else
+ {
+ rtti = iFind->second;
+ }
+
+ return rtti;
+}
+
+
+static void deleteException( void * pExc )
+{
+ __cxa_exception const * header = static_cast<__cxa_exception const *>(pExc) - 1;
+ // The libcxxabi commit
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+ // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+ // LLVM 5.0 changed the size of __cxa_exception by adding
+ //
+ // __attribute__((aligned))
+ //
+ // to the final member unwindHeader, on x86-64 effectively adding a hole of
+ // size 8 in front of that member (changing its offset from 88 to 96,
+ // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+ // from 8 to 16); a hack to dynamically determine whether we run against a
+ // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+ // point to this function (the use of __cxa_exception in fillUnoException is
+ // unaffected, as it only accesses members towards the start of the struct,
+ // through a pointer known to actually point at the start). The libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+ // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+ // removes the need for this hack, so it can be removed again once we can be sure that we only
+ // run against libcxxabi from LLVM >= 6:
+ if (header->exceptionDestructor != &deleteException) {
+ header = reinterpret_cast<__cxa_exception const *>(
+ reinterpret_cast<char const *>(header) - 8);
+ assert(header->exceptionDestructor == &deleteException);
+ }
+ typelib_TypeDescription * pTD = nullptr;
+ OUString unoName( toUNOname( header->exceptionType->name() ) );
+ ::typelib_typedescription_getByName( &pTD, unoName.pData );
+ assert(pTD && "### unknown exception type! leaving out destruction => leaking!!!");
+ if (pTD)
+ {
+ ::uno_destructData( pExc, pTD, cpp_release );
+ ::typelib_typedescription_release( pTD );
+ }
+}
+
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr(
+ OUStringToOString(
+ OUString::unacquired( &pUnoExc->pType->pTypeName ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+ void * pCppExc;
+ std::type_info * rtti;
+
+ {
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+ assert(pTypeDescr);
+ if (! pTypeDescr)
+ {
+ throw RuntimeException(
+ "cannot get typedescription for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+
+ pCppExc = __cxxabiv1::__cxa_allocate_exception( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, nullptr );
+ // avoiding locked counts
+ static RTTI rtti_data;
+ rtti = rtti_data.getRTTI(reinterpret_cast<typelib_CompoundTypeDescription*>(pTypeDescr));
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ assert(rtti && "### no rtti for throwing exception!");
+ if (! rtti)
+ {
+ throw RuntimeException(
+ "no rtti for type " +
+ OUString::unacquired( &pUnoExc->pType->pTypeName ) );
+ }
+ }
+
+ __cxxabiv1::__cxa_throw( pCppExc, rtti, deleteException );
+}
+
+void fillUnoException(uno_Any * pUnoExc, uno_Mapping * pCpp2Uno)
+{
+ __cxa_exception * header = __cxa_get_globals()->caughtExceptions;
+ if (! header)
+ {
+ RuntimeException aRE( "no exception header!" );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ return;
+ }
+
+ // Very bad HACK to find out whether we run against a libcxxabi that has a new
+ // __cxa_exception::reserved member at the start, introduced with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of the
+ // start of __cxa_exception is
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // where the (bad, hacky) assumption is that reserve (if present) is null
+ // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+ // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+ // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+ // __cxa_dependent_exception, the referenceCount member is rather
+ //
+ // 8 byte void* primaryException
+ //
+ // but which also will always be set to a non-null value in __cxa_rethrow_primary_exception).
+ // As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx), this hack (together with the "#if 0"
+ // there) can be dropped once we can be sure that we only run against new libcxxabi that has the
+ // reserve member:
+ if (*reinterpret_cast<void **>(header) == nullptr) {
+ header = reinterpret_cast<__cxa_exception *>(reinterpret_cast<void **>(header) + 1);
+ }
+
+ std::type_info *exceptionType = __cxxabiv1::__cxa_current_exception_type();
+
+ typelib_TypeDescription * pExcTypeDescr = nullptr;
+ OUString unoName( toUNOname( exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+ OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+ typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+ if (nullptr == pExcTypeDescr)
+ {
+ RuntimeException aRE( "exception type not found: " + unoName );
+ Type const & rType = cppu::UnoType<decltype(aRE)>::get();
+ uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
+ SAL_WARN("bridges", aRE.Message);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx
new file mode 100644
index 0000000000..6b09d99a56
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <uno/mapping.h>
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+// From opensource.apple.com: libunwind-35.1/include/unwind.h
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+struct _Unwind_Exception
+{
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
+ uintptr_t private_1; // non-zero means forced unwind
+ uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+#if !__LP64__
+ // The gcc implementation of _Unwind_Exception used attribute mode on the above fields
+ // which had the side effect of causing this whole struct to round up to 32 bytes in size.
+ // To be more explicit, we add pad fields added for binary compatibility.
+ uint32_t reserved[3];
+#endif
+};
+
+
+// From libcppabi-24.2/include/unwind-cxx.h
+
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+
+// A C++ exception object consists of a header, which is a wrapper around
+// an unwind object header with additional C++ specific information,
+// followed by the exception object itself.
+
+struct __cxa_exception
+{
+#if __LP64__
+#if 0
+ // This is a new field added with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The HACK in
+ // fillUnoException (bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx) tries to find out at
+ // runtime whether a __cxa_exception has this member. Once we can be sure that we only run
+ // against new libcxxabi that has this member, we can drop the "#if 0" here and drop the hack
+ // in fillUnoException.
+
+ // Now _Unwind_Exception is marked with __attribute__((aligned)),
+ // which implies __cxa_exception is also aligned. Insert padding
+ // in the beginning of the struct, rather than before unwindHeader.
+ void *reserve;
+#endif
+
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is at the start of this
+ // struct which is prepended to the object thrown in
+ // __cxa_allocate_exception.
+ size_t referenceCount;
+#endif
+ // Manage the exception object itself.
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+
+ // The C++ standard has entertaining rules wrt calling set_terminate
+ // and set_unexpected in the middle of the exception cleanup process.
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+
+ // The caught exception stack threads through here.
+ __cxa_exception *nextException;
+
+ // How many nested handlers have caught this exception. A negated
+ // value is a signal that this object has been rethrown.
+ int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+ // Stack of exceptions in cleanups.
+ __cxa_exception* nextPropagatingException;
+
+ // The number of active cleanup handlers for this exception.
+ int propagationCount;
+#else
+ // Cache parsed handler data from the personality routine Phase 1
+ // for Phase 2 and __cxa_call_unexpected.
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ _Unwind_Ptr catchTemp;
+ void *adjustedPtr;
+#endif
+#if !__LP64__
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is placed where the compiler
+ // previously adding padded to 64-bit align unwindHeader.
+ size_t referenceCount;
+#endif
+
+ // The generic exception header. Must be last.
+ _Unwind_Exception unwindHeader;
+};
+
+// Each thread in a C++ program has access to a __cxa_eh_globals object.
+struct __cxa_eh_globals
+{
+ __cxa_exception *caughtExceptions;
+ unsigned int uncaughtExceptions;
+#ifdef __ARM_EABI_UNWINDER__
+ __cxa_exception* propagatingExceptions;
+#endif
+};
+
+}
+
+extern "C" CPPU_CURRENT_NAMESPACE::__cxa_eh_globals *__cxa_get_globals () noexcept;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void raiseException(
+ uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+
+void fillUnoException(uno_Any *, uno_Mapping * pCpp2Uno);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx
new file mode 100644
index 0000000000..0b320a00c6
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx
@@ -0,0 +1,442 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/alloca.h>
+
+#include <exception>
+#include <typeinfo>
+
+#include <rtl/alloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <o3tl/runtimetooustring.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include "abi.hxx"
+#include "callvirtualmethod.hxx"
+#include "share.hxx"
+
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+// Functions for easier insertion of values to registers or stack
+// pSV - pointer to the source
+// nr - order of the value [will be increased if stored to register]
+// pFPR, pGPR - pointer to the registers
+// pDS - pointer to the stack [will be increased if stored here]
+
+// The value in %xmm register is already prepared to be retrieved as a float,
+// thus we treat float and double the same
+void INSERT_FLOAT_DOUBLE(
+ void const * pSV, sal_uInt32 & nr, double * pFPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_SSE_REGS )
+ pFPR[nr++] = *static_cast<double const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt64 const *>( pSV ); // verbatim!
+}
+
+void INSERT_INT64(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt64 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt64 const *>( pSV );
+}
+
+void INSERT_INT32(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt32 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt32 const *>( pSV );
+}
+
+void INSERT_INT16(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt16 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt16 const *>( pSV );
+}
+
+void INSERT_INT8(
+ void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
+{
+ if ( nr < x86_64::MAX_GPR_REGS )
+ pGPR[nr++] = *static_cast<sal_uInt8 const *>( pSV );
+ else
+ *pDS++ = *static_cast<sal_uInt8 const *>( pSV );
+}
+
+}
+
+static void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams, typelib_MethodParameter * pParams,
+ void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+ // Maximum space for [complex ret ptr], values | ptr ...
+ // (but will be used less - some of the values will be in pGPR and pFPR)
+ sal_uInt64 *pStack = static_cast<sal_uInt64 *>(__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ));
+ sal_uInt64 *pStackStart = pStack;
+
+ sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
+ sal_uInt32 nGPR = 0;
+
+ double pFPR[x86_64::MAX_SSE_REGS];
+ sal_uInt32 nFPR = 0;
+
+ // Return
+ typelib_TypeDescription * pReturnTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+ assert(pReturnTypeDescr);
+
+ void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion (see below)
+
+ bool bSimpleReturn = true;
+ if ( pReturnTypeDescr )
+ {
+ if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
+ bSimpleReturn = false;
+
+ if ( bSimpleReturn )
+ pCppReturn = pUnoReturn; // direct way for simple types
+ else
+ {
+ // complex return via ptr
+ pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
+ __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
+ INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
+ }
+ }
+
+ // Push "this" pointer
+ void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
+ INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+ // Args
+ void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
+ // Indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
+ // Type descriptions for reconversions
+ typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndices = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
+ break;
+ default:
+ break;
+ }
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // cpp out is constructed mem, uno out is not!
+ uno_constructData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pParamTypeDescr );
+ pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+ {
+ uno_copyAndConvertData(
+ pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
+ pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
+
+ pTempIndices[nTempIndices] = nPos; // has to be reconverted
+ // will be released at reconversion
+ ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
+ }
+ else // direct way
+ {
+ pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+ }
+ }
+
+ try
+ {
+ try {
+ CPPU_CURRENT_NAMESPACE::callVirtualMethod(
+ pAdjustedThisPtr, aVtableSlot.index,
+ pCppReturn, pReturnTypeRef, bSimpleReturn,
+ pStackStart, ( pStack - pStackStart ),
+ pGPR, pFPR );
+ } catch (const Exception &) {
+ throw;
+ } catch (const std::exception & e) {
+ throw RuntimeException(
+ "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name())
+ + ": " + o3tl::runtimeToOUString(e.what()));
+ } catch (...) {
+ throw RuntimeException("C++ code threw unknown exception");
+ }
+
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr ); // destroy uno value
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+ }
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
+ pThis->getBridge()->getCpp2Uno() );
+ uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
+ }
+ }
+ catch (...)
+ {
+ // fill uno exception
+ CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
+
+ // temporary params
+ for ( ; nTempIndices--; )
+ {
+ sal_Int32 nIndex = pTempIndices[nTempIndices];
+ // destroy temp cpp param => cpp: every param was constructed
+ uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
+ TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
+ }
+ // return type
+ if (pReturnTypeDescr)
+ TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+ }
+}
+
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberDescr)));
+
+ if (pReturn)
+ {
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ // dependent dispatch
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot, // get, then set method
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ // standard calls
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
+ if (pTD)
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if (pInterface)
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ // dependent dispatch
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
+ pReturn, pArgs, ppException );
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
+
+ Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx
new file mode 100644
index 0000000000..fd7fa81758
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/cpp2uno.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#include <typelib/typedescription.hxx>
+#include <vtablefactory.hxx>
+
+using namespace ::com::sun::star::uno;
+
+using bridges::cpp_uno::shared::VtableFactory;
+
+struct VtableFactory::Slot
+{
+};
+
+VtableFactory::Slot* VtableFactory::mapBlockToVtable(void* block)
+{
+ return static_cast<Slot*>(block) + 2;
+}
+
+std::size_t VtableFactory::getBlockSize(sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof(Slot);
+}
+
+VtableFactory::Slot* VtableFactory::initializeBlock(void* block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription*)
+{
+ Slot* slots = mapBlockToVtable(block);
+ return slots + slotCount;
+}
+
+unsigned char* VtableFactory::addLocalFunctions(Slot**, unsigned char*,
+ typelib_InterfaceTypeDescription const*, sal_Int32,
+ sal_Int32, sal_Int32)
+{
+ std::abort();
+}
+
+void VtableFactory::flushCode(unsigned char const*, unsigned char const*) {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/except.cxx b/bridges/source/cpp_uno/gcc3_wasm/except.cxx
new file mode 100644
index 0000000000..36778c65a1
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/except.cxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#include <cstdlib>
+
+#include <uno/mapping.h>
+#include <uno/any2.h>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+void raiseException(uno_Any*, uno_Mapping*) { std::abort(); }
+
+void fillUnoException(uno_Any*, uno_Mapping*) { std::abort(); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
new file mode 100644
index 0000000000..ddb51166b5
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_wasm/uno2cpp.cxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ */
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+using namespace ::com::sun::star::uno;
+
+namespace bridges::cpp_uno::shared
+{
+void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const typelib_TypeDescription* pMemberDescr,
+ void* pReturn, void* pArgs[], uno_Any** ppException)
+{
+ bridges::cpp_uno::shared::UnoInterfaceProxy* pThis
+ = static_cast<bridges::cpp_uno::shared::UnoInterfaceProxy*>(pUnoI);
+
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ std::abort();
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(getVtableSlot(
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(pMemberDescr)));
+
+ switch (aVtableSlot.index)
+ {
+ case 1: // acquire uno interface
+ (*pUnoI->acquire)(pUnoI);
+ *ppException = 0;
+ break;
+ case 2: // release uno interface
+ (*pUnoI->release)(pUnoI);
+ *ppException = 0;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription* pTD = 0;
+ TYPELIB_DANGER_GET(&pTD, reinterpret_cast<Type*>(pArgs[0])->getTypeLibType());
+ if (pTD)
+ {
+ uno_Interface* pInterface = 0;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(), (void**)&pInterface, pThis->oid.pData,
+ (typelib_InterfaceTypeDescription*)pTD);
+
+ if (pInterface)
+ {
+ ::uno_any_construct(reinterpret_cast<uno_Any*>(pReturn), &pInterface,
+ pTD, 0);
+ (*pInterface->release)(pInterface);
+ TYPELIB_DANGER_RELEASE(pTD);
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pTD);
+ }
+ } // else perform queryInterface()
+ [[fallthrough]];
+ default:
+ std::abort();
+ }
+ break;
+ }
+ default:
+ {
+ ::com::sun::star::uno::RuntimeException aExc(
+ "illegal member type description!",
+ ::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface>());
+
+ Type const& rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), 0);
+ }
+ }
+}
+
+} // namespace bridges::cpp_uno::shared
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_shared/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_shared/cpp2uno.cxx
new file mode 100644
index 0000000000..15aa14d9b9
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_shared/cpp2uno.cxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include <msvc/except.hxx>
+#include <msvc/cpp2uno.hxx>
+
+using namespace ::com::sun::star;
+
+static typelib_TypeClass
+cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
+ const typelib_TypeDescription* pMemberTD,
+ typelib_TypeDescriptionReference* pReturnTypeRef, // nullptr indicates void return
+ const sal_Int32 nParams, typelib_MethodParameter* pParams, void** pCallStack,
+ void** const pReturnAddr)
+{
+ // return type
+ typelib_TypeDescription* pReturnTD = nullptr;
+ if (pReturnTypeRef)
+ TYPELIB_DANGER_GET(&pReturnTD, pReturnTypeRef);
+
+ // if we don't return via register, the first stack parameter is the return value
+ int nFirstRealParam = 2;
+ if (pReturnAddr == pCallStack)
+ ++nFirstRealParam;
+
+ void* pUnoReturn = nullptr;
+ // complex return ptr: if != nullptr && != pUnoReturn, reconversion needed
+ void* pCppReturn = nullptr;
+
+ if (pReturnTD)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType(pReturnTD))
+ pUnoReturn = pReturnAddr;
+ else
+ {
+ pCppReturn = pCallStack[nFirstRealParam++];
+ pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTD)
+ ? alloca(pReturnTD->nSize)
+ : pCppReturn);
+ }
+ }
+
+ // parameters passed to the UNO function
+ void** pUnoArgs = static_cast<void**>(alloca(sizeof(void*) * nParams));
+
+ // parameters received from C++
+ void** pCppArgs = static_cast<void**>(alloca(sizeof(void*) * nParams));
+
+ // TODO: switch to typedef std::pair<sal_Int32, typelib_TypeDescription*> ReconversationInfo;
+ sal_Int32 nTempIndex = 0;
+ // indexes of values this have to be converted (interface conversion C++<=>UNO)
+ sal_Int32* pTempIndexes = static_cast<sal_Int32*>(alloca(sizeof(sal_Int32) * nParams));
+ // type descriptions for reconversions
+ typelib_TypeDescription** ppTempParamTD
+ = static_cast<typelib_TypeDescription**>(alloca(sizeof(void*) * nParams));
+
+ for (std::pair<sal_Int32, void**> p(0, pCallStack + nFirstRealParam); p.first < nParams;
+ ++p.first, ++p.second)
+ {
+ const auto& nPos = p.first;
+ auto& pCppIncomingParams = p.second;
+
+ const typelib_MethodParameter& rParam = pParams[nPos];
+ typelib_TypeDescription* pParamTD = nullptr;
+ TYPELIB_DANGER_GET(&pParamTD, rParam.pTypeRef);
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
+ {
+ pCppArgs[nPos] = pCppIncomingParams;
+ pUnoArgs[nPos] = pCppIncomingParams;
+ if (sizeof(void*) == sizeof(sal_Int32)) // account 64bit types on 32bit arch
+ {
+ switch (pParamTD->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ ++pCppIncomingParams;
+ break;
+ default:
+ break;
+ }
+ }
+ TYPELIB_DANGER_RELEASE(pParamTD);
+ }
+ else // ptr to complex value | ref
+ {
+ pCppArgs[nPos] = *pCppIncomingParams;
+
+ if (!rParam.bIn) // is pure out
+ {
+ // UNO out is unconstructed memory
+ pUnoArgs[nPos] = alloca(pParamTD->nSize);
+ // pParamTD will be released at reconversion
+ pTempIndexes[nTempIndex] = nPos;
+ ppTempParamTD[nTempIndex++] = pParamTD;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTD))
+ {
+ ::uno_copyAndConvertData(pUnoArgs[nPos] = alloca(pParamTD->nSize),
+ *pCppIncomingParams, pParamTD,
+ pThis->getBridge()->getCpp2Uno());
+ // pParamTD will be released at reconversion
+ pTempIndexes[nTempIndex] = nPos;
+ ppTempParamTD[nTempIndex++] = pParamTD;
+ }
+ else // direct way
+ {
+ pUnoArgs[nPos] = *pCppIncomingParams;
+ TYPELIB_DANGER_RELEASE(pParamTD);
+ }
+ }
+ }
+
+ // ExceptionHolder
+ uno_Any aUnoExc; // Any will be constructed by callee
+ uno_Any* pUnoExc = &aUnoExc;
+
+ // invoke UNO dispatch call
+ pThis->getUnoI()->pDispatcher(pThis->getUnoI(), pMemberTD, pUnoReturn, pUnoArgs, &pUnoExc);
+
+ // in case an exception occurred...
+ if (pUnoExc)
+ {
+ // destruct temporary in/inout params
+ while (nTempIndex--)
+ {
+ const sal_Int32 nIndex = pTempIndexes[nTempIndex];
+ if (pParams[nIndex].bIn) // is in/inout => was constructed
+ ::uno_destructData(pUnoArgs[nIndex], ppTempParamTD[nTempIndex], nullptr);
+ TYPELIB_DANGER_RELEASE(ppTempParamTD[nTempIndex]);
+ }
+ if (pReturnTD)
+ TYPELIB_DANGER_RELEASE(pReturnTD);
+
+ msvc_raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp()); // has to destruct the any
+
+ // is here for dummy
+ return typelib_TypeClass_VOID;
+ }
+ else // no exception occurred...
+ {
+ // handle temporary params
+ while (nTempIndex--)
+ {
+ const sal_Int32 nIndex = pTempIndexes[nTempIndex];
+ typelib_TypeDescription* pParamTD = ppTempParamTD[nTempIndex];
+
+ if (pParams[nIndex].bOut) // inout/out
+ {
+ // convert and assign
+ ::uno_destructData(pCppArgs[nIndex], pParamTD, uno::cpp_release);
+ ::uno_copyAndConvertData(pCppArgs[nIndex], pUnoArgs[nIndex], pParamTD,
+ pThis->getBridge()->getUno2Cpp());
+ }
+ // destroy temp UNO param
+ ::uno_destructData(pUnoArgs[nIndex], pParamTD, nullptr);
+
+ TYPELIB_DANGER_RELEASE(pParamTD);
+ }
+
+ // handle return
+ if (pCppReturn) // has complex return
+ {
+ if (pUnoReturn != pCppReturn) // needs reconversion
+ {
+ ::uno_copyAndConvertData(pCppReturn, pUnoReturn, pReturnTD,
+ pThis->getBridge()->getUno2Cpp());
+ // destroy temp UNO return
+ ::uno_destructData(pUnoReturn, pReturnTD, nullptr);
+ }
+ *pReturnAddr = pCppReturn;
+ }
+
+ if (!pReturnTD)
+ return typelib_TypeClass_VOID;
+ else
+ {
+ typelib_TypeClass eRet = pReturnTD->eTypeClass;
+ TYPELIB_DANGER_RELEASE(pReturnTD);
+ return eRet;
+ }
+ }
+}
+
+typelib_TypeClass __cdecl cpp_mediate(void** pCallStack, const sal_Int32 nFunctionIndex,
+ const sal_Int32 nVtableOffset,
+ sal_Int64* const pRegisterReturn)
+{
+ // pCallStack:
+ // x64: ret value, ret adr, this, [complex ret *], cpp params
+ // x86: ret adr, this, [complex ret *], cpp params
+ //
+ // pRegisterReturn is just set on x86
+ // the return value is either the direct set for simply types, or it is set
+ // to "complex ret *" and the real return value is constructed at that memory.
+
+ // if we don't return via register, the first stack parameter is the return value
+ void** const pReturnAddr
+ = pRegisterReturn ? reinterpret_cast<void**>(pRegisterReturn) : pCallStack;
+
+ void* const pThis = static_cast<char*>(pCallStack[pRegisterReturn ? 1 : 2]) - nVtableOffset;
+ bridges::cpp_uno::shared::CppInterfaceProxy* pCppI
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis);
+
+ typelib_InterfaceTypeDescription* pInterfaceTD = pCppI->getTypeDescr();
+
+ SAL_INFO("bridges", "cpp_vtable_call: pCallStack=["
+ << std::hex << pCallStack[0] << "," << pCallStack[1] << ","
+ << pCallStack[2] << ",...], pThis=" << pThis << ", pCppI=" << pCppI
+ << std::dec << ", nFunctionIndex=" << nFunctionIndex
+ << ", nVtableOffset=" << nVtableOffset);
+ SAL_INFO("bridges", "name=" << OUString::unacquired(&pInterfaceTD->aBase.pTypeName));
+
+ if (nFunctionIndex >= pInterfaceTD->nMapFunctionIndexToMemberIndex)
+ {
+ OUString sError = "illegal " + OUString::unacquired(&pInterfaceTD->aBase.pTypeName)
+ + " vtable index " + OUString::number(nFunctionIndex) + "/"
+ + OUString::number(pInterfaceTD->nMapFunctionIndexToMemberIndex);
+ SAL_WARN("bridges", sError);
+ throw uno::RuntimeException(sError, static_cast<uno::XInterface*>(pThis));
+ }
+
+ // determine called method
+ sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+ assert(nMemberPos < pInterfaceTD->nAllMembers);
+
+ uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
+
+ SAL_INFO("bridges", "Calling " << OUString::unacquired(&aMemberDescr.get()->pTypeName));
+
+ typelib_TypeClass eRet = typelib_TypeClass_VOID;
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference* pAttrTypeRef
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
+ ->pAttributeTypeRef;
+
+ if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
+ { // is GET method
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pAttrTypeRef, 0, nullptr, pCallStack,
+ pReturnAddr);
+ }
+ else
+ { // is SET method
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef = pAttrTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), nullptr, 1, &aParam, pCallStack,
+ pReturnAddr);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ // is METHOD
+ switch (nFunctionIndex)
+ {
+ // standard XInterface vtable calls
+ case 1: // acquire()
+ pCppI->acquireProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 2: // release()
+ pCppI->releaseProxy(); // non virtual call!
+ eRet = typelib_TypeClass_VOID;
+ break;
+ case 0: // queryInterface() opt
+ {
+ const unsigned int nCppStackPos = (pReturnAddr == pCallStack) ? 4 : 3;
+ typelib_TypeDescription* pQueryTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pQueryTD,
+ static_cast<uno::Type*>(pCallStack[nCppStackPos])->getTypeLibType());
+ if (pQueryTD)
+ {
+ uno::XInterface* pInterface = nullptr;
+
+ pCppI->getBridge()->getCppEnv()->getRegisteredInterface(
+ pCppI->getBridge()->getCppEnv(), reinterpret_cast<void**>(&pInterface),
+ pCppI->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(pQueryTD));
+
+ if (pInterface)
+ {
+ const unsigned int nReturnAddrPos = nCppStackPos - 1;
+ ::uno_any_construct(static_cast<uno_Any*>(pCallStack[nReturnAddrPos]),
+ &pInterface, pQueryTD, uno::cpp_acquire);
+ pInterface->release();
+ TYPELIB_DANGER_RELEASE(pQueryTD);
+
+ *pReturnAddr = pCallStack[nReturnAddrPos];
+ eRet = typelib_TypeClass_ANY;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(pQueryTD);
+ }
+ [[fallthrough]];
+ }
+ default: // perform queryInterface()
+ {
+ typelib_InterfaceMethodTypeDescription* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
+ aMemberDescr.get());
+
+ eRet = cpp2uno_call(pCppI, aMemberDescr.get(), pMethodTD->pReturnTypeRef,
+ pMethodTD->nParams, pMethodTD->pParams, pCallStack,
+ pReturnAddr);
+ }
+ }
+ break;
+ }
+ default:
+ throw uno::RuntimeException("no member description found!",
+ static_cast<uno::XInterface*>(pThis));
+ }
+
+ return eRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_shared/except.cxx b/bridges/source/cpp_uno/msvc_shared/except.cxx
new file mode 100644
index 0000000000..b68dd41d6b
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_shared/except.cxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <malloc.h>
+#include <new.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <unordered_map>
+#include <except.hxx>
+#include <msvc/except.hxx>
+
+#if defined(_M_IX86)
+#include <msvc/x86.hxx>
+#elif defined(_M_AMD64)
+#include <msvc/amd64.hxx>
+#elif defined(_M_ARM64)
+#include <msvc/arm64.hxx>
+#else
+#error "Unsupported machine type"
+#endif
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star;
+
+static OUString toUNOname(OUString const& rRTTIname) noexcept
+{
+ OUStringBuffer aRet(64);
+ OUString aStr(rRTTIname.copy(4, rRTTIname.getLength() - 4 - 2)); // filter .?AUzzz@yyy@xxx@@
+ sal_Int32 nPos = aStr.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = aStr.lastIndexOf('@', nPos);
+ aRet.append(aStr.subView(n + 1, nPos - n - 1));
+ if (n >= 0)
+ aRet.append('.');
+ nPos = n;
+ }
+ return aRet.makeStringAndClear();
+}
+
+static OUString toRTTIname(OUString const& rUNOname) noexcept
+{
+ OUStringBuffer aRet(64);
+ aRet.append(".?AV"); // class ".?AV"; struct ".?AU"
+ sal_Int32 nPos = rUNOname.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = rUNOname.lastIndexOf('.', nPos);
+ aRet.append(OUString::Concat(rUNOname.subView(n + 1, nPos - n - 1)) + "@");
+ nPos = n;
+ }
+ aRet.append('@');
+ return aRet.makeStringAndClear();
+}
+
+ExceptionTypeInfo::~ExceptionTypeInfo() noexcept { (void)m_data; }
+
+ExceptionTypeInfoWrapper* RTTInfos::getInfo(OUString const& rUNOname) noexcept
+{
+ ExceptionTypeInfoWrapper* pRTTI;
+ t_string2PtrMap::const_iterator const iFind(m_allRTTI.find(rUNOname));
+
+ if (iFind != m_allRTTI.end())
+ pRTTI = static_cast<ExceptionTypeInfoWrapper*>(iFind->second);
+ else
+ {
+ OString aRawName(OUStringToOString(toRTTIname(rUNOname), RTL_TEXTENCODING_ASCII_US));
+ // Wrap new ExceptionTypeInfo in ExceptionTypeInfoWrapper to preserve length info
+ pRTTI = new (std::malloc(sizeof(ExceptionTypeInfoWrapper) + aRawName.getLength()))
+ ExceptionTypeInfoWrapper(nullptr, aRawName.getStr());
+
+ std::pair<t_string2PtrMap::iterator, bool> insertion(
+ m_allRTTI.insert(t_string2PtrMap::value_type(rUNOname, pRTTI)));
+ assert(insertion.second && "### rtti insertion failed?!");
+ }
+
+ return pRTTI;
+}
+
+type_info* RTTInfos::get(OUString const& rUNOname, int* len) noexcept
+{
+ static RTTInfos* s_pRTTIs = new RTTInfos();
+
+ static_assert(sizeof(ExceptionTypeInfo) == sizeof(std::type_info),
+ "### type info structure size differ!");
+
+ osl::MutexGuard aGuard(s_pRTTIs->m_aMutex);
+ ExceptionTypeInfoWrapper* pETIW = s_pRTTIs->getInfo(rUNOname);
+ if (len)
+ *len = pETIW->get_type_info_size();
+ return pETIW->get_type_info();
+}
+
+RTTInfos::RTTInfos() noexcept {}
+
+DWORD ExceptionInfos::allocationGranularity = 0;
+
+ExceptionInfos::ExceptionInfos() noexcept {}
+
+ExceptionInfos::~ExceptionInfos() noexcept
+{
+ SAL_INFO("bridges", "> freeing exception infos... <");
+
+ std::unique_lock aGuard(m_aMutex);
+ for (auto& rEntry : m_allRaiseInfos)
+ delete static_cast<RaiseInfo*>(rEntry.second);
+}
+
+RaiseInfo* ExceptionInfos::getRaiseInfo(typelib_TypeDescription* pTD) noexcept
+{
+ static ExceptionInfos* s_pInfos = []() {
+#if defined _M_AMD64 || defined _M_ARM64
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ allocationGranularity = systemInfo.dwAllocationGranularity;
+#endif
+ return new ExceptionInfos();
+ }();
+
+ assert(pTD
+ && (pTD->eTypeClass == typelib_TypeClass_STRUCT
+ || pTD->eTypeClass == typelib_TypeClass_EXCEPTION));
+
+ RaiseInfo* pRaiseInfo;
+
+ OUString const& rTypeName = OUString::unacquired(&pTD->pTypeName);
+ std::unique_lock aGuard(s_pInfos->m_aMutex);
+ t_string2PtrMap::const_iterator const iFind(s_pInfos->m_allRaiseInfos.find(rTypeName));
+ if (iFind != s_pInfos->m_allRaiseInfos.end())
+ pRaiseInfo = static_cast<RaiseInfo*>(iFind->second);
+ else
+ {
+ pRaiseInfo = new RaiseInfo(pTD);
+
+ std::pair<t_string2PtrMap::iterator, bool> insertion(s_pInfos->m_allRaiseInfos.insert(
+ t_string2PtrMap::value_type(rTypeName, static_cast<void*>(pRaiseInfo))));
+ assert(insertion.second && "### raise info insertion failed?!");
+ }
+
+ return pRaiseInfo;
+}
+
+void msvc_raiseException(uno_Any* pUnoExc, uno_Mapping* pUno2Cpp)
+{
+ // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
+ // thus this obj file will be compiled without opt, so no inlining of
+ // ExceptionInfos::getRaiseInfo()
+
+ // construct cpp exception object
+ typelib_TypeDescription* pTD = nullptr;
+ TYPELIB_DANGER_GET(&pTD, pUnoExc->pType);
+
+ void* pCppExc = alloca(pTD->nSize);
+ ::uno_copyAndConvertData(pCppExc, pUnoExc->pData, pTD, pUno2Cpp);
+
+ ULONG_PTR arFilterArgs[MSVC_EH_PARAMETERS];
+ arFilterArgs[0] = MSVC_EH_MAGIC_PARAM;
+ arFilterArgs[1] = reinterpret_cast<ULONG_PTR>(pCppExc);
+ arFilterArgs[2] = reinterpret_cast<ULONG_PTR>(ExceptionInfos::getRaiseInfo(pTD));
+#if MSVC_EH_PARAMETERS == 4
+ arFilterArgs[3] = reinterpret_cast<RaiseInfo*>(arFilterArgs[2])->_codeBase;
+#endif
+
+ // Destruct uno exception
+ ::uno_any_destruct(pUnoExc, nullptr);
+ TYPELIB_DANGER_RELEASE(pTD);
+
+ // last point to release anything not affected by stack unwinding
+ RaiseException(MSVC_EH_MAGIC_CODE, EXCEPTION_NONCONTINUABLE, MSVC_EH_PARAMETERS, arFilterArgs);
+}
+
+// This function does the same check as __CxxDetectRethrow from msvcrt (see its
+// crt/src/vcruntime/mgdframe.cpp). But it does not alter the global state, i.e. it does not
+// increment __ProcessingThrow, and so does not break following exception handling. We rely on the
+// definition of EHExceptionRecord, PER_IS_MSVC_EH and PER_PTHROW, that are current as of msvcrt
+// 2017 (14.14.26428).
+static bool DetectRethrow(void* ppExcept)
+{
+ struct EHExceptionRecord
+ {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD* ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+#if MSVC_EH_PARAMETERS == 3
+ struct EHParameters
+#else
+ struct alignas(8)
+#endif
+ {
+ DWORD magicNumber;
+ PVOID pExceptionObject;
+ PVOID pThrowInfo;
+#if MSVC_EH_PARAMETERS == 4
+ PVOID pThrowImageBase;
+#endif
+ } params;
+ };
+
+ constexpr auto PER_IS_MSVC_EH = [](EHExceptionRecord* p) {
+ return p->ExceptionCode == MSVC_EH_MAGIC_CODE && p->NumberParameters == MSVC_EH_PARAMETERS
+ && (p->params.magicNumber == MSVC_EH_MAGIC_PARAM
+ || p->params.magicNumber == MSVC_EH_MAGIC_PARAM + 1
+ || p->params.magicNumber == MSVC_EH_MAGIC_PARAM + 2);
+ };
+
+ constexpr auto PER_PTHROW = [](EHExceptionRecord* p) { return p->params.pThrowInfo; };
+
+ EHExceptionRecord* pExcept;
+ if (!ppExcept)
+ return false;
+ pExcept = *static_cast<EHExceptionRecord**>(ppExcept);
+ if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr)
+ return true;
+ return false;
+}
+
+int msvc_filterCppException(EXCEPTION_POINTERS* pPointers, uno_Any* pUnoExc, uno_Mapping* pCpp2Uno)
+{
+ if (pPointers == nullptr)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ EXCEPTION_RECORD* pRecord = pPointers->ExceptionRecord;
+
+ // Handle only C++ exceptions:
+ if (pRecord == nullptr || pRecord->ExceptionCode != MSVC_EH_MAGIC_CODE)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ const bool rethrow = DetectRethrow(&pRecord);
+ assert(pRecord == pPointers->ExceptionRecord);
+
+ if (rethrow && pRecord == pPointers->ExceptionRecord)
+ pRecord = *reinterpret_cast<EXCEPTION_RECORD**>(__current_exception());
+
+ // Rethrow: handle only C++ exceptions:
+ if (pRecord == nullptr || pRecord->ExceptionCode != MSVC_EH_MAGIC_CODE)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if (pRecord->NumberParameters == MSVC_EH_PARAMETERS
+#if MSVC_EH_PARAMETERS == 4
+ && pRecord->ExceptionInformation[0] == MSVC_EH_MAGIC_PARAM
+#endif
+ && pRecord->ExceptionInformation[1] != 0 && pRecord->ExceptionInformation[2] != 0
+#if MSVC_EH_PARAMETERS == 4
+ && pRecord->ExceptionInformation[3] != 0
+#endif
+ )
+ {
+ // ExceptionInformation[1] is the address of the thrown object
+ // (or the address of a pointer to it, in most cases when it
+ // is a C++ class, obviously).
+
+ // [2] is the pThrowInfo pointer
+ RaiseInfo* pInfo = reinterpret_cast<RaiseInfo*>(pRecord->ExceptionInformation[2]);
+
+#if MSVC_EH_PARAMETERS == 3
+ ULONG_PTR base = 0;
+ DWORD* types = reinterpret_cast<DWORD*>(pInfo->_types);
+#else
+ // [3] is the image base address which is added the 32-bit
+ // rva_t fields in throwinfo to get actual 64-bit addresses
+ ULONG_PTR base = pRecord->ExceptionInformation[3];
+ DWORD* types = reinterpret_cast<DWORD*>(base + pInfo->_types);
+#endif
+ if (types != nullptr && types[0] != 0 && types[1] != 0)
+ {
+ ExceptionType* et = reinterpret_cast<ExceptionType*>(base + types[1]);
+ if (et->_pTypeInfo != 0)
+ {
+ OUString aRTTIname(OStringToOUString(
+ reinterpret_cast<ExceptionTypeInfo*>(base + et->_pTypeInfo)->m_d_name,
+ RTL_TEXTENCODING_ASCII_US));
+ OUString aUNOname(toUNOname(aRTTIname));
+
+ typelib_TypeDescription* pExcTD = nullptr;
+ typelib_typedescription_getByName(&pExcTD, aUNOname.pData);
+ if (pExcTD == nullptr)
+ {
+ OUString sMsg = "[mscx_uno bridge error] UNO type of C++ exception unknown: \""
+ + aUNOname + "\", RTTI-name=\"" + aRTTIname + "\"!";
+
+ uno::RuntimeException exc(sMsg);
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(),
+ pCpp2Uno);
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert(
+ pUnoExc, reinterpret_cast<void*>(pRecord->ExceptionInformation[1]), pExcTD,
+ pCpp2Uno);
+ typelib_typedescription_release(pExcTD);
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ }
+ }
+
+ // though this unknown exception leaks now, no user-defined exception
+ // is ever thrown through the binary C-UNO dispatcher call stack.
+ uno::RuntimeException exc("[mscx_uno bridge error] unexpected C++ exception occurred!");
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno);
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+#pragma pack(pop)
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx
new file mode 100644
index 0000000000..c888731438
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/types.h>
+
+#include <cassert>
+
+#include "abi.hxx"
+
+enum StructKind
+{
+ STRUCT_KIND_EMPTY,
+ STRUCT_KIND_FLOAT,
+ STRUCT_KIND_DOUBLE,
+ STRUCT_KIND_POD,
+ STRUCT_KIND_DTOR
+};
+
+static StructKind getStructKind(typelib_CompoundTypeDescription const* type)
+{
+ StructKind k = type->pBaseTypeDescription == 0 ? STRUCT_KIND_EMPTY
+ : getStructKind(type->pBaseTypeDescription);
+
+ for (sal_Int32 i = 0; i != type->nMembers; ++i)
+ {
+ StructKind k2 = StructKind();
+ switch (type->ppTypeRefs[i]->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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ k2 = STRUCT_KIND_POD;
+ break;
+ case typelib_TypeClass_FLOAT:
+ k2 = STRUCT_KIND_FLOAT;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ k2 = STRUCT_KIND_DOUBLE;
+ break;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ k2 = STRUCT_KIND_DTOR;
+ break;
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription* td = 0;
+ TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
+ k2 = getStructKind(reinterpret_cast<typelib_CompoundTypeDescription const*>(td));
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ default:
+ assert(false);
+ }
+ switch (k2)
+ {
+ case STRUCT_KIND_EMPTY:
+ // this means an empty sub-object, which nevertheless obtains a byte
+ // of storage (TODO: does it?), so the full object cannot be a
+ // homogeneous collection of float or double
+ case STRUCT_KIND_POD:
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ break;
+ case STRUCT_KIND_FLOAT:
+ case STRUCT_KIND_DOUBLE:
+ if (k == STRUCT_KIND_EMPTY)
+ {
+ k = k2;
+ }
+ else if (k != k2)
+ {
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ }
+ break;
+ case STRUCT_KIND_DTOR:
+ return STRUCT_KIND_DTOR;
+ }
+ }
+ return k;
+}
+
+ReturnKind getReturnKind(typelib_TypeDescription const* type)
+{
+ switch (type->eTypeClass)
+ {
+ default:
+ assert(false);
+ [[fallthrough]];
+ case typelib_TypeClass_VOID:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ assert(type->nSize <= 16);
+ return RETURN_KIND_REG;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ return RETURN_KIND_INDIRECT;
+ case typelib_TypeClass_STRUCT:
+ if (type->nSize > 16)
+ {
+ return RETURN_KIND_INDIRECT;
+ }
+ switch (getStructKind(reinterpret_cast<typelib_CompoundTypeDescription const*>(type)))
+ {
+ case STRUCT_KIND_FLOAT:
+ return RETURN_KIND_HFA_FLOAT;
+ case STRUCT_KIND_DOUBLE:
+ return RETURN_KIND_HFA_DOUBLE;
+ case STRUCT_KIND_DTOR:
+ return RETURN_KIND_INDIRECT;
+ default:
+ return RETURN_KIND_REG;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx b/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx
new file mode 100644
index 0000000000..38a61161ca
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <typelib/typedescription.h>
+
+enum ReturnKind
+{
+ RETURN_KIND_REG,
+ RETURN_KIND_HFA_FLOAT,
+ RETURN_KIND_HFA_DOUBLE,
+ RETURN_KIND_INDIRECT
+};
+
+ReturnKind getReturnKind(typelib_TypeDescription const* type);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S b/bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S
new file mode 100644
index 0000000000..a058e47d00
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S
@@ -0,0 +1,72 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; 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/.
+ */
+
+ OPT 2 // disable listing
+// macros to add unwind information
+#include "ksarm64.h"
+ OPT 1 // re-enable listing
+
+ EXPORT callVirtualFunction
+
+ TEXTAREA, ALIGN=8
+
+/*
+ extern void callVirtualFunction
+
+ x0 stack
+ x1 frame
+ x2 function
+ x3 return
+*/
+
+ NESTED_ENTRY callVirtualFunction_fake
+
+ // for unwind information, Windows has to store fp and lr
+ PROLOG_SAVE_REG_PAIR x29, x30, #-32!
+
+ ALTERNATE_ENTRY callVirtualFunction
+
+ // use a stack frame allocated by our caller
+ stp x29, x30, [x1]
+ mov x29, x1
+ mov sp, x0
+
+ mov x9, x2 // function
+ mov x8, x3 // complex return
+ str x3, [x29, #16] // save rvalue
+
+ // load the core argument passing registers
+ ldp x0, x1, [sp, #-128]
+ ldp x2, x3, [sp, #-112]
+ ldp x4, x5, [sp, #-96]
+ ldp x6, x7, [sp, #-80]
+
+ ldp d0, d1, [sp, #-64]
+ ldp d2, d3, [sp, #-48]
+ ldp d4, d5, [sp, #-32]
+ ldp d6, d7, [sp, #-16]
+
+ blr x9 // call
+
+ ldr x3, [x29, #16] // reload rvalue
+
+ // partially deconstruct the stack frame
+ mov sp, x29
+ ldp x29, x30, [x29]
+
+ // save the simple return values
+ stp x0, x1, [sp, #0]
+ stp d0, d1, [sp, #64]
+ stp d2, d3, [sp, #80]
+
+ NESTED_END callVirtualFunction_fake
+
+ END
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx
new file mode 100644
index 0000000000..fc956121dc
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <typeinfo>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include <msvc/arm64.hxx>
+
+#include "abi.hxx"
+
+extern "C" IMAGE_DOS_HEADER const __ImageBase;
+
+extern "C" void vtableSlotCall();
+
+using namespace ::com::sun::star;
+
+namespace
+{
+void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
+ uno::TypeDescription const& description, typelib_TypeDescriptionReference* returnType,
+ sal_Int32 count, typelib_MethodParameter* parameters, sal_uInt64* gpr, sal_uInt64* fpr,
+ sal_uInt64* stack, void* indirectRet)
+{
+ typelib_TypeDescription* rtd = 0;
+ if (returnType != 0)
+ TYPELIB_DANGER_GET(&rtd, returnType);
+
+ ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd);
+ bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
+
+ void* retin = retKind == RETURN_KIND_INDIRECT && !retConv ? indirectRet
+ : rtd == 0 ? 0 : alloca(rtd->nSize);
+ void** args = static_cast<void**>(alloca(count * sizeof(void*)));
+ void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
+ typelib_TypeDescription** argtds
+ = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
+
+ sal_Int32 ngpr = 1;
+ sal_Int32 nfpr = 0;
+ sal_Int32 sp = 0;
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ switch (parameters[i].pTypeRef->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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
+ break;
+ default:
+ assert(false);
+ }
+ argtds[i] = 0;
+ }
+ else
+ {
+ cppArgs[i] = reinterpret_cast<void*>(ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
+ typelib_TypeDescription* ptd = 0;
+ 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] = 0;
+ TYPELIB_DANGER_RELEASE(ptd);
+ }
+ }
+ }
+
+ uno_Any exc;
+ uno_Any* pexc = &exc;
+ proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
+ if (pexc != 0)
+ {
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (argtds[i] == 0)
+ continue;
+ if (parameters[i].bIn)
+ uno_destructData(args[i], argtds[i], 0);
+ TYPELIB_DANGER_RELEASE(argtds[i]);
+ }
+ if (rtd != 0)
+ TYPELIB_DANGER_RELEASE(rtd);
+ assert(pexc == &exc);
+ msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp());
+ }
+
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (argtds[i] != 0)
+ {
+ if (parameters[i].bOut)
+ {
+ uno_destructData(cppArgs[i], argtds[i],
+ reinterpret_cast<uno_ReleaseFunc>(uno::cpp_release));
+ uno_copyAndConvertData(cppArgs[i], args[i], argtds[i],
+ proxy->getBridge()->getUno2Cpp());
+ }
+ uno_destructData(args[i], argtds[i], 0);
+ TYPELIB_DANGER_RELEASE(argtds[i]);
+ }
+ }
+
+ void* retout = 0; // avoid false -Werror=maybe-uninitialized
+ switch (retKind)
+ {
+ case RETURN_KIND_REG:
+ switch (rtd == 0 ? typelib_TypeClass_VOID : rtd->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ std::memcpy(gpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_STRUCT:
+ if (retConv)
+ {
+ retout = gpr;
+ }
+ else
+ {
+ std::memcpy(gpr, retin, rtd->nSize);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case RETURN_KIND_HFA_FLOAT:
+ assert(rtd != 0);
+ switch (rtd->nSize)
+ {
+ case 16:
+ std::memcpy(fpr + 3, static_cast<char*>(retin) + 12, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(fpr + 2, static_cast<char*>(retin) + 8, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(fpr + 1, static_cast<char*>(retin) + 4, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(fpr, retin, 4);
+ break;
+ default:
+ assert(false);
+ }
+ assert(!retConv);
+ break;
+ case RETURN_KIND_HFA_DOUBLE:
+ assert(rtd != 0);
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case RETURN_KIND_INDIRECT:
+ retout = indirectRet;
+ break;
+ }
+
+ if (retConv)
+ {
+ uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
+ uno_destructData(retin, rtd, 0);
+ }
+
+ if (rtd != 0)
+ TYPELIB_DANGER_RELEASE(rtd);
+}
+
+extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr,
+ sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet)
+{
+ bridges::cpp_uno::shared::CppInterfaceProxy* proxy
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ reinterpret_cast<char*>(gpr[0]) - vtableOffset);
+ typelib_InterfaceTypeDescription* pInterfaceTD = proxy->getTypeDescr();
+ assert(functionIndex < pInterfaceTD->nMapFunctionIndexToMemberIndex);
+ sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[functionIndex];
+ assert(nMemberPos < pInterfaceTD->nAllMembers);
+ uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
+
+ switch (aMemberDescr.get()->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_TypeDescriptionReference* pAttrTypeRef
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
+ ->pAttributeTypeRef;
+
+ if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex)
+ {
+ // Getter:
+ call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet);
+ }
+ else
+ {
+ // Setter:
+ typelib_MethodParameter param = { 0, pAttrTypeRef, true, false };
+ call(proxy, aMemberDescr, 0, 1, &param, gpr, fpr, stack, 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<uno::Type*>(gpr[1])->getTypeLibType()));
+ if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ uno::XInterface* ifc = nullptr;
+ proxy->getBridge()->getCppEnv()->getRegisteredInterface(
+ proxy->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc),
+ proxy->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
+ if (ifc != 0)
+ {
+ uno_any_construct(reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
+ reinterpret_cast<uno_AcquireFunc>(uno::cpp_acquire));
+ ifc->release();
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ }
+ [[fallthrough]];
+ default:
+ typelib_InterfaceMethodTypeDescription* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
+ aMemberDescr.get());
+ call(proxy, aMemberDescr, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
+ pMethodTD->pParams, gpr, fpr, stack, indirectRet);
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+std::size_t const codeSnippetSize = 8 * 4;
+
+unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex,
+ sal_Int32 vtableOffset)
+{
+ // movz x9, <low functionIndex>
+ reinterpret_cast<unsigned int*>(code)[0] = 0xD2800009 | ((functionIndex & 0xFFFF) << 5);
+ // movk x9, <high functionIndex>, LSL #16
+ reinterpret_cast<unsigned int*>(code)[1] = 0xF2A00009 | ((functionIndex >> 16) << 5);
+ // movz x10, <low vtableOffset>
+ reinterpret_cast<unsigned int*>(code)[2] = 0xD280000A | ((vtableOffset & 0xFFFF) << 5);
+ // movk x10, <high vtableOffset>, LSL #16
+ reinterpret_cast<unsigned int*>(code)[3] = 0xF2A0000A | ((vtableOffset >> 16) << 5);
+ // ldr x11, +2*4
+ reinterpret_cast<unsigned int*>(code)[4] = 0x5800004B;
+ // br x11
+ reinterpret_cast<unsigned int*>(code)[5] = 0xD61F0160;
+ reinterpret_cast<void**>(code)[3] = reinterpret_cast<void*>(&vtableSlotCall);
+ return code + codeSnippetSize;
+}
+}
+
+namespace bridges::cpp_uno::shared
+{
+struct bridges::cpp_uno::shared::VtableFactory::Slot
+{
+ void* fn;
+};
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block)
+{
+ return static_cast<Slot*>(block) + 1;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
+{
+ return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize;
+}
+
+static sal_uInt32 imageRelative(void const* p)
+{
+ assert(reinterpret_cast<sal_uIntPtr>(p) >= reinterpret_cast<sal_uIntPtr>(&__ImageBase)
+ && reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase)
+ <= std::numeric_limits<sal_uInt32>::max());
+ return reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase);
+}
+
+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
+{
+};
+
+// The following vtable RTTI data is based on how the code at
+// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
+// such data, and on how <https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483>
+// "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase:
+
+struct RttiClassHierarchyDescriptor;
+
+#pragma warning(push)
+#pragma warning(disable : 4324) // "structure was padded due to alignment specifier"
+
+struct alignas(16) RttiBaseClassDescriptor
+{
+ sal_uInt32 n0 = imageRelative(&typeid(ProxyRtti));
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = 0xFFFFFFFF;
+ sal_uInt32 n4 = 0;
+ sal_uInt32 n5 = 0x40;
+ sal_uInt32 n6;
+ RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const* chd)
+ : n6(imageRelative(chd))
+ {
+ }
+};
+
+struct alignas(4) RttiBaseClassArray
+{
+ sal_uInt32 n0;
+ sal_uInt32 n1 = 0;
+ RttiBaseClassArray(RttiBaseClassDescriptor const* bcd)
+ : n0(imageRelative(bcd))
+ {
+ }
+};
+
+struct alignas(8) RttiClassHierarchyDescriptor
+{
+ sal_uInt32 n0 = 0;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 1;
+ sal_uInt32 n3;
+ RttiClassHierarchyDescriptor(RttiBaseClassArray const* bca)
+ : n3(imageRelative(bca))
+ {
+ }
+};
+
+struct alignas(16) RttiCompleteObjectLocator
+{
+ sal_uInt32 n0 = 1;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = imageRelative(&typeid(ProxyRtti));
+ sal_uInt32 n4;
+ sal_uInt32 n5 = imageRelative(this);
+ RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const* chd)
+ : n4(imageRelative(chd))
+ {
+ }
+};
+
+struct Rtti
+{
+ RttiBaseClassDescriptor bcd;
+ RttiBaseClassArray bca;
+ RttiClassHierarchyDescriptor chd;
+ RttiCompleteObjectLocator col;
+ Rtti()
+ : bcd(&chd)
+ , bca(&bcd)
+ , chd(&bca)
+ , col(&chd)
+ {
+ }
+};
+
+#pragma warning(pop)
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot*
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
+ sal_Int32,
+ typelib_InterfaceTypeDescription*)
+{
+ static Rtti rtti;
+
+ Slot* slots = mapBlockToVtable(block);
+ slots[-1].fn = &rtti.col;
+ return slots + slotCount;
+}
+
+unsigned char* VtableFactory::addLocalFunctions(VtableFactory::Slot** slots, unsigned char* code,
+ typelib_InterfaceTypeDescription const* type,
+ sal_Int32 functionOffset, sal_Int32 functionCount,
+ sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ VtableFactory::Slot* s = *slots;
+ for (sal_Int32 i = 0; i != type->nMembers; ++i)
+ {
+ typelib_TypeDescription* td = nullptr;
+ TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
+ assert(td != 0);
+ switch (td->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription* atd
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(td);
+ // Getter:
+ (s++)->fn = code;
+ code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
+ // Setter:
+ if (!atd->bReadOnly)
+ {
+ (s++)->fn = code;
+ code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code;
+ code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
+ break;
+ default:
+ assert(false);
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ return code;
+}
+
+void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end)
+{
+ FlushInstructionCache(GetCurrentProcess(), begin, end - begin);
+}
+
+} // namespace bridges::cpp_uno::shared
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx
new file mode 100644
index 0000000000..8cc380c5d7
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <malloc.h>
+#include <new.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <msvc/arm64.hxx>
+#include <except.hxx>
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star;
+
+static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
+ typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
+ return pExcThis;
+}
+
+static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_destructData(pExcThis, pTD, uno::cpp_release);
+ return pExcThis;
+}
+
+const int nCodeSnippetSize = 28;
+
+static void GenerateCopyConstructorTrampoline(unsigned char* target,
+ typelib_TypeDescription* pTD) noexcept
+{
+ // ldr x2, #12
+ // ldr x3, #20
+ // br x3
+ // pTD
+ // &copyConstruct
+ static const char code[] = "\x62\x00\x00\x58\x83\x00\x00\x58\x60\x00\x1f\xd6";
+ static_assert(sizeof(code) == 13);
+ static const unsigned int code_size = sizeof(code) - 1;
+
+ memcpy(target, code, code_size);
+ *reinterpret_cast<void**>(target + code_size) = pTD;
+ *reinterpret_cast<void**>(target + code_size + 8) = &copyConstruct;
+}
+
+static void GenerateDestructorTrampoline(unsigned char* target,
+ typelib_TypeDescription* pTD) noexcept
+{
+ // ldr x1, #12
+ // ldr x2, #20
+ // br x2
+ // pTD
+ // &destruct
+ static const char code[] = "\x61\x00\x00\x58\x82\x00\x00\x58\x40\x00\x1f\xd6";
+ static_assert(sizeof(code) == 13);
+ static const unsigned int code_size = sizeof(code) - 1;
+
+ memcpy(target, code, code_size);
+ *reinterpret_cast<void**>(target + code_size) = pTD;
+ *reinterpret_cast<void**>(target + code_size + 8) = &destruct;
+}
+
+ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+ typelib_TypeDescription* pTD) noexcept
+ : _n0(0)
+ , _n1(0)
+ , _n2(-1)
+ , _n3(0)
+ , _n4(pTD->nSize)
+ , exc_type_info(nullptr, "")
+{
+ // As _n0 is always initialized to zero, that means the
+ // hasvirtbase flag (see the ONTL catchabletype struct) is
+ // off, and thus the copyctor is of the ctor_ptr kind.
+
+ int len;
+ type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);
+
+ memcpy(static_cast<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
+ _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_type_info) - pCodeBase);
+ GenerateCopyConstructorTrampoline(pCode, pTD);
+
+ assert(pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
+ && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase < 0x100000000));
+ _pCopyCtor = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
+}
+
+/* Rewrite of 32-Bit-Code to work under 64 Bit:
+* To use the 32 Bit offset values in the ExceptionType we have to
+* allocate a single allocation block and use it for all code and date
+* all offsets inside this area are guaranteed to be in 32 bit address range.
+* So we have to calc total memory allocation size for D-tor, C-Tors,
+* ExceptionType and type_info. ExceptionType is allocated via placement new
+* to locate everything inside our mem block.
+* There is one caveat: Struct type_info is kept in
+* a map and was referenced from class ExceptionType. Therefore type_info now
+* is also member of ExceptionType and can be referenced via 32 bit offset.
+*/
+
+RaiseInfo::RaiseInfo(typelib_TypeDescription* pTD) noexcept
+ : _n0(0)
+ , _n2(0)
+ , _pTD(pTD)
+{
+ typelib_CompoundTypeDescription* pCompTD;
+
+ // Count how many trampolines we need
+ int codeSize = nCodeSnippetSize;
+
+ // Info count
+ int nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ ++nLen;
+ codeSize += nCodeSnippetSize;
+ }
+
+ // Array with size (4) and all _pTypeInfo (4*nLen)
+ int typeInfoArraySize = 4 + 4 * nLen;
+
+ // 2.Pass: Get the total needed memory for class ExceptionType
+ // (with embedded type_info) and keep the sizes for each instance
+ // is stored in allocated int array
+ auto exceptionTypeSizeArray = std::make_unique<int[]>(nLen);
+
+ nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ int typeInfoLen;
+ RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
+ // Mem has to be on 4-byte Boundary
+ if (typeInfoLen % 4 != 0)
+ {
+ int n = typeInfoLen / 4;
+ n++;
+ typeInfoLen = n * 4;
+ }
+ exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
+ }
+
+ // Total ExceptionType related mem
+ int excTypeAddLen = 0;
+ for (int i = 0; i < nLen; i++)
+ {
+ excTypeAddLen += exceptionTypeSizeArray[i];
+ }
+
+ // Allocate mem for code and all dynamic data in one chunk to guarantee
+ // 32 bit offsets
+ const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
+ unsigned char* pCode = _code = static_cast<unsigned char*>(std::malloc(totalSize));
+ int pCodeOffset = 0;
+
+ // New base of types array, starts after Trampoline D-Tor / C-Tors
+ DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);
+
+ // New base of ExceptionType array, starts after types array
+ unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
+ int etMemOffset = 0;
+
+ _codeBase = reinterpret_cast<sal_uInt64>(pCode)
+ & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
+
+ DWORD old_protect;
+ bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
+ (void)success;
+ assert(success && "VirtualProtect() failed!");
+
+ ::typelib_typedescription_acquire(pTD);
+
+ // Fill pCode with D-Tor code
+ GenerateDestructorTrampoline(pCode, pTD);
+ _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
+ pCodeOffset += nCodeSnippetSize;
+
+ // Info count accompanied by type info ptrs: type, base type, base base type, ...
+ // Keep offset of types_array
+ _types = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
+ // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
+ types[0] = nLen;
+
+ int nPos = 1;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ // Create instance in mem block with placement new
+ ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
+ pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(pCompTD));
+
+ // Next trampoline entry offset
+ pCodeOffset += nCodeSnippetSize;
+ // Next ExceptionType placement offset
+ etMemOffset += exceptionTypeSizeArray[nPos - 1];
+
+ // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
+ types[nPos++] = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et) - _codeBase);
+ }
+ // Final check: end of address calculation must be end of mem
+ assert(etMem + etMemOffset == pCode + totalSize);
+}
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx
new file mode 100644
index 0000000000..a0c2adc6f6
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx
@@ -0,0 +1,341 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstring>
+#include <exception>
+#include <typeinfo>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <rtl/textenc.h>
+#include <rtl/ustring.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+
+#include "abi.hxx"
+#include <msvc/arm64.hxx>
+
+namespace
+{
+extern "C" void callVirtualFunction(sal_uInt64* stack, sal_uInt64* frame, sal_uInt64 function,
+ void* ret);
+
+void pushArgument(sal_uInt64 value, sal_uInt64* stack, sal_Int32& sp, sal_uInt64* regs,
+ sal_Int32& nregs)
+{
+ (nregs != 8 ? regs[nregs++] : stack[sp++]) = value;
+}
+
+void call(bridges::cpp_uno::shared::UnoInterfaceProxy* pProxy,
+ bridges::cpp_uno::shared::VtableSlot slot, typelib_TypeDescriptionReference* returnType,
+ const sal_Int32 count, typelib_MethodParameter* parameters, void* returnValue,
+ void** arguments, uno_Any** exception)
+{
+ static_assert(sizeof(sal_uInt64) == sizeof(void*));
+ typelib_TypeDescription* aReturnTD = nullptr;
+ TYPELIB_DANGER_GET(&aReturnTD, returnType);
+ const ReturnKind eRetKind = getReturnKind(aReturnTD);
+ const bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(aReturnTD);
+ void* ret = retConv ? alloca(aReturnTD->nSize) : returnValue;
+
+ sal_uInt64** thisPtr = reinterpret_cast<sal_uInt64**>(pProxy->getCppI()) + slot.offset;
+
+ sal_uInt64* gpr = static_cast<sal_uInt64*>(alloca((count + 16) * sizeof(sal_uInt64) + 32));
+ sal_uInt64* fpr = &gpr[8];
+ sal_uInt64* stack = &gpr[16];
+ sal_uInt64* frame = &gpr[16 + count];
+ void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
+ typelib_TypeDescription** ptds
+ = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
+
+ sal_Int32 sp = 0;
+ sal_Int32 nGPR = 0;
+ sal_Int32 nFPR = 0;
+ gpr[nGPR++] = reinterpret_cast<sal_uInt64>(thisPtr);
+
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ cppArgs[i] = 0;
+ switch (parameters[i].pTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_BOOLEAN:
+ pushArgument(*static_cast<sal_Bool*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_BYTE:
+ pushArgument(*static_cast<sal_Int8*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_SHORT:
+ pushArgument(*static_cast<sal_Int16*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pushArgument(*static_cast<sal_uInt16*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_ENUM:
+ pushArgument(*static_cast<sal_Int32*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_HYPER:
+ pushArgument(*static_cast<sal_Int64*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ case typelib_TypeClass_FLOAT:
+ pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, fpr, nFPR);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, fpr, nFPR);
+ break;
+ case typelib_TypeClass_CHAR:
+ pushArgument(*static_cast<sal_Unicode*>(arguments[i]), stack, sp, gpr, nGPR);
+ break;
+ default:
+ assert(false);
+ }
+ }
+ else
+ {
+ typelib_TypeDescription* ptd = 0;
+ TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
+ if (!parameters[i].bIn)
+ {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_constructData(cppArgs[i], ptd);
+ ptds[i] = ptd;
+ pushArgument(reinterpret_cast<sal_uInt64>(cppArgs[i]), stack, sp, gpr, nGPR);
+ }
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd))
+ {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_copyAndConvertData(cppArgs[i], arguments[i], ptd,
+ pProxy->getBridge()->getUno2Cpp());
+ ptds[i] = ptd;
+ pushArgument(reinterpret_cast<sal_uInt64>(cppArgs[i]), stack, sp, gpr, nGPR);
+ }
+ else
+ {
+ cppArgs[i] = 0;
+ pushArgument(reinterpret_cast<sal_uInt64>(arguments[i]), stack, sp, gpr, nGPR);
+ TYPELIB_DANGER_RELEASE(ptd);
+ }
+ }
+ }
+
+ __try
+ {
+ callVirtualFunction(stack, frame, (*thisPtr)[slot.index], ret);
+ }
+ __except (msvc_filterCppException(GetExceptionInformation(), *exception,
+ pProxy->getBridge()->getCpp2Uno()))
+ {
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (cppArgs[i] != 0)
+ {
+ uno_destructData(cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+ TYPELIB_DANGER_RELEASE(aReturnTD);
+ return;
+ }
+
+ *exception = 0;
+ for (sal_Int32 i = 0; i != count; ++i)
+ {
+ if (cppArgs[i] != 0)
+ {
+ if (parameters[i].bOut)
+ {
+ if (parameters[i].bIn)
+ {
+ uno_destructData(arguments[i], ptds[i], 0);
+ }
+ uno_copyAndConvertData(arguments[i], cppArgs[i], ptds[i],
+ pProxy->getBridge()->getCpp2Uno());
+ }
+ uno_destructData(cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+
+ switch (eRetKind)
+ {
+ case RETURN_KIND_REG:
+ switch (aReturnTD->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ 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_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ std::memcpy(ret, gpr, aReturnTD->nSize);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(ret, fpr, aReturnTD->nSize);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case RETURN_KIND_HFA_FLOAT:
+ switch (aReturnTD->nSize)
+ {
+ case 16:
+ std::memcpy(static_cast<char*>(ret) + 12, fpr + 3, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(static_cast<char*>(ret) + 8, fpr + 2, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(static_cast<char*>(ret) + 4, fpr + 1, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(ret, fpr, 4);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case RETURN_KIND_HFA_DOUBLE:
+ std::memcpy(ret, fpr, aReturnTD->nSize);
+ break;
+ case RETURN_KIND_INDIRECT:
+ break;
+ }
+
+ if (retConv)
+ {
+ uno_copyAndConvertData(returnValue, ret, aReturnTD, pProxy->getBridge()->getCpp2Uno());
+ uno_destructData(ret, aReturnTD, reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ }
+ TYPELIB_DANGER_RELEASE(aReturnTD);
+}
+}
+
+namespace bridges::cpp_uno::shared
+{
+void unoInterfaceProxyDispatch(uno_Interface* pUnoI, typelib_TypeDescription const* pMemberDescr,
+ void* pReturn, void** pArgs, uno_Any** ppException)
+{
+ UnoInterfaceProxy* pProxy = static_cast<UnoInterfaceProxy*>(pUnoI);
+ switch (pMemberDescr->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription const* atd
+ = reinterpret_cast<typelib_InterfaceAttributeTypeDescription const*>(pMemberDescr);
+ VtableSlot slot(getVtableSlot(atd));
+ if (pReturn != 0)
+ { // getter
+ call(pProxy, slot, atd->pAttributeTypeRef, 0, 0, pReturn, pArgs, ppException);
+ }
+ else
+ { // setter
+ typelib_MethodParameter param = { 0, atd->pAttributeTypeRef, true, false };
+ typelib_TypeDescriptionReference* pReturnTD = nullptr;
+ typelib_typedescriptionreference_new(&pReturnTD, typelib_TypeClass_VOID,
+ OUString("void").pData);
+ slot.index += 1;
+ call(pProxy, slot, pReturnTD, 1, &param, pReturn, pArgs, ppException);
+ typelib_typedescriptionreference_release(pReturnTD);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const* mtd
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription const*>(pMemberDescr);
+ VtableSlot slot(getVtableSlot(mtd));
+ switch (slot.index)
+ {
+ case 1:
+ pUnoI->acquire(pUnoI);
+ *ppException = 0;
+ break;
+ case 2:
+ pUnoI->release(pUnoI);
+ *ppException = 0;
+ break;
+ case 0:
+ {
+ typelib_TypeDescription* td = 0;
+ TYPELIB_DANGER_GET(
+ &td, (reinterpret_cast<css::uno::Type*>(pArgs[0])->getTypeLibType()));
+ if (td != 0)
+ {
+ uno_Interface* ifc = 0;
+ pProxy->pBridge->getUnoEnv()->getRegisteredInterface(
+ pProxy->pBridge->getUnoEnv(), reinterpret_cast<void**>(&ifc),
+ pProxy->oid.pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
+ if (ifc != 0)
+ {
+ uno_any_construct(reinterpret_cast<uno_Any*>(pReturn), &ifc, td, 0);
+ ifc->release(ifc);
+ TYPELIB_DANGER_RELEASE(td);
+ *ppException = 0;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ }
+ [[fallthrough]];
+ default:
+ call(pProxy, slot, mtd->pReturnTypeRef, mtd->nParams, mtd->pParams, pReturn,
+ pArgs, ppException);
+ break;
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S b/bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S
new file mode 100644
index 0000000000..cda427c5c2
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S
@@ -0,0 +1,72 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ OPT 2 // disable listing
+// macros to add unwind information
+#include "ksarm64.h"
+ OPT 1 // re-enable listing
+
+ EXPORT vtableSlotCall
+ IMPORT vtableCall
+
+ TEXTAREA, ALIGN=2
+
+ NESTED_ENTRY vtableSlotCall
+
+ PROLOG_SAVE_REG_PAIR fp, lr, #-192!
+ PROLOG_SAVE_REG_PAIR x19, x20, #16
+
+ add x11, sp, 192
+ add x20, sp, 128
+ add x19, sp, 64
+
+ stp x11, x11, [sp, 32]
+ str x11, [sp, 48]
+ stp wzr, wzr, [sp, 56]
+ stp x0, x1, [sp, 64]
+ mov w0, w9
+ mov w1, w10
+ stp x2, x3, [sp, 80]
+ mov x3, x20
+ mov x2, x19
+ stp x4, x5, [sp, 96]
+ mov x5, x8
+ mov x4, x11
+ stp x6, x7, [sp, 112]
+ stp d0, d1, [sp, 128]
+ stp d2, d3, [sp, 144]
+ stp d4, d5, [sp, 160]
+ stp d6, d7, [sp, 176]
+
+ bl vtableCall
+
+ ldp x0, x1, [x19]
+ ldp d0, d1, [x20]
+ ldp d2, d3, [x20, #16]
+
+ EPILOG_STACK_RESTORE
+ EPILOG_RESTORE_REG_PAIR x19, x20, #16
+ EPILOG_RESTORE_REG_PAIR fp, lr, #192!
+ EPILOG_RETURN
+
+ NESTED_END vtableSlotCall
+
+ END
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab */
diff --git a/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx
new file mode 100644
index 0000000000..577c318c57
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/config.h>
+
+#include <typeinfo>
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridge.hxx"
+#include "cppinterfaceproxy.hxx"
+#include "types.hxx"
+#include "vtablefactory.hxx"
+
+#include <msvc/x86.hxx>
+#include <msvc/cpp2uno.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+/**
+ * is called on incoming vtable calls
+ * (called by asm snippets)
+ */
+static __declspec(naked) void __cdecl cpp_vtable_call()
+{
+__asm
+ {
+ sub esp, 8 // space for immediate return type
+ push esp
+ push edx // vtable offset
+ push eax // function index
+ mov eax, esp
+ add eax, 20
+ push eax // original stack ptr
+
+ call cpp_mediate
+ add esp, 16
+
+ cmp eax, typelib_TypeClass_FLOAT
+ je Lfloat
+ cmp eax, typelib_TypeClass_DOUBLE
+ je Ldouble
+ cmp eax, typelib_TypeClass_HYPER
+ je Lhyper
+ cmp eax, typelib_TypeClass_UNSIGNED_HYPER
+ je Lhyper
+ // rest is eax
+ pop eax
+ add esp, 4
+ ret
+Lhyper:
+ pop eax
+ pop edx
+ ret
+Lfloat:
+ fld dword ptr [esp]
+ add esp, 8
+ ret
+Ldouble:
+ fld qword ptr [esp]
+ add esp, 8
+ ret
+ }
+}
+
+int const codeSnippetSize = 16;
+
+unsigned char * codeSnippet(
+ unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
+{
+ unsigned char * p = code;
+ static_assert(sizeof (sal_Int32) == 4, "boo");
+ // mov eax, functionIndex:
+ *p++ = 0xB8;
+ *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
+ p += sizeof (sal_Int32);
+ // mov edx, vtableOffset:
+ *p++ = 0xBA;
+ *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
+ p += sizeof (sal_Int32);
+ // jmp rel32 cpp_vtable_call:
+ *p++ = 0xE9;
+ *reinterpret_cast< sal_Int32 * >(p)
+ = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32);
+ p += sizeof (sal_Int32);
+ assert(p - code <= codeSnippetSize);
+ return code + codeSnippetSize;
+}
+
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+ return static_cast< Slot * >(block) + 1;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+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 {};
+
+// The following vtable RTTI data is based on how the code at
+// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
+// such data:
+
+struct RttiClassHierarchyDescriptor;
+
+#pragma warning (push)
+#pragma warning (disable: 4324) // "structure was padded due to alignment specifier"
+
+struct alignas(16) RttiBaseClassDescriptor {
+ sal_uInt32 n0 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = 0xFFFFFFFF;
+ sal_uInt32 n4 = 0;
+ sal_uInt32 n5 = 0x40;
+ sal_uInt32 n6;
+ RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd):
+ n6(reinterpret_cast<sal_uInt32>(chd)) {}
+};
+
+struct alignas(4) RttiBaseClassArray {
+ sal_uInt32 n0;
+ sal_uInt32 n1 = 0;
+ RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(reinterpret_cast<sal_uInt32>(bcd))
+ {}
+};
+
+struct alignas(4) RttiClassHierarchyDescriptor {
+ sal_uInt32 n0 = 0;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 1;
+ sal_uInt32 n3;
+ RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca):
+ n3(reinterpret_cast<sal_uInt32>(bca)) {}
+};
+
+struct alignas(16) RttiCompleteObjectLocator {
+ sal_uInt32 n0 = 0;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
+ sal_uInt32 n4;
+ RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd):
+ n4(reinterpret_cast<sal_uInt32>(chd)) {}
+};
+
+struct Rtti {
+ RttiBaseClassDescriptor bcd;
+ RttiBaseClassArray bca;
+ RttiClassHierarchyDescriptor chd;
+ RttiCompleteObjectLocator col;
+ Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {}
+};
+
+#pragma warning (pop)
+
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ static Rtti rtti;
+
+ Slot * slots = mapBlockToVtable(block);
+ slots[-1].fn = &rtti.col;
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+ typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i < functionCount; ++i) {
+ (s++)->fn = code;
+ code = codeSnippet(code, functionOffset++, vtableOffset);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *,
+ unsigned char const *)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_intel/except.cxx b/bridges/source/cpp_uno/msvc_win32_intel/except.cxx
new file mode 100644
index 0000000000..d65152b29d
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_intel/except.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/config.h>
+#include <malloc.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <unordered_map>
+#include <msvc/x86.hxx>
+#include <except.hxx>
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star;
+
+void * ObjectFunction::operator new ( size_t nSize )
+{
+ void * pMem = std::malloc( nSize );
+ if (pMem != 0)
+ {
+ DWORD old_protect;
+ BOOL success =
+ VirtualProtect(pMem, nSize, PAGE_EXECUTE_READWRITE, &old_protect);
+ (void) success;
+ assert(success && "VirtualProtect() failed!");
+ }
+ return pMem;
+}
+
+void ObjectFunction::operator delete ( void * pMem )
+{
+ std::free( pMem );
+}
+
+ObjectFunction::ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ()
+ : _pTypeDescr( pTypeDescr )
+{
+ ::typelib_typedescription_acquire( _pTypeDescr );
+
+ unsigned char * pCode = (unsigned char *)somecode;
+ // a must be!
+ assert((void *)this == (void *)pCode);
+
+ // push ObjectFunction this
+ *pCode++ = 0x68;
+ *(void **)pCode = this;
+ pCode += sizeof(void *);
+ // jmp rel32 fpFunc
+ *pCode++ = 0xe9;
+ *(sal_Int32 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int32);
+}
+
+ObjectFunction::~ObjectFunction() throw ()
+{
+ ::typelib_typedescription_release( _pTypeDescr );
+}
+
+static void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis )
+ throw ()
+{
+ ::uno_copyData(pExcThis, pSource, pThis->_pTypeDescr, uno::cpp_acquire);
+ return pExcThis;
+}
+
+static void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis )
+ throw ()
+{
+ ::uno_destructData(pExcThis, pThis->_pTypeDescr, uno::cpp_release);
+ return pExcThis;
+}
+
+// these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr
+
+static __declspec(naked) void copyConstruct() throw ()
+{
+ __asm
+ {
+ // ObjectFunction this already on stack
+ push [esp+8] // source exc object this
+ push ecx // exc object
+ call __copyConstruct
+ add esp, 12 // + ObjectFunction this
+ ret 4
+ }
+}
+
+static __declspec(naked) void destruct() throw ()
+{
+ __asm
+ {
+ // ObjectFunction this already on stack
+ push ecx // exc object
+ call __destruct
+ add esp, 8 // + ObjectFunction this
+ ret
+ }
+}
+
+ExceptionType::ExceptionType( typelib_TypeDescription * pTypeDescr ) throw ()
+ : _n0( 0 )
+ , _n1( 0 )
+ , _n2( -1 )
+ , _n3( 0 )
+ , _n4( pTypeDescr->nSize )
+ , _pCopyCtor( new ObjectFunction( pTypeDescr, copyConstruct ) )
+ , _n5( 0 )
+{
+ _pTypeInfo = RTTInfos::get(pTypeDescr->pTypeName);
+}
+
+ExceptionType::~ExceptionType() throw ()
+{
+ delete _pCopyCtor;
+}
+
+RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
+ : _n0( 0 )
+ , _pDtor( new ObjectFunction( pTypeDescr, destruct ) )
+ , _n2( 0 )
+ , _n3( 0 )
+ , _n4( 0 )
+{
+ // a must be
+ static_assert(sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer size differs from sal_Int32!");
+
+ typelib_CompoundTypeDescription * pCompTypeDescr;
+
+ // info count
+ sal_Int32 nLen = 0;
+ for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
+ pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ ++nLen;
+ }
+
+ // info count accompanied by type info ptrs: type, base type, base base type, ...
+ _types = std::malloc( sizeof(sal_Int32) + (sizeof(ExceptionType *) * nLen) );
+ *(sal_Int32 *)_types = nLen;
+
+ ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
+
+ sal_Int32 nPos = 0;
+ for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
+ pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ ppTypes[nPos++] = new ExceptionType( (typelib_TypeDescription *)pCompTypeDescr );
+ }
+}
+
+RaiseInfo::~RaiseInfo() throw ()
+{
+ ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
+ for ( sal_Int32 nTypes = *(sal_Int32 *)_types; nTypes--; )
+ {
+ delete ppTypes[nTypes];
+ }
+ std::free( _types );
+
+ delete _pDtor;
+}
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_intel/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_intel/uno2cpp.cxx
new file mode 100644
index 0000000000..570495294e
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_intel/uno2cpp.cxx
@@ -0,0 +1,460 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include <msvc/except.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+inline void callVirtualMethod(
+ void * pAdjustedThisPtr, sal_Int32 nVtableIndex,
+ void * pRegisterReturn, typelib_TypeClass eReturnTypeClass,
+ sal_Int32 * pStackLongs, sal_Int32 nStackLongs )
+{
+ // parameter list is mixed list of * and values
+ // reference parameters are pointers
+
+ assert(pStackLongs && pAdjustedThisPtr);
+ static_assert( (sizeof(void *) == 4) &&
+ (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
+
+__asm
+ {
+ mov eax, nStackLongs
+ test eax, eax
+ je Lcall
+ // copy values
+ mov ecx, eax
+ shl eax, 2 // sizeof(sal_Int32) == 4
+ add eax, pStackLongs // params stack space
+Lcopy: sub eax, 4
+ push dword ptr [eax]
+ dec ecx
+ jne Lcopy
+Lcall:
+ // call
+ mov ecx, pAdjustedThisPtr
+ push ecx // this ptr
+ mov edx, [ecx] // pvft
+ mov eax, nVtableIndex
+ shl eax, 2 // sizeof(void *) == 4
+ add edx, eax
+ call [edx] // interface method call must be __cdecl!!!
+
+ // register return
+ mov ecx, eReturnTypeClass
+ cmp ecx, typelib_TypeClass_VOID
+ je Lcleanup
+ mov ebx, pRegisterReturn
+// int32
+ cmp ecx, typelib_TypeClass_LONG
+ je Lint32
+ cmp ecx, typelib_TypeClass_UNSIGNED_LONG
+ je Lint32
+ cmp ecx, typelib_TypeClass_ENUM
+ je Lint32
+// int8
+ cmp ecx, typelib_TypeClass_BOOLEAN
+ je Lint8
+ cmp ecx, typelib_TypeClass_BYTE
+ je Lint8
+// int16
+ cmp ecx, typelib_TypeClass_CHAR
+ je Lint16
+ cmp ecx, typelib_TypeClass_SHORT
+ je Lint16
+ cmp ecx, typelib_TypeClass_UNSIGNED_SHORT
+ je Lint16
+// float
+ cmp ecx, typelib_TypeClass_FLOAT
+ je Lfloat
+// double
+ cmp ecx, typelib_TypeClass_DOUBLE
+ je Ldouble
+// int64
+ cmp ecx, typelib_TypeClass_HYPER
+ je Lint64
+ cmp ecx, typelib_TypeClass_UNSIGNED_HYPER
+ je Lint64
+ jmp Lcleanup // no simple type
+Lint8:
+ mov byte ptr [ebx], al
+ jmp Lcleanup
+Lint16:
+ mov word ptr [ebx], ax
+ jmp Lcleanup
+Lfloat:
+ fstp dword ptr [ebx]
+ jmp Lcleanup
+Ldouble:
+ fstp qword ptr [ebx]
+ jmp Lcleanup
+Lint64:
+ mov dword ptr [ebx], eax
+ mov dword ptr [ebx+4], edx
+ jmp Lcleanup
+Lint32:
+ mov dword ptr [ebx], eax
+ jmp Lcleanup
+Lcleanup:
+ // cleanup stack (obsolete though because of function)
+ mov eax, nStackLongs
+ shl eax, 2 // sizeof(sal_Int32) == 4
+ add eax, 4 // this ptr
+ add esp, eax
+ }
+}
+
+void cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams,
+ typelib_MethodParameter * pParams,
+ void * pUnoReturn,
+ void * pUnoArgs[],
+ uno_Any ** ppUnoExc ) throw ()
+{
+ // max space for: [complex ret ptr], values|ptr ...
+ char * pCppStack = (char *)alloca( sizeof(sal_Int32) + (nParams * sizeof(sal_Int64)) );
+ char * pCppStackStart = pCppStack;
+
+ // return type
+ typelib_TypeDescription * pReturnTD = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
+ assert(pReturnTD);
+
+ void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion
+
+ if (pReturnTD)
+ {
+ if (bridges::cpp_uno::shared::isSimpleType( pReturnTD ))
+ {
+ pCppReturn = pUnoReturn; // direct way for simple types
+ }
+ else
+ {
+ // complex return via ptr
+ pCppReturn = *(void **)pCppStack
+ = (bridges::cpp_uno::shared::relatesToInterfaceType(
+ pReturnTD )
+ ? alloca( pReturnTD->nSize )
+ : pUnoReturn); // direct way
+ pCppStack += sizeof(void *);
+ }
+ }
+
+ // stack space
+
+ static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
+ // args
+ void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+ // indices of values this have to be converted (interface conversion cpp<=>uno)
+ sal_Int32 * pTempIndexes = (sal_Int32 *)(pCppArgs + nParams);
+ // type descriptions for reconversions
+ typelib_TypeDescription ** pTempParamTD = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+ sal_Int32 nTempIndexes = 0;
+
+ for (int nPos = 0; nPos < nParams; ++nPos)
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTD = nullptr;
+ TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
+ {
+ ::uno_copyAndConvertData(
+ pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ switch (pParamTD->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_DOUBLE:
+ pCppStack += sizeof(sal_Int32); // extra long
+ break;
+ default:
+ break;
+ }
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ else // ptr to complex value | ref
+ {
+ if (! rParam.bIn) // is pure out
+ {
+ // C++ out is constructed mem, UNO out is not!
+ ::uno_constructData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTD->nSize ),
+ pParamTD );
+
+ // default constructed for C++ call
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTD))
+ {
+ ::uno_copyAndConvertData(
+ *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTD->nSize ),
+ pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ // has to be reconverted
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ else // direct way
+ {
+ *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ }
+ pCppStack += sizeof(sal_Int32); // standard parameter length
+ }
+
+ __try
+ {
+ // pCppI is msci this pointer
+ callVirtualMethod(
+ reinterpret_cast< void ** >(pThis->getCppI()) + aVtableSlot.offset,
+ aVtableSlot.index,
+ pCppReturn, pReturnTD->eTypeClass,
+ (sal_Int32 *)pCppStackStart,
+ (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
+ }
+ __except (msvc_filterCppException(
+ GetExceptionInformation(),
+ *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
+ {
+ // *ppUnoExc was constructed by filter function
+ // temporary params
+ while (nTempIndexes--)
+ {
+ sal_Int32 nIndex = pTempIndexes[nTempIndexes];
+ // destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ pCppArgs[nIndex], pTempParamTD[nTempIndexes],
+ uno::cpp_release );
+ TYPELIB_DANGER_RELEASE( pTempParamTD[nTempIndexes] );
+ }
+
+ // return type
+ if (pReturnTD)
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return;
+ }
+
+ // NO exception occurred
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ while (nTempIndexes--)
+ {
+ int nIndex = pTempIndexes[nTempIndexes];
+ typelib_TypeDescription * pParamTD =
+ pTempParamTD[nTempIndexes];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ ::uno_destructData(
+ pUnoArgs[nIndex], pParamTD, nullptr ); // destroy UNO value
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], pCppArgs[nIndex], pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], pCppArgs[nIndex], pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+
+ // destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ pCppArgs[nIndex], pParamTD, uno::cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+
+ // return value
+ if (pCppReturn && pUnoReturn != pCppReturn)
+ {
+ ::uno_copyAndConvertData(
+ pUnoReturn, pCppReturn, pReturnTD,
+ pThis->getBridge()->getCpp2Uno() );
+ ::uno_destructData(
+ pCppReturn, pReturnTD, uno::cpp_release );
+ }
+
+ // return type
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+}
+
+} // namespace
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI,
+ const typelib_TypeDescription * pMemberTD,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+
+ switch (pMemberTD->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberTD)));
+ if ( pReturn )
+ {
+ // is GET
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef;
+ aParam.bIn = sal_True;
+ aParam.bOut = sal_False;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberTD)));
+
+ switch (aVtableSlot.index)
+ {
+ case 1: // acquire UNO interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release UNO interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< uno::Type * >( pArgs[0] )->getTypeLibType() );
+
+ if ( pTD )
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if ( pInterface )
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ typelib_InterfaceMethodTypeDescription const* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD);
+
+ cpp_call(pThis, aVtableSlot, pMethodTD->pReturnTypeRef, pMethodTD->nParams, pMethodTD->pParams,
+ pReturn, pArgs, ppException);
+ }
+ break;
+ }
+ default:
+ {
+ uno::RuntimeException aExc("Illegal member type description!", uno::Reference<uno::XInterface>());
+
+ uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
new file mode 100644
index 0000000000..fc12d6873a
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
@@ -0,0 +1,112 @@
+; -*- Mode: text; tab-width: 8; indent-tabs-mode: nil comment-column: 44; comment-start: ";; " comment-start-skip: ";; *" -*-
+
+;;
+;; 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/.
+;;
+
+;; This is the function jumped to from the trampoline generated by
+;; codeSnippet() in cpp2uno.cxx. Here we call cpp_vtable_call() which
+;; then calls the actual UNO function.
+
+;; The code snippet generated is called from "normal" C++ code which
+;; has no idea that it is calling dynamically generated code.
+
+;; The generated short code snippet is not covered by any function
+;; table and unwind info, but that doesn't matter, as the instructions
+;; in it are not really going to cause any exception. Once it jumps
+;; here it is covered by a function table, and the calls further down
+;; through cpp_vtable_call() can be unwound cleanly.
+
+;; This is in a separate file for x86-64 as MSVC doesn't have in-line
+;; assembly for x64.
+
+;; Random web links and other documentation about low-level
+;; implementation details for the C++/UNO bridge on x64 Windows kept
+;; here:
+
+;; Caolan's "Lazy Hackers Guide To Porting" is useful:
+;; http://wiki.openoffice.org/wiki/Lazy_Hackers_Guide_To_Porting
+
+;; As for details about the x64 Windows calling convention, register
+;; usage, stack usage, exception handling etc, the official
+;; documentation (?) on MSDN is a bit fragmented and split up into a
+;; needlessly large number of short pages. But still:
+;; http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=VS.90%29.aspx
+
+;; Also see Raymond Chen's blog post:
+;; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/14/58579.aspx
+
+;; This one is actually more readable: "Improving Automated Analysis
+;; of Windows x64 Binaries": http://www.uninformed.org/?v=4&a=1
+
+;; This one has a mass of information about different architectures
+;; and compilers, and contains some details about the x64 Windows
+;; calling convention in particular that Microsoft doesn't mention
+;; above:
+;; http://www.agner.org/optimize/calling_conventions.pdf
+
+;; Random interesting discussion threads:
+;; http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/300bd6d3-9381-4d2d-8129-e48b392c05d8
+
+;; Ken Johnson's blog http://www.nynaeve.net/ has much interesting
+;; information, for instance:
+;; http://www.nynaeve.net/?p=11
+
+typelib_TypeClass_FLOAT equ 10
+typelib_TypeClass_DOUBLE equ 11
+
+extern cpp_vtable_call: proc
+
+.code
+
+privateSnippetExecutor proc frame
+
+ ;; Make stack frame. Re-align RSP at 16 bytes. We need just one
+ ;; qword of stack for our own purposes: Where cpp_vtable_call()
+ ;; will store the return value of the UNO callee. But we of course
+ ;; must also allocate space for the functions we call (i.e., just
+ ;; cpp_vtable_call()) to spill their register parameters.
+
+ sub rsp, 40
+ .allocstack (40)
+ .endprolog
+
+ ;; Call cpp_vtable_call() with 2 parameters:
+
+ ;; 1 (rcx): nOffsetAndIndex (already put there in code generated by codeSnippet)
+ ;; 2 (rdx): pointer to where to store return value, followed by our
+ ;; return address (uninteresting to cpp_vtable_call()), followed
+ ;; by our spilled register parameters, as stored above, followed
+ ;; by the rest of our parameters, if any.
+
+ lea rdx, 32[rsp]
+
+ call cpp_vtable_call
+
+ ;; cpp_vtable_call() returns the typelib_TypeClass type of the
+ ;; return value of the called UNO function
+
+ cmp rax, typelib_TypeClass_FLOAT
+ je Lfloat
+
+ cmp rax, typelib_TypeClass_DOUBLE
+ je Lfloat
+
+ mov rax, qword ptr 32[rsp]
+ jmp Lepilogue
+
+Lfloat:
+ movsd xmm0, qword ptr 32[rsp]
+
+Lepilogue:
+ add rsp, 40
+ ret
+privateSnippetExecutor endp
+
+end
+
+; vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx b/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx
new file mode 100644
index 0000000000..393f8fcb45
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.hxx
@@ -0,0 +1,29 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+
+extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void** pStack);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
new file mode 100644
index 0000000000..974a4a94d4
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <limits>
+#include <typeinfo>
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/log.hxx>
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "call.hxx"
+#include <msvc/cpp2uno.hxx>
+#include <msvc/amd64.hxx>
+
+extern "C" IMAGE_DOS_HEADER const __ImageBase;
+
+using namespace ::com::sun::star;
+
+extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void ** pCallStack)
+{
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+ sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF);
+ return cpp_mediate(pCallStack, nFunctionIndex, nVtableOffset, nullptr);
+}
+
+int const codeSnippetSize = 48;
+
+namespace {
+
+typedef enum { REGPARAM_INT, REGPARAM_FLT } RegParamKind;
+
+}
+
+extern "C" char privateSnippetExecutor;
+
+// This function generates the code that acts as a proxy for the UNO function to be called.
+// The generated code does the following:
+// - Spills register parameters on stack
+// - Loads functionIndex and vtableOffset into scratch registers
+// - Jumps to privateSnippetExecutor
+
+static unsigned char * codeSnippet(
+ unsigned char * code,
+ RegParamKind param_kind[4],
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset )
+{
+ sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>(nVtableOffset) << 32 ) | static_cast<sal_uInt64>(nFunctionIndex);
+ unsigned char *p = code;
+
+ // Spill parameters
+ if (param_kind[0] == REGPARAM_INT)
+ {
+ // mov qword ptr 8[rsp], rcx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x08;
+ }
+ else
+ {
+ // movsd qword ptr 8[rsp], xmm0
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08;
+ }
+ if ( param_kind[1] == REGPARAM_INT )
+ {
+ // mov qword ptr 16[rsp], rdx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
+ }
+ else
+ {
+ // movsd qword ptr 16[rsp], xmm1
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x10;
+ }
+ if ( param_kind[2] == REGPARAM_INT )
+ {
+ // mov qword ptr 24[rsp], r8
+ *p++ = 0x4C; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18;
+ }
+ else
+ {
+ // movsd qword ptr 24[rsp], xmm2
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
+ }
+ if ( param_kind[3] == REGPARAM_INT )
+ {
+ // mov qword ptr 32[rsp], r9
+ *p++ = 0x4C;*p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x20;
+ }
+ else
+ {
+ // movsd qword ptr 32[rsp], xmm3
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x5C; *p++ = 0x24; *p++ = 0x20;
+ }
+
+ // mov rcx, nOffsetAndIndex
+ *p++ = 0x48; *p++ = 0xB9;
+ *reinterpret_cast<sal_uInt64 *>(p) = nOffsetAndIndex; p += 8;
+
+ // mov r11, privateSnippetExecutor
+ *p++ = 0x49; *p++ = 0xBB;
+ *reinterpret_cast<void **>(p) = &privateSnippetExecutor; p += 8;
+
+ // jmp r11
+ *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
+
+ assert(p < code + codeSnippetSize);
+
+ return code + codeSnippetSize;
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(
+ void * block )
+{
+ return static_cast< Slot * >(block) + 1;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+static sal_uInt32 imageRelative(void const * p) {
+ assert(
+ reinterpret_cast<sal_uIntPtr>(p) >= reinterpret_cast<sal_uIntPtr>(&__ImageBase)
+ && reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase)
+ <= std::numeric_limits<sal_uInt32>::max());
+ return reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase);
+}
+
+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 {};
+
+// The following vtable RTTI data is based on how the code at
+// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
+// such data, and on how <https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483>
+// "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase:
+
+struct RttiClassHierarchyDescriptor;
+
+#pragma warning (push)
+#pragma warning (disable: 4324) // "structure was padded due to alignment specifier"
+
+struct alignas(16) RttiBaseClassDescriptor {
+ sal_uInt32 n0 = imageRelative(&typeid(ProxyRtti));
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = 0xFFFFFFFF;
+ sal_uInt32 n4 = 0;
+ sal_uInt32 n5 = 0x40;
+ sal_uInt32 n6;
+ RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd): n6(imageRelative(chd)) {}
+};
+
+struct alignas(4) RttiBaseClassArray {
+ sal_uInt32 n0;
+ sal_uInt32 n1 = 0;
+ RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(imageRelative(bcd)) {}
+};
+
+struct alignas(8) RttiClassHierarchyDescriptor {
+ sal_uInt32 n0 = 0;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 1;
+ sal_uInt32 n3;
+ RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca): n3(imageRelative(bca)) {}
+};
+
+struct alignas(16) RttiCompleteObjectLocator {
+ sal_uInt32 n0 = 1;
+ sal_uInt32 n1 = 0;
+ sal_uInt32 n2 = 0;
+ sal_uInt32 n3 = imageRelative(&typeid(ProxyRtti));
+ sal_uInt32 n4;
+ sal_uInt32 n5 = imageRelative(this);
+ RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd): n4(imageRelative(chd)) {}
+};
+
+struct Rtti {
+ RttiBaseClassDescriptor bcd;
+ RttiBaseClassArray bca;
+ RttiClassHierarchyDescriptor chd;
+ RttiCompleteObjectLocator col;
+ Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {}
+};
+
+#pragma warning (pop)
+
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block,
+ sal_Int32 slotCount,
+ sal_Int32, typelib_InterfaceTypeDescription *)
+{
+ static Rtti rtti;
+
+ Slot * slots = mapBlockToVtable(block);
+ slots[-1].fn = &rtti.col;
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots,
+ unsigned char * code,
+ typelib_InterfaceTypeDescription const * type,
+ sal_Int32 nFunctionOffset,
+ sal_Int32 functionCount,
+ sal_Int32 nVtableOffset )
+{
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+
+ for (int member = 0; member < type->nMembers; ++member) {
+ typelib_TypeDescription * pTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pTD, type->ppMembers[ member ] );
+ assert(pTD);
+
+ RegParamKind param_kind[4];
+ int nr = 0;
+
+ for (int i = 0; i < 4; ++i)
+ param_kind[i] = REGPARAM_INT;
+
+ // 'this'
+ ++nr;
+
+ if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
+ {
+ typelib_InterfaceAttributeTypeDescription * pIfaceAttrTD =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
+
+ // Getter
+
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+ if ( ! pIfaceAttrTD->bReadOnly )
+ {
+ typelib_TypeDescription * pAttrTD = nullptr;
+ TYPELIB_DANGER_GET( &pAttrTD, pIfaceAttrTD->pAttributeTypeRef );
+ assert(pAttrTD);
+
+ // Setter
+ if ( pAttrTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pAttrTD->eTypeClass == typelib_TypeClass_DOUBLE )
+ param_kind[nr++] = REGPARAM_FLT;
+
+ TYPELIB_DANGER_RELEASE( pAttrTD );
+
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+ }
+ }
+ else if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
+ {
+ typelib_InterfaceMethodTypeDescription * pMethodTD =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
+
+ typelib_TypeDescription * pReturnTD = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTD, pMethodTD->pReturnTypeRef );
+ assert(pReturnTD);
+
+ if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD ) )
+ {
+ // Return value
+ ++nr;
+ }
+
+ for (int param = 0; nr < 4 && param < pMethodTD->nParams; ++param, ++nr)
+ {
+ typelib_TypeDescription * pParamTD = nullptr;
+
+ TYPELIB_DANGER_GET( &pParamTD, pMethodTD->pParams[param].pTypeRef );
+ assert(pParamTD);
+
+ if ( pParamTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pParamTD->eTypeClass == typelib_TypeClass_DOUBLE )
+ param_kind[nr] = REGPARAM_FLT;
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ (s++)->fn = code;
+ code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
+
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+ }
+ else
+ assert(false);
+
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const *,
+ unsigned char const *)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
new file mode 100644
index 0000000000..e5836dd11d
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
@@ -0,0 +1,465 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// Interesting info can be found in:
+
+// MSDN, obviously
+
+// http://www.osronline.com/article.cfm?article=469
+
+// ONTL, "Open NT Native Template Library", a C++ STL-like library
+// that can be used even when writing Windows drivers. This is some
+// quite badass code. The author has done impressive heavy spelunking
+// of MSVCR structures. http://code.google.com/p/ontl/
+
+// Geoff Chappell's pages:
+// http://www.geoffchappell.com/studies/msvc/language/index.htm
+
+// The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts:
+
+#if 0
+
+/* This information until the corresponding '#endif // 0' is covered
+ * by ONTL's license, which is said to be the "zlib/libpng license"
+ * below, which as far as I see is permissive enough to allow this
+ * information to be included here in this source file. Note that no
+ * actual code from ONTL below gets compiled into the object file.
+ */
+
+/*
+ * Copyright (c) 2011 <copyright holders> (The ONTL main
+ * developer(s) don't tell their real name(s) on the ONTL site.)
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ */
+
+typedef uint32_t rva_t;
+
+///\note the calling convention should not matter since this has no arguments
+typedef void generic_function_t();
+
+struct ptrtomember // _PMD
+{
+ typedef __w64 int32_t mdiff_t;
+ mdiff_t member_offset;
+ mdiff_t vbtable_offset; // -1 if not a virtual base
+ mdiff_t vdisp_offset; // offset to the displacement value inside the vbtable
+
+ template<typename T>
+ T * operator()(T * const thisptr) const
+ {
+ uintptr_t tp = reinterpret_cast<uintptr_t>(thisptr);
+ uintptr_t ptr = tp + member_offset;
+ if ( vbtable_offset != -1 ) // !(vbtable_offset < 0)
+ {
+ ptr += *reinterpret_cast<mdiff_t*>( static_cast<intptr_t>(vdisp_offset + *reinterpret_cast<mdiff_t*>(tp + vbtable_offset)) )
+ + vbtable_offset;
+ }
+ return reinterpret_cast<T*>(ptr);
+ }
+};
+
+struct eobject
+{
+ typedef void (* dtor_ptr )(eobject*);
+ typedef void (* ctor_ptr )(eobject*, eobject*);
+ typedef void (* ctor_ptr2)(eobject*, eobject*, int);
+};
+
+struct catchabletype
+{
+ /** is simple type */
+ uint32_t memmoveable : 1;
+ /** catchable as reference only */
+ uint32_t refonly : 1;
+ /** class with virtual base */
+ uint32_t hasvirtbase : 1;
+ /** offset to the type descriptor */
+ rva_t typeinfo;
+
+ /** catch type instance location within a thrown object */
+ ptrtomember thiscast;
+ /** size of the simple type or offset into buffer of \c this pointer for catch object */
+ uint32_t object_size;
+
+ union
+ {
+ rva_t copyctor;
+ rva_t copyctor2;
+ };
+};
+
+#pragma pack(push, 4)
+struct catchabletypearray
+{
+ uint32_t size;
+ rva_t type[1];
+};
+#pragma pack(pop)
+
+#pragma pack(push, 4)
+struct throwinfo
+{
+ typedef exception_disposition __cdecl forwardcompathandler_t(...);
+
+ /* 0x00 */ uint32_t econst : 1;
+ /* 0x00 */ uint32_t evolatile : 1;
+ /* 0x00 */ uint32_t : 1;
+ /* 0x00 */ uint32_t e8 : 1;
+ /* 0x04 */ rva_t exception_dtor;
+ /* 0x08 */ rva_t forwardcompathandler;
+ /* 0x0C */ rva_t catchabletypearray; ///< types able to catch the exception.
+};
+#pragma pack(pop)
+
+/// This type represents the catch clause
+struct ehandler
+{
+ // union { uint32_t adjectives; void * ptr; };
+ uint32_t isconst : 1;
+ uint32_t isvolatile : 1;
+ uint32_t isunaligned : 1;// guess it is not used on x86
+ uint32_t isreference : 1;
+
+ uint32_t :27;
+ uint32_t ishz : 1;
+
+ /** offset to the type descriptor of this catch object */
+ /*0x04*/ rva_t typeinfo; // dispType
+ /*0x08*/ int eobject_bpoffset; // dispCatchObj
+ /** offset to the catch clause funclet */
+ /*0x0C*/ rva_t handler; // dispOfHandler
+ /*0x10*/ uint32_t frame; // dispFrame
+}
+
+// ___BuildCatchObject
+/// 15.3/16 When the exception-declaration specifies a class type, a copy
+/// constructor is used to initialize either the object declared
+/// in the exception-declaration or,
+/// if the exception-declaration does not specify a name,
+/// a temporary object of that type.
+///\note This is the question may we optimize out the last case.
+///\warning If the copy constructor throws an exception, std::unexpected would be called
+void
+ constructcatchobject(
+ cxxregistration * cxxreg,
+ const ehandler * const catchblock,
+ catchabletype * const convertible,
+ const dispatcher_context* const dispatch
+ )
+ const
+{
+ _EH_TRACE_ENTER();
+ // build helper
+ __try {
+ struct typeinfo_t { void* vtbl; void* spare; char name[1]; };
+ enum catchable_info { cidefault, cicomplex, civirtual } cinfo = cidefault;
+
+ const typeinfo_t* ti = catchblock->typeinfo ? dispatch->va<typeinfo_t*>(catchblock->typeinfo) : NULL;
+ if(ti && *ti->name && (catchblock->eobject_bpoffset || catchblock->ishz)){
+ eobject** objplace = catchblock->ishz
+ ? reinterpret_cast<eobject**>(cxxreg)
+ : reinterpret_cast<eobject**>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers);
+ if(catchblock->isreference){
+ // just ref/pointer
+ *objplace = adjust_pointer(get_object(), convertible);
+ }else if(convertible->memmoveable){
+ // POD
+ std::memcpy(objplace, get_object(), convertible->object_size);
+ if(convertible->object_size == sizeof(void*) && *objplace)
+ *objplace = adjust_pointer((void*)*objplace, convertible);
+ }else{
+ // if copy ctor exists, call it; binary copy otherwise
+ if(convertible->copyctor){
+ cinfo = convertible->hasvirtbase ? civirtual : cicomplex;
+ }else{
+ std::memcpy(objplace, (const void*)adjust_pointer(get_object(), convertible), convertible->object_size);
+ }
+ }
+ }
+ // end of build helper
+ if(cinfo != cidefault){
+ eobject* objthis = catchblock->ishz
+ ? reinterpret_cast<eobject*>(cxxreg)
+ : reinterpret_cast<eobject*>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers);
+ void* copyctor = thrown_va(convertible->copyctor);
+ eobject* copyarg = adjust_pointer(get_object(), convertible);
+ if(cinfo == cicomplex)
+ (eobject::ctor_ptr (copyctor))(objthis, copyarg);
+ else
+ (eobject::ctor_ptr2(copyctor))(objthis, copyarg, 1);
+ }
+ }
+ __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus>(_exception_code())))
+ {
+ nt::exception::inconsistency();
+ }
+ _EH_TRACE_LEAVE();
+}
+
+#endif // 0
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <malloc.h>
+#include <new.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <msvc/amd64.hxx>
+#include <except.hxx>
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star;
+
+static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
+ typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
+ return pExcThis;
+}
+
+static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
+{
+ ::uno_destructData(pExcThis, pTD, uno::cpp_release);
+ return pExcThis;
+}
+
+const int codeSnippetSize = 40;
+
+static void GenerateConstructorTrampoline(unsigned char* code,
+ typelib_TypeDescription* pTD) noexcept
+{
+ unsigned char* p = code;
+
+ // mov r8, pTD
+ *p++ = 0x49;
+ *p++ = 0xB8;
+ *reinterpret_cast<void**>(p) = pTD;
+ p += 8;
+
+ // mov r11, copyConstruct
+ *p++ = 0x49;
+ *p++ = 0xBB;
+ *reinterpret_cast<void**>(p) = reinterpret_cast<void*>(&copyConstruct);
+ p += 8;
+
+ // jmp r11
+ *p++ = 0x41;
+ *p++ = 0xFF;
+ *p++ = 0xE3;
+
+ assert(p < code + codeSnippetSize);
+}
+
+static void GenerateDestructorTrampoline(unsigned char* code, typelib_TypeDescription* pTD) noexcept
+{
+ unsigned char* p = code;
+
+ // mov rdx, pTD
+ *p++ = 0x48;
+ *p++ = 0xBA;
+ *reinterpret_cast<void**>(p) = pTD;
+ p += 8;
+
+ // mov r11, destruct
+ *p++ = 0x49;
+ *p++ = 0xBB;
+ *reinterpret_cast<void**>(p) = reinterpret_cast<void*>(&destruct);
+ p += 8;
+
+ // jmp r11
+ *p++ = 0x41;
+ *p++ = 0xFF;
+ *p++ = 0xE3;
+
+ assert(p < code + codeSnippetSize);
+}
+
+ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+ typelib_TypeDescription* pTD) noexcept
+ : _n0(0)
+ , _n1(0)
+ , _n2(-1)
+ , _n3(0)
+ , _n4(pTD->nSize)
+ , exc_type_info(nullptr, "")
+{
+ // As _n0 is always initialized to zero, that means the
+ // hasvirtbase flag (see the ONTL catchabletype struct) is
+ // off, and thus the copyctor is of the ctor_ptr kind.
+
+ int len;
+ type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);
+
+ memcpy(static_cast<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
+ _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_type_info) - pCodeBase);
+ GenerateConstructorTrampoline(pCode, pTD);
+
+ assert(pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
+ && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase < 0x100000000));
+ _pCopyCtor = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
+}
+
+/* Rewrite of 32-Bit-Code to work under 64 Bit:
+* To use the 32 Bit offset values in the ExceptionType we have to
+* allocate a single allocation block and use it for all code and date
+* all offsets inside this area are guaranteed to be in 32 bit address range.
+* So we have to calc total memory allocation size for D-tor, C-Tors,
+* ExceptionType and type_info. ExceptionType is allocated via placement new
+* to locate everything inside our mem block.
+* There is one caveat: Struct type_info is kept in
+* a map and was referenced from class ExceptionType. Therefore type_info now
+* is also member of ExceptionType and can be referenced via 32 bit offset.
+*/
+
+RaiseInfo::RaiseInfo(typelib_TypeDescription* pTD) noexcept
+ : _n0(0)
+ , _n2(0)
+ , _pTD(pTD)
+{
+ typelib_CompoundTypeDescription* pCompTD;
+
+ // Count how many trampolines we need
+ int codeSize = codeSnippetSize;
+
+ // Info count
+ int nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ ++nLen;
+ codeSize += codeSnippetSize;
+ }
+
+ // Array with size (4) and all _pTypeInfo (4*nLen)
+ int typeInfoArraySize = 4 + 4 * nLen;
+
+ // 2.Pass: Get the total needed memory for class ExceptionType
+ // (with embedded type_info) and keep the sizes for each instance
+ // is stored in allocated int array
+ auto exceptionTypeSizeArray = std::make_unique<int[]>(nLen);
+
+ nLen = 0;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ int typeInfoLen;
+ RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
+ // Mem has to be on 4-byte Boundary
+ if (typeInfoLen % 4 != 0)
+ {
+ int n = typeInfoLen / 4;
+ n++;
+ typeInfoLen = n * 4;
+ }
+ exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
+ }
+
+ // Total ExceptionType related mem
+ int excTypeAddLen = 0;
+ for (int i = 0; i < nLen; i++)
+ {
+ excTypeAddLen += exceptionTypeSizeArray[i];
+ }
+
+ // Allocate mem for code and all dynamic data in one chunk to guarantee
+ // 32 bit offsets
+ const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
+ unsigned char* pCode = _code = static_cast<unsigned char*>(std::malloc(totalSize));
+ int pCodeOffset = 0;
+
+ // New base of types array, starts after Trampoline D-Tor / C-Tors
+ DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);
+
+ // New base of ExceptionType array, starts after types array
+ unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
+ int etMemOffset = 0;
+
+ _codeBase = reinterpret_cast<sal_uInt64>(pCode)
+ & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
+
+ DWORD old_protect;
+ bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
+ (void)success;
+ assert(success && "VirtualProtect() failed!");
+
+ ::typelib_typedescription_acquire(pTD);
+
+ // Fill pCode with D-Tor code
+ GenerateDestructorTrampoline(pCode, pTD);
+ _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
+ pCodeOffset += codeSnippetSize;
+
+ // Info count accompanied by type info ptrs: type, base type, base base type, ...
+ // Keep offset of types_array
+ _types = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
+ // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
+ types[0] = nLen;
+
+ int nPos = 1;
+ for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+ pCompTD = pCompTD->pBaseTypeDescription)
+ {
+ // Create instance in mem block with placement new
+ ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
+ pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(pCompTD));
+
+ // Next trampoline entry offset
+ pCodeOffset += codeSnippetSize;
+ // Next ExceptionType placement offset
+ etMemOffset += exceptionTypeSizeArray[nPos - 1];
+
+ // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
+ types[nPos++] = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et) - _codeBase);
+ }
+ // Final check: end of address calculation must be end of mem
+ assert(etMem + etMemOffset == pCode + totalSize);
+}
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
new file mode 100644
index 0000000000..d5df4a161e
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx
@@ -0,0 +1,454 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <malloc.h>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include <uno/data.h>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+
+#include <msvc/except.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+bool cpp_call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+ bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ sal_Int32 nParams,
+ typelib_MethodParameter * pParams,
+ void * pUnoReturn,
+ void * pUnoArgs[],
+ uno_Any ** ppUnoExc ) noexcept
+{
+ const int MAXPARAMS = 32;
+
+ if ( nParams > MAXPARAMS )
+ {
+ // We have a hard limit on the number of parameters so that we
+ // don't need any assembler code here but can call the
+ // function using normal C++.
+
+ return false;
+ }
+
+ // Table with this pointer, optional complex return value ptr, and the parameters
+ union {
+ sal_Int64 i;
+ void *p;
+ double d;
+ } aCppArgs[MAXPARAMS+2], uRetVal;
+ int nCppParamIndex = 0;
+
+ // return type
+ typelib_TypeDescription * pReturnTD = nullptr;
+ TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
+ assert(pReturnTD);
+
+ // 'this'
+ void * pAdjustedThisPtr = reinterpret_cast<void **>( pThis->getCppI() ) + aVtableSlot.offset;
+ aCppArgs[nCppParamIndex++].p = pAdjustedThisPtr;
+
+ enum class ReturnKind { Void, Simple, Complex, ComplexConvert };
+ ReturnKind retKind;
+ if (pUnoReturn == nullptr) {
+ retKind = ReturnKind::Void;
+ } else {
+ assert(pReturnTD != nullptr);
+ if (bridges::cpp_uno::shared::isSimpleType(pReturnTD)) {
+ retKind = ReturnKind::Simple;
+ } else if (bridges::cpp_uno::shared::relatesToInterfaceType(pReturnTD))
+ {
+ retKind = ReturnKind::ComplexConvert;
+ aCppArgs[nCppParamIndex++].p = alloca(pReturnTD->nSize);
+ } else {
+ retKind = ReturnKind::Complex;
+ aCppArgs[nCppParamIndex++].p = pUnoReturn;
+ }
+ }
+
+ // indexes of values this have to be converted (interface conversion C++<=>UNO)
+ int pTempCppIndexes[MAXPARAMS];
+ int pTempIndexes[MAXPARAMS];
+ int nTempIndexes = 0;
+
+ // type descriptions for reconversions
+ typelib_TypeDescription *pTempParamTD[MAXPARAMS];
+
+ for (int nPos = 0; nPos < nParams; ++nPos, ++nCppParamIndex)
+ {
+ const typelib_MethodParameter & rParam = pParams[nPos];
+ typelib_TypeDescription * pParamTD = nullptr;
+ TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
+
+ if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
+ {
+ ::uno_copyAndConvertData(
+ &aCppArgs[nCppParamIndex], pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ else // ptr to complex value | ref
+ {
+ if (!rParam.bIn) // Is pure out
+ {
+ // C++ out is constructed mem, UNO out is not!
+ ::uno_constructData(
+ aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pParamTD );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+
+ // default constructed for C++ call
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ // is in/inout
+ else if (bridges::cpp_uno::shared::relatesToInterfaceType(pParamTD))
+ {
+ ::uno_copyAndConvertData(
+ aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
+ pUnoArgs[nPos], pParamTD,
+ pThis->getBridge()->getUno2Cpp() );
+
+ pTempCppIndexes[nTempIndexes] = nCppParamIndex;
+
+ // has to be reconverted
+ pTempIndexes[nTempIndexes] = nPos;
+
+ // will be released at reconversion
+ pTempParamTD[nTempIndexes++] = pParamTD;
+ }
+ else // direct way
+ {
+ aCppArgs[nCppParamIndex].p = pUnoArgs[nPos];
+ // no longer needed
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+ }
+ }
+
+ __try
+ {
+ // The first real parameter is always 'this'.
+
+ // The Windows x64 calling convention is very regular and
+ // elegant (even if perhaps then slightly slower than the
+ // Linux x64 one): The first four parameters, never more, are
+ // passed in registers, as long as they are a qword in size
+ // or less. (If larger, a pointer to a temp copy is passed, so
+ // it's equivalent anyway.) Floating point values are passed
+ // in XMM0..3 registers, others in RCX, RDX, R8, R9.
+
+ // Now, the nice thing for us is that when calling varargs
+ // functions, floating-point parameters among the four first
+ // ones are always passed *both* in an XMM and integer
+ // register. So we don't need to bother here calling the
+ // method different ways depending on what types of parameters
+ // it actually expects. We just pretend parameters 3..4 are
+ // doubles, and they will be passed both in XMM and integer
+ // registers, and the callee will find them where it
+ // expects. (The callee is not actually varargs, of course.)
+
+ sal_Int64 (*pIMethod)(sal_Int64, ...) =
+ reinterpret_cast<sal_Int64 (*)(sal_Int64, ...)>(
+ (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
+
+ double (*pFMethod)(sal_Int64, ...) =
+ reinterpret_cast<double (*)(sal_Int64, ...)>(
+ (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
+
+ // Pass parameters 2..4 as if it was a floating-point value so
+ // that it gets put in both XMM and integer registers per the
+ // calling convention. It doesn't matter if it actually is a
+ // fp or not.
+
+ if ( pReturnTD &&
+ (pReturnTD->eTypeClass == typelib_TypeClass_FLOAT ||
+ pReturnTD->eTypeClass == typelib_TypeClass_DOUBLE) )
+ uRetVal.d =
+ pFMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
+ aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
+ aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
+ aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
+ aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
+ aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
+ aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
+ aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
+ else
+ uRetVal.i =
+ pIMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
+ aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
+ aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
+ aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
+ aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
+ aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
+ aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
+ aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
+ }
+ __except (msvc_filterCppException(
+ GetExceptionInformation(),
+ *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
+ {
+ // *ppUnoExc was constructed by filter function
+ // temporary params
+ while (nTempIndexes--)
+ {
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ // destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ aCppArgs[nCppIndex].p, pTempParamTD[nTempIndexes],
+ uno::cpp_release );
+ TYPELIB_DANGER_RELEASE( pTempParamTD[nTempIndexes] );
+ }
+
+ // return type
+ if (pReturnTD)
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return true;
+ }
+
+ // NO exception occurred
+ *ppUnoExc = nullptr;
+
+ // reconvert temporary params
+ while (nTempIndexes--)
+ {
+ int nCppIndex = pTempCppIndexes[nTempIndexes];
+ int nIndex = pTempIndexes[nTempIndexes];
+ typelib_TypeDescription * pParamTD =
+ pTempParamTD[nTempIndexes];
+
+ if (pParams[nIndex].bIn)
+ {
+ if (pParams[nIndex].bOut) // inout
+ {
+ ::uno_destructData(
+ pUnoArgs[nIndex], pParamTD, nullptr ); // destroy UNO value
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+ }
+ else // pure out
+ {
+ ::uno_copyAndConvertData(
+ pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
+ pThis->getBridge()->getCpp2Uno() );
+ }
+
+ // destroy temp C++ param => C++: every param was constructed
+ ::uno_destructData(
+ aCppArgs[nCppIndex].p, pParamTD, uno::cpp_release );
+
+ TYPELIB_DANGER_RELEASE( pParamTD );
+ }
+
+ // return value
+ switch (retKind) {
+ case ReturnKind::Void:
+ break;
+ case ReturnKind::Simple:
+ *static_cast<sal_Int64*>(pUnoReturn) = uRetVal.i;
+ break;
+ case ReturnKind::Complex:
+ assert(uRetVal.p == pUnoReturn);
+ break;
+ case ReturnKind::ComplexConvert:
+ assert(uRetVal.p == aCppArgs[1].p);
+ ::uno_copyAndConvertData(
+ pUnoReturn, uRetVal.p, pReturnTD,
+ pThis->getBridge()->getCpp2Uno() );
+ ::uno_destructData(
+ uRetVal.p, pReturnTD, uno::cpp_release );
+ break;
+ }
+
+ // return type
+ if ( pReturnTD )
+ TYPELIB_DANGER_RELEASE( pReturnTD );
+
+ return true;
+}
+
+} // namespace
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI,
+ const typelib_TypeDescription * pMemberTD,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException )
+{
+ // is my surrogate
+ bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+ = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+ typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+ switch (pMemberTD->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ pMemberTD)));
+ if ( pReturn )
+ {
+ // is GET
+ cpp_call(
+ pThis, aVtableSlot,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef,
+ 0, nullptr, // no params
+ pReturn, pArgs, ppException );
+ }
+ else
+ {
+ // is SET
+ typelib_MethodParameter aParam;
+ aParam.pTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef;
+ aParam.bIn = true;
+ aParam.bOut = false;
+
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ OUString aVoidName("void");
+ typelib_typedescriptionreference_new(
+ &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
+
+ aVtableSlot.index += 1; // get, then set method
+ cpp_call(
+ pThis, aVtableSlot,
+ pReturnTypeRef,
+ 1, &aParam,
+ pReturn, pArgs, ppException );
+
+ typelib_typedescriptionreference_release( pReturnTypeRef );
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // determine vtable call index
+ sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
+ assert(nMemberPos < pTypeDescr->nAllMembers);
+#endif
+ VtableSlot aVtableSlot(
+ getVtableSlot(
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ pMemberTD)));
+
+ switch (aVtableSlot.index)
+ {
+ case 1: // acquire UNO interface
+ (*pUnoI->acquire)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 2: // release UNO interface
+ (*pUnoI->release)( pUnoI );
+ *ppException = nullptr;
+ break;
+ case 0: // queryInterface() opt
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, static_cast< uno::Type * >( pArgs[0] )->getTypeLibType() );
+
+ if ( pTD )
+ {
+ uno_Interface * pInterface = nullptr;
+ (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+ pThis->getBridge()->getUnoEnv(),
+ reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+
+ if ( pInterface )
+ {
+ ::uno_any_construct(
+ static_cast< uno_Any * >( pReturn ),
+ &pInterface, pTD, nullptr );
+ (*pInterface->release)( pInterface );
+ TYPELIB_DANGER_RELEASE( pTD );
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ [[fallthrough]]; // else perform queryInterface()
+ }
+ default:
+ typelib_InterfaceMethodTypeDescription const* pMethodTD
+ = reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD);
+
+ if (!cpp_call(pThis, aVtableSlot, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
+ pMethodTD->pParams, pReturn, pArgs, ppException))
+ {
+ uno::RuntimeException aExc( "Too many parameters!" );
+
+ uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ uno::RuntimeException aExc("Illegal member type description!", uno::Reference<uno::XInterface>());
+
+ uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
+ // binary identical null reference
+ ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/bridge.cxx b/bridges/source/cpp_uno/shared/bridge.cxx
new file mode 100644
index 0000000000..3753341ccd
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/bridge.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <bridge.hxx>
+
+#include <cppinterfaceproxy.hxx>
+#include <unointerfaceproxy.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <rtl/ustring.h>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+#include <uno/environment.h>
+#include <uno/mapping.h>
+
+namespace bridges::cpp_uno::shared {
+
+void freeMapping(uno_Mapping * pMapping)
+{
+ delete static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+}
+
+void acquireMapping(uno_Mapping * pMapping)
+{
+ static_cast< Bridge::Mapping * >( pMapping )->pBridge->acquire();
+}
+
+void releaseMapping(uno_Mapping * pMapping)
+{
+ static_cast< Bridge::Mapping * >( pMapping )->pBridge->release();
+}
+
+void cpp2unoMapping(
+ uno_Mapping * pMapping, void ** ppUnoI, void * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ assert(ppUnoI && pTypeDescr);
+ if (*ppUnoI)
+ {
+ (*static_cast< uno_Interface * >( *ppUnoI )->release)(
+ static_cast< uno_Interface * >( *ppUnoI ) );
+ *ppUnoI = nullptr;
+ }
+ if (!pCppI)
+ return;
+
+ Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+
+ // get object id of interface to be wrapped
+ rtl_uString * pOId = nullptr;
+ (*pBridge->pCppEnv->getObjectIdentifier)(
+ pBridge->pCppEnv, &pOId, pCppI );
+ assert(pOId);
+
+ // try to get any known interface from target environment
+ (*pBridge->pUnoEnv->getRegisteredInterface)(
+ pBridge->pUnoEnv, ppUnoI, pOId, pTypeDescr );
+
+ if (! *ppUnoI) // no existing interface, register new proxy interface
+ {
+ // try to publish a new proxy (refcount initially 1)
+ uno_Interface * pSurrogate
+ = bridges::cpp_uno::shared::UnoInterfaceProxy::create(
+ pBridge,
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI ),
+ pTypeDescr, pOId );
+
+ // proxy may be exchanged during registration
+ (*pBridge->pUnoEnv->registerProxyInterface)(
+ pBridge->pUnoEnv, reinterpret_cast< void ** >( &pSurrogate ),
+ freeUnoInterfaceProxy, pOId,
+ pTypeDescr );
+
+ *ppUnoI = pSurrogate;
+ }
+ ::rtl_uString_release( pOId );
+}
+
+void uno2cppMapping(
+ uno_Mapping * pMapping, void ** ppCppI, void * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ assert(ppCppI && pTypeDescr);
+ if (*ppCppI)
+ {
+ static_cast< ::com::sun::star::uno::XInterface * >( *ppCppI )->
+ release();
+ *ppCppI = nullptr;
+ }
+ if (!pUnoI)
+ return;
+
+ Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+
+ // get object id of uno interface to be wrapped
+ rtl_uString * pOId = nullptr;
+ (*pBridge->pUnoEnv->getObjectIdentifier)(
+ pBridge->pUnoEnv, &pOId, pUnoI );
+ assert(pOId);
+
+ // try to get any known interface from target environment
+ (*pBridge->pCppEnv->getRegisteredInterface)(
+ pBridge->pCppEnv, ppCppI, pOId, pTypeDescr );
+
+ if (! *ppCppI) // no existing interface, register new proxy interface
+ {
+ // try to publish a new proxy (ref count initially 1)
+ com::sun::star::uno::XInterface * pProxy
+ = bridges::cpp_uno::shared::CppInterfaceProxy::create(
+ pBridge, static_cast< uno_Interface * >( pUnoI ),
+ pTypeDescr, pOId );
+
+ // proxy may be exchanged during registration
+ (*pBridge->pCppEnv->registerProxyInterface)(
+ pBridge->pCppEnv, reinterpret_cast< void ** >( &pProxy ),
+ freeCppInterfaceProxy, pOId,
+ pTypeDescr );
+
+ *ppCppI = pProxy;
+ }
+ ::rtl_uString_release( pOId );
+}
+
+uno_Mapping * Bridge::createMapping(
+ uno_ExtEnvironment * pCppEnv, uno_ExtEnvironment * pUnoEnv,
+ bool bExportCpp2Uno)
+{
+ Bridge * bridge = new Bridge(pCppEnv, pUnoEnv, bExportCpp2Uno);
+ // coverity[leaked_storage] - on purpose
+ return bExportCpp2Uno ? &bridge->aCpp2Uno : &bridge->aUno2Cpp;
+}
+
+void Bridge::acquire()
+{
+ if (++nRef != 1)
+ return;
+
+ if (bExportCpp2Uno)
+ {
+ uno_Mapping * pMapping = &aCpp2Uno;
+ ::uno_registerMapping(
+ &pMapping, freeMapping, &pCppEnv->aBase,
+ &pUnoEnv->aBase, nullptr );
+ }
+ else
+ {
+ uno_Mapping * pMapping = &aUno2Cpp;
+ ::uno_registerMapping(
+ &pMapping, freeMapping, &pUnoEnv->aBase,
+ &pCppEnv->aBase, nullptr );
+ }
+}
+
+void Bridge::release()
+{
+ if (! --nRef )
+ {
+ ::uno_revokeMapping( bExportCpp2Uno ? &aCpp2Uno : &aUno2Cpp );
+ }
+}
+
+Bridge::Bridge(
+ uno_ExtEnvironment * pCppEnv_, uno_ExtEnvironment * pUnoEnv_,
+ bool bExportCpp2Uno_)
+ : nRef( 1 )
+ , pCppEnv( pCppEnv_ )
+ , pUnoEnv( pUnoEnv_ )
+ , bExportCpp2Uno( bExportCpp2Uno_ )
+{
+ aCpp2Uno.pBridge = this;
+ aCpp2Uno.acquire = acquireMapping;
+ aCpp2Uno.release = releaseMapping;
+ aCpp2Uno.mapInterface = cpp2unoMapping;
+
+ aUno2Cpp.pBridge = this;
+ aUno2Cpp.acquire = acquireMapping;
+ aUno2Cpp.release = releaseMapping;
+ aUno2Cpp.mapInterface = uno2cppMapping;
+
+ (*pCppEnv->aBase.acquire)( &pCppEnv->aBase );
+ (*pUnoEnv->aBase.acquire)( &pUnoEnv->aBase );
+}
+
+Bridge::~Bridge()
+{
+ (*pUnoEnv->aBase.release)( &pUnoEnv->aBase );
+ (*pCppEnv->aBase.release)( &pCppEnv->aBase );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/component.cxx b/bridges/source/cpp_uno/shared/component.cxx
new file mode 100644
index 0000000000..0a2f1a2515
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/component.cxx
@@ -0,0 +1,224 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <bridge.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <osl/mutex.hxx>
+#include <osl/time.h>
+#include <rtl/process.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <uno/environment.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.h>
+#include <cppu/EnvDcp.hxx>
+
+
+namespace {
+
+const OUString & cppu_cppenv_getStaticOIdPart()
+{
+ static OUString s_aStaticOidPart = []() {
+ OUStringBuffer aRet(64);
+ aRet.append("];");
+ // good guid
+ sal_uInt8 ar[16];
+ ::rtl_getGlobalProcessId(ar);
+ for (unsigned char i : ar)
+ {
+ aRet.append(static_cast<sal_Int32>(i), 16);
+ }
+ return aRet.makeStringAndClear();
+ }();
+ return s_aStaticOidPart;
+}
+
+}
+
+extern "C" {
+
+static void s_stub_computeObjectIdentifier(va_list * pParam)
+{
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ rtl_uString ** ppOId = va_arg(*pParam, rtl_uString **);
+ void * pInterface = va_arg(*pParam, void *);
+
+
+ assert(pEnv && ppOId && pInterface);
+ if (!(pEnv && ppOId && pInterface))
+ return;
+
+ if (*ppOId)
+ {
+ rtl_uString_release( *ppOId );
+ *ppOId = nullptr;
+ }
+
+ try
+ {
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XInterface > xHome(
+ static_cast< ::com::sun::star::uno::XInterface * >(
+ pInterface ),
+ ::com::sun::star::uno::UNO_QUERY );
+ assert(xHome.is() && "### query to XInterface failed!");
+ if (xHome.is())
+ {
+ // interface
+ OUString aRet =
+ OUString::number( reinterpret_cast< sal_IntPtr >(xHome.get()), 16 ) +
+ ";" +
+ // ;environment[context]
+ OUString::unacquired(&pEnv->aBase.pTypeName) +
+ "[" +
+ OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->aBase.pContext), 16 ) +
+ // ];good guid
+ cppu_cppenv_getStaticOIdPart();
+ *ppOId = aRet.pData;
+ ::rtl_uString_acquire( *ppOId );
+ }
+ }
+ catch (const ::com::sun::star::uno::RuntimeException & e)
+ {
+ SAL_WARN("bridges",
+ "### RuntimeException occurred during queryInterface(): "
+ << e.Message);
+ }
+}
+
+static void computeObjectIdentifier(
+ uno_ExtEnvironment * pExtEnv, rtl_uString ** ppOId, void * pInterface )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_computeObjectIdentifier, pExtEnv, ppOId, pInterface);
+}
+
+static void s_stub_acquireInterface(va_list * pParam)
+{
+ /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *);
+ void * pCppI = va_arg(*pParam, void *);
+
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI )->acquire();
+}
+
+static void acquireInterface( uno_ExtEnvironment * pExtEnv, void * pCppI )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_acquireInterface, pExtEnv, pCppI);
+}
+
+static void s_stub_releaseInterface(va_list * pParam)
+{
+ /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *);
+ void * pCppI = va_arg(*pParam, void *);
+
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI )->release();
+}
+
+static void releaseInterface( uno_ExtEnvironment * pExtEnv, void * pCppI )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_releaseInterface, pExtEnv, pCppI);
+}
+
+static void environmentDisposing(
+ SAL_UNUSED_PARAMETER uno_Environment * )
+{
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_initEnvironment CPPU_ENV_uno_initEnvironment
+#endif
+
+SAL_DLLPUBLIC_EXPORT void uno_initEnvironment(uno_Environment * pCppEnv)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pCppEnv->pExtEnv);
+ assert(
+ ::rtl_ustr_ascii_compare_WithLength(
+ pCppEnv->pTypeName->buffer, rtl_str_getLength(CPPU_CURRENT_LANGUAGE_BINDING_NAME), CPPU_CURRENT_LANGUAGE_BINDING_NAME )
+ == 0
+ && "### wrong environment type!");
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->computeObjectIdentifier
+ = computeObjectIdentifier;
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->acquireInterface = acquireInterface;
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->releaseInterface = releaseInterface;
+ pCppEnv->environmentDisposing = environmentDisposing;
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_ext_getMapping CPPU_ENV_uno_ext_getMapping
+#endif
+
+SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(
+ uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo)
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping && pFrom && pTo);
+ if (!(ppMapping && pFrom && pTo && pFrom->pExtEnv && pTo->pExtEnv))
+ return;
+
+ uno_Mapping * pMapping = nullptr;
+
+ OUString from_envTypeName(cppu::EnvDcp::getTypeName(pFrom->pTypeName));
+ OUString to_envTypeName(cppu::EnvDcp::getTypeName(pTo->pTypeName));
+
+ if (rtl_ustr_ascii_compare(
+ from_envTypeName.pData->buffer,
+ CPPU_CURRENT_LANGUAGE_BINDING_NAME ) == 0 &&
+ rtl_ustr_ascii_compare(
+ to_envTypeName.pData->buffer, UNO_LB_UNO ) == 0)
+ {
+ // ref count initially 1
+ pMapping = bridges::cpp_uno::shared::Bridge::createMapping(
+ pFrom->pExtEnv, pTo->pExtEnv, true );
+ ::uno_registerMapping(
+ &pMapping, bridges::cpp_uno::shared::freeMapping,
+ &pFrom->pExtEnv->aBase,
+ &pTo->pExtEnv->aBase, nullptr );
+ }
+ else if (rtl_ustr_ascii_compare(
+ to_envTypeName.pData->buffer,
+ CPPU_CURRENT_LANGUAGE_BINDING_NAME ) == 0 &&
+ rtl_ustr_ascii_compare(
+ from_envTypeName.pData->buffer, UNO_LB_UNO ) == 0)
+ {
+ // ref count initially 1
+ pMapping = bridges::cpp_uno::shared::Bridge::createMapping(
+ pTo->pExtEnv, pFrom->pExtEnv, false );
+ ::uno_registerMapping(
+ &pMapping, bridges::cpp_uno::shared::freeMapping,
+ &pFrom->pExtEnv->aBase,
+ &pTo->pExtEnv->aBase, nullptr );
+ }
+
+ if (*ppMapping)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ }
+ if (pMapping)
+ *ppMapping = pMapping;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx
new file mode 100644
index 0000000000..189b3c2a4e
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppinterfaceproxy.hxx>
+
+#include <bridge.hxx>
+#include <utility>
+#include <vtablefactory.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <typelib/typedescription.h>
+
+#include <cstddef>
+#include <memory>
+#include <new>
+
+namespace bridges::cpp_uno::shared {
+
+void freeCppInterfaceProxy(uno_ExtEnvironment * pEnv, void * pInterface)
+{
+ CppInterfaceProxy * pThis = CppInterfaceProxy::castInterfaceToProxy(
+ pInterface);
+ if (pEnv != pThis->pBridge->getCppEnv()) {
+ assert(false);
+ }
+
+ (*pThis->pBridge->getUnoEnv()->revokeInterface)(
+ pThis->pBridge->getUnoEnv(), pThis->pUnoI );
+ (*pThis->pUnoI->release)( pThis->pUnoI );
+ ::typelib_typedescription_release(
+ &pThis->pTypeDescr->aBase );
+ pThis->pBridge->release();
+
+#if OSL_DEBUG_LEVEL > 1
+ *(int *)pInterface = 0xdeadbabe;
+#endif
+ pThis->~CppInterfaceProxy();
+ delete[] reinterpret_cast< char * >(pThis);
+}
+
+com::sun::star::uno::XInterface * CppInterfaceProxy::create(
+ bridges::cpp_uno::shared::Bridge * pBridge, uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr, OUString const & rOId)
+{
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&pTypeDescr));
+ static bridges::cpp_uno::shared::VtableFactory factory;
+ const bridges::cpp_uno::shared::VtableFactory::Vtables& rVtables(
+ factory.getVtables(pTypeDescr));
+ std::unique_ptr< char[] > pMemory(
+ new char[
+ sizeof (CppInterfaceProxy)
+ + (rVtables.count - 1) * sizeof (void **)]);
+ new(pMemory.get()) CppInterfaceProxy(pBridge, pUnoI, pTypeDescr, rOId);
+ CppInterfaceProxy * pProxy = reinterpret_cast< CppInterfaceProxy * >(
+ pMemory.release());
+ for (sal_Int32 i = 0; i < rVtables.count; ++i) {
+ pProxy->vtables[i] = VtableFactory::mapBlockToVtable(
+ rVtables.blocks[i].start);
+ }
+ // coverity[leaked_storage : FALSE] - see freeCppInterfaceProxy
+ return castProxyToInterface(pProxy);
+}
+
+void CppInterfaceProxy::acquireProxy()
+{
+ if (++nRef == 1)
+ {
+ // rebirth of proxy zombie
+ // register at cpp env
+ void * pThis = castProxyToInterface( this );
+ (*pBridge->getCppEnv()->registerProxyInterface)(
+ pBridge->getCppEnv(), &pThis, freeCppInterfaceProxy, oid.pData,
+ pTypeDescr );
+ assert(pThis == castProxyToInterface(this));
+ }
+}
+
+void CppInterfaceProxy::releaseProxy()
+{
+ if (! --nRef ) // last release
+ {
+ // revoke from cpp env
+ (*pBridge->getCppEnv()->revokeInterface)(
+ pBridge->getCppEnv(), castProxyToInterface( this ) );
+ }
+}
+
+CppInterfaceProxy::CppInterfaceProxy(
+ bridges::cpp_uno::shared::Bridge * pBridge_, uno_Interface * pUnoI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_, OUString aOId_)
+ : nRef( 1 )
+ , pBridge( pBridge_ )
+ , pUnoI( pUnoI_ )
+ , pTypeDescr( pTypeDescr_ )
+ , oid(std::move( aOId_ ))
+{
+ pBridge->acquire();
+ ::typelib_typedescription_acquire( &pTypeDescr->aBase );
+ (*pUnoI->acquire)( pUnoI );
+ (*pBridge->getUnoEnv()->registerInterface)(
+ pBridge->getUnoEnv(), reinterpret_cast< void ** >( &pUnoI ), oid.pData,
+ pTypeDescr );
+}
+
+CppInterfaceProxy::~CppInterfaceProxy()
+{}
+
+com::sun::star::uno::XInterface * CppInterfaceProxy::castProxyToInterface(
+ CppInterfaceProxy * pProxy)
+{
+ return reinterpret_cast< com::sun::star::uno::XInterface * >(
+ &pProxy->vtables);
+}
+
+CppInterfaceProxy * CppInterfaceProxy::castInterfaceToProxy(void * pInterface)
+{
+ // pInterface == &pProxy->vtables (this emulated offsetof is not truly
+ // portable):
+ char const * const base = reinterpret_cast< char const * >(16);
+ std::ptrdiff_t const offset = reinterpret_cast< char const * >(
+ &reinterpret_cast< CppInterfaceProxy const * >(base)->vtables) - base;
+ return reinterpret_cast< CppInterfaceProxy * >(
+ static_cast< char * >(pInterface) - offset);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/types.cxx b/bridges/source/cpp_uno/shared/types.cxx
new file mode 100644
index 0000000000..61dc3dabec
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/types.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <types.hxx>
+
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+namespace bridges::cpp_uno::shared {
+
+bool isSimpleType(typelib_TypeClass typeClass) {
+ return typeClass <= typelib_TypeClass_DOUBLE
+ || typeClass == typelib_TypeClass_ENUM;
+}
+
+bool isSimpleType(typelib_TypeDescriptionReference const * type) {
+ return isSimpleType(type->eTypeClass);
+}
+
+bool isSimpleType(typelib_TypeDescription const * type) {
+ return isSimpleType(type->eTypeClass);
+}
+
+bool relatesToInterfaceType(typelib_TypeDescription const * type) {
+ switch (type->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_CompoundTypeDescription const * p
+ = reinterpret_cast< typelib_CompoundTypeDescription const * >(
+ type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i) {
+ switch (p->ppTypeRefs[i]->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ {
+ typelib_TypeDescription * t = nullptr;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = relatesToInterfaceType(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (p->pBaseTypeDescription != nullptr) {
+ return relatesToInterfaceType(&p->pBaseTypeDescription->aBase);
+ }
+ }
+ break;
+
+ case typelib_TypeClass_SEQUENCE:
+ switch (reinterpret_cast< typelib_IndirectTypeDescription const * >(
+ type)->pType->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ {
+ typelib_TypeDescription * t = nullptr;
+ TYPELIB_DANGER_GET(
+ &t,
+ reinterpret_cast< typelib_IndirectTypeDescription const * >(
+ type)->pType);
+ bool b = relatesToInterfaceType(t);
+ TYPELIB_DANGER_RELEASE(t);
+ return b;
+ }
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx
new file mode 100644
index 0000000000..3c03c1cffc
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unointerfaceproxy.hxx>
+
+#include <bridge.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <utility>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+
+namespace bridges::cpp_uno::shared {
+
+void freeUnoInterfaceProxy(uno_ExtEnvironment * pEnv, void * pProxy)
+{
+ UnoInterfaceProxy * pThis =
+ static_cast< UnoInterfaceProxy * >(
+ static_cast< uno_Interface * >( pProxy ) );
+ if (pEnv != pThis->pBridge->getUnoEnv()) {
+ assert(false);
+ }
+
+ (*pThis->pBridge->getCppEnv()->revokeInterface)(
+ pThis->pBridge->getCppEnv(), pThis->pCppI );
+ pThis->pCppI->release();
+ ::typelib_typedescription_release(&pThis->pTypeDescr->aBase);
+ pThis->pBridge->release();
+
+#if OSL_DEBUG_LEVEL > 1
+ *(int *)pProxy = 0xdeadbabe;
+#endif
+ delete pThis;
+}
+
+void acquireProxy(uno_Interface * pUnoI)
+{
+ if (++static_cast< UnoInterfaceProxy * >( pUnoI )->nRef != 1)
+ return;
+
+ // rebirth of proxy zombie
+ // register at uno env
+#if OSL_DEBUG_LEVEL > 1
+ void * pThis = pUnoI;
+#endif
+ (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()->
+ registerProxyInterface)(
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(),
+ reinterpret_cast< void ** >( &pUnoI ), freeUnoInterfaceProxy,
+ static_cast< UnoInterfaceProxy * >( pUnoI )->oid.pData,
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pTypeDescr );
+#if OSL_DEBUG_LEVEL > 1
+ assert(pThis == pUnoI);
+#endif
+}
+
+void releaseProxy(uno_Interface * pUnoI)
+{
+ if (! --static_cast< UnoInterfaceProxy * >( pUnoI )->nRef )
+ {
+ // revoke from uno env on last release
+ (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()->
+ revokeInterface)(
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(),
+ pUnoI );
+ }
+}
+
+UnoInterfaceProxy * UnoInterfaceProxy::create(
+ bridges::cpp_uno::shared::Bridge * pBridge,
+ com::sun::star::uno::XInterface * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId)
+{
+ return new UnoInterfaceProxy(pBridge, pCppI, pTypeDescr, rOId);
+}
+
+UnoInterfaceProxy::UnoInterfaceProxy(
+ bridges::cpp_uno::shared::Bridge * pBridge_,
+ com::sun::star::uno::XInterface * pCppI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_, OUString aOId_)
+ : nRef( 1 )
+ , pBridge( pBridge_ )
+ , pCppI( pCppI_ )
+ , pTypeDescr( pTypeDescr_ )
+ , oid(std::move( aOId_ ))
+{
+ pBridge->acquire();
+ ::typelib_typedescription_acquire(&pTypeDescr->aBase);
+ if (!pTypeDescr->aBase.bComplete)
+ ::typelib_typedescription_complete(
+ reinterpret_cast<typelib_TypeDescription **>(&pTypeDescr));
+ assert(pTypeDescr->aBase.bComplete);
+ pCppI->acquire();
+ (*pBridge->getCppEnv()->registerInterface)(
+ pBridge->getCppEnv(), reinterpret_cast< void ** >( &pCppI ), oid.pData,
+ pTypeDescr );
+
+ // uno_Interface
+ acquire = acquireProxy;
+ release = releaseProxy;
+ pDispatcher = unoInterfaceProxyDispatch;
+}
+
+UnoInterfaceProxy::~UnoInterfaceProxy()
+{}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/vtablefactory.cxx b/bridges/source/cpp_uno/shared/vtablefactory.cxx
new file mode 100644
index 0000000000..53b516cded
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/vtablefactory.cxx
@@ -0,0 +1,403 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <vtablefactory.hxx>
+
+#include <vtables.hxx>
+
+#include <osl/thread.h>
+#include <osl/security.hxx>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/alloc.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.hxx>
+
+#include <memory>
+#include <new>
+#include <unordered_map>
+#include <vector>
+
+#if defined SAL_UNX
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#elif defined _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#error Unsupported platform
+#endif
+
+#if defined USE_DOUBLE_MMAP
+#include <fcntl.h>
+#endif
+
+#if defined MACOSX && defined __aarch64__
+#include <pthread.h>
+#endif
+
+using bridges::cpp_uno::shared::VtableFactory;
+
+namespace {
+
+extern "C" void * allocExec(
+ SAL_UNUSED_PARAMETER rtl_arena_type *, sal_Size * size)
+{
+ std::size_t pagesize;
+#if defined SAL_UNX
+#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY || defined HAIKU
+ pagesize = getpagesize();
+#else
+ pagesize = sysconf(_SC_PAGESIZE);
+#endif
+#elif defined _WIN32
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ pagesize = info.dwPageSize;
+#else
+#error Unsupported platform
+#endif
+ std::size_t n = (*size + (pagesize - 1)) & ~(pagesize - 1);
+ void * p;
+#if defined SAL_UNX
+#if defined MACOSX
+ p = mmap(
+ nullptr, n, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1,
+ 0);
+ if (p != MAP_FAILED) {
+ goto done;
+ }
+ {
+ auto const e = errno;
+ SAL_INFO("bridges.osx", "mmap failed with " << e);
+ if (e != EINVAL) {
+ p = nullptr;
+ goto done;
+ }
+ }
+ // At least some macOS 10.13 machines are reported to fail the above mmap with EINVAL (see
+ // tdf#134754 "Crash on macOS 10.13 opening local HSQLDB-based odb file in Base on LibreOffice 7
+ // rc1", so in that case retry with the "traditional" approach:
+#endif
+ p = mmap(
+ nullptr, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
+ 0);
+ if (p == MAP_FAILED) {
+ p = nullptr;
+ }
+ else if (mprotect (p, n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
+ {
+ munmap (p, n);
+ p = nullptr;
+ }
+#if defined MACOSX
+done:
+#endif
+#elif defined _WIN32
+ p = VirtualAlloc(nullptr, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+#endif
+ if (p != nullptr) {
+ *size = n;
+ }
+ return p;
+}
+
+extern "C" void freeExec(
+ SAL_UNUSED_PARAMETER rtl_arena_type *, void * address, sal_Size size)
+{
+#if defined SAL_UNX
+ munmap(address, size);
+#elif defined _WIN32
+ (void) size; // unused
+ VirtualFree(address, 0, MEM_RELEASE);
+#endif
+}
+
+#if defined MACOSX && defined __aarch64__
+struct JitMemoryProtectionGuard {
+ JitMemoryProtectionGuard() { pthread_jit_write_protect_np(0); }
+ ~JitMemoryProtectionGuard() { pthread_jit_write_protect_np(1); }
+};
+#endif
+
+}
+
+class VtableFactory::GuardedBlocks:
+ public std::vector<Block>
+{
+public:
+ GuardedBlocks(const GuardedBlocks&) = delete;
+ const GuardedBlocks& operator=(const GuardedBlocks&) = delete;
+
+ explicit GuardedBlocks(VtableFactory const & factory):
+ m_factory(factory), m_guarded(true) {}
+
+ ~GuardedBlocks();
+
+ void unguard() { m_guarded = false; }
+
+private:
+ VtableFactory const & m_factory;
+ bool m_guarded;
+};
+
+VtableFactory::GuardedBlocks::~GuardedBlocks() {
+ if (m_guarded) {
+ for (iterator i(begin()); i != end(); ++i) {
+ m_factory.freeBlock(*i);
+ }
+ }
+}
+
+class VtableFactory::BaseOffset {
+public:
+ explicit BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); }
+
+ sal_Int32 getFunctionOffset(OUString const & name) const
+ { return m_map.find(name)->second; }
+
+private:
+ sal_Int32 calculate(
+ typelib_InterfaceTypeDescription * type, sal_Int32 offset);
+
+ std::unordered_map< OUString, sal_Int32 > m_map;
+};
+
+sal_Int32 VtableFactory::BaseOffset::calculate(
+ typelib_InterfaceTypeDescription * type, sal_Int32 offset)
+{
+ OUString name(type->aBase.pTypeName);
+ if (m_map.find(name) == m_map.end()) {
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ offset = calculate(type->ppBaseTypes[i], offset);
+ }
+ m_map.insert({name, offset});
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ offset += bridges::cpp_uno::shared::getLocalFunctions(type);
+ }
+ return offset;
+}
+
+VtableFactory::VtableFactory(): m_arena(
+ rtl_arena_create(
+ "bridges::cpp_uno::shared::VtableFactory",
+ sizeof (void *), // to satisfy alignment requirements
+ 0, nullptr, allocExec, freeExec, 0))
+{
+ if (m_arena == nullptr) {
+ throw std::bad_alloc();
+ }
+}
+
+VtableFactory::~VtableFactory() {
+ {
+ std::scoped_lock guard(m_mutex);
+ for (const auto& rEntry : m_map) {
+ for (sal_Int32 j = 0; j < rEntry.second.count; ++j) {
+ freeBlock(rEntry.second.blocks[j]);
+ }
+ }
+ }
+ rtl_arena_destroy(m_arena);
+}
+
+const VtableFactory::Vtables& VtableFactory::getVtables(
+ typelib_InterfaceTypeDescription * type)
+{
+ OUString name(type->aBase.pTypeName);
+ std::scoped_lock guard(m_mutex);
+ Map::iterator i(m_map.find(name));
+ if (i == m_map.end()) {
+ GuardedBlocks blocks(*this);
+ createVtables(blocks, BaseOffset(type), type, 0, type, true);
+ Vtables vtables;
+ assert(blocks.size() <= SAL_MAX_INT32);
+ vtables.count = static_cast< sal_Int32 >(blocks.size());
+ vtables.blocks.reset(new Block[vtables.count]);
+ for (sal_Int32 j = 0; j < vtables.count; ++j) {
+ vtables.blocks[j] = blocks[j];
+ }
+ i = m_map.emplace(name, std::move(vtables)).first;
+ blocks.unguard();
+ }
+ return i->second;
+}
+
+#ifdef USE_DOUBLE_MMAP
+bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
+{
+ std::size_t size = getBlockSize(slotCount);
+ std::size_t pagesize = sysconf(_SC_PAGESIZE);
+ block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
+ block.fd = -1;
+
+ // Try non-doublemmaped allocation first:
+ block.start = block.exec = rtl_arena_alloc(m_arena, &block.size);
+ if (block.start != nullptr) {
+ return true;
+ }
+
+ osl::Security aSecurity;
+ OUString strDirectory;
+ OUString strURLDirectory;
+ if (aSecurity.getHomeDir(strURLDirectory))
+ osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);
+
+ for (int i = strDirectory.isEmpty() ? 1 : 0; i < 2; ++i)
+ {
+ if (strDirectory.isEmpty())
+ strDirectory = "/tmp";
+
+ strDirectory += "/.execoooXXXXXX";
+ OString aTmpName = OUStringToOString(strDirectory, osl_getThreadTextEncoding());
+ std::unique_ptr<char[]> tmpfname(new char[aTmpName.getLength()+1]);
+ strncpy(tmpfname.get(), aTmpName.getStr(), aTmpName.getLength()+1);
+ // coverity[secure_temp] - https://communities.coverity.com/thread/3179
+ if ((block.fd = mkstemp(tmpfname.get())) == -1)
+ fprintf(stderr, "mkstemp(\"%s\") failed: %s\n", tmpfname.get(), strerror(errno));
+ if (block.fd == -1)
+ {
+ break;
+ }
+ unlink(tmpfname.get());
+ tmpfname.reset();
+#if defined(HAVE_POSIX_FALLOCATE)
+ int err = posix_fallocate(block.fd, 0, block.size);
+#else
+ int err = ftruncate(block.fd, block.size);
+#endif
+ if (err != 0)
+ {
+#if defined(HAVE_POSIX_FALLOCATE)
+ SAL_WARN("bridges", "posix_fallocate failed with code " << err);
+#else
+ SAL_WARN("bridges", "truncation of executable memory area failed with code " << err);
+#endif
+ close(block.fd);
+ block.fd = -1;
+ break;
+ }
+ block.start = mmap(nullptr, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
+ if (block.start== MAP_FAILED) {
+ block.start = nullptr;
+ }
+ block.exec = mmap(nullptr, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
+ if (block.exec == MAP_FAILED) {
+ block.exec = nullptr;
+ }
+
+ //All good
+ if (block.start && block.exec && block.fd != -1)
+ break;
+
+ freeBlock(block);
+
+ strDirectory.clear();
+ }
+ return (block.start != nullptr && block.exec != nullptr);
+}
+
+void VtableFactory::freeBlock(Block const & block) const {
+ //if the double-map failed we were allocated on the arena
+ if (block.fd == -1 && block.start == block.exec && block.start != nullptr)
+ rtl_arena_free(m_arena, block.start, block.size);
+ else
+ {
+ if (block.start) munmap(block.start, block.size);
+ if (block.exec) munmap(block.exec, block.size);
+ if (block.fd != -1) close(block.fd);
+ }
+}
+#else
+bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
+{
+ block.size = getBlockSize(slotCount);
+ block.start = rtl_arena_alloc(m_arena, &block.size);
+ return block.start != nullptr;
+}
+
+void VtableFactory::freeBlock(Block const & block) const {
+ rtl_arena_free(m_arena, block.start, block.size);
+}
+#endif
+
+sal_Int32 VtableFactory::createVtables(
+ GuardedBlocks & blocks, BaseOffset const & baseOffset,
+ typelib_InterfaceTypeDescription * type, sal_Int32 vtableNumber,
+ typelib_InterfaceTypeDescription * mostDerived, bool includePrimary) const
+{
+ {
+#if defined MACOSX && defined __aarch64__
+ JitMemoryProtectionGuard guard;
+#endif
+ if (includePrimary) {
+ sal_Int32 slotCount
+ = bridges::cpp_uno::shared::getPrimaryFunctions(type);
+ Block block;
+ if (!createBlock(block, slotCount)) {
+ throw std::bad_alloc();
+ }
+ try {
+ Slot * slots = initializeBlock(
+ block.start, slotCount, vtableNumber, mostDerived);
+ unsigned char * codeBegin =
+ reinterpret_cast< unsigned char * >(slots);
+ unsigned char * code = codeBegin;
+ sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *);
+ for (typelib_InterfaceTypeDescription const * type2 = type;
+ type2 != nullptr; type2 = type2->pBaseTypeDescription)
+ {
+ code = addLocalFunctions(
+ &slots, code,
+#ifdef USE_DOUBLE_MMAP
+ reinterpret_cast<sal_uIntPtr>(block.exec) - reinterpret_cast<sal_uIntPtr>(block.start),
+#endif
+ type2,
+ baseOffset.getFunctionOffset(type2->aBase.pTypeName),
+ bridges::cpp_uno::shared::getLocalFunctions(type2),
+ vtableOffset);
+ }
+ flushCode(codeBegin, code);
+#ifdef USE_DOUBLE_MMAP
+ //Finished generating block, swap writable pointer with executable
+ //pointer
+ std::swap(block.start, block.exec);
+#endif
+ blocks.push_back(block);
+ } catch (...) {
+ freeBlock(block);
+ throw;
+ }
+ }
+ }
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ vtableNumber = createVtables(
+ blocks, baseOffset, type->ppBaseTypes[i],
+ vtableNumber + (i == 0 ? 0 : 1), mostDerived, i != 0);
+ }
+ return vtableNumber;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/vtables.cxx b/bridges/source/cpp_uno/shared/vtables.cxx
new file mode 100644
index 0000000000..9a7d7b3768
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/vtables.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <vtables.hxx>
+
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+#include <algorithm>
+#include <cassert>
+
+namespace
+{
+
+/**
+ * Calculates the number of vtables associated with an interface type.
+ *
+ * <p>Multiple-inheritance C++ classes have more than one vtable.</p>
+ *
+ * @param type a non-null pointer to an interface type description
+ * @return the number of vtables associated with the given interface type
+ */
+sal_Int32 getVtableCount(typelib_InterfaceTypeDescription const * type) {
+ sal_Int32 n = 0;
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ n += getVtableCount(type->ppBaseTypes[i]);
+ }
+ return std::max< sal_Int32 >(n, 1);
+}
+
+/**
+ * Maps a local member index to a local function index.
+ *
+ * <p><em>Local</em> members/functions are those not inherited from any base
+ * types. The number of <em>functions</em> is potentially larger than the
+ * number of <em>members</em>, as each read&ndash;write attribute member counts
+ * as two functions.</p>
+ *
+ * @param type a non-null pointer to an interface type description
+ * @param localMember a local member index, relative to the given interface type
+ * @return the local function index corresponding to the given local member
+ * index, relative to the given interface type
+ */
+sal_Int32 mapLocalMemberToLocalFunction(
+ typelib_InterfaceTypeDescription * type, sal_Int32 localMember)
+{
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ sal_Int32 localMemberOffset = type->nAllMembers - type->nMembers;
+ sal_Int32 localFunctionOffset = type->nMapFunctionIndexToMemberIndex
+ - bridges::cpp_uno::shared::getLocalFunctions(type);
+ return type->pMapMemberIndexToFunctionIndex[localMemberOffset + localMember]
+ - localFunctionOffset;
+}
+
+// Since on Solaris we compile with --instances=static, getVtableSlot cannot be
+// a template function, with explicit instantiates for
+// T = typelib_InterfaceAttributeTypeDescription and
+// T = typelib_InterfaceMethodTypeDescription in this file; hence, there are two
+// overloaded versions of getVtableSlot that both delegate to this template
+// function:
+template< typename T > bridges::cpp_uno::shared::VtableSlot doGetVtableSlot(
+ T const * ifcMember)
+{
+ bridges::cpp_uno::shared::VtableSlot slot;
+ slot.offset = 0;
+ T * member = const_cast< T * >(ifcMember);
+ while (member->pBaseRef != nullptr) {
+ assert(member->nIndex < member->pInterface->nBaseTypes);
+ for (sal_Int32 i = 0; i < member->nIndex; ++i) {
+ slot.offset += getVtableCount(member->pInterface->ppBaseTypes[i]);
+ }
+ typelib_TypeDescription * desc = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ &desc, member->pBaseRef);
+ assert(
+ desc != nullptr && desc->eTypeClass == member->aBase.aBase.eTypeClass);
+ if (member != ifcMember) {
+ typelib_typedescription_release(&member->aBase.aBase);
+ }
+ member = reinterpret_cast< T * >(desc);
+ }
+ slot.index
+ = bridges::cpp_uno::shared::getPrimaryFunctions(
+ member->pInterface->pBaseTypeDescription)
+ + mapLocalMemberToLocalFunction(member->pInterface, member->nIndex);
+ if (member != ifcMember) {
+ typelib_typedescription_release(&member->aBase.aBase);
+ }
+ return slot;
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const * type) {
+ return type->nMembers == 0
+ ? 0
+ : (type->nMapFunctionIndexToMemberIndex
+ - type->pMapMemberIndexToFunctionIndex[
+ type->nAllMembers - type->nMembers]);
+}
+
+sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription * type) {
+ sal_Int32 n = 0;
+ for (; type != nullptr; type = type->pBaseTypeDescription) {
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ n += getLocalFunctions(type);
+ }
+ return n;
+}
+
+VtableSlot getVtableSlot(
+ typelib_InterfaceAttributeTypeDescription const * ifcMember)
+{
+ return doGetVtableSlot(ifcMember);
+}
+
+VtableSlot getVtableSlot(
+ typelib_InterfaceMethodTypeDescription const * ifcMember)
+{
+ return doGetVtableSlot(ifcMember);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java
new file mode 100644
index 0000000000..e129f10327
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java
@@ -0,0 +1,61 @@
+// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.bridges.jni_uno;
+
+import com.sun.star.lib.util.NativeLibraryLoader;
+
+public final class JNI_info_holder
+{
+ static {
+ if ("The Android Project".equals(System.getProperty("java.vendor"))) {
+ // See corresponding code in
+ // javaunohelper/com/sun/star/comp/helper/Bootstrap.java for more
+ // comments.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary("lo-bootstrap");
+ } catch (UnsatisfiedLinkError e) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ } else
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ }
+
+ private static JNI_info_holder s_holder = new JNI_info_holder();
+
+ private static long s_jni_info_handle;
+
+ private native void finalize( long jni_info_handle );
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ finalize( s_jni_info_handle );
+ super.finalize();
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java
new file mode 100644
index 0000000000..200f664f32
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java
@@ -0,0 +1,225 @@
+// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package com.sun.star.bridges.jni_uno;
+
+import com.sun.star.lib.util.AsynchronousFinalizer;
+import com.sun.star.lib.util.NativeLibraryLoader;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.IEnvironment;
+import com.sun.star.uno.IQueryInterface;
+
+
+
+public final class JNI_proxy implements java.lang.reflect.InvocationHandler
+{
+ static {
+ if ("The Android Project".equals(System.getProperty("java.vendor"))) {
+ // See corresponding code in
+ // javaunohelper/com/sun/star/comp/helper/Bootstrap.java for more
+ // comments.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary("lo-bootstrap");
+ } catch (UnsatisfiedLinkError e) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(),
+ "java_uno");
+ } else
+ NativeLibraryLoader.loadLibrary(JNI_proxy.class.getClassLoader(),
+ "java_uno");
+ }
+ private static ClassLoader s_classloader =
+ JNI_proxy.class.getClassLoader();
+ private static Class s_InvocationHandler [] =
+ new Class [] { java.lang.reflect.InvocationHandler.class };
+
+ private long m_bridge_handle;
+ private final IEnvironment m_java_env;
+ /** these 2 fields are accessed directly from C++ */
+ private long m_receiver_handle; // on the C++ side, this is a "UNO_Interface *"
+ private long m_td_handle; // on the C++ side, this is a "typelib_TypeDescription *"
+ private final Type m_type;
+ private final String m_oid;
+ private final Class m_class;
+ private final AsynchronousFinalizer m_finalizer;
+
+ public static String get_stack_trace( Throwable throwable )
+ throws Throwable
+ {
+ boolean current_trace = false;
+ if (null == throwable)
+ {
+ throwable = new Throwable();
+ current_trace = true;
+ }
+ java.io.StringWriter string_writer =
+ new java.io.StringWriter();
+ java.io.PrintWriter print_writer =
+ new java.io.PrintWriter( string_writer, true );
+ throwable.printStackTrace( print_writer );
+ print_writer.flush();
+ print_writer.close();
+ string_writer.flush();
+ String trace = string_writer.toString();
+ if (current_trace)
+ {
+ // cut out first two lines
+ int n = trace.indexOf( '\n' );
+ n = trace.indexOf( '\n', n +1 );
+ trace = trace.substring( n +1 );
+ }
+ return "\njava stack trace:\n" + trace;
+ }
+
+ private native void finalize( long bridge_handle );
+
+ @Override
+ protected void finalize()
+ {
+ if (m_finalizer != null) {
+ m_finalizer.add(new AsynchronousFinalizer.Job() {
+ public void run() throws Throwable {
+ JNI_proxy.this.finalize( m_bridge_handle );
+ }
+ });
+ }
+ }
+
+ private JNI_proxy(
+ long bridge_handle, IEnvironment java_env,
+ long receiver_handle, long td_handle, Type type, String oid,
+ AsynchronousFinalizer finalizer)
+ {
+ m_bridge_handle = bridge_handle;
+ m_java_env = java_env;
+ m_receiver_handle = receiver_handle;
+ m_td_handle = td_handle;
+ m_type = type;
+ m_oid = oid;
+ m_class = m_type.getZClass();
+ m_finalizer = finalizer;
+ }
+
+ public static Object create(
+ long bridge_handle, IEnvironment java_env,
+ long receiver_handle, long td_handle, Type type, String oid,
+ java.lang.reflect.Constructor proxy_ctor,
+ AsynchronousFinalizer finalizer)
+ throws Throwable
+ {
+ JNI_proxy handler = new JNI_proxy(
+ bridge_handle, java_env, receiver_handle, td_handle, type, oid,
+ finalizer);
+ Object proxy = proxy_ctor.newInstance( new Object [] { handler } );
+ return java_env.registerInterface( proxy, new String [] { oid }, type );
+ }
+
+ public static java.lang.reflect.Constructor get_proxy_ctor( Class clazz )
+ throws Throwable
+ {
+ Class<?> proxy_class = java.lang.reflect.Proxy.getProxyClass(
+ s_classloader,
+ new Class [] { clazz, IQueryInterface.class,
+ com.sun.star.lib.uno.Proxy.class } );
+ return proxy_class.getConstructor( s_InvocationHandler );
+ }
+
+ private native Object dispatch_call(
+ long bridge_handle, String method, Object args [] )
+ throws Throwable;
+
+ // InvocationHandler impl
+
+ public Object invoke(
+ Object proxy, java.lang.reflect.Method method, Object args [] )
+ throws Throwable
+ {
+ Class<?> decl_class = method.getDeclaringClass();
+ String method_name = method.getName();
+
+ if (Object.class.equals( decl_class ))
+ {
+ if (method_name.equals( "hashCode" ))
+ {
+ // int hashCode()
+ return Integer.valueOf( m_oid.hashCode() );
+ }
+ else if (method_name.equals( "equals" ))
+ {
+ // boolean equals( Object obj )
+ return isSame(args[0]);
+ }
+ else if (method_name.equals( "toString" ))
+ {
+ // String toString()
+ return this.toString() + " [oid=" + m_oid +
+ ", type=" + m_type.getTypeName() + "]";
+ }
+ }
+ // UNO interface call
+ else if (decl_class.isAssignableFrom( m_class ))
+ {
+ // dispatch interface call
+ return dispatch_call( m_bridge_handle, method_name, args );
+ }
+ // IQueryInterface impl
+ else if (IQueryInterface.class.equals( decl_class ))
+ {
+ if (method_name.equals( "queryInterface" ))
+ {
+ Object registered_proxy =
+ m_java_env.getRegisteredInterface( m_oid, (Type)args[ 0 ] );
+ if (null == registered_proxy)
+ {
+ return dispatch_call( m_bridge_handle, method_name, args );
+ }
+ else
+ {
+ return registered_proxy;
+ }
+ }
+ else if (method_name.equals( "isSame" ))
+ {
+ // boolean isSame( Object object )
+ return isSame(args[0]);
+ }
+ else if (method_name.equals( "getOid" ))
+ {
+ return m_oid;
+ }
+ }
+
+ throw new com.sun.star.uno.RuntimeException(
+ "[jni_uno bridge error] unexpected call on proxy " +
+ proxy.toString() + ": " + method.toString() );
+ }
+
+ private Boolean isSame(Object obj) {
+ return Boolean.valueOf(obj != null
+ && m_oid.equals(UnoRuntime.generateOid(obj)));
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest
new file mode 100644
index 0000000000..7ad02e156d
--- /dev/null
+++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest
@@ -0,0 +1 @@
+Sealed: true
diff --git a/bridges/source/jni_uno/jni_base.h b/bridges/source/jni_uno/jni_base.h
new file mode 100644
index 0000000000..0d02261adb
--- /dev/null
+++ b/bridges/source/jni_uno/jni_base.h
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+
+#include <osl/diagnose.h>
+
+#include <rtl/alloc.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <utility>
+
+#include <uno/environment.h>
+#include <typelib/typedescription.h>
+
+
+namespace jni_uno
+{
+
+class JNI_info;
+
+struct BridgeRuntimeError
+{
+ OUString m_message;
+
+ explicit BridgeRuntimeError( OUString message )
+ : m_message(std::move( message ))
+ {}
+};
+
+
+class JNI_context
+{
+ JNI_info const * m_jni_info;
+ JNIEnv * m_env;
+ jobject m_class_loader;
+
+ JNI_context( JNI_context const & ) = delete;
+ JNI_context& operator = ( JNI_context const &) = delete;
+
+ void java_exc_occurred() const;
+public:
+ explicit JNI_context(
+ JNI_info const * jni_info, JNIEnv * env, jobject class_loader )
+ : m_jni_info( jni_info ),
+ m_env( env ),
+ m_class_loader( class_loader )
+ {}
+
+ JNI_info const * get_info() const
+ { return m_jni_info; }
+
+ JNIEnv * operator -> () const
+ { return m_env; }
+ JNIEnv * get_jni_env() const
+ { return m_env; }
+
+ // does not handle exceptions, *classClass will be null if exception
+ // occurred:
+ void getClassForName(jclass * classClass, jmethodID * methodForName) const;
+
+ // if inException, does not handle exceptions, in which case returned value
+ // will be null if exception occurred:
+ jclass findClass(
+ char const * name, jclass classClass, jmethodID methodForName,
+ bool inException) const;
+
+ inline void ensure_no_exception() const; // throws BridgeRuntimeError
+ inline bool assert_no_exception() const; // asserts and clears exception
+
+ OUString get_stack_trace( jobject jo_exc = nullptr ) const;
+};
+
+inline void JNI_context::ensure_no_exception() const
+{
+ if (m_env->ExceptionCheck())
+ {
+ java_exc_occurred();
+ }
+}
+
+inline bool JNI_context::assert_no_exception() const
+{
+ if (m_env->ExceptionCheck())
+ {
+ SAL_WARN("bridges", "unexpected java exception occurred");
+#if OSL_DEBUG_LEVEL > 0
+ m_env->ExceptionDescribe();
+#endif
+ m_env->ExceptionClear();
+ return false;
+ }
+ return true;
+}
+
+
+class JNI_guarded_context
+ : private ::jvmaccess::VirtualMachine::AttachGuard,
+ public JNI_context
+{
+ JNI_guarded_context( JNI_guarded_context const & ) = delete;
+ JNI_guarded_context& operator = ( JNI_guarded_context const &) = delete;
+
+public:
+ explicit JNI_guarded_context(
+ JNI_info const * jni_info,
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const & vm_access)
+ : AttachGuard( vm_access->getVirtualMachine() ),
+ JNI_context(
+ jni_info, AttachGuard::getEnvironment(),
+ static_cast< jobject >(vm_access->getClassLoader()) )
+ {}
+};
+
+
+class JLocalAutoRef
+{
+ JNI_context const & m_jni;
+ jobject m_jo;
+
+public:
+ explicit JLocalAutoRef( JNI_context const & jni )
+ : m_jni( jni ),
+ m_jo( nullptr )
+ {}
+ explicit JLocalAutoRef( JNI_context const & jni, jobject jo )
+ : m_jni( jni ),
+ m_jo( jo )
+ {}
+ inline JLocalAutoRef( JLocalAutoRef & auto_ref );
+ inline ~JLocalAutoRef();
+
+ jobject get() const
+ { return m_jo; }
+ bool is() const
+ { return (nullptr != m_jo); }
+ inline jobject release();
+ inline void reset( jobject jo );
+ inline JLocalAutoRef & operator = ( JLocalAutoRef & auto_ref );
+};
+
+inline JLocalAutoRef::~JLocalAutoRef()
+{
+ if (nullptr != m_jo)
+ m_jni->DeleteLocalRef( m_jo );
+}
+
+inline JLocalAutoRef::JLocalAutoRef( JLocalAutoRef & auto_ref )
+ : m_jni( auto_ref.m_jni ),
+ m_jo( auto_ref.m_jo )
+{
+ auto_ref.m_jo = nullptr;
+}
+
+inline jobject JLocalAutoRef::release()
+{
+ jobject jo = m_jo;
+ m_jo = nullptr;
+ return jo;
+}
+
+inline void JLocalAutoRef::reset( jobject jo )
+{
+ if (jo != m_jo)
+ {
+ if (nullptr != m_jo)
+ m_jni->DeleteLocalRef( m_jo );
+ m_jo = jo;
+ }
+}
+
+inline JLocalAutoRef & JLocalAutoRef::operator = ( JLocalAutoRef & auto_ref )
+{
+ assert( m_jni.get_jni_env() == auto_ref.m_jni.get_jni_env() );
+ reset( auto_ref.m_jo );
+ auto_ref.m_jo = nullptr;
+ return *this;
+}
+
+
+
+struct rtl_mem
+{
+ static void * operator new ( size_t nSize )
+ { return std::malloc( nSize ); }
+ static void operator delete ( void * mem )
+ { std::free( mem ); }
+ static void * operator new ( size_t, void * mem )
+ { return mem; }
+ static void operator delete ( void *, void * )
+ {}
+
+ static inline rtl_mem * allocate( std::size_t bytes );
+};
+
+inline rtl_mem * rtl_mem::allocate( std::size_t bytes )
+{
+ void * p = std::malloc( bytes );
+ if (nullptr == p)
+ throw BridgeRuntimeError( "out of memory!" );
+ return static_cast<rtl_mem *>(p);
+}
+
+
+class TypeDescr
+{
+ typelib_TypeDescription * m_td;
+
+ TypeDescr( TypeDescr const & ) = delete;
+ TypeDescr& operator = ( TypeDescr const & ) = delete;
+
+public:
+ inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref );
+ ~TypeDescr()
+ { TYPELIB_DANGER_RELEASE( m_td ); }
+
+ typelib_TypeDescription * get() const
+ { return m_td; }
+};
+
+inline TypeDescr::TypeDescr( typelib_TypeDescriptionReference * td_ref )
+ : m_td( nullptr )
+{
+ TYPELIB_DANGER_GET( &m_td, td_ref );
+ if (nullptr == m_td)
+ {
+ throw BridgeRuntimeError(
+ "cannot get comprehensive type description for " +
+ OUString::unacquired( &td_ref->pTypeName ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_bridge.cxx b/bridges/source/jni_uno/jni_bridge.cxx
new file mode 100644
index 0000000000..5e09a88996
--- /dev/null
+++ b/bridges/source/jni_uno/jni_bridge.cxx
@@ -0,0 +1,577 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cassert>
+#include <memory>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/strbuf.hxx>
+#include <uno/lbnames.h>
+
+using namespace ::jni_uno;
+
+namespace
+{
+extern "C"
+{
+
+
+void Mapping_acquire( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping const * that = static_cast< Mapping const * >( mapping );
+ that->m_bridge->acquire();
+}
+
+
+void Mapping_release( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping const * that = static_cast< Mapping const * >( mapping );
+ that->m_bridge->release();
+}
+
+
+void Mapping_map_to_uno(
+ uno_Mapping * mapping, void ** ppOut,
+ void * pIn, typelib_InterfaceTypeDescription * td )
+ SAL_THROW_EXTERN_C()
+{
+ uno_Interface ** ppUnoI = reinterpret_cast<uno_Interface **>(ppOut);
+ jobject javaI = static_cast<jobject>(pIn);
+
+ static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
+ assert(ppUnoI != nullptr);
+ assert(td != nullptr);
+
+ if (javaI == nullptr)
+ {
+ if (*ppUnoI != nullptr)
+ {
+ uno_Interface * p = *ppUnoI;
+ (*p->release)( p );
+ *ppUnoI = nullptr;
+ }
+ }
+ else
+ {
+ try
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ bridge->getJniInfo()->get_type_info(
+ jni, &td->aBase ) );
+ uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info );
+ if (*ppUnoI != nullptr)
+ {
+ uno_Interface * p = *ppUnoI;
+ (*p->release)( p );
+ }
+ *ppUnoI = pUnoI;
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+ }
+}
+
+
+void Mapping_map_to_java(
+ uno_Mapping * mapping, void ** ppOut,
+ void * pIn, typelib_InterfaceTypeDescription * td )
+ SAL_THROW_EXTERN_C()
+{
+ jobject * ppJavaI = reinterpret_cast<jobject *>(ppOut);
+ uno_Interface * pUnoI = static_cast<uno_Interface *>(pIn);
+
+ static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
+ assert(ppJavaI != nullptr);
+ assert(td != nullptr);
+
+ try
+ {
+ if (pUnoI == nullptr)
+ {
+ if (*ppJavaI != nullptr)
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+ jni->DeleteGlobalRef( *ppJavaI );
+ *ppJavaI = nullptr;
+ }
+ }
+ else
+ {
+ Bridge const * bridge =
+ static_cast< Mapping const * >( mapping )->m_bridge;
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<jni_uno::JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ bridge->getJniInfo()->get_type_info(
+ jni, &td->aBase ) );
+ jobject jlocal = bridge->map_to_java( jni, pUnoI, info );
+ if (*ppJavaI != nullptr)
+ jni->DeleteGlobalRef( *ppJavaI );
+ *ppJavaI = jni->NewGlobalRef( jlocal );
+ jni->DeleteLocalRef( jlocal );
+ }
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+}
+
+
+void Bridge_free( uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * that = static_cast< Mapping * >( mapping );
+ delete that->m_bridge;
+}
+
+}
+
+}
+
+namespace jni_uno
+{
+
+
+void Bridge::acquire() const
+{
+ if (++m_ref != 1)
+ return;
+
+ if (m_registered_java2uno)
+ {
+ uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno );
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ m_java_env, &m_uno_env->aBase, nullptr );
+ }
+ else
+ {
+ uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java );
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ &m_uno_env->aBase, m_java_env, nullptr );
+ }
+}
+
+
+void Bridge::release() const
+{
+ if (! --m_ref )
+ {
+ uno_revokeMapping(
+ m_registered_java2uno
+ ? const_cast< Mapping * >( &m_java2uno )
+ : const_cast< Mapping * >( &m_uno2java ) );
+ }
+}
+
+
+Bridge::Bridge(
+ uno_Environment * java_env, uno_ExtEnvironment * uno_env,
+ bool registered_java2uno )
+ : m_ref( 1 ),
+ m_uno_env( uno_env ),
+ m_java_env( java_env ),
+ m_registered_java2uno( registered_java2uno )
+{
+ assert(m_java_env != nullptr);
+ assert(m_uno_env != nullptr);
+
+ // uno_initEnvironment (below) cannot report errors directly, so it clears
+ // its pContext upon error to indirectly report errors from here:
+ if (static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
+ == nullptr)
+ {
+ throw BridgeRuntimeError("error during JNI-UNO's uno_initEnvironment");
+ }
+
+ (*m_uno_env->aBase.acquire)( &m_uno_env->aBase );
+ (*m_java_env->acquire)( m_java_env );
+
+ // java2uno
+ m_java2uno.acquire = Mapping_acquire;
+ m_java2uno.release = Mapping_release;
+ m_java2uno.mapInterface = Mapping_map_to_uno;
+ m_java2uno.m_bridge = this;
+ // uno2java
+ m_uno2java.acquire = Mapping_acquire;
+ m_uno2java.release = Mapping_release;
+ m_uno2java.mapInterface = Mapping_map_to_java;
+ m_uno2java.m_bridge = this;
+}
+
+
+Bridge::~Bridge()
+{
+ (*m_java_env->release)( m_java_env );
+ (*m_uno_env->aBase.release)( &m_uno_env->aBase );
+}
+
+JNI_info const * Bridge::getJniInfo() const {
+ return static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
+ ->info;
+}
+
+void JNI_context::java_exc_occurred() const
+{
+ // !don't rely on JNI_info!
+
+ JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() );
+ m_env->ExceptionClear();
+ assert(jo_exc.is());
+ if (! jo_exc.is())
+ {
+ throw BridgeRuntimeError(
+ "java exception occurred, but not available!?" +
+ get_stack_trace() );
+ }
+
+ // call toString(); don't rely on m_jni_info
+ jclass jo_class = m_env->FindClass( "java/lang/Object" );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "cannot get class java.lang.Object!" + get_stack_trace() );
+ }
+ JLocalAutoRef jo_Object( *this, jo_class );
+ // method Object.toString()
+ jmethodID method_Object_toString = m_env->GetMethodID(
+ static_cast<jclass>(jo_Object.get()), "toString", "()Ljava/lang/String;" );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "cannot get method id of java.lang.Object.toString()!" +
+ get_stack_trace() );
+ }
+ assert(method_Object_toString != nullptr);
+
+ JLocalAutoRef jo_descr(
+ *this, m_env->CallObjectMethodA(
+ jo_exc.get(), method_Object_toString, nullptr ) );
+ if (m_env->ExceptionCheck()) // no chance at all
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "error examining java exception object!" +
+ get_stack_trace() );
+ }
+
+ jsize len = m_env->GetStringLength( static_cast<jstring>(jo_descr.get()) );
+ std::unique_ptr< rtl_mem > ustr_mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
+ m_env->GetStringRegion( static_cast<jstring>(jo_descr.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ if (m_env->ExceptionCheck())
+ {
+ m_env->ExceptionClear();
+ throw BridgeRuntimeError(
+ "invalid java string object!" + get_stack_trace() );
+ }
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ OUString message( reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
+
+ throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) );
+}
+
+
+void JNI_context::getClassForName(
+ jclass * classClass, jmethodID * methodForName) const
+{
+ jclass c = m_env->FindClass("java/lang/Class");
+ if (c != nullptr) {
+ *methodForName = m_env->GetStaticMethodID(
+ c, "forName",
+ "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+ }
+ *classClass = c;
+}
+
+
+jclass JNI_context::findClass(
+ char const * name, jclass classClass, jmethodID methodForName,
+ bool inException) const
+{
+ jclass c = nullptr;
+ JLocalAutoRef s(*this, m_env->NewStringUTF(name));
+ if (s.is()) {
+ jvalue a[3];
+ a[0].l = s.get();
+ a[1].z = JNI_FALSE;
+ a[2].l = m_class_loader;
+ c = static_cast< jclass >(
+ m_env->CallStaticObjectMethodA(classClass, methodForName, a));
+ }
+ if (!inException) {
+ ensure_no_exception();
+ }
+ return c;
+}
+
+
+OUString JNI_context::get_stack_trace( jobject jo_exc ) const
+{
+ JLocalAutoRef jo_JNI_proxy(
+ *this,
+ find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
+ if (assert_no_exception())
+ {
+ // static method JNI_proxy.get_stack_trace()
+ jmethodID method = m_env->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "get_stack_trace",
+ "(Ljava/lang/Throwable;)Ljava/lang/String;" );
+ if (assert_no_exception() && (method != nullptr))
+ {
+ jvalue arg;
+ arg.l = jo_exc;
+ JLocalAutoRef jo_stack_trace(
+ *this, m_env->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_JNI_proxy.get()), method, &arg ) );
+ if (assert_no_exception())
+ {
+ jsize len =
+ m_env->GetStringLength( static_cast<jstring>(jo_stack_trace.get()) );
+ std::unique_ptr< rtl_mem > ustr_mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
+ m_env->GetStringRegion(
+ static_cast<jstring>(jo_stack_trace.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ if (assert_no_exception())
+ {
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ return OUString(
+ reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
+ }
+ }
+ }
+ }
+ return OUString();
+}
+
+}
+
+using namespace ::jni_uno;
+
+extern "C" {
+
+static void java_env_dispose(uno_Environment * env) {
+ auto * envData
+ = static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
+ if (envData == nullptr) return;
+
+ jobject async;
+ {
+ std::unique_lock g(envData->mutex);
+ async = envData->asynchronousFinalizer;
+ envData->asynchronousFinalizer = nullptr;
+ }
+ if (async == nullptr) return;
+
+ try {
+ JNI_guarded_context jni(envData->info, envData->machine);
+ jni->CallObjectMethodA(
+ async, envData->info->m_method_AsynchronousFinalizer_drain,
+ nullptr);
+ jni.ensure_no_exception();
+ jni->DeleteGlobalRef(async);
+ } catch (const BridgeRuntimeError & e) {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << e.m_message << "\"");
+ } catch (
+ jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN(
+ "bridges",
+ ("ignoring jvmaccess::VirtualMachine::AttachGuard"
+ "::CreationException"));
+ }
+}
+
+static void java_env_disposing(uno_Environment * env) {
+ java_env_dispose(env);
+ delete static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_initEnvironment java_uno_initEnvironment
+#endif
+
+
+SAL_DLLPUBLIC_EXPORT void uno_initEnvironment( uno_Environment * java_env )
+ SAL_THROW_EXTERN_C()
+{
+ try {
+ // JavaComponentLoader::getJavaLoader (in
+ // stoc/source/javaloader/javaloader.cxx) stores a
+ // jvmaccess::UnoVirtualMachine pointer into java_env->pContext; replace
+ // it here with either a pointer to a full JniUnoEnvironmentData upon
+ // success, or with a null pointer upon failure (as this function cannot
+ // directly report back failure, so it uses that way to indirectly
+ // report failure later from within the Bridge ctor):
+ rtl::Reference<jvmaccess::UnoVirtualMachine> vm(
+ static_cast<jvmaccess::UnoVirtualMachine *>(java_env->pContext));
+ java_env->pContext = nullptr;
+ java_env->dispose = java_env_dispose;
+ java_env->environmentDisposing = java_env_disposing;
+ java_env->pExtEnv = nullptr; // no extended support
+ std::unique_ptr<jni_uno::JniUnoEnvironmentData> envData(
+ new jni_uno::JniUnoEnvironmentData(vm));
+ {
+ JNI_guarded_context jni(envData->info, envData->machine);
+ JLocalAutoRef ref(
+ jni,
+ jni->NewObject(
+ envData->info->m_class_AsynchronousFinalizer,
+ envData->info->m_ctor_AsynchronousFinalizer));
+ jni.ensure_no_exception();
+ envData->asynchronousFinalizer = jni->NewGlobalRef(ref.get());
+ jni.ensure_no_exception();
+ }
+ java_env->pContext = envData.release();
+ } catch (const BridgeRuntimeError & e) {
+ SAL_WARN("bridges", "BridgeRuntimeError \"" << e.m_message << "\"");
+ } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ SAL_WARN(
+ "bridges",
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException");
+ }
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_ext_getMapping java_uno_ext_getMapping
+#endif
+
+
+SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(
+ uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping != nullptr);
+ assert(pFrom != nullptr);
+ assert(pTo != nullptr);
+ if (*ppMapping != nullptr)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ *ppMapping = nullptr;
+ }
+
+ static_assert(int(JNI_FALSE) == int(false), "must be equal");
+ static_assert(int(JNI_TRUE) == int(true), "must be equal");
+ static_assert(sizeof (jboolean) == sizeof (sal_Bool), "must be the same size");
+ static_assert(sizeof (jchar) == sizeof (sal_Unicode), "must be the same size");
+ static_assert(sizeof (jdouble) == sizeof (double), "must be the same size");
+ static_assert(sizeof (jfloat) == sizeof (float), "must be the same size");
+ static_assert(sizeof (jbyte) == sizeof (sal_Int8), "must be the same size");
+ static_assert(sizeof (jshort) == sizeof (sal_Int16), "must be the same size");
+ static_assert(sizeof (jint) == sizeof (sal_Int32), "must be the same size");
+ static_assert(sizeof (jlong) == sizeof (sal_Int64), "must be the same size");
+
+ OUString const & from_env_typename =
+ OUString::unacquired( &pFrom->pTypeName );
+ OUString const & to_env_typename =
+ OUString::unacquired( &pTo->pTypeName );
+
+ uno_Mapping * mapping = nullptr;
+
+ try
+ {
+ if ( from_env_typename == UNO_LB_JAVA && to_env_typename == UNO_LB_UNO )
+ {
+ Bridge * bridge =
+ new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
+ mapping = &bridge->m_java2uno;
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ pFrom, &pTo->pExtEnv->aBase, nullptr );
+ // coverity[leaked_storage] - on purpose
+ }
+ else if ( from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_JAVA )
+ {
+ Bridge * bridge =
+ new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
+ mapping = &bridge->m_uno2java;
+ uno_registerMapping(
+ &mapping, Bridge_free,
+ &pFrom->pExtEnv->aBase, pTo, nullptr );
+ // coverity[leaked_storage] - on purpose
+ }
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN("bridges", "BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+
+ *ppMapping = mapping;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_bridge.h b/bridges/source/jni_uno/jni_bridge.h
new file mode 100644
index 0000000000..ea55a13915
--- /dev/null
+++ b/bridges/source/jni_uno/jni_bridge.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include "jni_base.h"
+#include "jni_helper.h"
+
+#include <osl/diagnose.h>
+
+#include <uno/mapping.h>
+#include <uno/dispatcher.h>
+
+#include <com/sun/star/uno/XInterface.hpp>
+
+
+namespace jni_uno
+{
+
+class JNI_info;
+struct Bridge;
+
+struct Mapping : public uno_Mapping
+{
+ Bridge * m_bridge;
+};
+
+// Holds environments and mappings:
+struct Bridge
+{
+ mutable std::atomic<std::size_t> m_ref;
+
+ uno_ExtEnvironment * m_uno_env;
+ uno_Environment * m_java_env;
+
+ Mapping m_java2uno;
+ Mapping m_uno2java;
+ bool m_registered_java2uno;
+
+ ~Bridge();
+ explicit Bridge(
+ uno_Environment * java_env, uno_ExtEnvironment * uno_env,
+ bool registered_java2uno );
+
+ void acquire() const;
+ void release() const;
+
+ // jni_data.cxx
+ void map_to_uno(
+ JNI_context const & jni,
+ void * uno_data, jvalue java_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool assign, bool out_param,
+ bool special_wrapped_integral_types = false ) const;
+ void map_to_java(
+ JNI_context const & jni,
+ jvalue * java_data, void const * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool in_param, bool out_param,
+ bool special_wrapped_integral_types = false ) const;
+
+ // jni_uno2java.cxx
+ void handle_uno_exc(
+ JNI_context const & jni, uno_Any * uno_exc ) const;
+ void call_java(
+ jobject javaI,
+ typelib_InterfaceTypeDescription * iface_td,
+ sal_Int32 local_member_index, sal_Int32 function_pos_offset,
+ typelib_TypeDescriptionReference * return_type,
+ typelib_MethodParameter * params, sal_Int32 nParams,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const;
+ jobject map_to_java(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, JNI_interface_type_info const * info ) const;
+
+ // jni_java2uno.cxx
+ void handle_java_exc(
+ JNI_context const & jni,
+ JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const;
+ jobject call_uno(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, typelib_TypeDescription * member_td,
+ typelib_TypeDescriptionReference * return_tdref,
+ sal_Int32 nParams, typelib_MethodParameter const * pParams,
+ jobjectArray jo_args ) const;
+ uno_Interface * map_to_uno(
+ JNI_context const & jni,
+ jobject javaI, JNI_interface_type_info const * info ) const;
+
+ JNI_info const * getJniInfo() const;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_data.cxx b/bridges/source/jni_uno/jni_data.cxx
new file mode 100644
index 0000000000..06e8467f7e
--- /dev/null
+++ b/bridges/source/jni_uno/jni_data.cxx
@@ -0,0 +1,2476 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <memory>
+
+#include "jni_bridge.h"
+
+#include <rtl/strbuf.hxx>
+#include <uno/sequence2.h>
+
+namespace jni_uno
+{
+
+
+static std::unique_ptr<rtl_mem> seq_allocate(
+ sal_Int32 nElements, sal_Int32 nSize )
+{
+ std::unique_ptr< rtl_mem > seq(
+ rtl_mem::allocate( SAL_SEQUENCE_HEADER_SIZE + (nElements * nSize) ) );
+ uno_Sequence * p = reinterpret_cast<uno_Sequence *>(seq.get());
+ p->nRefCount = 1;
+ p->nElements = nElements;
+ return seq;
+}
+
+
+namespace {
+
+void createDefaultUnoValue(
+ JNI_context const & jni, void * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */, bool assign)
+{
+ switch (type->eTypeClass) {
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast< sal_Bool * >(uno_data) = false;
+ break;
+
+ case typelib_TypeClass_BYTE:
+ *static_cast< sal_Int8 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_SHORT:
+ *static_cast< sal_Int16 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast< sal_uInt16 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_LONG:
+ *static_cast< sal_Int32 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast< sal_uInt32 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_HYPER:
+ *static_cast< sal_Int64 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast< sal_uInt64 * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_FLOAT:
+ *static_cast< float * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_DOUBLE:
+ *static_cast< double * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_CHAR:
+ *static_cast< sal_Unicode * >(uno_data) = 0;
+ break;
+
+ case typelib_TypeClass_STRING:
+ if (!assign) {
+ *static_cast< rtl_uString ** >(uno_data) = nullptr;
+ }
+ rtl_uString_new(static_cast< rtl_uString ** >(uno_data));
+ break;
+
+ case typelib_TypeClass_TYPE:
+ if (assign) {
+ typelib_typedescriptionreference_release(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data));
+ }
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data)
+ = *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID);
+ assert(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data) != nullptr);
+ typelib_typedescriptionreference_acquire(
+ *static_cast< typelib_TypeDescriptionReference ** >(uno_data));
+ break;
+
+ case typelib_TypeClass_ANY:
+ if (assign) {
+ uno_any_destruct(static_cast< uno_Any * >(uno_data), nullptr);
+ }
+ uno_any_construct(
+ static_cast< uno_Any * >(uno_data), nullptr,
+ jni.get_info()->m_XInterface_type_info->m_td.get(), nullptr);
+ break;
+
+ case typelib_TypeClass_SEQUENCE:
+ {
+ std::unique_ptr< rtl_mem > seq(seq_allocate(0, 0));
+ if (assign) {
+ uno_type_destructData(uno_data, type, nullptr);
+ }
+ *static_cast< uno_Sequence ** >(uno_data)
+ = reinterpret_cast< uno_Sequence * >(seq.release());
+ break;
+ }
+
+ case typelib_TypeClass_ENUM:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type);
+ *static_cast< sal_Int32 * >(uno_data)
+ = (reinterpret_cast< typelib_EnumTypeDescription * >(td)->
+ nDefaultEnumValue);
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+
+ case typelib_TypeClass_STRUCT:
+ {
+ if (info == nullptr) {
+ info = jni.get_info()->get_type_info(jni, type);
+ }
+ JNI_compound_type_info const * comp_info
+ = static_cast< JNI_compound_type_info const * >(info);
+ typelib_CompoundTypeDescription * comp_td
+ = reinterpret_cast< typelib_CompoundTypeDescription * >(
+ comp_info->m_td.get());
+ sal_Int32 nPos = 0;
+ sal_Int32 nMembers = comp_td->nMembers;
+ try {
+ if (comp_td->pBaseTypeDescription != nullptr) {
+ createDefaultUnoValue(
+ jni, uno_data,
+ comp_td->pBaseTypeDescription->aBase.pWeakRef,
+ comp_info->m_base, assign);
+ }
+ for (; nPos < nMembers; ++nPos) {
+ createDefaultUnoValue(
+ jni,
+ (static_cast< char * >(uno_data)
+ + comp_td->pMemberOffsets[nPos]),
+ comp_td->ppTypeRefs[nPos], nullptr, assign);
+ }
+ } catch (...) {
+ if (!assign) {
+ for (sal_Int32 i = 0; i < nPos; ++i) {
+ uno_type_destructData(
+ (static_cast< char * >(uno_data)
+ + comp_td->pMemberOffsets[i]),
+ comp_td->ppTypeRefs[i], nullptr);
+ }
+ if (comp_td->pBaseTypeDescription != nullptr) {
+ uno_destructData(
+ uno_data, &comp_td->pBaseTypeDescription->aBase, nullptr);
+ }
+ }
+ throw;
+ }
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE:
+ if (assign) {
+ uno_Interface * p = *static_cast< uno_Interface ** >(uno_data);
+ if (p != nullptr) {
+ (*p->release)(p);
+ }
+ }
+ *static_cast< uno_Interface ** >(uno_data) = nullptr;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+}
+
+void Bridge::map_to_uno(
+ JNI_context const & jni,
+ void * uno_data, jvalue java_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool assign, bool out_param,
+ bool special_wrapped_integral_types ) const
+{
+ assert(
+ !out_param ||
+ (jni->GetArrayLength( static_cast<jarray>(java_data.l) ) == 1) );
+
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (out_param)
+ {
+ jni->GetCharArrayRegion(
+ static_cast<jcharArray>(java_data.l), 0, 1, static_cast<jchar *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jchar *>(uno_data) = jni->CallCharMethodA(
+ java_data.l, getJniInfo()->m_method_Character_charValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jchar *>(uno_data) = java_data.c;
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (out_param)
+ {
+ jni->GetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data.l), 0, 1, static_cast<jboolean *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jboolean *>(uno_data) = jni->CallBooleanMethodA(
+ java_data.l, getJniInfo()->m_method_Boolean_booleanValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jboolean *>(uno_data) = java_data.z;
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (out_param)
+ {
+ jni->GetByteArrayRegion(
+ static_cast<jbyteArray>(java_data.l), 0, 1, static_cast<jbyte *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jbyte *>(uno_data) = jni->CallByteMethodA(
+ java_data.l, getJniInfo()->m_method_Byte_byteValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jbyte *>(uno_data) = java_data.b;
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (out_param)
+ {
+ jni->GetShortArrayRegion(
+ static_cast<jshortArray>(java_data.l), 0, 1, static_cast<jshort *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jshort *>(uno_data) = jni->CallShortMethodA(
+ java_data.l, getJniInfo()->m_method_Short_shortValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jshort *>(uno_data) = java_data.s;
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (out_param)
+ {
+ jni->GetIntArrayRegion(
+ static_cast<jintArray>(java_data.l), 0, 1, static_cast<jint *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jint *>(uno_data) = jni->CallIntMethodA(
+ java_data.l, getJniInfo()->m_method_Integer_intValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jint *>(uno_data) = java_data.i;
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (out_param)
+ {
+ jni->GetLongArrayRegion(
+ static_cast<jlongArray>(java_data.l), 0, 1, static_cast<jlong *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jlong *>(uno_data) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jlong *>(uno_data) = java_data.j;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (out_param)
+ {
+ jni->GetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data.l), 0, 1, static_cast<jfloat *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jfloat *>(uno_data) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jfloat *>(uno_data) = java_data.f;
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (out_param)
+ {
+ jni->GetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data.l), 0, 1, static_cast<jdouble *>(uno_data) );
+ jni.ensure_no_exception();
+ }
+ else if (special_wrapped_integral_types)
+ {
+ *static_cast<jdouble *>(uno_data) = jni->CallDoubleMethodA(
+ java_data.l, getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ *static_cast<jdouble *>(uno_data) = java_data.d;
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+ if (! assign)
+ *static_cast<rtl_uString **>(uno_data) = nullptr;
+ jstring_to_ustring(
+ jni, static_cast<rtl_uString **>(uno_data), static_cast<jstring>(java_data.l) );
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ // type name
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Type_typeName ) );
+ if (! jo_type_name.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] incomplete type object: no type name!"
+ + jni.get_stack_trace() );
+ }
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+ ::com::sun::star::uno::TypeDescription td( type_name );
+ if (! td.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] UNO type not found: " + type_name
+ + jni.get_stack_trace() );
+ }
+ typelib_typedescriptionreference_acquire( td.get()->pWeakRef );
+ if (assign)
+ {
+ typelib_typedescriptionreference_release(
+ *static_cast<typelib_TypeDescriptionReference **>(uno_data) );
+ }
+ *static_cast<typelib_TypeDescriptionReference **>(uno_data) = td.get()->pWeakRef;
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+
+ uno_Any * pAny = static_cast<uno_Any *>(uno_data);
+ if (java_data.l == nullptr) // null-ref maps to XInterface null-ref
+ {
+ if (assign)
+ uno_any_destruct( pAny, nullptr );
+ uno_any_construct(
+ pAny, nullptr, getJniInfo()->m_XInterface_type_info->m_td.get(), nullptr );
+ break;
+ }
+
+ JLocalAutoRef jo_type( jni );
+ JLocalAutoRef jo_wrapped_holder( jni );
+
+ if (jni->IsInstanceOf( java_data.l, getJniInfo()->m_class_Any ))
+ {
+ // boxed any
+ jo_type.reset( jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Any_type ) );
+ if (! jo_type.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] no type set at com.sun.star.uno.Any!"
+ + jni.get_stack_trace() );
+ }
+ // wrapped value
+ jo_wrapped_holder.reset(
+ jni->GetObjectField(
+ java_data.l, getJniInfo()->m_field_Any_object ) );
+ java_data.l = jo_wrapped_holder.get();
+ }
+ else
+ {
+ // create type out of class
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( java_data.l ) );
+ jo_type.reset( create_type( jni, static_cast<jclass>(jo_class.get()) ) );
+ }
+
+ // get type name
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ jo_type.get(), getJniInfo()->m_field_Type_typeName ) );
+ jni.ensure_no_exception();
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+
+ ::com::sun::star::uno::TypeDescription value_td( type_name );
+ if (! value_td.is())
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] UNO type not found: " + type_name
+ + jni.get_stack_trace() );
+ }
+ typelib_TypeClass type_class = value_td.get()->eTypeClass;
+
+ if (assign)
+ {
+ uno_any_destruct( pAny, nullptr );
+ }
+ try
+ {
+ switch (type_class)
+ {
+ case typelib_TypeClass_VOID:
+ pAny->pData = &pAny->pReserved;
+ break;
+ case typelib_TypeClass_CHAR:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jchar *>(pAny->pData) = jni->CallCharMethodA(
+ java_data.l, getJniInfo()->m_method_Character_charValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jboolean *>(pAny->pData) = jni->CallBooleanMethodA(
+ java_data.l, getJniInfo()->m_method_Boolean_booleanValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BYTE:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jbyte *>(pAny->pData) = jni->CallByteMethodA(
+ java_data.l, getJniInfo()->m_method_Byte_byteValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jshort *>(pAny->pData) = jni->CallShortMethodA(
+ java_data.l, getJniInfo()->m_method_Short_shortValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jint *>(pAny->pData) = jni->CallIntMethodA(
+ java_data.l, getJniInfo()->m_method_Integer_intValue, nullptr );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof (sal_Int64) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jlong *>(pAny->pData) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (sal_Int64) ) );
+ *reinterpret_cast<jlong *>(mem.get()) = jni->CallLongMethodA(
+ java_data.l, getJniInfo()->m_method_Long_longValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof (float) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jfloat *>(pAny->pData) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (float) ) );
+ *reinterpret_cast<jfloat *>(mem.get()) = jni->CallFloatMethodA(
+ java_data.l, getJniInfo()->m_method_Float_floatValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof (double) <= sizeof (void *))
+ {
+ pAny->pData = &pAny->pReserved;
+ *static_cast<jdouble *>(pAny->pData) =
+ jni->CallDoubleMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( sizeof (double) ) );
+ *reinterpret_cast<jdouble *>(mem.get()) =
+ jni->CallDoubleMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Double_doubleValue, nullptr );
+ jni.ensure_no_exception();
+ pAny->pData = mem.release();
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ // opt: anies often contain strings; copy string directly
+ pAny->pReserved = nullptr;
+ pAny->pData = &pAny->pReserved;
+ jstring_to_ustring(
+ jni, static_cast<rtl_uString **>(pAny->pData),
+ static_cast<jstring>(java_data.l) );
+ break;
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ pAny->pData = &pAny->pReserved;
+ map_to_uno(
+ jni, pAny->pData, java_data,
+ value_td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate( value_td.get()->nSize ) );
+ map_to_uno(
+ jni, mem.get(), java_data, value_td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+ pAny->pData = mem.release();
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + type_name
+ + "] unsupported value type of any!"
+ + jni.get_stack_trace() );
+ }
+ }
+ }
+ catch (...)
+ {
+ if (assign)
+ {
+ // restore to valid any
+ uno_any_construct( pAny, nullptr, nullptr, nullptr );
+ }
+ throw;
+ }
+ typelib_typedescriptionreference_acquire( value_td.get()->pWeakRef );
+ pAny->pType = value_td.get()->pWeakRef;
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ *static_cast<jint *>(uno_data) = jni->GetIntField(
+ java_data.l, getJniInfo()->m_field_Enum_m_value );
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_compound_type_info const * comp_info =
+ static_cast< JNI_compound_type_info const * >( info );
+
+ typelib_CompoundTypeDescription * comp_td =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(comp_info->m_td.get());
+ bool polymorphic
+ = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes != nullptr;
+
+ sal_Int32 nPos = 0;
+ sal_Int32 nMembers = comp_td->nMembers;
+ try
+ {
+ if (comp_td->pBaseTypeDescription != nullptr)
+ {
+ map_to_uno(
+ jni, uno_data, java_data,
+ comp_td->pBaseTypeDescription->aBase.pWeakRef,
+ comp_info->m_base,
+ assign, false /* no out param */ );
+ }
+
+ for ( ; nPos < nMembers; ++nPos )
+ {
+ void * p = static_cast<char *>(uno_data) + comp_td->pMemberOffsets[ nPos ];
+ typelib_TypeDescriptionReference * member_type =
+ comp_td->ppTypeRefs[ nPos ];
+ jfieldID field_id = comp_info->m_fields[ nPos ];
+ bool parameterizedType = polymorphic
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes[nPos];
+ switch (member_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jchar *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jchar *>(p) = jni->GetCharField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jboolean *>(p) = false;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jboolean *>(p) = jni->GetBooleanField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jbyte *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jbyte *>(p) = jni->GetByteField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jshort *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jshort *>(p) = jni->GetShortField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jint *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jint *>(p) = jni->GetIntField( java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jlong *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jlong *>(p) = jni->GetLongField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jfloat *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jfloat *>(p) = jni->GetFloatField(
+ java_data.l, field_id );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (parameterizedType) {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectField( java_data.l, field_id ) );
+ if ( jo.get() == nullptr ) {
+ *static_cast<jdouble *>(p) = 0;
+ } else {
+ jvalue val;
+ val.l = jo.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr, assign, false,
+ true );
+ }
+ } else {
+ *static_cast<jdouble *>(p) = jni->GetDoubleField(
+ java_data.l, field_id );
+ }
+ break;
+ default:
+ {
+ JLocalAutoRef jo_field( jni );
+ bool checkNull;
+ if (field_id == nullptr)
+ {
+ // special for Message: call Throwable.getMessage()
+ assert(
+ type_equals(
+ type,
+ getJniInfo()->m_Exception_type.getTypeLibType() )
+ || type_equals(
+ type,
+ getJniInfo()->m_RuntimeException_type.
+ getTypeLibType() ) );
+ assert( nPos == 0 ); // first member
+ // call getMessage()
+ jo_field.reset(
+ jni->CallObjectMethodA(
+ java_data.l,
+ getJniInfo()->m_method_Throwable_getMessage, nullptr )
+ );
+ jni.ensure_no_exception();
+ checkNull = true;
+ }
+ else
+ {
+ jo_field.reset(
+ jni->GetObjectField( java_data.l, field_id ) );
+ checkNull = parameterizedType;
+ }
+ if (checkNull && !jo_field.is()) {
+ createDefaultUnoValue(jni, p, member_type, nullptr, assign);
+ } else {
+ jvalue val;
+ val.l = jo_field.get();
+ map_to_uno(
+ jni, p, val, member_type, nullptr,
+ assign, false /* no out param */ );
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ if (! assign)
+ {
+ // cleanup
+ for ( sal_Int32 nCleanup = 0; nCleanup < nPos; ++nCleanup )
+ {
+ void * p =
+ static_cast<char *>(uno_data) + comp_td->pMemberOffsets[ nCleanup ];
+ uno_type_destructData(
+ p, comp_td->ppTypeRefs[ nCleanup ], nullptr );
+ }
+ if (comp_td->pBaseTypeDescription != nullptr)
+ {
+ uno_destructData(
+ uno_data, &comp_td->pBaseTypeDescription->aBase, nullptr );
+ }
+ }
+ throw;
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+ if (java_data.l == nullptr)
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] null-ref given!" + jni.get_stack_trace() );
+ }
+
+ TypeDescr td( type );
+ typelib_TypeDescriptionReference * element_type =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType;
+
+ std::unique_ptr< rtl_mem > seq;
+ sal_Int32 nElements = jni->GetArrayLength( static_cast<jarray>(java_data.l) );
+
+ switch (element_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ seq = seq_allocate( nElements, sizeof (sal_Unicode) );
+ jni->GetCharArrayRegion(
+ static_cast<jcharArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jchar *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ seq = seq_allocate( nElements, sizeof (sal_Bool) );
+ jni->GetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jboolean *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_BYTE:
+ seq = seq_allocate( nElements, sizeof (sal_Int8) );
+ jni->GetByteArrayRegion(
+ static_cast<jbyteArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jbyte *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ seq = seq_allocate( nElements, sizeof (sal_Int16) );
+ jni->GetShortArrayRegion(
+ static_cast<jshortArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jshort *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ seq = seq_allocate( nElements, sizeof (sal_Int32) );
+ jni->GetIntArrayRegion(
+ static_cast<jintArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jint *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ seq = seq_allocate( nElements, sizeof (sal_Int64) );
+ jni->GetLongArrayRegion(
+ static_cast<jlongArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jlong *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_FLOAT:
+ seq = seq_allocate( nElements, sizeof (float) );
+ jni->GetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jfloat *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_DOUBLE:
+ seq = seq_allocate( nElements, sizeof (double) );
+ jni->GetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data.l), 0, nElements,
+ reinterpret_cast<jdouble *>(reinterpret_cast<uno_Sequence *>(seq.get())->elements) );
+ jni.ensure_no_exception();
+ break;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ {
+ TypeDescr element_td( element_type );
+ seq = seq_allocate( nElements, element_td.get()->nSize );
+
+ JNI_type_info const * element_info;
+ if (element_type->eTypeClass == typelib_TypeClass_STRUCT ||
+ element_type->eTypeClass == typelib_TypeClass_EXCEPTION ||
+ element_type->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ element_info =
+ getJniInfo()->get_type_info( jni, element_td.get() );
+ }
+ else
+ {
+ element_info = nullptr;
+ }
+
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ try
+ {
+ JLocalAutoRef jo(
+ jni, jni->GetObjectArrayElement(
+ static_cast<jobjectArray>(java_data.l), nPos ) );
+ jni.ensure_no_exception();
+ jvalue val;
+ val.l = jo.get();
+ void * p =
+ reinterpret_cast<uno_Sequence *>(seq.get())->elements +
+ (nPos * element_td.get()->nSize);
+ map_to_uno(
+ jni, p, val, element_td.get()->pWeakRef, element_info,
+ false /* no assign */, false /* no out param */ );
+ }
+ catch (...)
+ {
+ // cleanup
+ for ( sal_Int32 nCleanPos = 0;
+ nCleanPos < nPos; ++nCleanPos )
+ {
+ void * p =
+ reinterpret_cast<uno_Sequence *>(seq.get())->elements +
+ (nCleanPos * element_td.get()->nSize);
+ uno_destructData( p, element_td.get(), nullptr );
+ }
+ throw;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported sequence element type: "
+ + OUString::unacquired( &element_type->pTypeName )
+ + jni.get_stack_trace() );
+ }
+ }
+
+ if (assign)
+ uno_destructData( uno_data, td.get(), nullptr );
+ *static_cast<uno_Sequence **>(uno_data) = reinterpret_cast<uno_Sequence *>(seq.release());
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JLocalAutoRef jo_out_holder( jni );
+ if (out_param)
+ {
+ jo_out_holder.reset(
+ jni->GetObjectArrayElement( static_cast<jobjectArray>(java_data.l), 0 ) );
+ jni.ensure_no_exception();
+ java_data.l = jo_out_holder.get();
+ }
+
+ if (java_data.l == nullptr) // null-ref
+ {
+ if (assign)
+ {
+ uno_Interface * p = *static_cast<uno_Interface **>(uno_data);
+ if (p != nullptr)
+ (*p->release)( p );
+ }
+ *static_cast<uno_Interface **>(uno_data) = nullptr;
+ }
+ else
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+ uno_Interface * pUnoI = map_to_uno( jni, java_data.l, iface_info );
+ if (assign)
+ {
+ uno_Interface * p = *static_cast<uno_Interface **>(uno_data);
+ if (p != nullptr)
+ (*p->release)( p );
+ }
+ *static_cast<uno_Interface **>(uno_data) = pUnoI;
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_uno():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported type!" + jni.get_stack_trace() );
+ }
+ }
+}
+
+
+void Bridge::map_to_java(
+ JNI_context const & jni,
+ jvalue * java_data, void const * uno_data,
+ typelib_TypeDescriptionReference * type,
+ JNI_type_info const * info /* maybe 0 */,
+ bool in_param, bool out_param,
+ bool special_wrapped_integral_types ) const
+{
+ // 4th param of Set*ArrayRegion changed from pointer to non-const to pointer
+ // to const between <http://docs.oracle.com/javase/6/docs/technotes/guides/
+ // jni/spec/functions.html#wp22933> and <http://docs.oracle.com/javase/7/
+ // docs/technotes/guides/jni/spec/functions.html#wp22933>; work around that
+ // difference in a way that doesn't trigger loplugin:redundantcast:
+ void * data = const_cast<void *>(uno_data);
+
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewCharArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(jo_ar.get()), 0, 1, static_cast<jchar *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(java_data->l), 0, 1, static_cast<jchar *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.c = *static_cast<jchar const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Character,
+ getJniInfo()->m_ctor_Character_with_char, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->c = *static_cast<jchar const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewBooleanArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(jo_ar.get()),
+ 0, 1, static_cast<jboolean *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(java_data->l),
+ 0, 1, static_cast<jboolean *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.z = *static_cast<jboolean const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Boolean,
+ getJniInfo()->m_ctor_Boolean_with_boolean, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->z = *static_cast<jboolean const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewByteArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(jo_ar.get()), 0, 1, static_cast<jbyte *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(java_data->l), 0, 1, static_cast<jbyte *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.b = *static_cast<jbyte const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Byte,
+ getJniInfo()->m_ctor_Byte_with_byte, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->b = *static_cast<jbyte const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewShortArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(jo_ar.get()), 0, 1, static_cast<jshort *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(java_data->l), 0, 1, static_cast<jshort *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.s = *static_cast<jshort const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->s = *static_cast<jshort const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewIntArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(jo_ar.get()), 0, 1, static_cast<jint *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(java_data->l), 0, 1, static_cast<jint *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->i = *static_cast<jint const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewLongArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(jo_ar.get()), 0, 1, static_cast<jlong *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(java_data->l), 0, 1, static_cast<jlong *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.j = *static_cast<jlong const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->j = *static_cast<jlong const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewFloatArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(jo_ar.get()), 0, 1, static_cast<jfloat *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(java_data->l), 0, 1, static_cast<jfloat *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.f = *static_cast<jfloat const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Float,
+ getJniInfo()->m_ctor_Float_with_float, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->f = *static_cast<jfloat const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_ar( jni, jni->NewDoubleArray( 1 ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(jo_ar.get()),
+ 0, 1, static_cast<jdouble *>(data) );
+ jni.ensure_no_exception();
+ }
+ java_data->l = jo_ar.release();
+ }
+ else
+ {
+ if (in_param)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(java_data->l),
+ 0, 1, static_cast<jdouble *>(data) );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ else if (special_wrapped_integral_types)
+ {
+ jvalue arg;
+ arg.d = *static_cast<double const *>(uno_data);
+ java_data->l = jni->NewObjectA(
+ getJniInfo()->m_class_Double,
+ getJniInfo()->m_ctor_Double_with_double, &arg );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ java_data->d = *static_cast<jdouble const *>(uno_data);
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ if (out_param)
+ {
+ JLocalAutoRef jo_in( jni );
+ if (in_param)
+ {
+ jo_in.reset(
+ ustring_to_jstring(
+ jni, *static_cast<rtl_uString * const *>(uno_data) ) );
+ }
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_String, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ assert( in_param );
+ java_data->l =
+ ustring_to_jstring( jni, *static_cast<rtl_uString * const *>(uno_data) );
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ if (out_param)
+ {
+ JLocalAutoRef jo_in( jni );
+ if (in_param)
+ {
+ jo_in.reset(
+ create_type(
+ jni,
+ *static_cast<typelib_TypeDescriptionReference * const *>(uno_data) )
+ );
+ }
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_Type, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_in.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ assert( in_param );
+ java_data->l =
+ create_type(
+ jni,
+ *static_cast<typelib_TypeDescriptionReference * const *>(uno_data) );
+ }
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ JLocalAutoRef jo_any( jni );
+ if (in_param)
+ {
+ uno_Any const * pAny = static_cast<uno_Any const *>(uno_data);
+ switch (pAny->pType->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ jo_any.reset(
+ jni->NewLocalRef( getJniInfo()->m_object_Any_VOID ) );
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].s = *static_cast<jshort const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_SHORT;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].i = *static_cast<jint const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_LONG;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ jvalue args[ 2 ];
+ args[ 0 ].j = *static_cast<jlong const *>(pAny->pData);
+ JLocalAutoRef jo_val(
+ jni, jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long, args ) );
+ jni.ensure_no_exception();
+ // box up in com.sun.star.uno.Any
+ args[ 0 ].l = getJniInfo()->m_object_Type_UNSIGNED_HYPER;
+ args[ 1 ].l = jo_val.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ case typelib_TypeClass_STRING: // opt strings
+ jo_any.reset( ustring_to_jstring(
+ jni, static_cast<rtl_uString *>(pAny->pReserved) ) );
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ {
+ jvalue java_data2;
+ // prefetch sequence td
+ TypeDescr seq_td( pAny->pType );
+ map_to_java(
+ jni, &java_data2, pAny->pData, seq_td.get()->pWeakRef, nullptr,
+ true /* in */, false /* no out */,
+ true /* create integral wrappers */ );
+ jo_any.reset( java_data2.l );
+
+ // determine inner element type
+ ::com::sun::star::uno::Type element_type(
+ reinterpret_cast<typelib_IndirectTypeDescription *>(seq_td.get())->pType );
+ while (element_type.getTypeLibType()->eTypeClass ==
+ typelib_TypeClass_SEQUENCE)
+ {
+ TypeDescr element_td( element_type.getTypeLibType() );
+ typelib_typedescriptionreference_assign(
+ reinterpret_cast< typelib_TypeDescriptionReference ** >(
+ &element_type ),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(element_td.get())
+ ->pType );
+ }
+ // box up only if unsigned element type
+ switch (element_type.getTypeLibType()->eTypeClass)
+ {
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ jvalue args[ 2 ];
+ JLocalAutoRef jo_type(
+ jni, create_type( jni, seq_td.get()->pWeakRef ) );
+ args[ 0 ].l = jo_type.get();
+ args[ 1 ].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ uno_Interface * pUnoI = static_cast<uno_Interface *>(pAny->pReserved);
+ if (is_XInterface( pAny->pType ))
+ {
+ if (pUnoI != nullptr)
+ {
+ jo_any.reset(
+ map_to_java(
+ jni, pUnoI,
+ getJniInfo()->m_XInterface_type_info ) );
+ }
+ // else: empty XInterface ref maps to null-ref
+ }
+ else
+ {
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, pAny->pType ) );
+ if (pUnoI != nullptr)
+ {
+ jo_any.reset( map_to_java( jni, pUnoI, iface_info ) );
+ }
+ // box up in com.sun.star.uno.Any
+ jvalue args[ 2 ];
+ args[ 0 ].l = iface_info->m_type;
+ args[ 1 ].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args ) );
+ jni.ensure_no_exception();
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ {
+ // Do not lose information about type arguments of instantiated
+ // polymorphic struct types:
+ OUString const & name = OUString::unacquired(
+ &pAny->pType->pTypeName);
+ assert(!name.isEmpty());
+ if (name[name.getLength() - 1] == '>')
+ {
+ // Box up in com.sun.star.uno.Any:
+ JLocalAutoRef jo_type(jni, create_type(jni, pAny->pType));
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, pAny->pData, pAny->pType, nullptr, true,
+ false);
+ jo_any.reset(java_data2.l);
+ jvalue args[2];
+ args[0].l = jo_type.get();
+ args[1].l = jo_any.get();
+ jo_any.reset(
+ jni->NewObjectA(
+ getJniInfo()->m_class_Any,
+ getJniInfo()->m_ctor_Any_with_Type_Object, args));
+ jni.ensure_no_exception();
+ break;
+ }
+ [[fallthrough]];
+ }
+ default:
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, pAny->pData, pAny->pType, nullptr,
+ true /* in */, false /* no out */,
+ true /* create integral wrappers */ );
+ jo_any.reset( java_data2.l );
+ break;
+ }
+ }
+ }
+
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, getJniInfo()->m_class_Object, jo_any.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_any.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_any.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ OUString const & type_name = OUString::unacquired( &type->pTypeName );
+ OString class_name(
+ OUStringToOString( type_name, RTL_TEXTENCODING_JAVA_UTF8 ) );
+ JLocalAutoRef jo_enum_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ JLocalAutoRef jo_enum( jni );
+ if (in_param)
+ {
+ // call static <enum_class>.fromInt( int )
+ OString sig = "(I)L" + class_name.replace( '.', '/' ) + ";";
+ jmethodID method_id = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_enum_class.get()), "fromInt", sig.getStr() );
+ jni.ensure_no_exception();
+ assert( method_id != nullptr );
+
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(uno_data);
+ jo_enum.reset(
+ jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_enum_class.get()), method_id, &arg ) );
+ jni.ensure_no_exception();
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_enum_class.get()), jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_enum.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_compound_type_info const * comp_info =
+ static_cast< JNI_compound_type_info const * >( info );
+
+ JLocalAutoRef jo_comp( jni );
+ if (in_param)
+ {
+ if (type->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ JLocalAutoRef jo_message(
+ jni, ustring_to_jstring( jni, *static_cast<rtl_uString * const *>(uno_data) ) );
+ jvalue arg;
+ arg.l = jo_message.get();
+ jo_comp.reset(
+ jni->NewObjectA(
+ comp_info->m_class, comp_info->m_exc_ctor, &arg ) );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jo_comp.reset( jni->AllocObject( comp_info->m_class ) );
+ jni.ensure_no_exception();
+ }
+
+ for ( JNI_compound_type_info const * linfo = comp_info;
+ linfo != nullptr;
+ linfo = static_cast< JNI_compound_type_info const * >(
+ linfo->m_base ) )
+ {
+ typelib_CompoundTypeDescription * comp_td =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(linfo->m_td.get());
+ typelib_TypeDescriptionReference ** ppMemberTypeRefs =
+ comp_td->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = comp_td->pMemberOffsets;
+ bool polymorphic
+ = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ comp_td)->pParameterizedTypes != nullptr;
+ for ( sal_Int32 nPos = comp_td->nMembers; nPos--; )
+ {
+ jfieldID field_id = linfo->m_fields[ nPos ];
+ if (field_id != nullptr)
+ {
+ void const * p =
+ static_cast<char const *>(uno_data) + pMemberOffsets[ nPos ];
+ typelib_TypeDescriptionReference * member_type =
+ ppMemberTypeRefs[ nPos ];
+ bool parameterizedType = polymorphic
+ && (reinterpret_cast<
+ typelib_StructTypeDescription * >(comp_td)->
+ pParameterizedTypes[nPos]);
+ switch (member_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.c = *static_cast<jchar const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Character,
+ getJniInfo()->m_ctor_Character_with_char,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetCharField(
+ jo_comp.get(),
+ field_id, *static_cast<jchar const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.z = *static_cast<jboolean const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Boolean,
+ getJniInfo()->m_ctor_Boolean_with_boolean,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetBooleanField(
+ jo_comp.get(),
+ field_id, *static_cast<jboolean const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.b = *static_cast<jbyte const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Byte,
+ getJniInfo()->m_ctor_Byte_with_byte,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetByteField(
+ jo_comp.get(),
+ field_id, *static_cast<jbyte const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.s = *static_cast<jshort const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Short,
+ getJniInfo()->m_ctor_Short_with_short,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetShortField(
+ jo_comp.get(),
+ field_id, *static_cast<jshort const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.i = *static_cast<jint const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Integer,
+ getJniInfo()->m_ctor_Integer_with_int,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetIntField(
+ jo_comp.get(),
+ field_id, *static_cast<jint const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.j = *static_cast<jlong const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Long,
+ getJniInfo()->m_ctor_Long_with_long,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetLongField(
+ jo_comp.get(),
+ field_id, *static_cast<jlong const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.f = *static_cast<jfloat const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Float,
+ getJniInfo()->m_ctor_Float_with_float,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetFloatField(
+ jo_comp.get(),
+ field_id, *static_cast<jfloat const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (parameterizedType) {
+ jvalue arg;
+ arg.d = *static_cast<jdouble const *>(p);
+ JLocalAutoRef jo(
+ jni,
+ jni->NewObjectA(
+ getJniInfo()->m_class_Double,
+ getJniInfo()->m_ctor_Double_with_double,
+ &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo.get() );
+ } else {
+ jni->SetDoubleField(
+ jo_comp.get(),
+ field_id, *static_cast<jdouble const *>(p) );
+ }
+ break;
+ case typelib_TypeClass_STRING: // string opt here
+ {
+ JLocalAutoRef jo_string(
+ jni, ustring_to_jstring(
+ jni, *static_cast<rtl_uString * const *>(p) ) );
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo_string.get() );
+ break;
+ }
+ default:
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, p, member_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_obj( jni, java_data2.l );
+ jni->SetObjectField(
+ jo_comp.get(), field_id, jo_obj.get() );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ java_data->l =
+ jni->NewObjectArray( 1, comp_info->m_class, jo_comp.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_comp.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_comp.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ // xxx todo: possible opt for pure out sequences
+ JLocalAutoRef jo_ar( jni );
+
+ sal_Int32 nElements;
+ uno_Sequence * seq = nullptr;
+ if (in_param)
+ {
+ seq = *static_cast<uno_Sequence * const *>(uno_data);
+ nElements = seq->nElements;
+ }
+ else
+ {
+ nElements = 0;
+ }
+
+ TypeDescr td( type );
+ typelib_TypeDescriptionReference * element_type =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType;
+
+ switch (element_type->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ jo_ar.reset( jni->NewCharArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetCharArrayRegion(
+ static_cast<jcharArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jchar *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ jo_ar.reset( jni->NewBooleanArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetBooleanArrayRegion(
+ static_cast<jbooleanArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jboolean *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ jo_ar.reset( jni->NewByteArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetByteArrayRegion(
+ static_cast<jbyteArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jbyte *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ jo_ar.reset( jni->NewShortArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetShortArrayRegion(
+ static_cast<jshortArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jshort *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ jo_ar.reset( jni->NewIntArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetIntArrayRegion(
+ static_cast<jintArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jint *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ jo_ar.reset( jni->NewLongArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetLongArrayRegion(
+ static_cast<jlongArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jlong *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ jo_ar.reset( jni->NewFloatArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetFloatArrayRegion(
+ static_cast<jfloatArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jfloat *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ jo_ar.reset( jni->NewDoubleArray( nElements ) );
+ jni.ensure_no_exception();
+ if (0 < nElements)
+ {
+ jni->SetDoubleArrayRegion(
+ static_cast<jdoubleArray>(jo_ar.get()),
+ 0, nElements, reinterpret_cast<jdouble *>(seq->elements) );
+ jni.ensure_no_exception();
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, getJniInfo()->m_class_String, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ rtl_uString * const * pp =
+ reinterpret_cast<rtl_uString * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ JLocalAutoRef jo_string(
+ jni, ustring_to_jstring( jni, pp[ nPos ] ) );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_string.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_TYPE:
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, getJniInfo()->m_class_Type, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ typelib_TypeDescriptionReference * const * pp =
+ reinterpret_cast<typelib_TypeDescriptionReference * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, &pp[ nPos ], element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_ANY:
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, getJniInfo()->m_class_Object, nullptr ) );
+ jni.ensure_no_exception();
+ if (in_param)
+ {
+ uno_Any const * p = reinterpret_cast<uno_Any const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, &p[ nPos ], element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ {
+ OUString const & element_type_name =
+ OUString::unacquired( &element_type->pTypeName );
+ OString class_name(
+ OUStringToOString(
+ element_type_name, RTL_TEXTENCODING_JAVA_UTF8 ) );
+ JLocalAutoRef jo_enum_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, static_cast<jclass>(jo_enum_class.get()), nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ // call static <enum_class>.fromInt( int )
+ OString sig = "(I)L" + class_name.replace( '.', '/' ) + ";";
+ jmethodID method_id = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_enum_class.get()), "fromInt", sig.getStr() );
+ jni.ensure_no_exception();
+ assert( method_id != nullptr );
+
+ sal_Int32 const * p = reinterpret_cast<sal_Int32 const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue arg;
+ arg.i = p[ nPos ];
+ JLocalAutoRef jo_enum(
+ jni, jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_enum_class.get()), method_id, &arg ) );
+ jni.ensure_no_exception();
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_enum.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ JNI_type_info const * element_info =
+ getJniInfo()->get_type_info( jni, element_type );
+
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, element_info->m_class, nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ char * p = const_cast<char *>(seq->elements);
+ sal_Int32 nSize = element_info->m_td.get()->nSize;
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue val;
+ map_to_java(
+ jni, &val, p + (nSize * nPos),
+ element_type, element_info,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_element( jni, val.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ OStringBuffer buf( 64 );
+ JNI_info::append_sig(
+ &buf, element_type, false /* use class XInterface */,
+ false /* '.' instead of '/' */ );
+ OString class_name( buf.makeStringAndClear() );
+ JLocalAutoRef jo_seq_class(
+ jni, find_class( jni, class_name.getStr() ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray(
+ nElements, static_cast<jclass>(jo_seq_class.get()), nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ uno_Sequence * const * elements = reinterpret_cast<uno_Sequence * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ jvalue java_data2;
+ map_to_java(
+ jni, &java_data2, elements + nPos, element_type, nullptr,
+ true /* in */, false /* no out */ );
+ JLocalAutoRef jo_seq( jni, java_data2.l );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()), nPos, jo_seq.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, element_type ) );
+
+ jo_ar.reset(
+ jni->NewObjectArray( nElements, iface_info->m_class, nullptr ) );
+ jni.ensure_no_exception();
+
+ if (0 < nElements)
+ {
+ uno_Interface * const * pp = reinterpret_cast<uno_Interface * const *>(seq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
+ {
+ uno_Interface * pUnoI = pp[ nPos ];
+ if (pUnoI != nullptr)
+ {
+ JLocalAutoRef jo_element(
+ jni, map_to_java( jni, pUnoI, iface_info ) );
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(jo_ar.get()),
+ nPos, jo_element.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_java():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported element type: "
+ + OUString::unacquired( &element_type->pTypeName )
+ + jni.get_stack_trace() );
+ }
+ }
+
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ JLocalAutoRef jo_element_class(
+ jni, jni->GetObjectClass( jo_ar.get() ) );
+ if (in_param)
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_element_class.get()), jo_ar.get() );
+ }
+ else
+ {
+ java_data->l = jni->NewObjectArray(
+ 1, static_cast<jclass>(jo_element_class.get()), nullptr );
+ }
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_ar.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_ar.release();
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ JLocalAutoRef jo_iface( jni );
+ if (in_param)
+ {
+ uno_Interface * pUnoI = *static_cast<uno_Interface * const *>(uno_data);
+ if (pUnoI != nullptr)
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+ jo_iface.reset( map_to_java( jni, pUnoI, iface_info ) );
+ }
+ }
+ if (out_param)
+ {
+ if (java_data->l == nullptr)
+ {
+ if (info == nullptr)
+ info = getJniInfo()->get_type_info( jni, type );
+ java_data->l =
+ jni->NewObjectArray( 1, info->m_class, jo_iface.get() );
+ jni.ensure_no_exception();
+ }
+ else
+ {
+ jni->SetObjectArrayElement(
+ static_cast<jobjectArray>(java_data->l), 0, jo_iface.get() );
+ jni.ensure_no_exception();
+ }
+ }
+ else
+ {
+ java_data->l = jo_iface.release();
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "[map_to_java():" + OUString::unacquired( &type->pTypeName )
+ + "] unsupported type!" + jni.get_stack_trace() );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_helper.h b/bridges/source/jni_uno/jni_helper.h
new file mode 100644
index 0000000000..6e82e12f40
--- /dev/null
+++ b/bridges/source/jni_uno/jni_helper.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include "jni_base.h"
+#include "jni_info.h"
+
+
+namespace jni_uno
+{
+
+inline void jstring_to_ustring(
+ JNI_context const & jni, rtl_uString ** out_ustr, jstring jstr )
+{
+ if (nullptr == jstr)
+ {
+ rtl_uString_new( out_ustr );
+ }
+ else
+ {
+ jsize len = jni->GetStringLength( jstr );
+ std::unique_ptr< rtl_mem > mem(
+ rtl_mem::allocate(
+ sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
+ rtl_uString * ustr = reinterpret_cast<rtl_uString *>(mem.get());
+ jni->GetStringRegion( jstr, 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
+ jni.ensure_no_exception();
+ ustr->refCount = 1;
+ ustr->length = len;
+ ustr->buffer[ len ] = '\0';
+ // coverity[leaked_storage : FALSE] - transfer ownership to *out_ustr
+ mem.release();
+ if (nullptr != *out_ustr)
+ rtl_uString_release( *out_ustr );
+ *out_ustr = ustr;
+ }
+}
+
+inline OUString jstring_to_oustring(
+ JNI_context const & jni, jstring jstr )
+{
+ rtl_uString * ustr = nullptr;
+ jstring_to_ustring( jni, &ustr, jstr );
+ return OUString( ustr, SAL_NO_ACQUIRE );
+}
+
+inline jstring ustring_to_jstring(
+ JNI_context const & jni, rtl_uString const * ustr )
+{
+ jstring jstr = jni->NewString( reinterpret_cast<jchar const *>(ustr->buffer), ustr->length );
+ jni.ensure_no_exception();
+ return jstr;
+}
+
+
+// if inException, does not handle exceptions, in which case returned value will
+// be null if exception occurred:
+inline jclass find_class(
+ JNI_context const & jni, char const * class_name, bool inException = false )
+{
+ // find_class may be called before the JNI_info is set:
+ jclass c=nullptr;
+ jmethodID m;
+ JNI_info const * info = jni.get_info();
+ if (info == nullptr) {
+ jni.getClassForName(&c, &m);
+ if (c == nullptr) {
+ if (inException) {
+ return nullptr;
+ }
+ jni.ensure_no_exception();
+ }
+ } else {
+ c = info->m_class_Class;
+ m = info->m_method_Class_forName;
+ }
+ return jni.findClass(class_name, c, m, inException);
+}
+
+
+inline jobject create_type( JNI_context const & jni, jclass clazz )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue arg;
+ arg.l = clazz;
+ jobject jo_type = jni->NewObjectA(
+ jni_info->m_class_Type, jni_info->m_ctor_Type_with_Class, &arg );
+ jni.ensure_no_exception();
+ return jo_type;
+}
+
+inline jobject create_type(
+ JNI_context const & jni, typelib_TypeDescriptionReference * type )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue args[ 2 ];
+ // get type class
+ args[ 0 ].i = type->eTypeClass;
+ JLocalAutoRef jo_type_class(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_TypeClass,
+ jni_info->m_method_TypeClass_fromInt, args ) );
+ jni.ensure_no_exception();
+ // construct type
+ JLocalAutoRef jo_type_name(
+ jni, ustring_to_jstring( jni, type->pTypeName ) );
+ args[ 0 ].l = jo_type_name.get();
+ args[ 1 ].l = jo_type_class.get();
+ jobject jo_type = jni->NewObjectA(
+ jni_info->m_class_Type,
+ jni_info->m_ctor_Type_with_Name_TypeClass, args );
+ jni.ensure_no_exception();
+ return jo_type;
+}
+
+inline jobject compute_oid( JNI_context const & jni, jobject jo )
+{
+ JNI_info const * jni_info = jni.get_info();
+ jvalue arg;
+ arg.l= jo;
+ jobject jo_oid = jni->CallStaticObjectMethodA(
+ jni_info->m_class_UnoRuntime,
+ jni_info->m_method_UnoRuntime_generateOid, &arg );
+ jni.ensure_no_exception();
+ return jo_oid;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_info.cxx b/bridges/source/jni_uno/jni_info.cxx
new file mode 100644
index 0000000000..a48412897d
--- /dev/null
+++ b/bridges/source/jni_uno/jni_info.cxx
@@ -0,0 +1,978 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include "jni_bridge.h"
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <rtl/string.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <uno/lbnames.h>
+
+
+namespace jni_uno
+{
+
+
+JNI_type_info::JNI_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td )
+ : m_td( td ),
+ m_class( nullptr )
+{
+ m_td.makeComplete();
+ if (! m_td.get()->bComplete)
+ {
+ throw BridgeRuntimeError(
+ "cannot make type complete: "
+ + OUString::unacquired( &m_td.get()->pTypeName )
+ + jni.get_stack_trace() );
+ }
+}
+
+
+void JNI_interface_type_info::destroy( JNIEnv * jni_env )
+{
+ JNI_type_info::destruct( jni_env );
+ jni_env->DeleteGlobalRef( m_proxy_ctor );
+ jni_env->DeleteGlobalRef( m_type );
+ m_methods.reset();
+ delete this;
+}
+
+
+JNI_interface_type_info::JNI_interface_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td_ )
+ : JNI_type_info( jni, td_ )
+{
+ assert( m_td.get()->eTypeClass == typelib_TypeClass_INTERFACE );
+
+ OUString const & uno_name = OUString::unacquired( &m_td.get()->pTypeName );
+ JNI_info const * jni_info = jni.get_info();
+
+ JLocalAutoRef jo_class(
+ jni,
+ find_class(
+ jni,
+ ( OUStringToOString( uno_name, RTL_TEXTENCODING_JAVA_UTF8 ).
+ getStr() ) ) );
+ JLocalAutoRef jo_type( jni, create_type( jni, static_cast<jclass>(jo_class.get()) ) );
+
+ // get proxy ctor
+ jvalue arg;
+ arg.l = jo_class.get();
+ JLocalAutoRef jo_proxy_ctor(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_JNI_proxy,
+ jni_info->m_method_JNI_proxy_get_proxy_ctor, &arg ) );
+
+ if (is_XInterface( m_td.get()->pWeakRef ))
+ {
+ m_methods = nullptr; // no methods
+ }
+ else
+ {
+ // retrieve method ids for all direct members
+ try
+ {
+ typelib_InterfaceTypeDescription * td =
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ m_td.get() );
+ // coverity[ctor_dtor_leak] - on purpose
+ m_methods.reset(new jmethodID[ td->nMapFunctionIndexToMemberIndex ]);
+ sal_Int32 nMethodIndex = 0;
+ typelib_TypeDescriptionReference ** ppMembers = td->ppMembers;
+ sal_Int32 nMembers = td->nMembers;
+
+ for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos )
+ {
+ TypeDescr member_td( ppMembers[ nPos ] );
+
+ OStringBuffer sig_buf( 64 );
+
+ if (member_td.get()->eTypeClass ==
+ typelib_TypeClass_INTERFACE_METHOD) // method
+ {
+ typelib_InterfaceMethodTypeDescription * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member_td.get() );
+
+ sig_buf.append( '(' );
+ for ( sal_Int32 i = 0; i < method_td->nParams; ++i )
+ {
+ typelib_MethodParameter const & param =
+ method_td->pParams[ i ];
+ if (param.bOut)
+ sig_buf.append( '[' );
+ JNI_info::append_sig( &sig_buf, param.pTypeRef );
+ }
+ sig_buf.append( ')' );
+ JNI_info::append_sig( &sig_buf, method_td->pReturnTypeRef );
+
+ OString method_signature( sig_buf.makeStringAndClear() );
+ OString method_name(
+ OUStringToOString( OUString::unacquired(
+ &method_td->aBase.pMemberName ),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ }
+ else // attribute
+ {
+ assert(
+ member_td.get()->eTypeClass ==
+ typelib_TypeClass_INTERFACE_ATTRIBUTE );
+ typelib_InterfaceAttributeTypeDescription * attribute_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+
+ // type sig
+ JNI_info::append_sig(
+ &sig_buf, attribute_td->pAttributeTypeRef );
+ OString type_sig( sig_buf.makeStringAndClear() );
+ sig_buf.ensureCapacity( 64 );
+ // member name
+ OUString const & member_name =
+ OUString::unacquired(
+ &attribute_td->aBase.pMemberName );
+
+ // getter
+ sig_buf.append( "()" + type_sig );
+ OString method_signature( sig_buf.makeStringAndClear() );
+ OString method_name(
+ OUStringToOString(
+ rtl::Concat2View("get" + member_name),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ if (! attribute_td->bReadOnly)
+ {
+ // setter
+ method_signature = "(" + type_sig + ")V";
+ method_name = OUStringToOString(
+ rtl::Concat2View("set" + member_name),
+ RTL_TEXTENCODING_JAVA_UTF8 );
+ m_methods[ nMethodIndex ] = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), method_name.getStr(),
+ method_signature.getStr() );
+ jni.ensure_no_exception();
+ assert( m_methods[ nMethodIndex ] != nullptr );
+ ++nMethodIndex;
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ m_methods.reset();
+ throw;
+ }
+ }
+ m_class = static_cast<jclass>(jni->NewGlobalRef( jo_class.get() ));
+ m_type = jni->NewGlobalRef( jo_type.get() );
+ m_proxy_ctor = jni->NewGlobalRef( jo_proxy_ctor.get() );
+}
+
+
+void JNI_compound_type_info::destroy( JNIEnv * jni_env )
+{
+ JNI_type_info::destruct( jni_env );
+ m_fields.reset();
+ delete this;
+}
+
+
+JNI_compound_type_info::JNI_compound_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td_ )
+ : JNI_type_info( jni, td_ ),
+ m_exc_ctor( nullptr )
+{
+ assert( m_td.get()->eTypeClass == typelib_TypeClass_STRUCT ||
+ m_td.get()->eTypeClass == typelib_TypeClass_EXCEPTION );
+ typelib_CompoundTypeDescription * td =
+ reinterpret_cast< typelib_CompoundTypeDescription * >( m_td.get() );
+
+ OUString const & uno_name =
+ OUString::unacquired( &td->aBase.pTypeName );
+
+ // Erase type arguments of instantiated polymorphic struct types:
+ std::u16string_view nucleus;
+ sal_Int32 i = uno_name.indexOf( '<' );
+ if ( i < 0 ) {
+ nucleus = uno_name;
+ } else {
+ nucleus = uno_name.subView( 0, i );
+ }
+ JLocalAutoRef jo_class(
+ jni,
+ find_class(
+ jni,
+ OUStringToOString(
+ nucleus, RTL_TEXTENCODING_JAVA_UTF8 ).getStr() ) );
+
+ JNI_info const * jni_info = jni.get_info();
+
+ if (m_td.get()->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ // retrieve exc ctor( msg )
+ m_exc_ctor = jni->GetMethodID(
+ static_cast<jclass>(jo_class.get()), "<init>", "(Ljava/lang/String;)V" );
+ jni.ensure_no_exception();
+ assert( m_exc_ctor != nullptr );
+ }
+
+ // retrieve info for base type
+ typelib_TypeDescription * base_td =
+ type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_RuntimeException_type.getTypeLibType())
+ ? nullptr
+ : reinterpret_cast< typelib_TypeDescription * >(
+ td->pBaseTypeDescription );
+ m_base = (base_td == nullptr ? nullptr : jni_info->get_type_info( jni, base_td ));
+
+ try
+ {
+ if (type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_Exception_type.getTypeLibType() ) ||
+ type_equals(
+ td->aBase.pWeakRef,
+ jni_info->m_RuntimeException_type.getTypeLibType() ))
+ {
+ // coverity[ctor_dtor_leak] - on purpose
+ m_fields.reset(new jfieldID[ 2 ]);
+ m_fields[ 0 ] = nullptr; // special Throwable.getMessage()
+ // field Context
+ m_fields[ 1 ] = jni->GetFieldID(
+ static_cast<jclass>(jo_class.get()), "Context", "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_fields[ 1 ] != nullptr );
+ }
+ else
+ {
+ // retrieve field ids for all direct members
+ sal_Int32 nMembers = td->nMembers;
+ m_fields.reset(new jfieldID[ nMembers ]);
+
+ for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos )
+ {
+ OString sig;
+ if (td->aBase.eTypeClass == typelib_TypeClass_STRUCT
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ td)->pParameterizedTypes != nullptr
+ && reinterpret_cast< typelib_StructTypeDescription * >(
+ td)->pParameterizedTypes[nPos])
+ {
+ sig = "Ljava/lang/Object;"_ostr;
+ } else {
+ OStringBuffer sig_buf( 32 );
+ JNI_info::append_sig( &sig_buf, td->ppTypeRefs[ nPos ] );
+ sig = sig_buf.makeStringAndClear();
+ }
+
+ OString member_name(
+ OUStringToOString(
+ OUString::unacquired( &td->ppMemberNames[ nPos ] ),
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+
+ m_fields[ nPos ] = jni->GetFieldID(
+ static_cast<jclass>(jo_class.get()), member_name.getStr(),
+ sig.getStr() );
+ jni.ensure_no_exception();
+ assert( m_fields[ nPos ] != nullptr );
+ }
+ }
+ }
+ catch (...)
+ {
+ m_fields.reset();
+ throw;
+ }
+
+ m_class = static_cast<jclass>(jni->NewGlobalRef( jo_class.get() ));
+}
+
+
+JNI_type_info const * JNI_info::create_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const
+{
+ OUString const & uno_name = OUString::unacquired( &td->pTypeName );
+
+ JNI_type_info * new_info;
+ switch (td->eTypeClass)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ new_info = new JNI_compound_type_info( jni, td );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ new_info = new JNI_interface_type_info( jni, td );
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "type info not supported for " + uno_name + jni.get_stack_trace() );
+ }
+ }
+
+ // look up
+ JNI_type_info * info;
+ std::unique_lock guard( m_mutex );
+ JNI_type_info_holder & holder = m_type_map[ uno_name ];
+ if (holder.m_info == nullptr) // new insertion
+ {
+ holder.m_info = new_info;
+ guard.unlock();
+ info = new_info;
+ }
+ else // inserted in the meantime
+ {
+ info = holder.m_info;
+ guard.unlock();
+ new_info->destroy( jni.get_jni_env() );
+ }
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const
+{
+ if (is_XInterface( td->pWeakRef ))
+ {
+ return m_XInterface_type_info;
+ }
+
+ OUString const & uno_name = OUString::unacquired( &td->pTypeName );
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ info = create_type_info( jni, td );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, typelib_TypeDescriptionReference * type ) const
+{
+ if (is_XInterface( type ))
+ {
+ return m_XInterface_type_info;
+ }
+
+ OUString const & uno_name = OUString::unacquired( &type->pTypeName );
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ TypeDescr td( type );
+ info = create_type_info( jni, td.get() );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_type_info const * JNI_info::get_type_info(
+ JNI_context const & jni, OUString const & uno_name ) const
+{
+ if ( uno_name == "com.sun.star.uno.XInterface" )
+ {
+ return m_XInterface_type_info;
+ }
+
+ JNI_type_info const * info;
+ std::unique_lock guard( m_mutex );
+ t_str2type::const_iterator iFind( m_type_map.find( uno_name ) );
+ if (iFind == m_type_map.end())
+ {
+ guard.unlock();
+ css::uno::TypeDescription td( uno_name );
+ if (! td.is())
+ {
+ throw BridgeRuntimeError(
+ "UNO type not found: " + uno_name + jni.get_stack_trace() );
+ }
+ info = create_type_info( jni, td.get() );
+ }
+ else
+ {
+ info = iFind->second.m_info;
+ }
+
+ return info;
+}
+
+
+JNI_info::JNI_info(
+ JNIEnv * jni_env, jobject class_loader, jclass classClass,
+ jmethodID methodForName )
+ : m_class_Class( classClass ),
+ m_method_Class_forName( methodForName ),
+ m_class_JNI_proxy( nullptr ),
+ m_XInterface_queryInterface_td(
+ (reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ css::uno::TypeDescription(
+ cppu::UnoType<css::uno::XInterface>::get())
+ .get())->ppMembers[ 0 ] ) ),
+ m_Exception_type(cppu::UnoType<css::uno::Exception>::get()),
+ m_RuntimeException_type(cppu::UnoType<css::uno::RuntimeException>::get()),
+ m_void_type(cppu::UnoType<void>::get()),
+ m_XInterface_type_info( nullptr )
+{
+ JNI_context jni( this, jni_env, class_loader ); // !no proper jni_info!
+
+ // class lookup
+ JLocalAutoRef jo_Object(
+ jni, find_class( jni, "java.lang.Object" ) );
+ JLocalAutoRef jo_Class(
+ jni, find_class( jni, "java.lang.Class" ) );
+ JLocalAutoRef jo_Throwable(
+ jni, find_class( jni, "java.lang.Throwable" ) );
+ JLocalAutoRef jo_Character(
+ jni, find_class( jni, "java.lang.Character" ) );
+ JLocalAutoRef jo_Boolean(
+ jni, find_class( jni, "java.lang.Boolean" ) );
+ JLocalAutoRef jo_Byte(
+ jni, find_class( jni, "java.lang.Byte" ) );
+ JLocalAutoRef jo_Short(
+ jni, find_class( jni, "java.lang.Short" ) );
+ JLocalAutoRef jo_Integer(
+ jni, find_class( jni, "java.lang.Integer" ) );
+ JLocalAutoRef jo_Long(
+ jni, find_class( jni, "java.lang.Long" ) );
+ JLocalAutoRef jo_Float(
+ jni, find_class( jni, "java.lang.Float" ) );
+ JLocalAutoRef jo_Double(
+ jni, find_class( jni, "java.lang.Double" ) );
+ JLocalAutoRef jo_String(
+ jni, find_class( jni, "java.lang.String" ) );
+ JLocalAutoRef jo_RuntimeException(
+ jni, find_class( jni, "com.sun.star.uno.RuntimeException" ) );
+ JLocalAutoRef jo_UnoRuntime(
+ jni, find_class( jni, "com.sun.star.uno.UnoRuntime" ) );
+ JLocalAutoRef jo_Any(
+ jni, find_class( jni, "com.sun.star.uno.Any" ) );
+ JLocalAutoRef jo_Enum(
+ jni, find_class( jni, "com.sun.star.uno.Enum" ) );
+ JLocalAutoRef jo_Type(
+ jni, find_class( jni, "com.sun.star.uno.Type" ) );
+ JLocalAutoRef jo_TypeClass(
+ jni, find_class( jni, "com.sun.star.uno.TypeClass" ) );
+ JLocalAutoRef jo_IEnvironment(
+ jni, find_class( jni, "com.sun.star.uno.IEnvironment" ) );
+ JLocalAutoRef jo_JNI_proxy(
+ jni, find_class( jni, "com.sun.star.bridges.jni_uno.JNI_proxy" ) );
+ JLocalAutoRef jo_AsynchronousFinalizer(
+ jni, find_class( jni, "com.sun.star.lib.util.AsynchronousFinalizer" ) );
+
+ // method Object.toString()
+ m_method_Object_toString = jni->GetMethodID(
+ static_cast<jclass>(jo_Object.get()), "toString", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Object_toString != nullptr );
+ // method Class.getName()
+ m_method_Class_getName = jni->GetMethodID(
+ static_cast<jclass>(jo_Class.get()), "getName", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Class_getName != nullptr );
+
+ // method Throwable.getMessage()
+ m_method_Throwable_getMessage = jni->GetMethodID(
+ static_cast<jclass>(jo_Throwable.get()), "getMessage", "()Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_Throwable_getMessage != nullptr );
+
+ // method Character.charValue()
+ m_method_Character_charValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Character.get()), "charValue", "()C" );
+ jni.ensure_no_exception();
+ assert( m_method_Character_charValue != nullptr );
+ // method Boolean.booleanValue()
+ m_method_Boolean_booleanValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Boolean.get()), "booleanValue", "()Z" );
+ jni.ensure_no_exception();
+ assert( m_method_Boolean_booleanValue != nullptr );
+ // method Byte.byteValue()
+ m_method_Byte_byteValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Byte.get()), "byteValue", "()B" );
+ jni.ensure_no_exception();
+ assert( m_method_Byte_byteValue != nullptr );
+ // method Short.shortValue()
+ m_method_Short_shortValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Short.get()), "shortValue", "()S" );
+ jni.ensure_no_exception();
+ assert( m_method_Short_shortValue != nullptr );
+ // method Integer.intValue()
+ m_method_Integer_intValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Integer.get()), "intValue", "()I" );
+ jni.ensure_no_exception();
+ assert( m_method_Integer_intValue != nullptr );
+ // method Long.longValue()
+ m_method_Long_longValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Long.get()), "longValue", "()J" );
+ jni.ensure_no_exception();
+ assert( m_method_Long_longValue != nullptr );
+ // method Float.floatValue()
+ m_method_Float_floatValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Float.get()), "floatValue", "()F" );
+ jni.ensure_no_exception();
+ assert( m_method_Float_floatValue != nullptr );
+ // method Double.doubleValue()
+ m_method_Double_doubleValue = jni->GetMethodID(
+ static_cast<jclass>(jo_Double.get()), "doubleValue", "()D" );
+ jni.ensure_no_exception();
+ assert( m_method_Double_doubleValue != nullptr );
+
+ // ctor Character( char )
+ m_ctor_Character_with_char = jni->GetMethodID(
+ static_cast<jclass>(jo_Character.get()), "<init>", "(C)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Character_with_char != nullptr );
+ // ctor Boolean( boolean )
+ m_ctor_Boolean_with_boolean = jni->GetMethodID(
+ static_cast<jclass>(jo_Boolean.get()), "<init>", "(Z)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Boolean_with_boolean != nullptr );
+ // ctor Byte( byte )
+ m_ctor_Byte_with_byte = jni->GetMethodID(
+ static_cast<jclass>(jo_Byte.get()), "<init>", "(B)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Byte_with_byte != nullptr );
+ // ctor Short( short )
+ m_ctor_Short_with_short = jni->GetMethodID(
+ static_cast<jclass>(jo_Short.get()), "<init>", "(S)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Short_with_short != nullptr );
+ // ctor Integer( int )
+ m_ctor_Integer_with_int = jni->GetMethodID(
+ static_cast<jclass>(jo_Integer.get()), "<init>", "(I)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Integer_with_int != nullptr );
+ // ctor Long( long )
+ m_ctor_Long_with_long = jni->GetMethodID(
+ static_cast<jclass>(jo_Long.get()), "<init>", "(J)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Long_with_long != nullptr );
+ // ctor Float( float )
+ m_ctor_Float_with_float = jni->GetMethodID(
+ static_cast<jclass>(jo_Float.get()), "<init>", "(F)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Float_with_float != nullptr );
+ // ctor Double( double )
+ m_ctor_Double_with_double = jni->GetMethodID(
+ static_cast<jclass>(jo_Double.get()), "<init>", "(D)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Double_with_double != nullptr );
+
+ // static method UnoRuntime.generateOid()
+ m_method_UnoRuntime_generateOid = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()),
+ "generateOid", "(Ljava/lang/Object;)Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_method_UnoRuntime_generateOid != nullptr );
+ // static method UnoRuntime.queryInterface()
+ m_method_UnoRuntime_queryInterface = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()),
+ "queryInterface",
+ "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_UnoRuntime_queryInterface != nullptr );
+
+ // field Enum.m_value
+ m_field_Enum_m_value = jni->GetFieldID(
+ static_cast<jclass>(jo_Enum.get()), "m_value", "I" );
+ jni.ensure_no_exception();
+ assert( m_field_Enum_m_value != nullptr );
+
+ // static method TypeClass.fromInt()
+ m_method_TypeClass_fromInt = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_TypeClass.get()),
+ "fromInt", "(I)Lcom/sun/star/uno/TypeClass;" );
+ jni.ensure_no_exception();
+ assert( m_method_TypeClass_fromInt != nullptr );
+
+ // ctor Type( Class )
+ m_ctor_Type_with_Class = jni->GetMethodID(
+ static_cast<jclass>(jo_Type.get()), "<init>", "(Ljava/lang/Class;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Type_with_Class != nullptr );
+ // ctor Type( String, TypeClass )
+ m_ctor_Type_with_Name_TypeClass = jni->GetMethodID(
+ static_cast<jclass>(jo_Type.get()),
+ "<init>", "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Type_with_Name_TypeClass != nullptr );
+ // field Type._typeName
+ m_field_Type_typeName = jni->GetFieldID(
+ static_cast<jclass>(jo_Type.get()), "_typeName", "Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_field_Type_typeName != nullptr );
+
+ // ctor Any( Type, Object )
+ m_ctor_Any_with_Type_Object = jni->GetMethodID(
+ static_cast<jclass>(jo_Any.get()),
+ "<init>", "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_Any_with_Type_Object != nullptr );
+
+ // field Any._type
+ m_field_Any_type = jni->GetFieldID(
+ static_cast<jclass>(jo_Any.get()), "_type", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( m_field_Any_type != nullptr );
+ // field Any._object
+ m_field_Any_object = jni->GetFieldID(
+ static_cast<jclass>(jo_Any.get()), "_object", "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_field_Any_object != nullptr );
+
+ // method IEnvironment.getRegisteredInterface()
+ m_method_IEnvironment_getRegisteredInterface = jni->GetMethodID(
+ static_cast<jclass>(jo_IEnvironment.get()),
+ "getRegisteredInterface",
+ "(Ljava/lang/String;Lcom/sun/star/uno/Type;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_IEnvironment_getRegisteredInterface != nullptr );
+ // method IEnvironment.registerInterface()
+ m_method_IEnvironment_registerInterface = jni->GetMethodID(
+ static_cast<jclass>(jo_IEnvironment.get()), "registerInterface",
+ "(Ljava/lang/Object;[Ljava/lang/String;Lcom/sun/star/uno/Type;)"
+ "Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_IEnvironment_registerInterface != nullptr );
+
+ // static method JNI_proxy.get_proxy_ctor()
+ m_method_JNI_proxy_get_proxy_ctor = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "get_proxy_ctor",
+ "(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;" );
+ jni.ensure_no_exception();
+ assert( m_method_JNI_proxy_get_proxy_ctor != nullptr );
+ // static method JNI_proxy.create()
+ m_method_JNI_proxy_create = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "create",
+ "(JLcom/sun/star/uno/IEnvironment;JJLcom/sun/star/uno/Type;Ljava/lang"
+ "/String;Ljava/lang/reflect/Constructor;"
+ "Lcom/sun/star/lib/util/AsynchronousFinalizer;)Ljava/lang/Object;" );
+ jni.ensure_no_exception();
+ assert( m_method_JNI_proxy_create != nullptr );
+ // field JNI_proxy.m_receiver_handle
+ m_field_JNI_proxy_m_receiver_handle = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_receiver_handle", "J" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_receiver_handle != nullptr );
+ // field JNI_proxy.m_td_handle
+ m_field_JNI_proxy_m_td_handle = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_td_handle", "J" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_td_handle != nullptr );
+ // field JNI_proxy.m_type
+ m_field_JNI_proxy_m_type = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_type", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_type != nullptr );
+ // field JNI_proxy.m_oid
+ m_field_JNI_proxy_m_oid = jni->GetFieldID(
+ static_cast<jclass>(jo_JNI_proxy.get()), "m_oid", "Ljava/lang/String;" );
+ jni.ensure_no_exception();
+ assert( m_field_JNI_proxy_m_oid != nullptr );
+
+ // ctor AsynchronousFinalizer
+ m_ctor_AsynchronousFinalizer = jni->GetMethodID(
+ static_cast<jclass>(jo_AsynchronousFinalizer.get()), "<init>", "()V" );
+ jni.ensure_no_exception();
+ assert( m_ctor_AsynchronousFinalizer != nullptr );
+ // method AsynchronousFinalizer.drain()
+ m_method_AsynchronousFinalizer_drain = jni->GetMethodID(
+ static_cast<jclass>(jo_AsynchronousFinalizer.get()), "drain", "()V" );
+ jni.ensure_no_exception();
+ assert( m_method_AsynchronousFinalizer_drain != nullptr );
+
+ // get java env
+ OUString java_env_type_name( UNO_LB_JAVA );
+ JLocalAutoRef jo_java(
+ jni, ustring_to_jstring( jni, java_env_type_name.pData ) );
+ jvalue args[ 2 ];
+ args[ 0 ].l = jo_java.get();
+ args[ 1 ].l = nullptr;
+ jmethodID method_getEnvironment = jni->GetStaticMethodID(
+ static_cast<jclass>(jo_UnoRuntime.get()), "getEnvironment",
+ "(Ljava/lang/String;Ljava/lang/Object;)"
+ "Lcom/sun/star/uno/IEnvironment;" );
+ jni.ensure_no_exception();
+ assert( method_getEnvironment != nullptr );
+ JLocalAutoRef jo_java_env(
+ jni, jni->CallStaticObjectMethodA(
+ static_cast<jclass>(jo_UnoRuntime.get()), method_getEnvironment, args ) );
+
+ // get com.sun.star.uno.Any.VOID
+ jfieldID field_Any_VOID = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Any.get()), "VOID", "Lcom/sun/star/uno/Any;" );
+ jni.ensure_no_exception();
+ assert( field_Any_VOID != nullptr );
+ JLocalAutoRef jo_Any_VOID(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Any.get()), field_Any_VOID ) );
+ // get com.sun.star.uno.Type.UNSIGNED_SHORT
+ jfieldID field_Type_UNSIGNED_SHORT = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_SHORT", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_SHORT != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_SHORT(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_SHORT ) );
+ // get com.sun.star.uno.Type.UNSIGNED_LONG
+ jfieldID field_Type_UNSIGNED_LONG = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_LONG", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_LONG != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_LONG(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_LONG ) );
+ // get com.sun.star.uno.Type.UNSIGNED_HYPER
+ jfieldID field_Type_UNSIGNED_HYPER = jni->GetStaticFieldID(
+ static_cast<jclass>(jo_Type.get()), "UNSIGNED_HYPER", "Lcom/sun/star/uno/Type;" );
+ jni.ensure_no_exception();
+ assert( field_Type_UNSIGNED_HYPER != nullptr );
+ JLocalAutoRef jo_Type_UNSIGNED_HYPER(
+ jni, jni->GetStaticObjectField(
+ static_cast<jclass>(jo_Type.get()), field_Type_UNSIGNED_HYPER ) );
+
+ // make global refs
+ m_class_UnoRuntime =
+ static_cast<jclass>(jni->NewGlobalRef( jo_UnoRuntime.get() ));
+ m_class_RuntimeException =
+ static_cast<jclass>(jni->NewGlobalRef( jo_RuntimeException.get() ));
+ m_class_Any =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Any.get() ));
+ m_class_Type =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Type.get() ));
+ m_class_TypeClass =
+ static_cast<jclass>(jni->NewGlobalRef( jo_TypeClass.get() ));
+ m_class_JNI_proxy =
+ static_cast<jclass>(jni->NewGlobalRef( jo_JNI_proxy.get() ));
+ m_class_AsynchronousFinalizer =
+ static_cast<jclass>(jni->NewGlobalRef( jo_AsynchronousFinalizer.get() ));
+
+ m_class_Character =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Character.get() ));
+ m_class_Boolean =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Boolean.get() ));
+ m_class_Byte =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Byte.get() ));
+ m_class_Short =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Short.get() ));
+ m_class_Integer =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Integer.get() ));
+ m_class_Long =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Long.get() ));
+ m_class_Float =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Float.get() ));
+ m_class_Double =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Double.get() ));
+ m_class_String =
+ static_cast<jclass>(jni->NewGlobalRef( jo_String.get() ));
+ m_class_Object =
+ static_cast<jclass>(jni->NewGlobalRef( jo_Object.get() ));
+ m_class_Class =
+ static_cast<jclass>(jni->NewGlobalRef( m_class_Class ));
+
+ m_object_Any_VOID =
+ jni->NewGlobalRef( jo_Any_VOID.get() );
+ m_object_Type_UNSIGNED_SHORT =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_SHORT.get() );
+ m_object_Type_UNSIGNED_LONG =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_LONG.get() );
+ m_object_Type_UNSIGNED_HYPER =
+ jni->NewGlobalRef( jo_Type_UNSIGNED_HYPER.get() );
+ m_object_java_env = jni->NewGlobalRef( jo_java_env.get() );
+
+ try
+ {
+ css::uno::TypeDescription XInterface_td(
+ cppu::UnoType<css::uno::XInterface>::get());
+ // coverity[ctor_dtor_leak] - on purpose
+ m_XInterface_type_info =
+ new JNI_interface_type_info( jni, XInterface_td.get() );
+ }
+ catch (...)
+ {
+ destruct( jni_env );
+ throw;
+ }
+}
+
+
+void JNI_info::destruct( JNIEnv * jni_env )
+{
+ for (auto & i: m_type_map)
+ {
+ i.second.m_info->destroy( jni_env );
+ }
+ if (m_XInterface_type_info != nullptr)
+ {
+ const_cast< JNI_interface_type_info * >(
+ m_XInterface_type_info )->destroy( jni_env );
+ }
+
+ // free global refs
+ jni_env->DeleteGlobalRef( m_object_java_env );
+ jni_env->DeleteGlobalRef( m_object_Any_VOID );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_SHORT );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_LONG );
+ jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_HYPER );
+
+ jni_env->DeleteGlobalRef( m_class_Class );
+ jni_env->DeleteGlobalRef( m_class_Object );
+ jni_env->DeleteGlobalRef( m_class_String );
+ jni_env->DeleteGlobalRef( m_class_Double );
+ jni_env->DeleteGlobalRef( m_class_Float );
+ jni_env->DeleteGlobalRef( m_class_Long );
+ jni_env->DeleteGlobalRef( m_class_Integer );
+ jni_env->DeleteGlobalRef( m_class_Short );
+ jni_env->DeleteGlobalRef( m_class_Byte );
+ jni_env->DeleteGlobalRef( m_class_Boolean );
+ jni_env->DeleteGlobalRef( m_class_Character );
+
+ jni_env->DeleteGlobalRef( m_class_AsynchronousFinalizer );
+ jni_env->DeleteGlobalRef( m_class_JNI_proxy );
+ jni_env->DeleteGlobalRef( m_class_RuntimeException );
+ jni_env->DeleteGlobalRef( m_class_UnoRuntime );
+ jni_env->DeleteGlobalRef( m_class_TypeClass );
+ jni_env->DeleteGlobalRef( m_class_Type );
+ jni_env->DeleteGlobalRef( m_class_Any );
+}
+
+
+JNI_info const * JNI_info::get_jni_info(
+ rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm )
+{
+ // !!!no JNI_info available at JNI_context!!!
+ ::jvmaccess::VirtualMachine::AttachGuard guard(
+ uno_vm->getVirtualMachine() );
+ JNIEnv * jni_env = guard.getEnvironment();
+ JNI_context jni(
+ nullptr, jni_env, static_cast< jobject >(uno_vm->getClassLoader()) );
+
+ jclass jo_class;
+ jmethodID jo_forName;
+ jni.getClassForName( &jo_class, &jo_forName );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_JNI_info_holder(
+ jni,
+ jni.findClass(
+ "com.sun.star.bridges.jni_uno.JNI_info_holder", jo_class,
+ jo_forName, false ) );
+ // field JNI_info_holder.m_jni_info_handle
+ jfieldID field_s_jni_info_handle =
+ jni->GetStaticFieldID(
+ static_cast<jclass>(jo_JNI_info_holder.get()), "s_jni_info_handle", "J" );
+ jni.ensure_no_exception();
+ assert( field_s_jni_info_handle != nullptr );
+
+ JNI_info const * jni_info =
+ reinterpret_cast< JNI_info const * >(
+ jni->GetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()), field_s_jni_info_handle ) );
+ if (jni_info == nullptr) // un-initialized?
+ {
+ JNI_info * new_info = new JNI_info(
+ jni_env, static_cast< jobject >(uno_vm->getClassLoader()), jo_class,
+ jo_forName );
+
+ osl::ClearableMutexGuard g( osl::Mutex::getGlobalMutex() );
+ jni_info =
+ reinterpret_cast< JNI_info const * >(
+ jni->GetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()),
+ field_s_jni_info_handle ) );
+ if (jni_info == nullptr) // still un-initialized?
+ {
+ jni->SetStaticLongField(
+ static_cast<jclass>(jo_JNI_info_holder.get()), field_s_jni_info_handle,
+ reinterpret_cast< jlong >( new_info ) );
+ jni_info = new_info;
+ }
+ else
+ {
+ g.clear();
+ new_info->destroy( jni_env );
+ }
+ }
+
+ return jni_info;
+}
+
+}
+
+extern "C"
+{
+
+
+SAL_JNI_EXPORT void
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1info_1holder_finalize__J(
+ JNIEnv * jni_env, SAL_UNUSED_PARAMETER jobject, jlong jni_info_handle )
+ SAL_THROW_EXTERN_C()
+{
+ ::jni_uno::JNI_info * jni_info =
+ reinterpret_cast< ::jni_uno::JNI_info * >( jni_info_handle );
+ jni_info->destroy( jni_env );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_info.h b/bridges/source/jni_uno/jni_info.h
new file mode 100644
index 0000000000..7a18e553e4
--- /dev/null
+++ b/bridges/source/jni_uno/jni_info.h
@@ -0,0 +1,366 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <unordered_map>
+
+#include "jni_base.h"
+
+#include <mutex>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/strbuf.hxx>
+
+#include <uno/environment.h>
+#include <typelib/typedescription.hxx>
+
+#include <com/sun/star/uno/Type.hxx>
+
+namespace jvmaccess { class UnoVirtualMachine; }
+
+namespace jni_uno
+{
+
+inline bool type_equals(
+ typelib_TypeDescriptionReference * type1,
+ typelib_TypeDescriptionReference * type2 )
+{
+ if (type1 == type2)
+ return true;
+ OUString const & name1 =
+ OUString::unacquired( &type1->pTypeName );
+ OUString const & name2 =
+ OUString::unacquired( &type2->pTypeName );
+ return ((type1->eTypeClass == type2->eTypeClass) && name1 == name2);
+}
+
+inline bool is_XInterface( typelib_TypeDescriptionReference * type )
+{
+ return ((typelib_TypeClass_INTERFACE == type->eTypeClass) &&
+ OUString::unacquired( &type->pTypeName ) == "com.sun.star.uno.XInterface");
+}
+
+struct JNI_type_info
+{
+ JNI_type_info(const JNI_type_info&) = delete;
+ const JNI_type_info& operator=(const JNI_type_info&) = delete;
+
+ ::com::sun::star::uno::TypeDescription m_td;
+ jclass m_class;
+
+ virtual void destroy( JNIEnv * jni_env ) = 0;
+protected:
+ void destruct( JNIEnv * jni_env )
+ { jni_env->DeleteGlobalRef( m_class ); }
+ virtual ~JNI_type_info() {}
+ explicit JNI_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+};
+
+struct JNI_interface_type_info : public JNI_type_info
+{
+ jobject m_proxy_ctor; // proxy ctor
+ jobject m_type;
+ // sorted via typelib function index
+ std::unique_ptr<jmethodID[]> m_methods;
+
+ virtual void destroy( JNIEnv * jni_env ) override;
+ explicit JNI_interface_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+
+private:
+ virtual ~JNI_interface_type_info() override {}
+};
+
+struct JNI_compound_type_info : public JNI_type_info
+{
+ JNI_type_info const * m_base;
+ // ctor( msg ) for exceptions
+ jmethodID m_exc_ctor;
+ // sorted via typelib member index
+ std::unique_ptr<jfieldID[]> m_fields;
+
+ virtual void destroy( JNIEnv * jni_env ) override;
+ explicit JNI_compound_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td );
+
+private:
+ virtual ~JNI_compound_type_info() override {}
+};
+
+struct JNI_type_info_holder
+{
+ JNI_type_info * m_info;
+
+ JNI_type_info_holder(const JNI_type_info_holder&) = delete;
+ const JNI_type_info_holder& operator=(const JNI_type_info_holder&) = delete;
+
+ JNI_type_info_holder() : m_info( nullptr ) {}
+};
+
+typedef std::unordered_map<
+ OUString, JNI_type_info_holder > t_str2type;
+
+class JNI_info
+{
+ mutable std::mutex m_mutex;
+ mutable t_str2type m_type_map;
+
+public:
+ // These two are needed very early by find_class from within the ctor:
+ jclass m_class_Class;
+ jmethodID m_method_Class_forName;
+
+ jobject m_object_java_env;
+ jobject m_object_Any_VOID;
+ jobject m_object_Type_UNSIGNED_SHORT;
+ jobject m_object_Type_UNSIGNED_LONG;
+ jobject m_object_Type_UNSIGNED_HYPER;
+
+ jclass m_class_Object;
+ jclass m_class_Character;
+ jclass m_class_Boolean;
+ jclass m_class_Byte;
+ jclass m_class_Short;
+ jclass m_class_Integer;
+ jclass m_class_Long;
+ jclass m_class_Float;
+ jclass m_class_Double;
+ jclass m_class_String;
+
+ jclass m_class_UnoRuntime;
+ jclass m_class_RuntimeException;
+ jclass m_class_Any;
+ jclass m_class_Type;
+ jclass m_class_TypeClass;
+ jclass m_class_JNI_proxy;
+ jclass m_class_AsynchronousFinalizer;
+
+ jmethodID m_method_Object_toString;
+ jmethodID m_method_Class_getName;
+ jmethodID m_method_Throwable_getMessage;
+ jmethodID m_ctor_Character_with_char;
+ jmethodID m_ctor_Boolean_with_boolean;
+ jmethodID m_ctor_Byte_with_byte;
+ jmethodID m_ctor_Short_with_short;
+ jmethodID m_ctor_Integer_with_int;
+ jmethodID m_ctor_Long_with_long;
+ jmethodID m_ctor_Float_with_float;
+ jmethodID m_ctor_Double_with_double;
+ jmethodID m_method_Boolean_booleanValue;
+ jmethodID m_method_Byte_byteValue;
+ jmethodID m_method_Character_charValue;
+ jmethodID m_method_Double_doubleValue;
+ jmethodID m_method_Float_floatValue;
+ jmethodID m_method_Integer_intValue;
+ jmethodID m_method_Long_longValue;
+ jmethodID m_method_Short_shortValue;
+
+ jmethodID m_method_IEnvironment_getRegisteredInterface;
+ jmethodID m_method_IEnvironment_registerInterface;
+ jmethodID m_method_UnoRuntime_generateOid;
+ jmethodID m_method_UnoRuntime_queryInterface;
+ jmethodID m_ctor_Any_with_Type_Object;
+ jfieldID m_field_Any_type;
+ jfieldID m_field_Any_object;
+ jmethodID m_ctor_Type_with_Class;
+ jmethodID m_ctor_Type_with_Name_TypeClass;
+ jfieldID m_field_Type_typeName;
+ jmethodID m_method_TypeClass_fromInt;
+ jfieldID m_field_Enum_m_value;
+
+ jmethodID m_method_JNI_proxy_get_proxy_ctor;
+ jmethodID m_method_JNI_proxy_create;
+ jfieldID m_field_JNI_proxy_m_receiver_handle;
+ jfieldID m_field_JNI_proxy_m_td_handle;
+ jfieldID m_field_JNI_proxy_m_type;
+ jfieldID m_field_JNI_proxy_m_oid;
+
+ jmethodID m_ctor_AsynchronousFinalizer;
+ jmethodID m_method_AsynchronousFinalizer_drain;
+
+ ::com::sun::star::uno::TypeDescription m_XInterface_queryInterface_td;
+ ::com::sun::star::uno::Type const & m_Exception_type;
+ ::com::sun::star::uno::Type const & m_RuntimeException_type;
+ ::com::sun::star::uno::Type const & m_void_type;
+ JNI_interface_type_info const * m_XInterface_type_info;
+
+ // noncopyable
+ JNI_info(const JNI_info&) = delete;
+ const JNI_info& operator=(const JNI_info&) = delete;
+
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ typelib_TypeDescription * type ) const;
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ typelib_TypeDescriptionReference * type ) const;
+ JNI_type_info const * get_type_info(
+ JNI_context const & jni,
+ OUString const & uno_name ) const;
+ inline static void append_sig(
+ OStringBuffer * buf, typelib_TypeDescriptionReference * type,
+ bool use_Object_for_type_XInterface = true, bool use_slashes = true );
+
+ // get this
+ static JNI_info const * get_jni_info(
+ rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm );
+ inline void destroy( JNIEnv * jni_env );
+
+private:
+ JNI_type_info const * create_type_info(
+ JNI_context const & jni, typelib_TypeDescription * td ) const;
+
+ void destruct( JNIEnv * jni_env );
+
+ JNI_info( JNIEnv * jni_env, jobject class_loader,
+ jclass classClass, jmethodID methodForName );
+ ~JNI_info() {}
+};
+
+inline void JNI_info::destroy( JNIEnv * jni_env )
+{
+ destruct( jni_env );
+ delete this;
+}
+
+inline void JNI_info::append_sig(
+ OStringBuffer * buf, typelib_TypeDescriptionReference * type,
+ bool use_Object_for_type_XInterface, bool use_slashes )
+{
+ switch (type->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ buf->append( 'V' );
+ break;
+ case typelib_TypeClass_CHAR:
+ buf->append( 'C' );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ buf->append( 'Z' );
+ break;
+ case typelib_TypeClass_BYTE:
+ buf->append( 'B' );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ buf->append( 'S' );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ buf->append( 'I' );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ buf->append( 'J' );
+ break;
+ case typelib_TypeClass_FLOAT:
+ buf->append( 'F' );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ buf->append( 'D' );
+ break;
+ case typelib_TypeClass_STRING:
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/String;" );
+ } else {
+ buf->append( "Ljava.lang.String;" );
+ }
+ break;
+ case typelib_TypeClass_TYPE:
+ if ( use_slashes ) {
+ buf->append( "Lcom/sun/star/uno/Type;" );
+ } else {
+ buf->append( "Lcom.sun.star.uno.Type;" );
+ }
+ break;
+ case typelib_TypeClass_ANY:
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/Object;" );
+ } else {
+ buf->append( "Ljava.lang.Object;" );
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ OUString const & uno_name =
+ OUString::unacquired( &type->pTypeName );
+ buf->append( 'L' );
+ // Erase type arguments of instantiated polymorphic struct types:
+ sal_Int32 i = uno_name.indexOf( '<' );
+ if ( i < 0 ) {
+ buf->append(
+ OUStringToOString(
+ use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ } else {
+ OUString s( uno_name.copy( 0, i ) );
+ buf->append(
+ OUStringToOString(
+ use_slashes ? s.replace( '.', '/' ) : s,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ }
+ buf->append( ';' );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ buf->append( '[' );
+ TypeDescr td( type );
+ append_sig(
+ buf, reinterpret_cast<typelib_IndirectTypeDescription *>(td.get())->pType,
+ use_Object_for_type_XInterface, use_slashes );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ if (use_Object_for_type_XInterface && is_XInterface( type ))
+ {
+ if ( use_slashes ) {
+ buf->append( "Ljava/lang/Object;" );
+ } else {
+ buf->append( "Ljava.lang.Object;" );
+ }
+ }
+ else
+ {
+ OUString const & uno_name =
+ OUString::unacquired( &type->pTypeName );
+ buf->append( 'L' );
+ buf->append(
+ OUStringToOString(
+ use_slashes ? uno_name.replace( '.', '/' ) : uno_name,
+ RTL_TEXTENCODING_JAVA_UTF8 ) );
+ buf->append( ';' );
+ }
+ break;
+ default:
+ throw BridgeRuntimeError(
+ "unsupported type: " +
+ OUString::unacquired( &type->pTypeName ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_java2uno.cxx b/bridges/source/jni_uno/jni_java2uno.cxx
new file mode 100644
index 0000000000..53f761e826
--- /dev/null
+++ b/bridges/source/jni_uno/jni_java2uno.cxx
@@ -0,0 +1,624 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <cassert>
+
+#include <sal/alloca.h>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+namespace jni_uno
+{
+
+
+jobject Bridge::map_to_java(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
+{
+ // get oid
+ rtl_uString * pOid = nullptr;
+ (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
+ assert( pOid != nullptr );
+ OUString oid( pOid, SAL_NO_ACQUIRE );
+
+ // opt getRegisteredInterface()
+ JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
+ jvalue args[ 2 ];
+ args[ 0 ].l = jo_oid.get();
+ args[ 1 ].l = info->m_type;
+ jobject jo_iface = jni->CallObjectMethodA(
+ getJniInfo()->m_object_java_env,
+ getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
+ jni.ensure_no_exception();
+
+ if (jo_iface == nullptr) // no registered iface
+ {
+ // register uno interface
+ (*m_uno_env->registerInterface)(
+ m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+
+ // create java and register java proxy
+ jvalue args2[ 8 ];
+ acquire();
+ args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
+ (*pUnoI->acquire)( pUnoI );
+ args2[ 1 ].l = getJniInfo()->m_object_java_env;
+ args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
+ typelib_typedescription_acquire( info->m_td.get() );
+ args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
+ args2[ 4 ].l = info->m_type;
+ args2[ 5 ].l = jo_oid.get();
+ args2[ 6 ].l = info->m_proxy_ctor;
+ auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
+ m_java_env->pContext);
+ {
+ std::unique_lock g(envData->mutex);
+ args2[ 7 ].l = envData->asynchronousFinalizer;
+ }
+ jo_iface = jni->CallStaticObjectMethodA(
+ getJniInfo()->m_class_JNI_proxy,
+ getJniInfo()->m_method_JNI_proxy_create, args2 );
+ jni.ensure_no_exception();
+ }
+
+ assert( jo_iface != nullptr );
+ return jo_iface;
+}
+
+
+void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
+{
+ if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ // append java stack trace to Message member
+ static_cast< css::uno::Exception * >(
+ uno_exc->pData )->Message += jni.get_stack_trace();
+#endif
+ SAL_INFO(
+ "bridges",
+ "exception occurred java->uno: ["
+ << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
+ << static_cast<css::uno::Exception const *>(
+ uno_exc->pData)->Message);
+ // signal exception
+ jvalue java_exc;
+ try
+ {
+ map_to_java(
+ jni, &java_exc, uno_exc->pData, uno_exc->pType, nullptr,
+ true /* in */, false /* no out */ );
+ }
+ catch (...)
+ {
+ uno_any_destruct( uno_exc, nullptr );
+ throw;
+ }
+ uno_any_destruct( uno_exc, nullptr );
+
+ JLocalAutoRef jo_exc( jni, java_exc.l );
+ jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
+ if (res != 0)
+ {
+ // call toString()
+ JLocalAutoRef jo_descr(
+ jni, jni->CallObjectMethodA(
+ jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ throw BridgeRuntimeError(
+ "throwing java exception failed: "
+ + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
+ + jni.get_stack_trace() );
+ }
+ }
+ else
+ {
+ OUString message(
+ "thrown exception is no uno exception: " +
+ OUString::unacquired( &uno_exc->pType->pTypeName ) +
+ jni.get_stack_trace() );
+ uno_any_destruct( uno_exc, nullptr );
+ throw BridgeRuntimeError( message );
+ }
+}
+
+namespace {
+
+union largest
+{
+ sal_Int64 n;
+ double d;
+ void * p;
+ uno_Any a;
+};
+
+}
+
+jobject Bridge::call_uno(
+ JNI_context const & jni,
+ uno_Interface * pUnoI, typelib_TypeDescription * member_td,
+ typelib_TypeDescriptionReference * return_type,
+ sal_Int32 nParams, typelib_MethodParameter const * pParams,
+ jobjectArray jo_args /* may be 0 */ ) const
+{
+ // return mem
+ sal_Int32 return_size;
+ switch (return_type->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ return_size = 0;
+ break;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ return_size = std::max(
+ TypeDescr(return_type).get()->nSize,
+ static_cast< sal_Int32 >(sizeof (largest)));
+ break;
+
+ default:
+ return_size = sizeof (largest);
+ break;
+ }
+
+ char * mem = static_cast<char *>(alloca(
+ (nParams * sizeof (void *)) +
+ return_size + (nParams * sizeof (largest)) ));
+ void ** uno_args = reinterpret_cast<void **>(mem);
+ void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
+ largest * uno_args_mem = reinterpret_cast<largest *>
+ (mem + (nParams * sizeof (void *)) + return_size);
+
+ assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ typelib_TypeDescriptionReference * type = param.pTypeRef;
+
+ uno_args[ nPos ] = &uno_args_mem[ nPos ];
+ if (type->eTypeClass == typelib_TypeClass_STRUCT ||
+ type->eTypeClass == typelib_TypeClass_EXCEPTION)
+ {
+ TypeDescr td( type );
+ if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
+ > sizeof (largest))
+ uno_args[ nPos ] = alloca( td.get()->nSize );
+ }
+
+ if (param.bIn)
+ {
+ try
+ {
+ JLocalAutoRef jo_arg(
+ jni, jni->GetObjectArrayElement( jo_args, nPos ) );
+ jni.ensure_no_exception();
+ jvalue java_arg;
+ java_arg.l = jo_arg.get();
+ map_to_uno(
+ jni, uno_args[ nPos ], java_arg, type, nullptr,
+ false /* no assign */, param.bOut,
+ true /* special wrapped integral types */ );
+ }
+ catch (...)
+ {
+ // cleanup uno in args
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & p = pParams[ n ];
+ if (p.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ n ], p.pTypeRef, nullptr );
+ }
+ }
+ throw;
+ }
+ }
+ }
+
+ uno_Any uno_exc_holder;
+ uno_Any * uno_exc = &uno_exc_holder;
+ // call binary uno
+ (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
+
+ if (uno_exc == nullptr)
+ {
+ // convert out args; destruct uno args
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ typelib_TypeDescriptionReference * type = param.pTypeRef;
+ if (param.bOut)
+ {
+ try
+ {
+ // get out holder array[ 1 ]
+ JLocalAutoRef jo_out_holder(
+ jni, jni->GetObjectArrayElement( jo_args, nPos ) );
+ jni.ensure_no_exception();
+ jvalue java_arg;
+ java_arg.l = jo_out_holder.get();
+ map_to_java(
+ jni, &java_arg, uno_args[ nPos ], type, nullptr,
+ true /* in */, true /* out holder */ );
+ }
+ catch (...)
+ {
+ // cleanup further uno args
+ for ( sal_Int32 n = nPos; n < nParams; ++n )
+ {
+ uno_type_destructData(
+ uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
+ }
+ // cleanup uno return value
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ throw;
+ }
+ }
+ if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
+ type->eTypeClass != typelib_TypeClass_ENUM) // opt
+ {
+ uno_type_destructData( uno_args[ nPos ], type, nullptr );
+ }
+ }
+
+ if (return_type->eTypeClass != typelib_TypeClass_VOID)
+ {
+ // convert uno return value
+ jvalue java_ret;
+ try
+ {
+ map_to_java(
+ jni, &java_ret, uno_ret, return_type, nullptr,
+ true /* in */, false /* no out */,
+ true /* special_wrapped_integral_types */ );
+ }
+ catch (...)
+ {
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ throw;
+ }
+ if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
+ return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
+ {
+ uno_type_destructData( uno_ret, return_type, nullptr );
+ }
+ return java_ret.l;
+ }
+ return nullptr; // void return
+ }
+ else // exception occurred
+ {
+ // destruct uno in args
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = pParams[ nPos ];
+ if (param.bIn)
+ uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
+ }
+
+ handle_uno_exc( jni, uno_exc );
+ return nullptr;
+ }
+}
+
+}
+
+using namespace ::jni_uno;
+
+extern "C"
+{
+
+
+SAL_JNI_EXPORT jobject
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
+ JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
+ jobjectArray jo_args /* may be 0 */ )
+{
+ Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_context jni(
+ jni_info, jni_env,
+ static_cast< jobject >(
+ static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine->getClassLoader()));
+
+ OUString method_name;
+
+ try
+ {
+ method_name = jstring_to_oustring( jni, jo_method );
+ SAL_INFO(
+ "bridges",
+ "java->uno call: " << method_name << " on oid "
+ << jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni,
+ jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
+ .get())));
+ // special IQueryInterface.queryInterface()
+ if ( method_name == "queryInterface" )
+ {
+ // oid
+ JLocalAutoRef jo_oid(
+ jni, jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
+ // type
+ JLocalAutoRef jo_type(
+ jni, jni->GetObjectArrayElement( jo_args, 0 ) );
+ jni.ensure_no_exception();
+
+ JLocalAutoRef jo_type_name(
+ jni, jni->GetObjectField(
+ jo_type.get(), jni_info->m_field_Type_typeName ) );
+ if (! jo_type_name.is())
+ {
+ throw BridgeRuntimeError(
+ "incomplete type object: no type name!" +
+ jni.get_stack_trace() );
+ }
+ OUString type_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
+ JNI_type_info const * info =
+ jni_info->get_type_info( jni, type_name );
+ if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
+ {
+ throw BridgeRuntimeError(
+ "queryInterface() call demands an INTERFACE type!" );
+ }
+ JNI_interface_type_info const * iface_info =
+ static_cast< JNI_interface_type_info const * >( info );
+
+ // getRegisteredInterface() already tested in JNI_proxy:
+ // perform queryInterface call on binary uno interface
+ uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+
+ uno_Any uno_ret;
+ void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
+ uno_Any uno_exc_holder;
+ uno_Any * uno_exc = &uno_exc_holder;
+ // call binary uno
+ (*pUnoI->pDispatcher)(
+ pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
+ &uno_ret, uno_args, &uno_exc );
+ if (uno_exc == nullptr)
+ {
+ jobject jo_ret = nullptr;
+ if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ uno_Interface * pUnoRet =
+ static_cast<uno_Interface *>(uno_ret.pReserved);
+ if (pUnoRet != nullptr)
+ {
+ try
+ {
+ jo_ret =
+ bridge->map_to_java( jni, pUnoRet, iface_info );
+ }
+ catch (...)
+ {
+ uno_any_destruct( &uno_ret, nullptr );
+ throw;
+ }
+ }
+ }
+ uno_any_destruct( &uno_ret, nullptr );
+ return jo_ret;
+ }
+ else
+ {
+ bridge->handle_uno_exc( jni, uno_exc );
+ return nullptr;
+ }
+ }
+
+ typelib_InterfaceTypeDescription * td =
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
+ uno_Interface * pUnoI =
+ reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+
+ typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
+ for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
+ {
+ // try to avoid getting typedescription as long as possible,
+ // because of a Mutex.acquire() in
+ // typelib_typedescriptionreference_getDescription()
+ typelib_TypeDescriptionReference * member_type =
+ ppAllMembers[ nPos ];
+
+ // check method_name against fully qualified type_name
+ // of member_type; type_name is of the form
+ // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
+ OUString const & type_name =
+ OUString::unacquired( &member_type->pTypeName );
+ sal_Int32 offset = type_name.indexOf( ':' ) + 2;
+ assert(offset >= 2);
+ assert(offset < type_name.getLength());
+ assert(type_name[offset - 1] == ':' );
+ sal_Int32 remainder = type_name.getLength() - offset;
+ if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
+ {
+ if ((method_name.getLength() == remainder
+ || (method_name.getLength() < remainder
+ && type_name[offset + method_name.getLength()] == ':'))
+ && type_name.match(method_name, offset))
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceMethodTypeDescription * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ member_td.get() );
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ method_td->pReturnTypeRef,
+ method_td->nParams, method_td->pParams,
+ jo_args );
+ }
+ }
+ else // attribute
+ {
+ assert(
+ member_type->eTypeClass ==
+ typelib_TypeClass_INTERFACE_ATTRIBUTE );
+
+ if (method_name.getLength() >= 3
+ && (method_name.getLength() - 3 == remainder
+ || (method_name.getLength() - 3 < remainder
+ && type_name[
+ offset + (method_name.getLength() - 3)] == ':'))
+ && method_name[1] == 'e' && method_name[2] == 't'
+ && rtl_ustr_compare_WithLength(
+ type_name.getStr() + offset,
+ method_name.getLength() - 3,
+ method_name.getStr() + 3,
+ method_name.getLength() - 3) == 0)
+ {
+ if (method_name[ 0 ] == 'g')
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attr_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ attr_td->pAttributeTypeRef,
+ 0, nullptr,
+ jo_args );
+ }
+ else if (method_name[ 0 ] == 's')
+ {
+ TypeDescr member_td( member_type );
+ typelib_InterfaceAttributeTypeDescription * attr_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ member_td.get() );
+ if (! attr_td->bReadOnly)
+ {
+ typelib_MethodParameter param;
+ param.pTypeRef = attr_td->pAttributeTypeRef;
+ param.bIn = true;
+ param.bOut = false;
+ return bridge->call_uno(
+ jni, pUnoI, member_td.get(),
+ jni_info->m_void_type.getTypeLibType(),
+ 1, &param,
+ jo_args );
+ }
+ }
+ }
+ }
+ }
+ // the thing that should not be... no method info found!
+ throw BridgeRuntimeError(
+ "calling undeclared function on interface "
+ + OUString::unacquired(&td->aBase.pTypeName)
+ + ": " + method_name + jni.get_stack_trace() );
+ }
+ catch (const BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "Java calling UNO method " << method_name << ": " << err.m_message);
+ // notify RuntimeException
+ OString cstr_msg(
+ "[jni_uno bridge error] Java calling UNO method "
+ + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
+ + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
+ if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
+ != 0)
+ {
+ assert( false );
+ }
+ return nullptr;
+ }
+ catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ OString cstr_msg(
+ "[jni_uno bridge error] attaching current thread to java failed"
+ + OUStringToOString(
+ jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
+ if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
+ != 0)
+ {
+ assert( false );
+ }
+ return nullptr;
+ }
+}
+
+
+SAL_JNI_EXPORT void
+JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
+ JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
+{
+ Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_context jni(
+ jni_info, jni_env,
+ static_cast< jobject >(
+ static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine->getClassLoader()));
+
+ uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
+ typelib_TypeDescription * td =
+ reinterpret_cast< typelib_TypeDescription * >(
+ jni->GetLongField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
+ SAL_INFO(
+ "bridges",
+ "freeing java uno proxy: "
+ << jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni,
+ jni->GetObjectField(
+ jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
+ .get())));
+ // revoke from uno env; has already been revoked from java env
+ (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
+ // release receiver
+ (*pUnoI->release)( pUnoI );
+ // release typedescription handle
+ typelib_typedescription_release( td );
+ // release bridge handle
+ bridge->release();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jni_uno2java.cxx b/bridges/source/jni_uno/jni_uno2java.cxx
new file mode 100644
index 0000000000..98666dfc19
--- /dev/null
+++ b/bridges/source/jni_uno/jni_uno2java.cxx
@@ -0,0 +1,804 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <memory>
+
+#include <sal/alloca.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <utility>
+
+#include "jni_bridge.h"
+#include "jniunoenvironmentdata.hxx"
+
+namespace
+{
+extern "C"
+{
+
+
+void UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C();
+
+
+void UNO_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C();
+}
+}
+
+namespace jni_uno
+{
+
+
+void Bridge::handle_java_exc(
+ JNI_context const & jni,
+ JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const
+{
+ assert( jo_exc.is() );
+ if (! jo_exc.is())
+ {
+ throw BridgeRuntimeError(
+ "java exception occurred, but no java exception available!?" +
+ jni.get_stack_trace() );
+ }
+
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( jo_exc.get() ) );
+ JLocalAutoRef jo_class_name(
+ jni, jni->CallObjectMethodA(
+ jo_class.get(), getJniInfo()->m_method_Class_getName, nullptr ) );
+ jni.ensure_no_exception();
+ OUString exc_name(
+ jstring_to_oustring( jni, static_cast<jstring>(jo_class_name.get()) ) );
+
+ css::uno::TypeDescription td( exc_name.pData );
+ if (!td.is() || (td.get()->eTypeClass != typelib_TypeClass_EXCEPTION))
+ {
+ // call toString()
+ JLocalAutoRef jo_descr(
+ jni, jni->CallObjectMethodA(
+ jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ throw BridgeRuntimeError(
+ "non-UNO exception occurred: "
+ + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
+ + jni.get_stack_trace( jo_exc.get() ) );
+ }
+
+ std::unique_ptr< rtl_mem > uno_data( rtl_mem::allocate( td.get()->nSize ) );
+ jvalue val;
+ val.l = jo_exc.get();
+ map_to_uno(
+ jni, uno_data.get(), val, td.get()->pWeakRef, nullptr,
+ false /* no assign */, false /* no out param */ );
+
+#if OSL_DEBUG_LEVEL > 0
+ // patch Message, append stack trace
+ reinterpret_cast< css::uno::Exception * >(
+ uno_data.get() )->Message += jni.get_stack_trace( jo_exc.get() );
+#endif
+
+ typelib_typedescriptionreference_acquire( td.get()->pWeakRef );
+ uno_exc->pType = td.get()->pWeakRef;
+ uno_exc->pData = uno_data.release();
+
+ SAL_INFO(
+ "bridges",
+ "exception occurred uno->java: [" << exc_name << "] "
+ << (static_cast<css::uno::Exception const *>(uno_exc->pData)
+ ->Message));
+}
+
+
+void Bridge::call_java(
+ jobject javaI, typelib_InterfaceTypeDescription * iface_td,
+ sal_Int32 local_member_index, sal_Int32 function_pos_offset,
+ typelib_TypeDescriptionReference * return_type,
+ typelib_MethodParameter * params, sal_Int32 nParams,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
+{
+ assert( function_pos_offset == 0 || function_pos_offset == 1 );
+
+ JNI_guarded_context jni(
+ getJniInfo(),
+ static_cast<JniUnoEnvironmentData *>(m_java_env->pContext)->machine);
+
+ // assure fully initialized iface_td:
+ css::uno::TypeDescription iface_holder;
+ if (! iface_td->aBase.bComplete) {
+ iface_holder = css::uno::TypeDescription(
+ reinterpret_cast<typelib_TypeDescription *>(iface_td) );
+ iface_holder.makeComplete();
+ if (! iface_holder.get()->bComplete) {
+ throw BridgeRuntimeError(
+ "cannot make type complete: "
+ + OUString::unacquired(&iface_holder.get()->pTypeName)
+ + jni.get_stack_trace() );
+ }
+ iface_td = reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ iface_holder.get() );
+ assert( iface_td->aBase.eTypeClass == typelib_TypeClass_INTERFACE );
+ }
+
+ // prepare java args, save param td
+ jvalue * java_args = static_cast<jvalue *>(alloca( sizeof (jvalue) * nParams ));
+
+ sal_Int32 nPos;
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ try
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ java_args[ nPos ].l = nullptr; // if out: build up array[ 1 ]
+ map_to_java(
+ jni, &java_args[ nPos ],
+ uno_args[ nPos ],
+ param.pTypeRef, nullptr,
+ param.bIn /* convert uno value */,
+ param.bOut /* build up array[ 1 ] */ );
+ }
+ catch (...)
+ {
+ // cleanup
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & param = params[ n ];
+ if (param.bOut ||
+ typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ n ].l );
+ }
+ }
+ throw;
+ }
+ }
+
+ sal_Int32 base_members = iface_td->nAllMembers - iface_td->nMembers;
+ assert( base_members < iface_td->nAllMembers );
+ sal_Int32 base_members_function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ base_members ];
+ sal_Int32 member_pos = base_members + local_member_index;
+ SAL_WARN_IF(
+ member_pos >= iface_td->nAllMembers, "bridges",
+ "member pos out of range");
+ sal_Int32 function_pos =
+ iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]
+ + function_pos_offset;
+ SAL_WARN_IF(
+ (function_pos < base_members_function_pos
+ || function_pos >= iface_td->nMapFunctionIndexToMemberIndex),
+ "bridges", "illegal function index");
+ function_pos -= base_members_function_pos;
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ getJniInfo()->get_type_info( jni, &iface_td->aBase ) );
+ jmethodID method_id = info->m_methods[ function_pos ];
+
+#if OSL_DEBUG_LEVEL > 0
+ JLocalAutoRef jo_method(
+ jni, jni->ToReflectedMethod( info->m_class, method_id, JNI_FALSE ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_descr1(
+ jni, jni->CallObjectMethodA(
+ jo_method.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_descr2(
+ jni,
+ jni->CallObjectMethodA(
+ javaI, getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ JLocalAutoRef jo_class( jni, jni->GetObjectClass( javaI ) );
+ JLocalAutoRef jo_descr3(
+ jni,
+ jni->CallObjectMethodA(
+ jo_class.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
+ jni.ensure_no_exception();
+ SAL_INFO(
+ "bridges",
+ "calling " << jstring_to_oustring( jni, static_cast<jstring>(jo_descr1.get()) ) << " on "
+ << jstring_to_oustring( jni, static_cast<jstring>(jo_descr2.get()) ) << " ("
+ << jstring_to_oustring( jni, static_cast<jstring>(jo_descr3.get()) ) << ")");
+#endif
+
+ // complex return value
+ JLocalAutoRef java_ret( jni );
+
+ switch (return_type->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ jni->CallVoidMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_CHAR:
+ *static_cast<sal_Unicode *>(uno_ret) =
+ jni->CallCharMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast<sal_Bool *>(uno_ret) =
+ jni->CallBooleanMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int8 *>(uno_ret) =
+ jni->CallByteMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int16 *>(uno_ret) =
+ jni->CallShortMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int32 *>(uno_ret) =
+ jni->CallIntMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_Int64 *>(uno_ret) =
+ jni->CallLongMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(uno_ret) =
+ jni->CallFloatMethodA( javaI, method_id, java_args );
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>(uno_ret) =
+ jni->CallDoubleMethodA( javaI, method_id, java_args );
+ break;
+ default:
+ java_ret.reset(
+ jni->CallObjectMethodA( javaI, method_id, java_args ) );
+ break;
+ }
+
+ if (jni->ExceptionCheck())
+ {
+ JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
+ jni->ExceptionClear();
+
+ // release temp java local refs
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ if (param.bOut ||
+ typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+
+ handle_java_exc( jni, jo_exc, *uno_exc );
+ }
+ else // no exception
+ {
+ for ( nPos = 0; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & param = params[ nPos ];
+ if (param.bOut)
+ {
+ try
+ {
+ map_to_uno(
+ jni, uno_args[ nPos ],
+ java_args[ nPos ], param.pTypeRef, nullptr,
+ param.bIn /* assign if inout */,
+ true /* out param */ );
+ }
+ catch (...)
+ {
+ // cleanup uno pure out
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ typelib_MethodParameter const & p = params[ n ];
+ if (! p.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ n ], p.pTypeRef, nullptr );
+ }
+ }
+ // cleanup java temp local refs
+ for ( ; nPos < nParams; ++nPos )
+ {
+ typelib_MethodParameter const & p = params[ nPos ];
+ if (p.bOut ||
+ typelib_TypeClass_DOUBLE <
+ p.pTypeRef->eTypeClass)
+ {
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+ throw;
+ }
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ else // pure temp in param
+ {
+ if (typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
+ jni->DeleteLocalRef( java_args[ nPos ].l );
+ }
+ }
+
+ // return value
+ if (typelib_TypeClass_DOUBLE < return_type->eTypeClass)
+ {
+ try
+ {
+ jvalue val;
+ val.l = java_ret.get();
+ map_to_uno(
+ jni, uno_ret, val, return_type, nullptr,
+ false /* no assign */, false /* no out param */ );
+ }
+ catch (...)
+ {
+ // cleanup uno pure out
+ for ( sal_Int32 i = 0; i < nParams; ++i )
+ {
+ typelib_MethodParameter const & param = params[ i ];
+ if (! param.bIn)
+ {
+ uno_type_destructData(
+ uno_args[ i ], param.pTypeRef, nullptr );
+ }
+ }
+ throw;
+ }
+ } // else: already set integral uno return value
+
+ // no exception occurred
+ *uno_exc = nullptr;
+ }
+}
+
+namespace {
+
+// a UNO proxy wrapping a Java interface
+struct UNO_proxy : public uno_Interface
+{
+ mutable std::atomic<std::size_t> m_ref;
+ Bridge const * m_bridge;
+
+ // mapping information
+ jobject m_javaI;
+ jstring m_jo_oid;
+ OUString m_oid;
+ JNI_interface_type_info const * m_type_info;
+
+ inline void acquire() const;
+ inline void release() const;
+
+ // ctor
+ inline UNO_proxy(
+ JNI_context const & jni, Bridge const * bridge,
+ jobject javaI, jstring jo_oid, OUString oid,
+ JNI_interface_type_info const * info );
+};
+
+}
+
+inline UNO_proxy::UNO_proxy(
+ JNI_context const & jni, Bridge const * bridge,
+ jobject javaI, jstring jo_oid, OUString oid,
+ JNI_interface_type_info const * info )
+ : m_ref( 1 ),
+ m_oid(std::move( oid )),
+ m_type_info( info )
+{
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JLocalAutoRef jo_string_array(
+ jni, jni->NewObjectArray( 1, jni_info->m_class_String, jo_oid ) );
+ jni.ensure_no_exception();
+ jvalue args[ 3 ];
+ args[ 0 ].l = javaI;
+ args[ 1 ].l = jo_string_array.get();
+ args[ 2 ].l = info->m_type;
+ jobject jo_iface = jni->CallObjectMethodA(
+ jni_info->m_object_java_env,
+ jni_info->m_method_IEnvironment_registerInterface, args );
+ jni.ensure_no_exception();
+
+ m_javaI = jni->NewGlobalRef( jo_iface );
+ m_jo_oid = static_cast<jstring>(jni->NewGlobalRef( jo_oid ));
+ bridge->acquire();
+ m_bridge = bridge;
+
+ // uno_Interface
+ uno_Interface::acquire = UNO_proxy_acquire;
+ uno_Interface::release = UNO_proxy_release;
+ uno_Interface::pDispatcher = UNO_proxy_dispatch;
+}
+
+
+inline void UNO_proxy::acquire() const
+{
+ if (++m_ref == 1)
+ {
+ // rebirth of proxy zombie
+ void * that = const_cast< UNO_proxy * >( this );
+ // register at uno env
+ (*m_bridge->m_uno_env->registerProxyInterface)(
+ m_bridge->m_uno_env, &that,
+ UNO_proxy_free, m_oid.pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(m_type_info->m_td.get()) );
+ assert( this == that );
+ }
+}
+
+
+inline void UNO_proxy::release() const
+{
+ if (--m_ref == 0)
+ {
+ // revoke from uno env on last release
+ (*m_bridge->m_uno_env->revokeInterface)(
+ m_bridge->m_uno_env, const_cast< UNO_proxy * >( this ) );
+ }
+}
+
+
+uno_Interface * Bridge::map_to_uno(
+ JNI_context const & jni,
+ jobject javaI, JNI_interface_type_info const * info ) const
+{
+ JLocalAutoRef jo_oid( jni, compute_oid( jni, javaI ) );
+ OUString oid( jstring_to_oustring( jni, static_cast<jstring>(jo_oid.get()) ) );
+
+ uno_Interface * pUnoI = nullptr;
+ (*m_uno_env->getRegisteredInterface)(
+ m_uno_env, reinterpret_cast<void **>(&pUnoI),
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+
+ if (pUnoI == nullptr) // no existing interface, register new proxy
+ {
+ // refcount initially 1
+ pUnoI = new UNO_proxy(
+ jni, this,
+ javaI, static_cast<jstring>(jo_oid.get()), oid, info );
+
+ (*m_uno_env->registerProxyInterface)(
+ m_uno_env, reinterpret_cast<void **>(&pUnoI),
+ UNO_proxy_free,
+ oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
+ }
+ return pUnoI;
+}
+
+}
+
+using namespace ::jni_uno;
+
+namespace
+{
+extern "C"
+{
+
+
+void UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy * that = static_cast< UNO_proxy * >( proxy );
+ Bridge const * bridge = that->m_bridge;
+
+ assert(env == bridge->m_uno_env); (void) env;
+ SAL_INFO("bridges", "freeing binary uno proxy: " << that->m_oid);
+
+ try
+ {
+ JNI_guarded_context jni(
+ bridge->getJniInfo(),
+ (static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
+ ->machine));
+
+ jni->DeleteGlobalRef( that->m_javaI );
+ jni->DeleteGlobalRef( that->m_jo_oid );
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ SAL_WARN(
+ "bridges",
+ "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
+ }
+ catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ SAL_WARN("bridges", "attaching current thread to java failed");
+ }
+
+ bridge->release();
+#if OSL_DEBUG_LEVEL > 0
+ *reinterpret_cast<int *>(that) = 0xdeadcafe;
+#endif
+ delete that;
+}
+
+
+void UNO_proxy_acquire( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ that->acquire();
+}
+
+
+void UNO_proxy_release( uno_Interface * pUnoI )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ that->release();
+}
+
+
+void UNO_proxy_dispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
+ void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
+ SAL_THROW_EXTERN_C()
+{
+ UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
+ Bridge const * bridge = that->m_bridge;
+
+ SAL_INFO(
+ "bridges",
+ "uno->java call: " << OUString::unacquired(&member_td->pTypeName)
+ << " on oid " << that->m_oid);
+
+ try
+ {
+ switch (member_td->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription const * attrib_td =
+ reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(
+ member_td );
+ com::sun::star::uno::TypeDescription attrib_holder;
+ while ( attrib_td->pBaseRef != nullptr ) {
+ attrib_holder = com::sun::star::uno::TypeDescription(
+ attrib_td->pBaseRef );
+ assert(
+ attrib_holder.get()->eTypeClass
+ == typelib_TypeClass_INTERFACE_ATTRIBUTE );
+ attrib_td = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(
+ attrib_holder.get() );
+ }
+ typelib_InterfaceTypeDescription * iface_td = attrib_td->pInterface;
+
+ if (uno_ret == nullptr) // is setter method
+ {
+ typelib_MethodParameter param;
+ param.pTypeRef = attrib_td->pAttributeTypeRef;
+ param.bIn = true;
+ param.bOut = false;
+
+ bridge->call_java(
+ that->m_javaI, iface_td,
+ attrib_td->nIndex, 1, // get, then set method
+ bridge->getJniInfo()->m_void_type.getTypeLibType(),
+ &param, 1,
+ nullptr, uno_args, uno_exc );
+ }
+ else // is getter method
+ {
+ bridge->call_java(
+ that->m_javaI, iface_td, attrib_td->nIndex, 0,
+ attrib_td->pAttributeTypeRef,
+ nullptr, 0, // no params
+ uno_ret, nullptr, uno_exc );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const * method_td =
+ reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(
+ member_td );
+ com::sun::star::uno::TypeDescription method_holder;
+ while ( method_td->pBaseRef != nullptr ) {
+ method_holder = com::sun::star::uno::TypeDescription(
+ method_td->pBaseRef );
+ assert(
+ method_holder.get()->eTypeClass
+ == typelib_TypeClass_INTERFACE_METHOD );
+ method_td = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(
+ method_holder.get() );
+ }
+ typelib_InterfaceTypeDescription * iface_td = method_td->pInterface;
+
+ switch ( method_td->aBase.nPosition )
+ {
+ case 0: // queryInterface()
+ {
+ TypeDescr demanded_td(
+ *static_cast< typelib_TypeDescriptionReference ** >(
+ uno_args[ 0 ] ) );
+ if (demanded_td.get()->eTypeClass !=
+ typelib_TypeClass_INTERFACE)
+ {
+ throw BridgeRuntimeError(
+ "queryInterface() call demands an INTERFACE type!" );
+ }
+
+ uno_Interface * pInterface = nullptr;
+ (*bridge->m_uno_env->getRegisteredInterface)(
+ bridge->m_uno_env,
+ reinterpret_cast<void **>(&pInterface), that->m_oid.pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(demanded_td.get()) );
+
+ if (pInterface == nullptr)
+ {
+ JNI_info const * jni_info = bridge->getJniInfo();
+ JNI_guarded_context jni(
+ jni_info,
+ (static_cast<JniUnoEnvironmentData *>(
+ bridge->m_java_env->pContext)
+ ->machine));
+
+ JNI_interface_type_info const * info =
+ static_cast< JNI_interface_type_info const * >(
+ jni_info->get_type_info( jni, demanded_td.get() ) );
+
+ jvalue args[ 2 ];
+ args[ 0 ].l = info->m_type;
+ args[ 1 ].l = that->m_javaI;
+
+ JLocalAutoRef jo_ret(
+ jni, jni->CallStaticObjectMethodA(
+ jni_info->m_class_UnoRuntime,
+ jni_info->m_method_UnoRuntime_queryInterface,
+ args ) );
+
+ if (jni->ExceptionCheck())
+ {
+ JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
+ jni->ExceptionClear();
+ bridge->handle_java_exc( jni, jo_exc, *uno_exc );
+ }
+ else
+ {
+ if (jo_ret.is())
+ {
+ SAL_WARN_IF(
+ (jstring_to_oustring(
+ jni,
+ static_cast<jstring>(
+ JLocalAutoRef(
+ jni, compute_oid(jni, jo_ret.get()))
+ .get()))
+ != that->m_oid),
+ "bridges", "different oids");
+ // refcount initially 1
+ uno_Interface * pUnoI2 = new UNO_proxy(
+ jni, bridge, jo_ret.get(),
+ that->m_jo_oid, that->m_oid, info );
+
+ (*bridge->m_uno_env->registerProxyInterface)(
+ bridge->m_uno_env,
+ reinterpret_cast<void **>(&pUnoI2),
+ UNO_proxy_free, that->m_oid.pData,
+ reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(
+ info->m_td.get() ) );
+
+ uno_any_construct(
+ static_cast<uno_Any *>(uno_ret), &pUnoI2,
+ demanded_td.get(), nullptr );
+ (*pUnoI2->release)( pUnoI2 );
+ }
+ else // object does not support demanded interface
+ {
+ uno_any_construct(
+ static_cast< uno_Any * >( uno_ret ),
+ nullptr, nullptr, nullptr );
+ }
+ // no exception occurred
+ *uno_exc = nullptr;
+ }
+ }
+ else
+ {
+ uno_any_construct(
+ static_cast< uno_Any * >( uno_ret ),
+ &pInterface, demanded_td.get(), nullptr );
+ (*pInterface->release)( pInterface );
+ *uno_exc = nullptr;
+ }
+ break;
+ }
+ case 1: // acquire this proxy
+ that->acquire();
+ *uno_exc = nullptr;
+ break;
+ case 2: // release this proxy
+ that->release();
+ *uno_exc = nullptr;
+ break;
+ default: // arbitrary method call
+ bridge->call_java(
+ that->m_javaI, iface_td, method_td->nIndex, 0,
+ method_td->pReturnTypeRef,
+ method_td->pParams, method_td->nParams,
+ uno_ret, uno_args, uno_exc );
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ throw BridgeRuntimeError(
+ "illegal member type description!" );
+ }
+ }
+ }
+ catch (BridgeRuntimeError & err)
+ {
+ OUStringBuffer buf( 128 );
+ buf.append( "[jni_uno bridge error] UNO calling Java method " );
+ if (member_td->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ||
+ member_td->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE)
+ {
+ buf.append( OUString::unacquired(
+ &reinterpret_cast<
+ typelib_InterfaceMemberTypeDescription const * >(
+ member_td )->pMemberName ) );
+ }
+ buf.append( ": " + err.m_message );
+ // binary identical struct
+ css::uno::RuntimeException exc(
+ buf.makeStringAndClear(),
+ css::uno::Reference<
+ css::uno::XInterface >() );
+ css::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
+ uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), nullptr );
+ SAL_INFO("bridges", exc.Message);
+ }
+ catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ // binary identical struct
+ css::uno::RuntimeException exc(
+ "[jni_uno bridge error] attaching current thread to java failed!",
+ css::uno::Reference<
+ css::uno::XInterface >() );
+ css::uno::Type const & exc_type = cppu::UnoType<decltype(exc)>::get();
+ uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), nullptr );
+ SAL_WARN("bridges", exc.Message);
+ }
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/jniunoenvironmentdata.hxx b/bridges/source/jni_uno/jniunoenvironmentdata.hxx
new file mode 100644
index 0000000000..d1f3bab4b1
--- /dev/null
+++ b/bridges/source/jni_uno/jniunoenvironmentdata.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <jni.h>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <rtl/ref.hxx>
+
+#include "jni_info.h"
+#include <mutex>
+
+namespace jni_uno {
+
+// The pContext payload of a JNI uno_Environment:
+struct JniUnoEnvironmentData {
+ JniUnoEnvironmentData(const JniUnoEnvironmentData&) = delete;
+ const JniUnoEnvironmentData& operator=(const JniUnoEnvironmentData&) = delete;
+
+ explicit JniUnoEnvironmentData(
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const & theMachine):
+ machine(theMachine), info(JNI_info::get_jni_info(theMachine)),
+ asynchronousFinalizer(nullptr)
+ {}
+
+ rtl::Reference<jvmaccess::UnoVirtualMachine> const machine;
+ JNI_info const * const info;
+
+ std::mutex mutex;
+ jobject asynchronousFinalizer;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/jni_uno/nativethreadpool.cxx b/bridges/source/jni_uno/nativethreadpool.cxx
new file mode 100644
index 0000000000..1d14c47bb0
--- /dev/null
+++ b/bridges/source/jni_uno/nativethreadpool.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <jvmaccess/virtualmachine.hxx>
+#include <rtl/byteseq.h>
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <sal/types.h>
+#include <uno/threadpool.h>
+
+#include <jni.h>
+
+#include <new>
+#include <utility>
+
+/* The native implementation part of
+ * jurt/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java.
+ */
+
+namespace {
+
+struct Pool {
+ Pool(rtl::Reference< jvmaccess::VirtualMachine > theVirtualMachine,
+ jmethodID theExecute, uno_ThreadPool thePool):
+ virtualMachine(std::move(theVirtualMachine)), execute(theExecute), pool(thePool) {}
+
+ rtl::Reference< jvmaccess::VirtualMachine > virtualMachine;
+ jmethodID execute;
+ uno_ThreadPool pool;
+};
+
+struct Job {
+ Job(Pool * thePool, jobject theJob): pool(thePool), job(theJob) {}
+
+ Pool * pool;
+ jobject job;
+};
+
+void throwOutOfMemory(JNIEnv * env) {
+ jclass c = env->FindClass("java/lang/OutOfMemoryError");
+ if (c != nullptr) {
+ env->ThrowNew(c, "");
+ }
+}
+
+}
+
+extern "C" {
+
+static void executeRequest(void * data) {
+ Job * job = static_cast< Job * >(data);
+ try {
+ jvmaccess::VirtualMachine::AttachGuard guard(job->pool->virtualMachine);
+ JNIEnv * env = guard.getEnvironment();
+ // Failure of the following Job.execute Java call is ignored; if that
+ // call fails, it should be due to a java.lang.Error, which is not
+ // handled well, anyway:
+ env->CallObjectMethod(job->job, job->pool->execute);
+ env->DeleteGlobalRef(job->job);
+ delete job;
+ } catch (const jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ //TODO: DeleteGlobalRef(job->job)
+ delete job;
+ }
+}
+
+}
+
+extern "C" SAL_JNI_EXPORT jbyteArray JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_threadId(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass) SAL_THROW_EXTERN_C()
+{
+ sal_Sequence * s = nullptr;
+ uno_getIdOfCurrentThread(&s); //TODO: out of memory
+ uno_releaseIdFromCurrentThread();
+ rtl::ByteSequence seq(s);
+ rtl_byte_sequence_release(s);
+ sal_Int32 n = seq.getLength();
+ jbyteArray a = env->NewByteArray(n);
+ // sal_Int32 and jsize are compatible here
+ if (a == nullptr) {
+ return nullptr;
+ }
+ void * p = env->GetPrimitiveArrayCritical(a, nullptr);
+ if (p == nullptr) {
+ return nullptr;
+ }
+ memcpy(p, seq.getConstArray(), n);
+ // sal_Int8 and jbyte ought to be compatible
+ env->ReleasePrimitiveArrayCritical(a, p, 0);
+ return a;
+}
+
+extern "C" SAL_JNI_EXPORT jlong JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_create(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass) SAL_THROW_EXTERN_C()
+{
+ JavaVM * vm;
+ if (env->GetJavaVM(&vm) != JNI_OK) { //TODO: no Java exception raised?
+ jclass c = env->FindClass("java/lang/RuntimeException");
+ if (c != nullptr) {
+ env->ThrowNew(c, "JNI GetJavaVM failed");
+ }
+ return 0;
+ }
+ jclass c = env->FindClass("com/sun/star/lib/uno/environments/remote/Job");
+ if (c == nullptr) {
+ return 0;
+ }
+ jmethodID execute = env->GetMethodID(c, "execute", "()Ljava/lang/Object;");
+ if (execute == nullptr) {
+ return 0;
+ }
+ try {
+ return reinterpret_cast< jlong >(new Pool(
+ new jvmaccess::VirtualMachine(vm, env->GetVersion(), false, env),
+ execute, uno_threadpool_create()));
+ } catch (const std::bad_alloc &) {
+ throwOutOfMemory(env);
+ return 0;
+ }
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_attach(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_attach(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT jobject JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_enter(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass, jlong pool) SAL_THROW_EXTERN_C()
+{
+ jobject job;
+ uno_threadpool_enter(
+ reinterpret_cast< Pool * >(pool)->pool,
+ reinterpret_cast< void ** >(&job));
+ if (job == nullptr) {
+ return nullptr;
+ }
+ jobject ref = env->NewLocalRef(job);
+ env->DeleteGlobalRef(job);
+ return ref;
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_detach(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_detach(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_putJob(
+ JNIEnv * env, SAL_UNUSED_PARAMETER jclass, jlong pool, jbyteArray threadId,
+ jobject job, jboolean request, jboolean oneWay) SAL_THROW_EXTERN_C()
+{
+ void * s = env->GetPrimitiveArrayCritical(threadId, nullptr);
+ if (s == nullptr) {
+ return;
+ }
+ rtl::ByteSequence seq(
+ static_cast< sal_Int8 * >(s), env->GetArrayLength(threadId));
+ // sal_Int8 and jbyte ought to be compatible; sal_Int32 and jsize are
+ // compatible here
+ //TODO: out of memory
+ env->ReleasePrimitiveArrayCritical(threadId, s, JNI_ABORT);
+ Pool * p = reinterpret_cast< Pool * >(pool);
+ jobject ref = env->NewGlobalRef(job);
+ if (ref == nullptr) {
+ return;
+ }
+ Job * j = nullptr;
+ if (request) {
+ j = new(std::nothrow) Job(p, ref);
+ if (j == nullptr) {
+ env->DeleteGlobalRef(ref);
+ throwOutOfMemory(env);
+ return;
+ }
+ }
+ uno_threadpool_putJob(
+ p->pool, seq.getHandle(),
+ request ? static_cast< void * >(j) : static_cast< void * >(ref),
+ request ? executeRequest : nullptr, oneWay);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_dispose(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ uno_threadpool_dispose(reinterpret_cast< Pool * >(pool)->pool);
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL
+Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_destroy(
+ SAL_UNUSED_PARAMETER JNIEnv *, SAL_UNUSED_PARAMETER jclass, jlong pool)
+ SAL_THROW_EXTERN_C()
+{
+ Pool * p = reinterpret_cast< Pool * >(pool);
+ uno_threadpool_destroy(p->pool);
+ delete p;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */