diff options
Diffstat (limited to 'bridges')
-rw-r--r-- | bridges/Library_gcc3_macosx_x86-64.mk | 72 | ||||
-rw-r--r-- | bridges/Module_bridges.mk | 3 | ||||
-rw-r--r-- | bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx | 3 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx | 330 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx | 70 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/call.s | 79 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx | 173 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx | 50 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx | 525 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx | 389 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx | 104 | ||||
-rw-r--r-- | bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx | 459 |
12 files changed, 2256 insertions, 1 deletions
diff --git a/bridges/Library_gcc3_macosx_x86-64.mk b/bridges/Library_gcc3_macosx_x86-64.mk new file mode 100644 index 000000000000..b7b69c474487 --- /dev/null +++ b/bridges/Library_gcc3_macosx_x86-64.mk @@ -0,0 +1,72 @@ +# -*- 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/. +# + +ifneq ($(strip $(bridges_SELECTED_BRIDGE)),) +$(eval $(call gb_Output_error,cannot build bridge gcc3_linux_x86-64: bridge $(bridges_SELECTED_BRIDGE) already selected)) +endif +bridges_SELECTED_BRIDGE := gcc3_macosx_x86-64 + +$(eval $(call gb_Library_Library,gcc3_uno)) + +$(eval $(call gb_Library_use_internal_comprehensive_api,gcc3_uno,\ + udkapi \ +)) + +$(eval $(call gb_Library_set_include,gcc3_uno,\ + -I$(SRCDIR)/bridges/inc \ + $$(INCLUDE) \ +)) + +ifeq ($(HAVE_POSIX_FALLOCATE),YES) +$(eval $(call gb_Library_add_defs,gcc3_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. +# In case the compiler supports AVX this code segfaults so specifically turn +# it off. +$(eval $(call gb_Library_add_cxxflags,gcc3_uno,\ + -fno-omit-frame-pointer \ + -fno-strict-aliasing \ + $(if $(filter TRUE,$(HAVE_GCC_AVX)),\ + -mno-avx \ + ) \ +)) + +$(eval $(call gb_Library_use_libraries,gcc3_uno,\ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_asmobjects,gcc3_uno,\ + bridges/source/cpp_uno/gcc3_macosx_x86-64/call \ +)) + +$(eval $(call gb_Library_add_exception_objects,gcc3_uno,\ + bridges/source/cpp_uno/gcc3_macosx_x86-64/abi \ + bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod \ + bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno \ + bridges/source/cpp_uno/gcc3_macosx_x86-64/except \ + bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp \ + 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 \ +)) + +$(eval $(call gb_Library_add_cxxobjects,gcc3_uno,\ + bridges/source/cpp_uno/shared/cppinterfaceproxy \ + , $(gb_COMPILERNOOPTFLAGS) $(gb_LinkTarget_EXCEPTIONFLAGS) \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/bridges/Module_bridges.mk b/bridges/Module_bridges.mk index 800c8ca17f1a..118e82f4466b 100644 --- a/bridges/Module_bridges.mk +++ b/bridges/Module_bridges.mk @@ -73,6 +73,9 @@ $(eval $(call gb_Module_add_targets,bridges,\ $(if $(filter GCCMACOSXI,$(COM)$(OS)$(CPU)),\ Library_gcc3_macosx_intel \ ) \ + $(if $(filter GCCMACOSXX,$(COM)$(OS)$(CPU)),\ + Library_gcc3_macosx_x86-64 \ + ) \ $(if $(filter GCCMACOSXP,$(COM)$(OS)$(CPU)),\ Library_gcc3_macosx_powerpc \ ) \ diff --git a/bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx b/bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx index bc43fb48e519..cc6ef427ea7f 100644 --- a/bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx +++ b/bridges/inc/bridges/cpp_uno/shared/vtablefactory.hxx @@ -39,7 +39,8 @@ /*See: http://people.redhat.com/drepper/selinux-mem.html*/ #if defined(LINUX) || defined(OPENBSD) || defined(FREEBSD) \ - || defined(NETBSD) || defined(DRAGONFLY) || defined (ANDROID) + || defined(NETBSD) || defined(DRAGONFLY) || defined (ANDROID) \ + || (defined(MACOSX) && defined(__LP64__)) #define USE_DOUBLE_MMAP #endif 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 000000000000..9fb14a90082c --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.cxx @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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" + +using namespace x86_64; + +/* 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 reformating penalties. + + Similary 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_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_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) + throw () +{ + /* 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 #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + 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 parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 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 ) throw () +{ + switch ( pTypeRef->eTypeClass ) + { + case typelib_TypeClass_VOID: + classes[0] = X86_64_NO_CLASS; + return 1; + 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_SSEDF_CLASS; + return 1; + /*case LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2;*/ + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_UNION: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_ARRAY: + case typelib_TypeClass_INTERFACE: + return 0; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTypeDescr = 0; + 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] ); + } + } + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + + /* Final merger cleanup. */ + for ( int i = 0; i < words; i++ ) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if ( classes[i] == X86_64_MEMORY_CLASS ) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if ( classes[i] == X86_64_SSEUP_CLASS + && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) ) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if ( classes[i] == X86_64_X87UP_CLASS + && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) ) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + default: +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "Unhandled case: pType->eTypeClass == %d", pTypeRef->eTypeClass ); +#endif + OSL_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* 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, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw () +{ + 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: + case X86_64_SSEDF_CLASS: + nUsedSSE++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + if ( !bInReturn ) + return false; + break; + default: +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "Unhandled case: classes[n] == %d", classes[n] ); +#endif + OSL_ASSERT(0); + } + return true; +} + +bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw () +{ + int g, s; + + return examine_argument( pTypeRef, true, g, s ) == 0; +} + +void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw () +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int n; + + n = classify_argument( pTypeRef, classes, 0 ); + + sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct ); + for ( n--; n >= 0; n-- ) + switch ( classes[n] ) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + *pStructAlign++ = *pGPR++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ ); + break; + default: + break; + } +} + +/* 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 000000000000..ba3e8f24542f --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/abi.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ +#define _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ + +// 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, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw (); + +/** 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 ) throw (); + +void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64* pGPR, const double* pSSE, void *pStruct ) throw (); + +} // namespace x86_64 + +#endif // _BRIDGES_CPP_UNO_X86_64_ABI_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.s b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.s new file mode 100644 index 000000000000..8b8072ff049c --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/call.s @@ -0,0 +1,79 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 4, 0x90 + .globl _privateSnippetExecutor +_privateSnippetExecutor: + .cfi_startproc +.LFB3: + pushq %rbp +.LCFI0: + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp +.LCFI1: + subq $160, %rsp +.LCFI2: + .cfi_def_cfa_register %rbp + 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 + + cmp $10, %rax # typelib_TypeClass_FLOAT + je .Lfloat + cmp $11, %rax # typelib_TypeClass_DOUBLE + je .Lfloat + + movq -144(%rbp), %rax # Return value (int case) + movq -136(%rbp), %rdx # Return value (int case) + movq -144(%rbp), %xmm0 # Return value (int case) + movq -136(%rbp), %xmm1 # Return value (int case) + jmp .Lfinish +.Lfloat: + movlpd -144(%rbp), %xmm0 # Return value (float/double case) + +.Lfinish: + leave + ret + .cfi_endproc + +.subsections_via_symbols 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 000000000000..57d039595982 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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, sal_uInt32 nGPR, + double * pFPR, sal_uInt32 nFPR) +{ + // Should not happen, but... + if ( nFPR > x86_64::MAX_SSE_REGS ) + nFPR = x86_64::MAX_SSE_REGS; + if ( nGPR > x86_64::MAX_GPR_REGS ) + nGPR = x86_64::MAX_GPR_REGS; + + // Get pointer to method + sal_uInt64 pMethod = *((sal_uInt64 *)pThis); + pMethod += 8 * nVtableIndex; + pMethod = *((sal_uInt64 *)pMethod); + + // Load parameters to stack, if necessary + if ( nStack ) + { + // 16-bytes aligned + sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16; + sal_uInt64 *pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes ); + std::memcpy( pCallStack, pStack, nStackBytes ); + } + + // Return values + sal_uInt64 rax; + sal_uInt64 rdx; + double xmm0; + double xmm1; + + asm volatile ( + + // Fill the xmm registers + "movq %6, %%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 %5, %%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 %4, %%r11\n\t" + "movq %7, %%rax\n\t" + "call *%%r11\n\t" + + // Fill the return values + "movq %%rax, %0\n\t" + "movq %%rdx, %1\n\t" + "movsd %%xmm0, %2\n\t" + "movsd %%xmm1, %3\n\t" + : "=m" ( rax ), "=m" ( rdx ), "=m" ( xmm0 ), "=m" ( xmm1 ) + : "m" ( pMethod ), "m" ( pGPR ), "m" ( pFPR ), "m" ( nFPR ) + : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" + ); + + switch (pReturnTypeRef->eTypeClass) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = rax; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32*>( &rax ); + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &rax ); + break; + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &rax ); + break; + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + *reinterpret_cast<double *>( pRegisterReturn ) = xmm0; + break; + default: + { + sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize; + if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0) + { + sal_uInt64 longs[2]; + longs[0] = rax; + longs[1] = rdx; + + double doubles[2]; + doubles[0] = xmm0; + doubles[1] = 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 000000000000..2a776b9e87e6 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/callvirtualmethod.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_GCC3_LINUX_X86_64_CALLVIRTUALMETHOD_HXX +#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_GCC3_LINUX_X86_64_CALLVIRTUALMETHOD_HXX + +#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, sal_uInt32 nGPR, + double * pFPR, sal_uInt32 nFPR); + +} + +#endif + +/* 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 000000000000..89ab4624911a --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include <stdio.h> +#include <stdlib.h> +#include <boost/unordered_map.hpp> + +#include <rtl/alloc.h> +#include <osl/mutex.hxx> + +#include <com/sun/star/uno/genfunc.hxx> +#include "com/sun/star/uno/RuntimeException.hpp" +#include <uno/data.h> +#include <typelib/typedescription.hxx> + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" +#include "bridges/cpp_uno/shared/types.hxx" +#include "bridges/cpp_uno/shared/vtablefactory.hxx" + +#include "abi.hxx" +#include "share.hxx" + +using namespace ::osl; +using namespace ::rtl; +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. +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 */ ) +{ + unsigned int nr_gpr = 0; //number of gpr registers used + unsigned int nr_fpr = 0; //number of fpr registers used + + // 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 ( x86_64::return_in_hidden_param( pReturnTypeRef ) ) + { + 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 = (void **)alloca( 4 * sizeof(void *) * nParams ); + void ** pCppArgs = pUnoArgs + nParams; + // indizes of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); + // type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); + + sal_Int32 nTempIndizes = 0; + + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + + int nUsedGPR = 0; + int nUsedSSE = 0; +#if OSL_DEBUG_LEVEL > 0 + bool bFitsRegisters = +#endif + x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE ); + if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value + { + // Simple types must fit exactly one register on x86_64 + OSL_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 // struct <= 16 bytes || ptr to complex value || ref + { + typelib_TypeDescription * pParamTypeDescr = 0; + 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 ); + pTempIndizes[nTempIndizes] = nPos; + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout + { + uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pCppStack, pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + pTempIndizes[nTempIndizes] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = 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 ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + + if (pParams[nIndex].bIn) // is in/inout => was constructed + uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + 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 ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; + + 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; + } +} + + +//================================================================================================== +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 */ ) +{ + // 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(); + + OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); + if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) + { + throw RuntimeException( OUString(RTL_CONSTASCII_USTRINGPARAM("illegal vtable index!")), + reinterpret_cast<XInterface *>( pCppI ) ); + } + + // determine called method + sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); + + TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); + + typelib_TypeClass 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 = 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, + 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: + { + 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( OUString(RTL_CONSTASCII_USTRINGPARAM("no member description found!")), + reinterpret_cast<XInterface *>( pCppI ) ); + } + } + + return eRet; +} + +//================================================================================================== +extern "C" void privateSnippetExecutor( ... ); + +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. +unsigned char * codeSnippet( unsigned char * code, + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, + bool bHasHiddenParam ) SAL_THROW(()) +{ + sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); + + if ( bHasHiddenParam ) + nOffsetAndIndex |= 0x80000000; + + // movq $<nOffsetAndIndex>, %r10 + *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49; + *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex; + + // movq $<address of the privateSnippetExecutor>, %r11 + *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49; + *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor ); + + // 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 * fn; }; + +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) +{ + return static_cast< Slot * >(block) + 2; +} + +//================================================================================================== +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( + sal_Int32 slotCount) +{ + return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; +} + +//================================================================================================== +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::initializeBlock( + void * block, sal_Int32 slotCount) +{ + Slot * slots = mapBlockToVtable(block); + slots[-2].fn = 0; + slots[-1].fn = 0; + 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 = 0; + + TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); + OSL_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 + OSL_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 000000000000..03a7ca5b36db --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> + +#include <cxxabi.h> +#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h +#define _GLIBCXX_CDTOR_CALLABI +#endif + +#include <boost/unordered_map.hpp> + +#include <sal/log.hxx> +#include <rtl/instance.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> +#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 "share.hxx" + + +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::__cxxabiv1; + + +namespace CPPU_CURRENT_NAMESPACE +{ + +#if MACOSX_SDK_VERSION >= 1070 + +// MacOSX10.4u.sdk/usr/include/c++/4.0.0/cxxabi.h defined +// __cxxabiv1::__class_type_info and __cxxabiv1::__si_class_type_info but +// MacOSX10.7.sdk/usr/include/cxxabi.h no longer does, so instances of those +// classes need to be created manually: + +// std::type_info defined in <typeinfo> offers a protected ctor: +struct FAKE_type_info: public std::type_info { + FAKE_type_info(char const * name): type_info(name) {} +}; + +// Modeled after __cxxabiv1::__si_class_type_info defined in +// MacOSX10.4u.sdk/usr/include/c++/4.0.0/cxxabi.h (i.e., +// abi::__si_class_type_info documented at +// <http://www.codesourcery.com/public/cxx-abi/abi.html#rtti>): +struct FAKE_si_class_type_info: public FAKE_type_info { + FAKE_si_class_type_info(char const * name, std::type_info const * theBase): + FAKE_type_info(name), base(theBase) {} + + std::type_info const * base; + // actually a __cxxabiv1::__class_type_info pointer +}; + +struct Base {}; +struct Derived: Base {}; + +std::type_info * create_FAKE_class_type_info(char const * name) { + std::type_info * p = new FAKE_type_info(name); + // cxxabiv1::__class_type_info has no data members in addition to + // std::type_info + *reinterpret_cast< void ** >(p) = *reinterpret_cast< void * const * >( + &typeid(Base)); + // copy correct __cxxabiv1::__class_type_info vtable into place + return p; +} + +std::type_info * create_FAKE_si_class_type_info( + char const * name, std::type_info const * base) +{ + std::type_info * p = new FAKE_si_class_type_info(name, base); + *reinterpret_cast< void ** >(p) = *reinterpret_cast< void * const * >( + &typeid(Derived)); + // copy correct __cxxabiv1::__si_class_type_info vtable into place + return p; +} + +#endif + +//================================================================================================== +static OUString toUNOname( char const * p ) SAL_THROW(()) +{ +#if OSL_DEBUG_LEVEL > 1 + char const * start = p; +#endif + + // example: N3com3sun4star4lang24IllegalArgumentExceptionE + + OUStringBuffer buf( 64 ); + OSL_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( (sal_Unicode)'.' ); + } + +#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 boost::unordered_map< OUString, type_info *, OUStringHash > t_rtti_map; + + Mutex m_mutex; + t_rtti_map m_rttis; + t_rtti_map m_generatedRttis; + + void * m_hApp; + +public: + RTTI() SAL_THROW(()); + ~RTTI() SAL_THROW(()); + + type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW(()); +}; +//__________________________________________________________________________________________________ +RTTI::RTTI() SAL_THROW(()) +#if defined(FREEBSD) && __FreeBSD_version < 702104 + : m_hApp( dlopen( 0, RTLD_NOW | RTLD_GLOBAL ) ) +#else + : m_hApp( dlopen( 0, RTLD_LAZY ) ) +#endif +{ +} +//__________________________________________________________________________________________________ +RTTI::~RTTI() SAL_THROW(()) +{ + dlclose( m_hApp ); +} + +//__________________________________________________________________________________________________ +type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW(()) +{ + 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( RTL_CONSTASCII_STRINGPARAM("_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(FREEBSD) && __FreeBSD_version < 702104 /* #i22253# */ + rtti = (type_info *)dlsym( RTLD_DEFAULT, symName.getStr() ); +#else + rtti = (type_info *)dlsym( m_hApp, 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", "key " << unoName << " already in rtti map" ); + } + 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 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 ); +#if MACOSX_SDK_VERSION < 1070 + rtti = new __si_class_type_info( + strdup( rttiName ), (__class_type_info *)base_rtti ); +#else + rtti = create_FAKE_si_class_type_info( + strdup( rttiName ), base_rtti ); +#endif + } + else + { + // this class has no base class +#if MACOSX_SDK_VERSION < 1070 + rtti = new __class_type_info( strdup( rttiName ) ); +#else + rtti = create_FAKE_class_type_info( strdup( rttiName ) ); +#endif + } + + pair< t_rtti_map::iterator, bool > insertion ( + m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) ); + SAL_WARN_IF( !insertion.second, "bridges", "key " << unoName << " already in generated rtti map" ); + } + else // taking already generated rtti + { + rtti = iFind2->second; + } + } + } + else + { + rtti = iFind->second; + } + + return rtti; +} + +struct RTTISingleton: public rtl::Static< RTTI, RTTISingleton > {}; + +//-------------------------------------------------------------------------------------------------- +extern "C" { +static void _GLIBCXX_CDTOR_CALLABI 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 ); + OSL_ENSURE( 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( + *reinterpret_cast< OUString const * >( &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 ); + OSL_ASSERT( pTypeDescr ); + if (! pTypeDescr) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) + + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + Reference< XInterface >() ); + } + + pCppExc = __cxa_allocate_exception( pTypeDescr->nSize ); + ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp ); + + // destruct uno exception + ::uno_any_destruct( pUnoExc, 0 ); + // avoiding locked counts + rtti = (type_info *)RTTISingleton::get().getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); + if (! rtti) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + Reference< XInterface >() ); + } + } + + __cxa_throw( pCppExc, rtti, deleteException ); +} + +//================================================================================================== +void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno ) +{ + if (! header) + { + RuntimeException aRE( + OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ), + Reference< XInterface >() ); + Type const & rType = ::getCppuType( &aRE ); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_FAIL( cstr.getStr() ); +#endif + return; + } + + typelib_TypeDescription * pExcTypeDescr = 0; + OUString unoName( toUNOname( header->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( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName, + Reference< XInterface >() ); + Type const & rType = ::getCppuType( &aRE ); + uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_FAIL( cstr.getStr() ); +#endif + } + 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 000000000000..f84958b96368 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/share.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "uno/mapping.h" + +#include <typeinfo> +#include <exception> +#include <cstddef> + +namespace CPPU_CURRENT_NAMESPACE +{ + +// ----- 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 *); + + ::std::unexpected_handler unexpectedHandler; + ::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; +}; + +} + +extern "C" CPPU_CURRENT_NAMESPACE::__cxa_eh_globals *__cxa_get_globals () throw(); + +namespace CPPU_CURRENT_NAMESPACE +{ + +// The following are in cxxabi.h since GCC 4.7 (they are wrapped in +// CPPU_CURRENT_NAMESPACE here as different GCC versions have slightly different +// declarations for them, e.g., with or without throw() specification, so would +// complain about redeclarations of these somewhat implicitly declared +// functions): +#if __GNUC__ == 4 && __GNUC_MINOR__ <= 6 +extern "C" void *__cxa_allocate_exception( + std::size_t thrown_size ) throw(); +extern "C" void __cxa_throw ( + void *thrown_exception, void *tinfo, void (*dest) (void *) ) __attribute__((noreturn)); +#endif + +// ----- + +//================================================================================================== +void raiseException( + uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ); +//================================================================================================== +void fillUnoException( + __cxa_exception * header, 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 000000000000..ff6fbdda7649 --- /dev/null +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/uno2cpp.cxx @@ -0,0 +1,459 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DRAGONFLY) +#include <stdlib.h> +#else +#include <alloca.h> +#endif +#include <exception> +#include <typeinfo> + +#include "rtl/alloc.h" +#include "rtl/ustrbuf.hxx" + +#include <com/sun/star/uno/genfunc.hxx> +#include "com/sun/star/uno/RuntimeException.hpp" +#include <uno/data.h> + +#include <bridges/cpp_uno/shared/bridge.hxx> +#include <bridges/cpp_uno/shared/types.hxx> +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "abi.hxx" +#include "callvirtualmethod.hxx" +#include "share.hxx" + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +// 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_DOUBLE( pSV, nr, pFPR, pDS ) \ + if ( nr < x86_64::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 < x86_64::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 < x86_64::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 < x86_64::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 < x86_64::MAX_GPR_REGS ) \ + pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \ + else \ + *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV ); + +//================================================================================================== + +namespace { + +void appendCString(OUStringBuffer & buffer, char const * text) { + if (text != 0) { + buffer.append( + OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1)); + // use 8859-1 to avoid conversion failure + } +} + +} + +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 ) +{ + // Maxium 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 = (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 = 0; + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); + + void * pCppReturn = 0; // 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 = (void **)alloca( 3 * sizeof(void *) * nParams ); + // Indizes of values this have to be converted (interface conversion cpp<=>uno) + sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); + // Type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); + + sal_Int32 nTempIndizes = 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: + 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 ); + pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = 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() ); + + pTempIndizes[nTempIndizes] = nPos; // has to be reconverted + // will be released at reconversion + ppTempParamTypeDescr[nTempIndizes++] = 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, nGPR, + pFPR, nFPR ); + } catch (const Exception &) { + throw; + } catch (const std::exception & e) { + OUStringBuffer buf; + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("C++ code threw ")); + appendCString(buf, typeid(e).name()); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(": ")); + appendCString(buf, e.what()); + throw RuntimeException( + buf.makeStringAndClear(), Reference< XInterface >()); + } catch (...) { + throw RuntimeException( + OUString( + RTL_CONSTASCII_USTRINGPARAM( + "C++ code threw unknown exception")), + Reference< XInterface >()); + } + + *ppUnoExc = 0; + + // reconvert temporary params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; + + 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 + fillUnoException( __cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); + + // temporary params + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + // destroy temp cpp param => cpp: every param was constructed + uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + // return type + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + } +} + +//================================================================================================== + +namespace bridges { namespace cpp_uno { namespace 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; + OSL_ENSURE( 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( RTL_CONSTASCII_USTRINGPARAM("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 = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; + OSL_ENSURE( 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() + 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( + OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); + + Type const & rExcType = ::getCppuType( &aExc ); + // binary identical null reference + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } +} + +} } } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |