Kaydet (Commit) 211544a5 authored tarafından Fridrich Štrba's avatar Fridrich Štrba

Compiling but not working mingw_x86-64 bridges

Change-Id: I5ea6edf367dd18e60a86d12c523b7732a8ac44d4
üst b9dc42fc
......@@ -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)
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this 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: */
......@@ -17,29 +17,45 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <windows.h>
#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)
void dso_init(void);
void dso_exit(void);
#include <typelib/typedescription.hxx>
extern "C" BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved)
namespace x86_64
{
switch(dwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
dso_init();
break;
/* 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 ();
case DLL_PROCESS_DETACH:
if (!lpvReserved)
dso_exit();
break;
}
} // namespace x86_64
return TRUE;
}
#endif // _BRIDGES_CPP_UNO_X86_64_ABI_HXX_
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -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:
......@@ -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;
}
}
}
......
......@@ -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);
}
......
......@@ -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: */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this 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: */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this 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: */
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment