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 ...@@ -135,10 +135,9 @@ bridge_noopt_objects := except
bridge_asm_objects := call bridge_asm_objects := call
else ifeq ($(OS)$(COM),WNTGCC) else ifeq ($(OS)$(COM),WNTGCC)
bridges_SELECTED_BRIDGE := mingw_x86-64 bridges_SELECTED_BRIDGE := mingw_x86-64
#bridge_asm_objects := call bridge_asm_objects := call
bridge_noopt_objects := uno2cpp bridge_noncallexception_noopt_objects := callvirtualmethod
bridge_exception_objects := callvirtualmethod cpp2uno dllinit except smallstruct bridge_exception_objects := abi cpp2uno except uno2cpp
#bridge_exception_objects := cpp2uno dllinit except smallstruct
endif endif
else ifeq ($(OS)$(CPU),SOLARISI) 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 @@ ...@@ -17,29 +17,45 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * 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); #include <typelib/typedescription.hxx>
void dso_exit(void);
namespace x86_64
extern "C" BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved)
{ {
switch(dwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
dso_init(); /* 6 general purpose registers are used for parameter passing */
break; 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: } // namespace x86_64
if (!lpvReserved)
dso_exit();
break;
}
return TRUE; #endif // _BRIDGES_CPP_UNO_X86_64_ABI_HXX_
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -16,264 +16,100 @@ ...@@ -16,264 +16,100 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * 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 movq %rdi, -112(%rbp) # Save GP registers
_privateSnippetExecutorGeneral: movq %rsi, -104(%rbp)
.LFBg: movq %rdx, -96(%rbp)
movl %esp,%ecx movq %rcx, -88(%rbp)
pushl %ebp # proper stack frame needed for exception handling movq %r8 , -80(%rbp)
.LCFIg0: movq %r9 , -72(%rbp)
movl %esp,%ebp
.LCFIg1: movsd %xmm0, -64(%rbp) # Save FP registers
subl $0x4,%esp # 32bit returnValue movsd %xmm1, -56(%rbp)
pushl %esp # 32bit &returnValue movsd %xmm2, -48(%rbp)
pushl %ecx # 32bit pCallStack movsd %xmm3, -40(%rbp)
pushl %edx # 32bit nVtableOffset movsd %xmm4, -32(%rbp)
pushl %eax # 32bit nFunctionIndex movsd %xmm5, -24(%rbp)
call _cpp_vtable_call movsd %xmm6, -16(%rbp)
movl 16(%esp),%eax # 32bit returnValue movsd %xmm7, -8(%rbp)
leave
ret
.LFEg:
.long .-_privateSnippetExecutorGeneral
.globl _privateSnippetExecutorVoid leaq -144(%rbp), %r9 # 6th param: sal_uInt64 * pRegisterReturn
_privateSnippetExecutorVoid: leaq 16(%rbp), %r8 # 5rd param: void ** ovrflw
.LFBv: leaq -64(%rbp), %rcx # 4th param: void ** fpreg
movl %esp,%ecx leaq -112(%rbp), %rdx # 3rd param: void ** gpreg
pushl %ebp # proper stack frame needed for exception handling movl -148(%rbp), %esi # 2nd param: sal_int32 nVtableOffset
.LCFIv0: movl -152(%rbp), %edi # 1st param: sal_int32 nFunctionIndex
movl %esp,%ebp
.LCFIv1: call cpp_vtable_call
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
.globl _privateSnippetExecutorHyper cmp $10, %rax # typelib_TypeClass_FLOAT
_privateSnippetExecutorHyper: je .Lfloat
.LFBh: cmp $11, %rax # typelib_TypeClass_DOUBLE
movl %esp,%ecx je .Lfloat
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
.globl _privateSnippetExecutorFloat movq -144(%rbp), %rax # Return value (int case)
_privateSnippetExecutorFloat: movq -136(%rbp), %rdx # Return value (int case)
.LFBf: movq -144(%rbp), %xmm0 # Return value (int case)
movl %esp,%ecx movq -136(%rbp), %xmm1 # Return value (int case)
pushl %ebp # proper stack frame needed for exception handling jmp .Lfinish
.LCFIf0: .Lfloat:
movl %esp,%ebp movlpd -144(%rbp), %xmm0 # Return value (float/double case)
.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
.globl _privateSnippetExecutorDouble .Lfinish:
_privateSnippetExecutorDouble: leave
.LFBd: ret
movl %esp,%ecx .LFE3:
pushl %ebp # proper stack frame needed for exception handling .long .-privateSnippetExecutor
.LCFId0: # see http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
movl %esp,%ebp # for details of the .eh_frame, the "Common Information Entry" and "Frame Description Entry" formats
.LCFId1: # and http://mentorembedded.github.io/cxx-abi/exceptions.pdf for more info
subl $0x8,%esp # 64bit returnValue .section .eh_frame,"a"
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"
.Lframe1: .Lframe1:
.long .LECIE1-.LSCIE1 # length .long .LECIE1-.LSCIE1
.LSCIE1: .LSCIE1:
.long 0 # CIE_ID .long 0x0
.byte 1 # version .byte 0x1
.string "zR" # augmentation .string "zR"
.uleb128 1 # code_alignment_factor .uleb128 0x1
.sleb128 -4 # data_alignment_factor .sleb128 -8
.byte 8 # return_address_register .byte 0x10
.uleb128 1 # augmentation size 1: .uleb128 0x1
.byte 0x1B # FDE Encoding (pcrel sdata4) .byte 0x1b
# initial_instructions: .byte 0xc
.byte 0x0C # DW_CFA_def_cfa %esp, 4 .uleb128 0x7
.uleb128 4 .uleb128 0x8
.uleb128 4 .byte 0x90
.byte 0x88 # DW_CFA_offset ret, 1 .uleb128 0x1
.uleb128 1 .align 8
.align 4
.LECIE1: .LECIE1:
.LSFDEg: .LSFDE1:
.long .LEFDEg-.LASFDEg # length .long .LEFDE1-.LASFDE1
.LASFDEg: .LASFDE1:
.long .LASFDEg-.Lframe1 # CIE_pointer .long .LASFDE1-.Lframe1
.long .LFBg-. # initial_location .long .LFB3-.
.long .LFEg-.LFBg # address_range .long .LFE3-.LFB3
.uleb128 0 # augmentation size 0 .uleb128 0x0
# instructions: .byte 0x4
.byte 0x04 # DW_CFA_advance_loc4 .long .LCFI0-.LFB3
.long .LCFIg0-.LFBg .byte 0xe
.byte 0x0E # DW_CFA_def_cfa_offset 8 .uleb128 0x10
.uleb128 8 .byte 0x86
.byte 0x85 # DW_CFA_offset %ebp, 2 .uleb128 0x2
.uleb128 2 .byte 0x4
.byte 0x04 # DW_CFA_advance_loc4 .long .LCFI1-.LCFI0
.long .LCFIg1-.LCFIg0 .byte 0xd
.byte 0x0D # DW_CFA_def_cfa_register %ebp .uleb128 0x6
.uleb128 5 .align 8
.align 4 .LEFDE1:
.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:
...@@ -19,120 +19,147 @@ ...@@ -19,120 +19,147 @@
#include "sal/config.h" #include "sal/config.h"
#include <cstring>
#include "cppu/macros.hxx" #include "cppu/macros.hxx"
#include "osl/diagnose.h"
#include "sal/types.h" #include "sal/types.h"
#include "typelib/typeclass.h" #include "typelib/typeclass.h"
#include "typelib/typedescription.h" #include "typelib/typedescription.h"
#include "abi.hxx"
#include "callvirtualmethod.hxx" #include "callvirtualmethod.hxx"
#include "share.hxx"
#include "smallstruct.hxx" // The call instruction within the asm block of callVirtualMethod may throw
// exceptions. At least GCC 4.7.0 with -O0 would create (unnecessary)
// For some reason, callVirtualMethod needs to be in a source file of its own, // .gcc_exception_table call-site table entries around all other calls in this
// so that stack unwinding upon a thrown exception from within the asm block // function that can throw, leading to std::terminate if the asm call throws an
// call works, at least with GCC 4.7.0 and --enable-dbgutil. // exception and the unwinding C++ personality routine finds the unexpected hole
// in the .gcc_exception_table. Therefore, make sure this function explicitly
// The call instruction within the asm section of callVirtualMethod may throw // only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
// exceptions. So that the compiler handles this correctly, it is important // .gcc_exception_table section at all for this function). For some reason,
// that (a) callVirtualMethod might call dummy_can_throw_anything (although this // this also needs to be in a source file of its own.
// 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 // Also, this file should be compiled with -fnon-call-exceptions, and ideally
// caught which are thrown from the instruction calling callVirtualMethod). [It // there would be a way to tell the compiler that the asm block contains calls
// is unclear how much of this comment is still relevent -- see the above // to functions that can potentially throw; see the mail thread starting at
// comment.] // <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 CPPU_CURRENT_NAMESPACE::callVirtualMethod(
void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn, void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
typelib_TypeDescription const * returnType, sal_Int32 * pStackLongs, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
sal_Int32 nStackLongs) 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 // Should not happen, but...
// reference parameters are pointers 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!" ); // Get pointer to method
OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); pMethod += 8 * nVtableIndex;
pMethod = *((sal_uInt64 *)pMethod);
// never called // Load parameters to stack, if necessary
if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 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 ( asm volatile (
"mov %%esp, %6\n\t"
// copy values // Fill the xmm registers
"mov %0, %%eax\n\t" "movq %6, %%rax\n\t"
"mov %%eax, %%edx\n\t"
"dec %%edx\n\t" "movsd (%%rax), %%xmm0\n\t"
"shl $2, %%edx\n\t" "movsd 8(%%rax), %%xmm1\n\t"
"add %1, %%edx\n" "movsd 16(%%rax), %%xmm2\n\t"
"Lcopy:\n\t" "movsd 24(%%rax), %%xmm3\n\t"
"pushl 0(%%edx)\n\t" "movsd 32(%%rax), %%xmm4\n\t"
"sub $4, %%edx\n\t" "movsd 40(%%rax), %%xmm5\n\t"
"dec %%eax\n\t" "movsd 48(%%rax), %%xmm6\n\t"
"jne Lcopy\n\t" "movsd 56(%%rax), %%xmm7\n\t"
// do the actual call
"mov %2, %%edx\n\t" // Fill the general purpose registers
"mov 0(%%edx), %%edx\n\t" "movq %5, %%rax\n\t"
"mov %3, %%eax\n\t"
"shl $2, %%eax\n\t" "movq (%%rax), %%rdi\n\t"
"add %%eax, %%edx\n\t" "movq 8(%%rax), %%rsi\n\t"
"mov 0(%%edx), %%edx\n\t" "movq 16(%%rax), %%rdx\n\t"
"call *%%edx\n\t" "movq 24(%%rax), %%rcx\n\t"
// save return registers "movq 32(%%rax), %%r8\n\t"
"mov %%eax, %4\n\t" "movq 40(%%rax), %%r9\n\t"
"mov %%edx, %5\n\t"
// cleanup stack // Perform the call
"mov %6, %%esp\n\t" "movq %4, %%r11\n\t"
: "movq %7, %%rax\n\t"
: "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), "call *%%r11\n\t"
"m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr)
: "eax", "ecx", "edx" ); // Fill the return values
switch( returnType->eTypeClass ) "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: case typelib_TypeClass_HYPER:
break; case typelib_TypeClass_UNSIGNED_HYPER:
case typelib_TypeClass_HYPER: *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = rax;
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:
break; 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 @@ ...@@ -17,8 +17,8 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/ */
#ifndef 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_MINGW_INTEL_CALLVIRTUALMETHOD_HXX #define INCLUDED_BRIDGES_SOURCE_CPP_UNO_GCC3_LINUX_X86_64_CALLVIRTUALMETHOD_HXX
#include "sal/config.h" #include "sal/config.h"
...@@ -29,9 +29,10 @@ ...@@ -29,9 +29,10 @@
namespace CPPU_CURRENT_NAMESPACE { namespace CPPU_CURRENT_NAMESPACE {
void callVirtualMethod( void callVirtualMethod(
void * pAdjustedThisPtr, sal_Int32 nVtableIndex, void * pRegisterReturn, void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
typelib_TypeDescription const * returnType, sal_Int32 * pStackLongs, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
sal_Int32 nStackLongs); sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, sal_uInt32 nGPR,
double * pFPR, sal_uInt32 nFPR);
} }
......
...@@ -18,36 +18,54 @@ ...@@ -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/genfunc.hxx>
#include "com/sun/star/uno/RuntimeException.hpp" #include "com/sun/star/uno/RuntimeException.hpp"
#include <uno/data.h> #include <uno/data.h>
#include <typelib/typedescription.hxx> #include <typelib/typedescription.hxx>
#include <sal/alloca.h>
#include "bridges/cpp_uno/shared/bridge.hxx" #include "bridges/cpp_uno/shared/bridge.hxx"
#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
#include "bridges/cpp_uno/shared/types.hxx" #include "bridges/cpp_uno/shared/types.hxx"
#include "bridges/cpp_uno/shared/vtablefactory.hxx" #include "bridges/cpp_uno/shared/vtablefactory.hxx"
#include "abi.hxx"
#include "share.hxx" #include "share.hxx"
#include "smallstruct.hxx"
using namespace ::osl;
using namespace ::rtl;
using namespace ::com::sun::star::uno; 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, bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
const typelib_TypeDescription * pMemberTypeDescr, const typelib_TypeDescription * pMemberTypeDescr,
typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
sal_Int32 nParams, typelib_MethodParameter * pParams, sal_Int32 nParams, typelib_MethodParameter * pParams,
void ** pCallStack, void ** gpreg, void ** fpreg, void ** ovrflw,
void * pReturnValue ) sal_uInt64 * pRegisterReturn /* space for register return */ )
{ {
// pCallStack: ret, [return ptr], this, params unsigned int nr_gpr = 0; //number of gpr registers used
char * pCppStack = (char *)(pCallStack +1); unsigned int nr_fpr = 0; //number of fpr registers used
// return // return
typelib_TypeDescription * pReturnTypeDescr = 0; typelib_TypeDescription * pReturnTypeDescr = 0;
...@@ -57,33 +75,26 @@ void cpp2uno_call( ...@@ -57,33 +75,26 @@ void cpp2uno_call(
void * pUnoReturn = 0; void * pUnoReturn = 0;
void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
if (pReturnTypeDescr) if ( pReturnTypeDescr )
{ {
if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
{
pUnoReturn = pReturnValue; // direct way for simple types
}
else // complex return via ptr (pCppReturn)
{ {
if (!bridges::cpp_uno::shared::isSmallStruct(pReturnTypeDescr)) { pCppReturn = *gpreg++;
pCppReturn = *(void **)pCppStack; nr_gpr++;
pCppStack += sizeof(void *);
}
else {
pCppReturn = pReturnValue;
}
pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
pReturnTypeDescr ) ? alloca( pReturnTypeDescr->nSize )
? alloca( pReturnTypeDescr->nSize ) : pCppReturn ); // direct way
: pCppReturn); // direct way
} }
else
pUnoReturn = pRegisterReturn; // direct way for simple types
} }
// pop this // pop this
pCppStack += sizeof( void* ); gpreg++;
nr_gpr++;
// stack space // stack space
OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
// parameters // parameters
void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
void ** pCppArgs = pUnoArgs + nParams; void ** pCppArgs = pUnoArgs + nParams;
...@@ -92,36 +103,57 @@ void cpp2uno_call( ...@@ -92,36 +103,57 @@ void cpp2uno_call(
// type descriptions for reconversions // type descriptions for reconversions
typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
sal_Int32 nTempIndizes = 0; sal_Int32 nTempIndizes = 0;
for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
{ {
const typelib_MethodParameter & rParam = pParams[nPos]; const typelib_MethodParameter & rParam = pParams[nPos];
typelib_TypeDescription * pParamTypeDescr = 0;
TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
if (!rParam.bOut int nUsedGPR = 0;
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) int nUsedSSE = 0;
// value #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; // Simple types must fit exactly one register on x86_64
pUnoArgs[nPos] = pCppStack; OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) );
switch (pParamTypeDescr->eTypeClass)
if ( nUsedSSE == 1 )
{ {
case typelib_TypeClass_HYPER: if ( nr_fpr < x86_64::MAX_SSE_REGS )
case typelib_TypeClass_UNSIGNED_HYPER: {
case typelib_TypeClass_DOUBLE: pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
pCppStack += sizeof(sal_Int32); // extra long nr_fpr++;
break; }
default: else
break; 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 if (! rParam.bIn) // is pure out
{ {
...@@ -131,12 +163,10 @@ void cpp2uno_call( ...@@ -131,12 +163,10 @@ void cpp2uno_call(
// will be released at reconversion // will be released at reconversion
ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
} }
// is in/inout else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
else if (bridges::cpp_uno::shared::relatesToInterfaceType(
pParamTypeDescr ))
{ {
uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
*(void **)pCppStack, pParamTypeDescr, pCppStack, pParamTypeDescr,
pThis->getBridge()->getCpp2Uno() ); pThis->getBridge()->getCpp2Uno() );
pTempIndizes[nTempIndizes] = nPos; // has to be reconverted pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
// will be released at reconversion // will be released at reconversion
...@@ -144,12 +174,11 @@ void cpp2uno_call( ...@@ -144,12 +174,11 @@ void cpp2uno_call(
} }
else // direct way else // direct way
{ {
pUnoArgs[nPos] = *(void **)pCppStack; pUnoArgs[nPos] = pCppStack;
// no longer needed // no longer needed
TYPELIB_DANGER_RELEASE( pParamTypeDescr ); TYPELIB_DANGER_RELEASE( pParamTypeDescr );
} }
} }
pCppStack += sizeof(sal_Int32); // standard parameter length
} }
// ExceptionHolder // ExceptionHolder
...@@ -157,11 +186,10 @@ void cpp2uno_call( ...@@ -157,11 +186,10 @@ void cpp2uno_call(
uno_Any * pUnoExc = &aUnoExc; uno_Any * pUnoExc = &aUnoExc;
// invoke uno dispatch call // invoke uno dispatch call
(*pThis->getUnoI()->pDispatcher)( (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
// in case an exception occurred... // in case an exception occurred...
if (pUnoExc) if ( pUnoExc )
{ {
// destruct temporary in/inout params // destruct temporary in/inout params
for ( ; nTempIndizes--; ) for ( ; nTempIndizes--; )
...@@ -175,9 +203,9 @@ void cpp2uno_call( ...@@ -175,9 +203,9 @@ void cpp2uno_call(
if (pReturnTypeDescr) if (pReturnTypeDescr)
TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
CPPU_CURRENT_NAMESPACE::raiseException( CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
&aUnoExc, pThis->getBridge()->getUno2Cpp() ); // is here for dummy
// has to destruct the any return typelib_TypeClass_VOID;
} }
else // else no exception occurred... else // else no exception occurred...
{ {
...@@ -187,7 +215,7 @@ void cpp2uno_call( ...@@ -187,7 +215,7 @@ void cpp2uno_call(
sal_Int32 nIndex = pTempIndizes[nTempIndizes]; sal_Int32 nIndex = pTempIndizes[nTempIndizes];
typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
if (pParams[nIndex].bOut) // inout/out if ( pParams[nIndex].bOut ) // inout/out
{ {
// convert and assign // convert and assign
uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
...@@ -200,237 +228,209 @@ void cpp2uno_call( ...@@ -200,237 +228,209 @@ void cpp2uno_call(
TYPELIB_DANGER_RELEASE( pParamTypeDescr ); TYPELIB_DANGER_RELEASE( pParamTypeDescr );
} }
// return // 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, uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
pThis->getBridge()->getUno2Cpp() ); pThis->getBridge()->getUno2Cpp() );
// destroy temp uno return // destroy temp uno return
uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
} }
if (pReturnValue != pCppReturn) // complex return ptr is set to return reg
// complex return ptr is set to eax *(void **)pRegisterReturn = pCppReturn;
*static_cast< void ** >(pReturnValue) = pCppReturn;
} }
if (pReturnTypeDescr) if ( pReturnTypeDescr )
{ {
typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
return eRet;
} }
else
return typelib_TypeClass_VOID;
} }
} }
//================================================================================================== //==================================================================================================
extern "C" void cpp_vtable_call( extern "C" typelib_TypeClass cpp_vtable_call(
int nFunctionIndex, int nVtableOffset, void** pCallStack, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
void * pReturnValue ) void ** gpreg, void ** fpreg, void ** ovrflw,
sal_uInt64 * pRegisterReturn /* space for register return */ )
{ {
OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); // gpreg: [ret *], this, [other gpr params]
// fpreg: [fpr params]
// pCallStack: ret adr, [ret *], this, params // ovrflw: [gpr or fpr params (properly aligned)]
void * pThis; void * pThis;
if( nFunctionIndex & 0x80000000 ) if ( nFunctionIndex & 0x80000000 )
{ {
nFunctionIndex &= 0x7fffffff; nFunctionIndex &= 0x7fffffff;
pThis = pCallStack[2]; pThis = gpreg[1];
} }
else else
{ {
pThis = pCallStack[1]; pThis = gpreg[0];
} }
pThis = static_cast< char * >(pThis) - nVtableOffset; pThis = static_cast<char *>( pThis ) - nVtableOffset;
bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
= bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
pThis); bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
{ {
throw RuntimeException( throw RuntimeException( OUString("illegal vtable index!"),
OUString( "illegal vtable index!" ), reinterpret_cast<XInterface *>( pCppI ) );
(XInterface *)pThis );
} }
// determine called method // determine called method
sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 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] ); TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
switch (aMemberDescr.get()->eTypeClass) typelib_TypeClass eRet;
{ 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:
{ {
// is METHOD case typelib_TypeClass_INTERFACE_ATTRIBUTE:
switch (nFunctionIndex)
{ {
case 1: // acquire() typelib_TypeDescriptionReference *pAttrTypeRef =
pCppI->acquireProxy(); // non virtual call! reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
break;
case 2: // release() if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
pCppI->releaseProxy(); // non virtual call! {
// 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; break;
case 0: // queryInterface() opt }
case typelib_TypeClass_INTERFACE_METHOD:
{ {
typelib_TypeDescription * pTD = 0; // is METHOD
TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() ); switch ( nFunctionIndex )
if (pTD)
{ {
XInterface * pInterface = 0; case 1: // acquire()
(*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( pCppI->acquireProxy(); // non virtual call!
pCppI->getBridge()->getCppEnv(), eRet = typelib_TypeClass_VOID;
(void **)&pInterface, pCppI->getOid().pData, break;
(typelib_InterfaceTypeDescription *)pTD ); case 2: // release()
pCppI->releaseProxy(); // non virtual call!
if (pInterface) eRet = typelib_TypeClass_VOID;
{
::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];
break; 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: default:
cpp2uno_call( {
pCppI, aMemberDescr.get(), throw RuntimeException( OUString("no member description found!"),
((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, reinterpret_cast<XInterface *>( pCppI ) );
((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
pCallStack, pReturnValue );
} }
break;
}
default:
{
throw RuntimeException(
OUString( "no member description found!" ),
(XInterface *)pThis );
}
} }
return eRet;
} }
//================================================================================================== //==================================================================================================
extern "C" void privateSnippetExecutorGeneral(); extern "C" void privateSnippetExecutor( ... );
extern "C" void privateSnippetExecutorVoid();
extern "C" void privateSnippetExecutorHyper(); const int codeSnippetSize = 24;
extern "C" void privateSnippetExecutorFloat();
extern "C" void privateSnippetExecutorDouble(); // Generate a trampoline that redirects method calls to
extern "C" void privateSnippetExecutorClass(); // privateSnippetExecutor().
extern "C" typedef void (*PrivateSnippetExecutor)(); //
// privateSnippetExecutor() saves all the registers that are used for
int const codeSnippetSize = 16; // parameter passing on x86_64, and calls the cpp_vtable_call().
// When it returns, privateSnippetExecutor() sets the return value.
unsigned char * codeSnippet( //
unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, // Note: The code snippet we build here must not create a stack frame,
typelib_TypeDescriptionReference * returnType) // 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; sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
if (returnType)
TYPELIB_DANGER_GET( &returnTypeDescr, returnType ); if ( bHasHiddenParam )
nOffsetAndIndex |= 0x80000000;
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;
}
// 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; }; struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::Slot *
...@@ -439,12 +439,14 @@ bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) ...@@ -439,12 +439,14 @@ bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
return static_cast< Slot * >(block) + 2; return static_cast< Slot * >(block) + 2;
} }
//==================================================================================================
sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
sal_Int32 slotCount) sal_Int32 slotCount)
{ {
return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
} }
//==================================================================================================
bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::Slot *
bridges::cpp_uno::shared::VtableFactory::initializeBlock( bridges::cpp_uno::shared::VtableFactory::initializeBlock(
void * block, sal_Int32 slotCount) void * block, sal_Int32 slotCount)
...@@ -455,56 +457,59 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( ...@@ -455,56 +457,59 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock(
return slots + slotCount; return slots + slotCount;
} }
//==================================================================================================
unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
Slot ** slots, unsigned char * code, Slot ** slots, unsigned char * code, typelib_InterfaceTypeDescription const * type,
typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, sal_Int32 nFunctionOffset, sal_Int32 functionCount, sal_Int32 nVtableOffset )
sal_Int32 functionCount, sal_Int32 vtableOffset)
{ {
(*slots) -= functionCount; (*slots) -= functionCount;
Slot * s = *slots; Slot * s = *slots;
for (sal_Int32 i = 0; i < type->nMembers; ++i) { for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
typelib_TypeDescription * member = 0; {
TYPELIB_DANGER_GET(&member, type->ppMembers[i]); typelib_TypeDescription * pTD = 0;
OSL_ASSERT(member != 0);
switch (member->eTypeClass) { TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
case typelib_TypeClass_INTERFACE_ATTRIBUTE: OSL_ASSERT( pTD );
// Getter:
if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
{
typelib_InterfaceAttributeTypeDescription *pAttrTD =
reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
// get method
(s++)->fn = code; (s++)->fn = code;
code = codeSnippet( code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
code, functionOffset++, vtableOffset, x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
member)->pAttributeTypeRef); if ( ! pAttrTD->bReadOnly )
// Setter:
if (!reinterpret_cast<
typelib_InterfaceAttributeTypeDescription * >(
member)->bReadOnly)
{ {
// set method
(s++)->fn = code; (s++)->fn = code;
code = codeSnippet( code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
code, functionOffset++, vtableOffset,
NULL);
} }
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; (s++)->fn = code;
code = codeSnippet( code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
code, functionOffset++, vtableOffset, x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
member)->pReturnTypeRef);
break;
default:
OSL_ASSERT(false);
break;
} }
TYPELIB_DANGER_RELEASE(member); else
OSL_ASSERT( false );
TYPELIB_DANGER_RELEASE( pTD );
} }
return code; return code;
} }
//==================================================================================================
void bridges::cpp_uno::shared::VtableFactory::flushCode( 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: */ /* 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 @@ ...@@ -17,26 +17,80 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * 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/genfunc.hxx>
#include "com/sun/star/uno/RuntimeException.hpp" #include "com/sun/star/uno/RuntimeException.hpp"
#include <uno/data.h> #include <uno/data.h>
#include <sal/alloca.h> #include <sal/alloca.h>
#include "bridges/cpp_uno/shared/bridge.hxx" #include <bridges/cpp_uno/shared/bridge.hxx>
#include "bridges/cpp_uno/shared/types.hxx" #include <bridges/cpp_uno/shared/types.hxx>
#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
#include "bridges/cpp_uno/shared/vtables.hxx" #include "bridges/cpp_uno/shared/vtables.hxx"
#include "abi.hxx"
#include "callvirtualmethod.hxx" #include "callvirtualmethod.hxx"
#include "share.hxx" #include "share.hxx"
#include "smallstruct.hxx"
using namespace ::rtl; using namespace ::rtl;
using namespace ::com::sun::star::uno; 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( static void cpp_call(
bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
...@@ -45,66 +99,53 @@ static void cpp_call( ...@@ -45,66 +99,53 @@ static void cpp_call(
sal_Int32 nParams, typelib_MethodParameter * pParams, sal_Int32 nParams, typelib_MethodParameter * pParams,
void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
{ {
// max space for: [complex ret ptr], values|ptr ... // Maxium space for [complex ret ptr], values | ptr ...
char * pCppStack = // (but will be used less - some of the values will be in pGPR and pFPR)
#ifdef BROKEN_ALLOCA sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) );
(char *)malloc( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); sal_uInt64 *pStackStart = pStack;
#else
(char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
#endif sal_uInt32 nGPR = 0;
char * pCppStackStart = pCppStack;
// return double pFPR[x86_64::MAX_SSE_REGS];
sal_uInt32 nFPR = 0;
// Return
typelib_TypeDescription * pReturnTypeDescr = 0; typelib_TypeDescription * pReturnTypeDescr = 0;
TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 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 pCppReturn = pUnoReturn; // direct way for simple types
}
else else
{ {
// complex return via ptr // complex return via ptr
pCppReturn pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
= (bridges::cpp_uno::shared::relatesToInterfaceType( __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
pReturnTypeDescr ) INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
#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 *);
}
} }
} }
// push this
void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) // Push "this" pointer
+ aVtableSlot.offset; void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
*(void**)pCppStack = pAdjustedThisPtr; INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
pCppStack += sizeof( void* );
// Args
// stack space void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); // Indizes of values this have to be converted (interface conversion cpp<=>uno)
// 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)
sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
// type descriptions for reconversions // Type descriptions for reconversions
typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
sal_Int32 nTempIndizes = 0; sal_Int32 nTempIndizes = 0;
for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
{ {
...@@ -112,22 +153,39 @@ static void cpp_call( ...@@ -112,22 +153,39 @@ static void cpp_call(
typelib_TypeDescription * pParamTypeDescr = 0; typelib_TypeDescription * pParamTypeDescr = 0;
TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
if (!rParam.bOut if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
&& 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() ); pThis->getBridge()->getUno2Cpp() );
switch (pParamTypeDescr->eTypeClass) switch (pParamTypeDescr->eTypeClass)
{ {
case typelib_TypeClass_HYPER: case typelib_TypeClass_HYPER:
case typelib_TypeClass_UNSIGNED_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: case typelib_TypeClass_DOUBLE:
pCppStack += sizeof(sal_Int32); // extra long INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
break; break;
default: default:
break; break;
} }
// no longer needed // no longer needed
TYPELIB_DANGER_RELEASE( pParamTypeDescr ); TYPELIB_DANGER_RELEASE( pParamTypeDescr );
} }
...@@ -137,28 +195,18 @@ static void cpp_call( ...@@ -137,28 +195,18 @@ static void cpp_call(
{ {
// cpp out is constructed mem, uno out is not! // cpp out is constructed mem, uno out is not!
uno_constructData( uno_constructData(
#ifdef BROKEN_ALLOCA pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
*(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ),
#else
*(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
#endif
pParamTypeDescr ); pParamTypeDescr );
pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
// will be released at reconversion // will be released at reconversion
ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
} }
// is in/inout // is in/inout
else if (bridges::cpp_uno::shared::relatesToInterfaceType( else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
pParamTypeDescr ))
{ {
uno_copyAndConvertData( uno_copyAndConvertData(
#ifdef BROKEN_ALLOCA pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
*(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ), pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
#else
*(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
#endif
pUnoArgs[nPos], pParamTypeDescr,
pThis->getBridge()->getUno2Cpp() );
pTempIndizes[nTempIndizes] = nPos; // has to be reconverted pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
// will be released at reconversion // will be released at reconversion
...@@ -166,22 +214,40 @@ static void cpp_call( ...@@ -166,22 +214,40 @@ static void cpp_call(
} }
else // direct way else // direct way
{ {
*(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; pCppArgs[nPos] = pUnoArgs[nPos];
// no longer needed // no longer needed
TYPELIB_DANGER_RELEASE( pParamTypeDescr ); TYPELIB_DANGER_RELEASE( pParamTypeDescr );
} }
INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
} }
pCppStack += sizeof(sal_Int32); // standard parameter length
} }
try try
{ {
OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); try {
CPPU_CURRENT_NAMESPACE::callVirtualMethod( CPPU_CURRENT_NAMESPACE::callVirtualMethod(
pAdjustedThisPtr, aVtableSlot.index, pAdjustedThisPtr, aVtableSlot.index,
pCppReturn, pReturnTypeDescr, pCppReturn, pReturnTypeRef, bSimpleReturn,
(sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); pStackStart, ( pStack - pStackStart ),
// NO exception occurred... 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; *ppUnoExc = 0;
// reconvert temporary params // reconvert temporary params
...@@ -206,9 +272,6 @@ static void cpp_call( ...@@ -206,9 +272,6 @@ static void cpp_call(
} }
// destroy temp cpp param => cpp: every param was constructed // destroy temp cpp param => cpp: every param was constructed
uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
#ifdef BROKEN_ALLOCA
free( pCppArgs[nIndex] );
#endif
TYPELIB_DANGER_RELEASE( pParamTypeDescr ); TYPELIB_DANGER_RELEASE( pParamTypeDescr );
} }
...@@ -232,26 +295,14 @@ static void cpp_call( ...@@ -232,26 +295,14 @@ static void cpp_call(
// destroy temp cpp param => cpp: every param was constructed // destroy temp cpp param => cpp: every param was constructed
uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
#ifdef BROKEN_ALLOCA
free( pCppArgs[nIndex] );
#endif
} }
// return type // return type
if (pReturnTypeDescr) if (pReturnTypeDescr)
TYPELIB_DANGER_RELEASE( 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 { namespace bridges { namespace cpp_uno { namespace shared {
...@@ -262,16 +313,25 @@ void unoInterfaceProxyDispatch( ...@@ -262,16 +313,25 @@ void unoInterfaceProxyDispatch(
// is my surrogate // is my surrogate
bridges::cpp_uno::shared::UnoInterfaceProxy * pThis bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
= static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
#if OSL_DEBUG_LEVEL > 0
typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
#endif
switch (pMemberDescr->eTypeClass) switch (pMemberDescr->eTypeClass)
{ {
case typelib_TypeClass_INTERFACE_ATTRIBUTE: 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( VtableSlot aVtableSlot(
getVtableSlot( getVtableSlot(
reinterpret_cast< reinterpret_cast<
typelib_InterfaceAttributeTypeDescription const * >( typelib_InterfaceAttributeTypeDescription const * >(
pMemberDescr))); pMemberDescr)));
if (pReturn) if (pReturn)
{ {
// dependent dispatch // dependent dispatch
...@@ -298,7 +358,7 @@ void unoInterfaceProxyDispatch( ...@@ -298,7 +358,7 @@ void unoInterfaceProxyDispatch(
// dependent dispatch // dependent dispatch
aVtableSlot.index += 1; // get, then set method aVtableSlot.index += 1; // get, then set method
cpp_call( cpp_call(
pThis, aVtableSlot, pThis, aVtableSlot, // get, then set method
pReturnTypeRef, pReturnTypeRef,
1, &aParam, 1, &aParam,
pReturn, pArgs, ppException ); pReturn, pArgs, ppException );
...@@ -310,11 +370,17 @@ void unoInterfaceProxyDispatch( ...@@ -310,11 +370,17 @@ void unoInterfaceProxyDispatch(
} }
case typelib_TypeClass_INTERFACE_METHOD: 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( VtableSlot aVtableSlot(
getVtableSlot( getVtableSlot(
reinterpret_cast< reinterpret_cast<
typelib_InterfaceMethodTypeDescription const * >( typelib_InterfaceMethodTypeDescription const * >(
pMemberDescr))); pMemberDescr)));
switch (aVtableSlot.index) switch (aVtableSlot.index)
{ {
// standard calls // standard calls
...@@ -333,8 +399,8 @@ void unoInterfaceProxyDispatch( ...@@ -333,8 +399,8 @@ void unoInterfaceProxyDispatch(
if (pTD) if (pTD)
{ {
uno_Interface * pInterface = 0; uno_Interface * pInterface = 0;
(*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
pThis->pBridge->getUnoEnv(), pThis->getBridge()->getUnoEnv(),
(void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
if (pInterface) 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