Make exceptions work better in the x86-64 MacOSX C++-UNO bridge

Putting the privateSnippetExecutor() assembly code as inline asm
inside an otherwise empty C++ function helps, for some reason.

Use the actual _Unwnd_Exception and __cxa_exception definitions as
used by Apple (from opensource.apple.com libunwind and libcppabi
sources) instead of guessing.

Change-Id: I1ef22a9c0c664d3a357b9a6474406141f53cc490
This commit is contained in:
Tor Lillqvist
2012-09-27 22:27:49 +03:00
parent 6beb0d37b0
commit 9f5227d66b
5 changed files with 156 additions and 104 deletions

View File

@@ -46,12 +46,9 @@ $(eval $(call gb_Library_use_libraries,gcc3_uno,\
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/call \
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 \

View File

@@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
extern "C" void
privateSnippetExecutor()
{
asm volatile
(
" subq $160, %rsp\n"
" movq %r10, -152(%rbp) # Save (nVtableOffset << 32) + nFunctionIndex\n"
" movq %rdi, -112(%rbp) # Save GP registers\n"
" movq %rsi, -104(%rbp)\n"
" movq %rdx, -96(%rbp)\n"
" movq %rcx, -88(%rbp)\n"
" movq %r8 , -80(%rbp)\n"
" movq %r9 , -72(%rbp)\n"
" movsd %xmm0, -64(%rbp) # Save FP registers\n"
" movsd %xmm1, -56(%rbp)\n"
" movsd %xmm2, -48(%rbp)\n"
" movsd %xmm3, -40(%rbp)\n"
" movsd %xmm4, -32(%rbp)\n"
" movsd %xmm5, -24(%rbp)\n"
" movsd %xmm6, -16(%rbp)\n"
" movsd %xmm7, -8(%rbp)\n"
" leaq -144(%rbp), %r9 # 6th param: sal_uInt64 * pRegisterReturn\n"
" leaq 16(%rbp), %r8 # 5rd param: void ** ovrflw\n"
" leaq -64(%rbp), %rcx # 4th param: void ** fpreg\n"
" leaq -112(%rbp), %rdx # 3rd param: void ** gpreg\n"
" movl -148(%rbp), %esi # 2nd param: sal_int32 nVtableOffset\n"
" movl -152(%rbp), %edi # 1st param: sal_int32 nFunctionIndex\n"
" call _cpp_vtable_call\n"
" cmp $10, %rax # typelib_TypeClass_FLOAT\n"
" je .Lfloat\n"
" cmp $11, %rax # typelib_TypeClass_DOUBLE\n"
" je .Lfloat\n"
" movq -144(%rbp), %rax # Return value (int case)\n"
" movq -136(%rbp), %rdx # Return value (int case)\n"
" movq -144(%rbp), %xmm0 # Return value (int case)\n"
" movq -136(%rbp), %xmm1 # Return value (int case)\n"
" jmp .Lfinish\n"
".Lfloat:\n"
" movlpd -144(%rbp), %xmm0 # Return value (float/double case)\n"
".Lfinish:\n"
" addq $160, %rsp\n"
);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -1,79 +0,0 @@
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this 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

View File

@@ -396,7 +396,7 @@ extern "C" typelib_TypeClass cpp_vtable_call(
}
//==================================================================================================
extern "C" void privateSnippetExecutor( ... );
extern "C" void privateSnippetExecutor();
const int codeSnippetSize = 24;

View File

@@ -35,41 +35,102 @@
namespace CPPU_CURRENT_NAMESPACE
{
// ----- following decl from libstdc++-v3/libsupc++/unwind-cxx.h and unwind.h
// From opensource.apple.com: libunwind-35.1/include/unwind.h
typedef enum {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
struct _Unwind_Exception
{
unsigned exception_class __attribute__((__mode__(__DI__)));
void * exception_cleanup;
unsigned private_1 __attribute__((__mode__(__word__)));
unsigned private_2 __attribute__((__mode__(__word__)));
} __attribute__((__aligned__));
uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc);
uintptr_t private_1; // non-zero means forced unwind
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
#if !__LP64__
// The gcc implementation of _Unwind_Exception used attribute mode on the above fields
// which had the side effect of causing this whole struct to round up to 32 bytes in size.
// To be more explicit, we add pad fields added for binary compatibility.
uint32_t reserved[3];
#endif
};
// From libcppabi-24.2/include/unwind-cxx.h
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
// A C++ exception object consists of a header, which is a wrapper around
// an unwind object header with additional C++ specific information,
// followed by the exception object itself.
struct __cxa_exception
{
::std::type_info *exceptionType;
void (*exceptionDestructor)(void *);
#if __LP64__
// This is a new field to support C++ 0x exception_ptr.
// For binary compatibility it is at the start of this
// struct which is prepended to the object thrown in
// __cxa_allocate_exception.
size_t referenceCount;
#endif
// Manage the exception object itself.
std::type_info *exceptionType;
void (*exceptionDestructor)(void *);
::std::unexpected_handler unexpectedHandler;
::std::terminate_handler terminateHandler;
// The C++ standard has entertaining rules wrt calling set_terminate
// and set_unexpected in the middle of the exception cleanup process.
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception *nextException;
// The caught exception stack threads through here.
__cxa_exception *nextException;
int handlerCount;
// How many nested handlers have caught this exception. A negated
// value is a signal that this object has been rethrown.
int handlerCount;
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void *catchTemp;
void *adjustedPtr;
#ifdef __ARM_EABI_UNWINDER__
// Stack of exceptions in cleanups.
__cxa_exception* nextPropagatingException;
_Unwind_Exception unwindHeader;
// The nuber of active cleanup handlers for this exception.
int propagationCount;
#else
// Cache parsed handler data from the personality routine Phase 1
// for Phase 2 and __cxa_call_unexpected.
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
_Unwind_Ptr catchTemp;
void *adjustedPtr;
#endif
#if !__LP64__
// This is a new field to support C++ 0x exception_ptr.
// For binary compatibility it is placed where the compiler
// previously adding padded to 64-bit align unwindHeader.
size_t referenceCount;
#endif
// The generic exception header. Must be last.
_Unwind_Exception unwindHeader;
};
// Each thread in a C++ program has access to a __cxa_eh_globals object.
struct __cxa_eh_globals
{
__cxa_exception *caughtExceptions;
unsigned int uncaughtExceptions;
__cxa_exception *caughtExceptions;
unsigned int uncaughtExceptions;
#ifdef __ARM_EABI_UNWINDER__
__cxa_exception* propagatingExceptions;
#endif
};
}