diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /bridges | |
parent | Initial commit. (diff) | |
download | libreoffice-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 'bridges')
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–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, ¶m, 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, ¶m, 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, ¶m, 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 + // ©Construct + 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) = ©Construct; +} + +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, ¶m, 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*>(©Construct); + 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–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, ¶m, + 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(), + ¶m, 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: */ |