diff options
author | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2013-06-04 15:14:57 +0200 |
---|---|---|
committer | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2013-06-04 15:15:21 +0200 |
commit | 211544a5f26a2258c39c6c6b948512e395fafa03 (patch) | |
tree | 13a9e86261482db1d40ad79071a5465e6ca4fca9 /bridges | |
parent | Hopefully fix build on Linux (diff) | |
download | core-211544a5f26a2258c39c6c6b948512e395fafa03.tar.gz core-211544a5f26a2258c39c6c6b948512e395fafa03.zip |
Compiling but not working mingw_x86-64 bridges
Change-Id: I5ea6edf367dd18e60a86d12c523b7732a8ac44d4
Diffstat (limited to 'bridges')
-rw-r--r-- | bridges/Library_cpp_uno.mk | 7 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/abi.cxx | 330 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/abi.hxx | 61 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/call.s | 342 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.cxx | 227 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.hxx | 11 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/cpp2uno.cxx | 553 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/dllinit.cxx | 45 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/smallstruct.cxx | 71 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/smallstruct.hxx | 29 | ||||
-rw-r--r-- | bridges/source/cpp_uno/mingw_x86-64/uno2cpp.cxx | 262 |
11 files changed, 1059 insertions, 879 deletions
diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk index abfc9a131115..06038447bc93 100644 --- a/bridges/Library_cpp_uno.mk +++ b/bridges/Library_cpp_uno.mk @@ -135,10 +135,9 @@ bridge_noopt_objects := except bridge_asm_objects := call else ifeq ($(OS)$(COM),WNTGCC) bridges_SELECTED_BRIDGE := mingw_x86-64 -#bridge_asm_objects := call -bridge_noopt_objects := uno2cpp -bridge_exception_objects := callvirtualmethod cpp2uno dllinit except smallstruct -#bridge_exception_objects := cpp2uno dllinit except smallstruct +bridge_asm_objects := call +bridge_noncallexception_noopt_objects := callvirtualmethod +bridge_exception_objects := abi cpp2uno except uno2cpp endif else ifeq ($(OS)$(CPU),SOLARISI) diff --git a/bridges/source/cpp_uno/mingw_x86-64/abi.cxx b/bridges/source/cpp_uno/mingw_x86-64/abi.cxx new file mode 100644 index 000000000000..9fb14a90082c --- /dev/null +++ b/bridges/source/cpp_uno/mingw_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/mingw_x86-64/abi.hxx b/bridges/source/cpp_uno/mingw_x86-64/abi.hxx new file mode 100644 index 000000000000..93981247978a --- /dev/null +++ b/bridges/source/cpp_uno/mingw_x86-64/abi.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#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/mingw_x86-64/call.s b/bridges/source/cpp_uno/mingw_x86-64/call.s index 345efb870686..88d568c599d4 100644 --- a/bridges/source/cpp_uno/mingw_x86-64/call.s +++ b/bridges/source/cpp_uno/mingw_x86-64/call.s @@ -16,264 +16,100 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ - .text + .text + .align 2 +.globl privateSnippetExecutor +privateSnippetExecutor: +.LFB3: + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $160, %rsp +.LCFI2: + movq %r10, -152(%rbp) # Save (nVtableOffset << 32) + nFunctionIndex -.globl _privateSnippetExecutorGeneral -_privateSnippetExecutorGeneral: -.LFBg: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFIg0: - movl %esp,%ebp -.LCFIg1: - subl $0x4,%esp # 32bit returnValue - 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: - .long .-_privateSnippetExecutorGeneral + 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) -.globl _privateSnippetExecutorVoid -_privateSnippetExecutorVoid: -.LFBv: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFIv0: - movl %esp,%ebp -.LCFIv1: - 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: - .long .-_privateSnippetExecutorVoid + 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 -.globl _privateSnippetExecutorHyper -_privateSnippetExecutorHyper: -.LFBh: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFIh0: - movl %esp,%ebp -.LCFIh1: - subl $0x8,%esp # 64bit returnValue - 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: - .long .-_privateSnippetExecutorHyper + cmp $10, %rax # typelib_TypeClass_FLOAT + je .Lfloat + cmp $11, %rax # typelib_TypeClass_DOUBLE + je .Lfloat -.globl _privateSnippetExecutorFloat -_privateSnippetExecutorFloat: -.LFBf: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFIf0: - movl %esp,%ebp -.LCFIf1: - subl $0x4,%esp # 32bit returnValue - 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: - .long .-_privateSnippetExecutorFloat + 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) -.globl _privateSnippetExecutorDouble -_privateSnippetExecutorDouble: -.LFBd: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFId0: - movl %esp,%ebp -.LCFId1: - subl $0x8,%esp # 64bit returnValue - 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: - .long .-_privateSnippetExecutorDouble - -.globl _privateSnippetExecutorClass -_privateSnippetExecutorClass: -.LFBc: - movl %esp,%ecx - pushl %ebp # proper stack frame needed for exception handling -.LCFIc0: - movl %esp,%ebp -.LCFIc1: - subl $0x4,%esp # 32bit returnValue - 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: - .long .-_privateSnippetExecutorClass - - .section .eh_frame,"dr" +.Lfinish: + leave + ret +.LFE3: + .long .-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" .Lframe1: - .long .LECIE1-.LSCIE1 # length + .long .LECIE1-.LSCIE1 .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 + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x1b + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 .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: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB3-. + .long .LFE3-.LFB3 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB3 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: diff --git a/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.cxx b/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.cxx index c1bb9b6e07ad..47b8f13a9c29 100644 --- a/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.cxx +++ b/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.cxx @@ -19,120 +19,147 @@ #include "sal/config.h" +#include <cstring> + #include "cppu/macros.hxx" -#include "osl/diagnose.h" #include "sal/types.h" #include "typelib/typeclass.h" #include "typelib/typedescription.h" +#include "abi.hxx" #include "callvirtualmethod.hxx" -#include "share.hxx" -#include "smallstruct.hxx" - -// For some reason, callVirtualMethod needs to be in a source file of its own, -// so that stack unwinding upon a thrown exception from within the asm block -// call works, at least with GCC 4.7.0 and --enable-dbgutil. - -// 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). [It -// is unclear how much of this comment is still relevent -- see the above -// comment.] + +// 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 const * returnType, sal_Int32 * pStackLongs, - sal_Int32 nStackLongs) + 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) { - // parameter list is mixed list of * and values - // reference parameters are pointers + // 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; - OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); - OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); - OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); + // Get pointer to method + sal_uInt64 pMethod = *((sal_uInt64 *)pThis); + pMethod += 8 * nVtableIndex; + pMethod = *((sal_uInt64 *)pMethod); - // never called - if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something + // 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 ); + } + + // Return values + sal_uInt64 rax; + sal_uInt64 rdx; + double xmm0; + double xmm1; - volatile long edx = 0, eax = 0; // for register returns - void * stackptr; asm volatile ( - "mov %%esp, %6\n\t" - // copy values - "mov %0, %%eax\n\t" - "mov %%eax, %%edx\n\t" - "dec %%edx\n\t" - "shl $2, %%edx\n\t" - "add %1, %%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 %2, %%edx\n\t" - "mov 0(%%edx), %%edx\n\t" - "mov %3, %%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, %4\n\t" - "mov %%edx, %5\n\t" - // cleanup stack - "mov %6, %%esp\n\t" - : - : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), - "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) - : "eax", "ecx", "edx" ); - switch( returnType->eTypeClass ) + + // 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 ), + "m" ( pCallStack ) // dummy input to prevent the compiler from optimizing the alloca out + : "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_VOID: - break; - case typelib_TypeClass_HYPER: - case typelib_TypeClass_UNSIGNED_HYPER: - ((long*)pRegisterReturn)[1] = edx; - case typelib_TypeClass_LONG: - case typelib_TypeClass_UNSIGNED_LONG: - case typelib_TypeClass_CHAR: - case typelib_TypeClass_ENUM: - ((long*)pRegisterReturn)[0] = eax; - break; - case typelib_TypeClass_SHORT: - case typelib_TypeClass_UNSIGNED_SHORT: - *(unsigned short*)pRegisterReturn = eax; - break; - case typelib_TypeClass_BOOLEAN: - case typelib_TypeClass_BYTE: - *(unsigned char*)pRegisterReturn = eax; - break; - case typelib_TypeClass_FLOAT: - asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) ); - break; - case typelib_TypeClass_DOUBLE: - asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) ); - break; - case typelib_TypeClass_STRUCT: - if (bridges::cpp_uno::shared::isSmallStruct(returnType)) { - if (returnType->nSize <= 1) { - *(unsigned char*)pRegisterReturn = eax; - } - else if (returnType->nSize <= 2) { - *(unsigned short*)pRegisterReturn = eax; - } - else if (returnType->nSize <= 8) { - ((long*)pRegisterReturn)[0] = eax; - if (returnType->nSize > 4) { - ((long*)pRegisterReturn)[1] = edx; - } - } - } - break; - default: + 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; + } } } diff --git a/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.hxx b/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.hxx index 76df8d96421c..cfea6ab40c41 100644 --- a/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.hxx +++ b/bridges/source/cpp_uno/mingw_x86-64/callvirtualmethod.hxx @@ -17,8 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_MINGW_INTEL_CALLVIRTUALMETHOD_HXX -#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_MINGW_INTEL_CALLVIRTUALMETHOD_HXX +#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" @@ -29,9 +29,10 @@ namespace CPPU_CURRENT_NAMESPACE { void callVirtualMethod( - void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn, - typelib_TypeDescription const * returnType, sal_Int32 * pStackLongs, - sal_Int32 nStackLongs); + 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); } diff --git a/bridges/source/cpp_uno/mingw_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/mingw_x86-64/cpp2uno.cxx index e87512a571fc..39caf1a43214 100644 --- a/bridges/source/cpp_uno/mingw_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/mingw_x86-64/cpp2uno.cxx @@ -18,36 +18,54 @@ */ +#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 <sal/alloca.h> #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" -#include "smallstruct.hxx" +using namespace ::osl; +using namespace ::rtl; using namespace ::com::sun::star::uno; -namespace -{ - //================================================================================================== -void cpp2uno_call( + +// 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 ** pCallStack, - void * pReturnValue ) + void ** gpreg, void ** fpreg, void ** ovrflw, + sal_uInt64 * pRegisterReturn /* space for register return */ ) { - // pCallStack: ret, [return ptr], this, params - char * pCppStack = (char *)(pCallStack +1); + 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; @@ -57,33 +75,26 @@ void cpp2uno_call( void * pUnoReturn = 0; void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need - if (pReturnTypeDescr) + if ( pReturnTypeDescr ) { - if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) - { - pUnoReturn = pReturnValue; // direct way for simple types - } - else // complex return via ptr (pCppReturn) + if ( x86_64::return_in_hidden_param( pReturnTypeRef ) ) { - if (!bridges::cpp_uno::shared::isSmallStruct(pReturnTypeDescr)) { - pCppReturn = *(void **)pCppStack; - pCppStack += sizeof(void *); - } - else { - pCppReturn = pReturnValue; - } + pCppReturn = *gpreg++; + nr_gpr++; - pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( - pReturnTypeDescr ) - ? alloca( pReturnTypeDescr->nSize ) - : pCppReturn); // direct way + pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) + ? alloca( pReturnTypeDescr->nSize ) + : pCppReturn ); // direct way } + else + pUnoReturn = pRegisterReturn; // direct way for simple types } + // pop this - pCppStack += sizeof( void* ); + gpreg++; + nr_gpr++; // stack space - OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); // parameters void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); void ** pCppArgs = pUnoArgs + nParams; @@ -92,36 +103,57 @@ void cpp2uno_call( // type descriptions for reconversions typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); - sal_Int32 nTempIndizes = 0; + 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 )) - // value + 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 { - pCppArgs[nPos] = pCppStack; - pUnoArgs[nPos] = pCppStack; - switch (pParamTypeDescr->eTypeClass) + // Simple types must fit exactly one register on x86_64 + OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); + + if ( nUsedSSE == 1 ) { - case typelib_TypeClass_HYPER: - case typelib_TypeClass_UNSIGNED_HYPER: - case typelib_TypeClass_DOUBLE: - pCppStack += sizeof(sal_Int32); // extra long - break; - default: - break; + 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++; } - // no longer needed - TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } - else // ptr to complex value | ref + else // struct <= 16 bytes || ptr to complex value || ref { - pCppArgs[nPos] = *(void **)pCppStack; + 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 { @@ -131,12 +163,10 @@ void cpp2uno_call( // will be released at reconversion ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; } - // is in/inout - else if (bridges::cpp_uno::shared::relatesToInterfaceType( - pParamTypeDescr )) + else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout { uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), - *(void **)pCppStack, pParamTypeDescr, + pCppStack, pParamTypeDescr, pThis->getBridge()->getCpp2Uno() ); pTempIndizes[nTempIndizes] = nPos; // has to be reconverted // will be released at reconversion @@ -144,12 +174,11 @@ void cpp2uno_call( } else // direct way { - pUnoArgs[nPos] = *(void **)pCppStack; + pUnoArgs[nPos] = pCppStack; // no longer needed TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } } - pCppStack += sizeof(sal_Int32); // standard parameter length } // ExceptionHolder @@ -157,11 +186,10 @@ void cpp2uno_call( uno_Any * pUnoExc = &aUnoExc; // invoke uno dispatch call - (*pThis->getUnoI()->pDispatcher)( - pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); + (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); // in case an exception occurred... - if (pUnoExc) + if ( pUnoExc ) { // destruct temporary in/inout params for ( ; nTempIndizes--; ) @@ -175,9 +203,9 @@ void cpp2uno_call( if (pReturnTypeDescr) TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); - CPPU_CURRENT_NAMESPACE::raiseException( - &aUnoExc, pThis->getBridge()->getUno2Cpp() ); - // has to destruct the any + 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... { @@ -187,7 +215,7 @@ void cpp2uno_call( sal_Int32 nIndex = pTempIndizes[nTempIndizes]; typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; - if (pParams[nIndex].bOut) // inout/out + if ( pParams[nIndex].bOut ) // inout/out { // convert and assign uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); @@ -200,237 +228,209 @@ void cpp2uno_call( TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } // return - if (pCppReturn) // has complex return + if ( pCppReturn ) // has complex return { - if (pUnoReturn != pCppReturn) // needs reconversion + if ( pUnoReturn != pCppReturn ) // needs reconversion { uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() ); // destroy temp uno return uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); } - if (pReturnValue != pCppReturn) - // complex return ptr is set to eax - *static_cast< void ** >(pReturnValue) = pCppReturn; + // complex return ptr is set to return reg + *(void **)pRegisterReturn = pCppReturn; } - if (pReturnTypeDescr) + if ( pReturnTypeDescr ) { + typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + return eRet; } + else + return typelib_TypeClass_VOID; } } //================================================================================================== -extern "C" void cpp_vtable_call( - int nFunctionIndex, int nVtableOffset, void** pCallStack, - void * pReturnValue ) +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 */ ) { - OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); - - // pCallStack: ret adr, [ret *], this, params + // gpreg: [ret *], this, [other gpr params] + // fpreg: [fpr params] + // ovrflw: [gpr or fpr params (properly aligned)] void * pThis; - if( nFunctionIndex & 0x80000000 ) + if ( nFunctionIndex & 0x80000000 ) { nFunctionIndex &= 0x7fffffff; - pThis = pCallStack[2]; + pThis = gpreg[1]; } else { - pThis = pCallStack[1]; + pThis = gpreg[0]; } - pThis = static_cast< char * >(pThis) - nVtableOffset; - bridges::cpp_uno::shared::CppInterfaceProxy * pCppI - = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( - pThis); + 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!" ); - if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) + OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); + if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) { - throw RuntimeException( - OUString( "illegal vtable index!" ), - (XInterface *)pThis ); + throw RuntimeException( OUString("illegal vtable index!"), + reinterpret_cast<XInterface *>( pCppI ) ); } // determine called method sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; - OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); 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(), - ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, - 0, 0, // no params - pCallStack, pReturnValue ); - } - else - { - // is SET method - typelib_MethodParameter aParam; - aParam.pTypeRef = - ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; - aParam.bIn = sal_True; - aParam.bOut = sal_False; - - cpp2uno_call( - pCppI, aMemberDescr.get(), - 0, // indicates void return - 1, &aParam, - pCallStack, pReturnValue ); - } - break; - } - case typelib_TypeClass_INTERFACE_METHOD: + typelib_TypeClass eRet; + switch ( aMemberDescr.get()->eTypeClass ) { - // is METHOD - switch (nFunctionIndex) + case typelib_TypeClass_INTERFACE_ATTRIBUTE: { - case 1: // acquire() - pCppI->acquireProxy(); // non virtual call! - break; - case 2: // release() - pCppI->releaseProxy(); // non virtual call! + 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 0: // queryInterface() opt + } + case typelib_TypeClass_INTERFACE_METHOD: { - typelib_TypeDescription * pTD = 0; - TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() ); - if (pTD) + // is METHOD + switch ( nFunctionIndex ) { - 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[1] ), - &pInterface, pTD, cpp_acquire ); - pInterface->release(); - TYPELIB_DANGER_RELEASE( pTD ); - *static_cast< void ** >(pReturnValue) = pCallStack[1]; + 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 ); } - TYPELIB_DANGER_RELEASE( pTD ); } - } // else perform queryInterface() + break; + } default: - cpp2uno_call( - pCppI, aMemberDescr.get(), - ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, - ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, - ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, - pCallStack, pReturnValue ); + { + throw RuntimeException( OUString("no member description found!"), + reinterpret_cast<XInterface *>( pCppI ) ); } - break; - } - default: - { - throw RuntimeException( - OUString( "no member description found!" ), - (XInterface *)pThis ); - } } + + return eRet; } //================================================================================================== -extern "C" void privateSnippetExecutorGeneral(); -extern "C" void privateSnippetExecutorVoid(); -extern "C" void privateSnippetExecutorHyper(); -extern "C" void privateSnippetExecutorFloat(); -extern "C" void privateSnippetExecutorDouble(); -extern "C" void privateSnippetExecutorClass(); -extern "C" typedef void (*PrivateSnippetExecutor)(); - -int const codeSnippetSize = 16; - -unsigned char * codeSnippet( - unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, - typelib_TypeDescriptionReference * returnType) +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(()) { - typelib_TypeDescription * returnTypeDescr = 0; - if (returnType) - TYPELIB_DANGER_GET( &returnTypeDescr, returnType ); - - typelib_TypeClass returnTypeClass = returnType ? returnType->eTypeClass : typelib_TypeClass_VOID; - if (!bridges::cpp_uno::shared::isSimpleType(returnTypeClass) && - !bridges::cpp_uno::shared::isSmallStruct(returnTypeDescr)) { - functionIndex |= 0x80000000; - } - PrivateSnippetExecutor exec = privateSnippetExecutorGeneral; - switch (returnTypeClass) { - 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: - if (bridges::cpp_uno::shared::isSmallStruct(returnTypeDescr)) { - if (returnType->pType->nSize <= 4) { - exec = privateSnippetExecutorGeneral; - } - else if (returnType->pType->nSize <= 8) { - exec = privateSnippetExecutorHyper; - } - } - else { - exec = privateSnippetExecutorClass; - } - break; - case typelib_TypeClass_STRING: - case typelib_TypeClass_TYPE: - case typelib_TypeClass_ANY: - case typelib_TypeClass_SEQUENCE: - case typelib_TypeClass_INTERFACE: - exec = privateSnippetExecutorClass; - break; - default: - exec = privateSnippetExecutorGeneral; - break; - } - if (returnType) - TYPELIB_DANGER_RELEASE( returnTypeDescr ); - unsigned char * p = code; - OSL_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) - = ((unsigned char *) exec) - p - sizeof (sal_Int32); - p += sizeof (sal_Int32); - OSL_ASSERT(p - code <= codeSnippetSize); - return code + codeSnippetSize; -} + 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 * @@ -439,12 +439,14 @@ 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) @@ -455,56 +457,59 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( 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) + Slot ** slots, unsigned char * code, typelib_InterfaceTypeDescription const * type, + sal_Int32 nFunctionOffset, sal_Int32 functionCount, sal_Int32 nVtableOffset ) { (*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]); - OSL_ASSERT(member != 0); - switch (member->eTypeClass) { - case typelib_TypeClass_INTERFACE_ATTRIBUTE: - // Getter: + 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; - code = codeSnippet( - code, functionOffset++, vtableOffset, - reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( - member)->pAttributeTypeRef); - // Setter: - if (!reinterpret_cast< - typelib_InterfaceAttributeTypeDescription * >( - member)->bReadOnly) + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); + + if ( ! pAttrTD->bReadOnly ) { + // set method (s++)->fn = code; - code = codeSnippet( - code, functionOffset++, vtableOffset, - NULL); + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false ); } - break; + } + else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass ) + { + typelib_InterfaceMethodTypeDescription *pMethodTD = + reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); - case typelib_TypeClass_INTERFACE_METHOD: (s++)->fn = code; - code = codeSnippet( - code, functionOffset++, vtableOffset, - reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( - member)->pReturnTypeRef); - break; - - default: - OSL_ASSERT(false); - break; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); } - TYPELIB_DANGER_RELEASE(member); + else + OSL_ASSERT( false ); + + TYPELIB_DANGER_RELEASE( pTD ); } return code; } +//================================================================================================== void bridges::cpp_uno::shared::VtableFactory::flushCode( - unsigned char const *, unsigned char const *) + 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/mingw_x86-64/dllinit.cxx b/bridges/source/cpp_uno/mingw_x86-64/dllinit.cxx deleted file mode 100644 index 0b004d7de92e..000000000000 --- a/bridges/source/cpp_uno/mingw_x86-64/dllinit.cxx +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this 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 <windows.h> - - -void dso_init(void); -void dso_exit(void); - - -extern "C" BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved) -{ - switch(dwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hModule); - - dso_init(); - break; - - case DLL_PROCESS_DETACH: - if (!lpvReserved) - dso_exit(); - break; - } - - return TRUE; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/mingw_x86-64/smallstruct.cxx b/bridges/source/cpp_uno/mingw_x86-64/smallstruct.cxx deleted file mode 100644 index 2f617e96cd37..000000000000 --- a/bridges/source/cpp_uno/mingw_x86-64/smallstruct.cxx +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this 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 "bridges/cpp_uno/shared/types.hxx" - -#include "typelib/typeclass.h" -#include "typelib/typedescription.h" - -namespace bridges { namespace cpp_uno { namespace shared { - -namespace { -bool isSimpleStruct(typelib_TypeDescription const * type) { - switch (type->eTypeClass) { - case typelib_TypeClass_STRUCT: - { - 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_STRUCT: - { - typelib_TypeDescription * t = 0; - TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]); - bool b = isSimpleStruct(t); - TYPELIB_DANGER_RELEASE(t); - if (!b) { - return false; - } - } - break; - - default: - if (!isSimpleType(p->ppTypeRefs[i]->eTypeClass)) - return false; - break; - } - } - } - return true; - - default: - return false; - } -} -} - -bool isSmallStruct(typelib_TypeDescription const * type) { - return (type->nSize <= 8 && isSimpleStruct(type)); -} - -} } } - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/mingw_x86-64/smallstruct.hxx b/bridges/source/cpp_uno/mingw_x86-64/smallstruct.hxx deleted file mode 100644 index 68bab382732f..000000000000 --- a/bridges/source/cpp_uno/mingw_x86-64/smallstruct.hxx +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this 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 "typelib/typeclass.h" -#include "typelib/typedescription.h" - -namespace bridges { namespace cpp_uno { namespace shared { - -bool isSmallStruct(typelib_TypeDescription const * type); - -} } } - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/mingw_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/mingw_x86-64/uno2cpp.cxx index 60a57a4b5a3b..2760f17625cc 100644 --- a/bridges/source/cpp_uno/mingw_x86-64/uno2cpp.cxx +++ b/bridges/source/cpp_uno/mingw_x86-64/uno2cpp.cxx @@ -17,26 +17,80 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#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 <sal/alloca.h> -#include "bridges/cpp_uno/shared/bridge.hxx" -#include "bridges/cpp_uno/shared/types.hxx" +#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" -#include "smallstruct.hxx" using namespace ::rtl; using namespace ::com::sun::star::uno; -namespace -{ +// 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, @@ -45,66 +99,53 @@ static void cpp_call( sal_Int32 nParams, typelib_MethodParameter * pParams, void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) { - // max space for: [complex ret ptr], values|ptr ... - char * pCppStack = -#ifdef BROKEN_ALLOCA - (char *)malloc( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); -#else - (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); -#endif - char * pCppStackStart = pCppStack; + // 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; - // return + 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 + void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion (see below) - if (pReturnTypeDescr) + bool bSimpleReturn = true; + if ( pReturnTypeDescr ) { - if (bridges::cpp_uno::shared::isSimpleType( 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 ) -#ifdef BROKEN_ALLOCA - ? malloc( pReturnTypeDescr->nSize ) -#else - ? alloca( pReturnTypeDescr->nSize ) -#endif - : pUnoReturn); // direct way - if (!bridges::cpp_uno::shared::isSmallStruct(pReturnTypeDescr)) { - *(void **)pCppStack = pCppReturn; - pCppStack += sizeof(void *); - } + pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )? + __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn; + INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack ); } } - // push this - void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) - + aVtableSlot.offset; - *(void**)pCppStack = pAdjustedThisPtr; - pCppStack += sizeof( void* ); - - // stack space - OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); - // args -#ifdef BROKEN_ALLOCA - void ** pCppArgs = (void **)malloc( 3 * sizeof(void *) * nParams ); -#else - void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); -#endif - // indizes of values this have to be converted (interface conversion cpp<=>uno) + + // 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 + // Type descriptions for reconversions typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); - sal_Int32 nTempIndizes = 0; + sal_Int32 nTempIndizes = 0; for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) { @@ -112,22 +153,39 @@ static void cpp_call( typelib_TypeDescription * pParamTypeDescr = 0; TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); - if (!rParam.bOut - && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) + if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) { - uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], 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: - pCppStack += sizeof(sal_Int32); // extra long + INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack ); break; default: break; } + // no longer needed TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } @@ -137,28 +195,18 @@ static void cpp_call( { // cpp out is constructed mem, uno out is not! uno_constructData( -#ifdef BROKEN_ALLOCA - *(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ), -#else - *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), -#endif + 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 )) + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) { uno_copyAndConvertData( -#ifdef BROKEN_ALLOCA - *(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ), -#else - *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), -#endif - pUnoArgs[nPos], pParamTypeDescr, - pThis->getBridge()->getUno2Cpp() ); + pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); pTempIndizes[nTempIndizes] = nPos; // has to be reconverted // will be released at reconversion @@ -166,22 +214,40 @@ static void cpp_call( } else // direct way { - *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; + pCppArgs[nPos] = pUnoArgs[nPos]; // no longer needed TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } + INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack ); } - pCppStack += sizeof(sal_Int32); // standard parameter length } try { - OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); - CPPU_CURRENT_NAMESPACE::callVirtualMethod( - pAdjustedThisPtr, aVtableSlot.index, - pCppReturn, pReturnTypeDescr, - (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); - // NO exception occurred... + 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.append("C++ code threw "); + appendCString(buf, typeid(e).name()); + buf.append(": "); + appendCString(buf, e.what()); + throw RuntimeException( + buf.makeStringAndClear(), Reference< XInterface >()); + } catch (...) { + throw RuntimeException( + OUString( + "C++ code threw unknown exception"), + Reference< XInterface >()); + } + *ppUnoExc = 0; // reconvert temporary params @@ -206,9 +272,6 @@ static void cpp_call( } // destroy temp cpp param => cpp: every param was constructed uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); -#ifdef BROKEN_ALLOCA - free( pCppArgs[nIndex] ); -#endif TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } @@ -232,26 +295,14 @@ static void cpp_call( // destroy temp cpp param => cpp: every param was constructed uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); -#ifdef BROKEN_ALLOCA - free( pCppArgs[nIndex] ); -#endif } // return type if (pReturnTypeDescr) TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); } - if (pCppReturn && pUnoReturn != pCppReturn) - { -#ifdef BROKEN_ALLOCA - free( pCppReturn ); -#endif - } -#ifdef BROKEN_ALLOCA - free( pCppStackStart ); -#endif } -} +//================================================================================================== namespace bridges { namespace cpp_uno { namespace shared { @@ -262,16 +313,25 @@ void unoInterfaceProxyDispatch( // 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< + getVtableSlot( + reinterpret_cast< typelib_InterfaceAttributeTypeDescription const * >( pMemberDescr))); + if (pReturn) { // dependent dispatch @@ -298,7 +358,7 @@ void unoInterfaceProxyDispatch( // dependent dispatch aVtableSlot.index += 1; // get, then set method cpp_call( - pThis, aVtableSlot, + pThis, aVtableSlot, // get, then set method pReturnTypeRef, 1, &aParam, pReturn, pArgs, ppException ); @@ -310,11 +370,17 @@ void unoInterfaceProxyDispatch( } 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< + getVtableSlot( + reinterpret_cast< typelib_InterfaceMethodTypeDescription const * >( pMemberDescr))); + switch (aVtableSlot.index) { // standard calls @@ -333,8 +399,8 @@ void unoInterfaceProxyDispatch( if (pTD) { uno_Interface * pInterface = 0; - (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( - pThis->pBridge->getUnoEnv(), + (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( + pThis->getBridge()->getUnoEnv(), (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); if (pInterface) |