From 266c2d6b349be355560ba6dbf782cebbc4de8609 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 20 Jan 2011 02:36:55 +0200 Subject: More hacking on the wntmscx bridge, still far from ready See asmbits.asm for some general comments and pointers to useful information. --- .../source/cpp_uno/msvc_win32_x86-64/asmbits.asm | 328 +++++++++++++++++++++ .../source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx | 82 +----- .../source/cpp_uno/msvc_win32_x86-64/except.cxx | 79 ++--- .../source/cpp_uno/msvc_win32_x86-64/makefile.mk | 4 +- .../source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx | 167 ++++------- 5 files changed, 433 insertions(+), 227 deletions(-) create mode 100644 bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm (limited to 'bridges') diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm new file mode 100644 index 000000000000..29e75ff38845 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/asmbits.asm @@ -0,0 +1,328 @@ +; -*- Mode: text; tab-width: 8; indent-tabs-mode: nil comment-column: 32; comment-start: "; " comment-start-skip: "; *" -*- + +;************************************************************************* +;* +;* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;* +;* Copyright 2000, 2011 Oracle and/or its affiliates. +;* +;* OpenOffice.org - a multi-platform office productivity suite +;* +;* This file is part of OpenOffice.org. +;* +;* OpenOffice.org is free software: you can redistribute it and/or modify +;* it under the terms of the GNU Lesser General Public License version 3 +;* only, as published by the Free Software Foundation. +;* +;* OpenOffice.org is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;* GNU Lesser General Public License version 3 for more details +;* (a copy is included in the LICENSE file that accompanied this code). +;* +;* You should have received a copy of the GNU Lesser General Public License +;* version 3 along with OpenOffice.org. If not, see +;* +;* for a copy of the LGPLv3 License. +;* +;************************************************************************ + +; Emacs asm-mode is not really ideal for the convention in this +; file. So I use text-mode with custom comment syntax... not really +; ideal either. Maybe I should just re-format this to match asm-mode's +; conventions? + +; NOTE: EXTREMELY UNFINISHED, I KNOW. WORK IN PROGRESS. + +; I really don't have a good high-level understanding of the big +; picture and what the actual task of the C++/UNO bridge is yet... I +; should debug the x86 version and see what is actually going on to +; get an understanding. + +; This is in a separate file for x86-64 as MSVC doesn't have in-line +; assembly for x64. The code here is still partly just a crude copy of +; the in-line x86 code from ../msvc_win32_intel that is totally +; pointless on x64. But parts have been properly changed into x64 +; calling convention and might even work. + +; Random web links and other documentation about low-level +; implementation details for the C++/UNO bridge on x64 Windows kept +; here: + +; Caolan's "Lazy Hackers Guide To Porting" is useful: +; http://wiki.services.openoffice.org/wiki/Lazy_Hackers_Guide_To_Porting + +; As for details about the x64 Windows calling convention, register +; usage, stack usage, exception handling etc, the official +; documentation (?) on MSDN is a bit fragmented and split up into a +; needlessly large number of short pages. But still: +; http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=VS.90%29.aspx + +; Also see Raymond Chen's blog post: +; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/14/58579.aspx + +; This one is actually more readable: "Improving Automated Analysis of +; Windows x64 Binaries": +; http://www.uninformed.org/?v=4&a=1 + +; The bridge uses dynamic code generation. For exception handling and +; unwinding to work across that (as I assume we want?), one apparently +; needs to use either RtlAddFunctionTable() or +; RtlInstallFunctionTableCallback(). See Windows SDK documentation. + +; Random interesting discussion threads: +; http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/300bd6d3-9381-4d2d-8129-e48b392c05d8 + +; Ken Johnson's blog http://www.nynaeve.net/ has much interesting +; information, for instance: +; http://www.nynaeve.net/?p=11 + +; From +typelib_TypeClass_VOID = 0 +typelib_TypeClass_CHAR = 1 +typelib_TypeClass_BOOLEAN = 2 +typelib_TypeClass_BYTE = 3 +typelib_TypeClass_SHORT = 4 +typelib_TypeClass_UNSIGNED_SHORT = 5 +typelib_TypeClass_LONG = 6 +typelib_TypeClass_UNSIGNED_LONG = 7 +typelib_TypeClass_HYPER = 8 +typelib_TypeClass_UNSIGNED_HYPER = 9 +typelib_TypeClass_FLOAT = 10 +typelib_TypeClass_DOUBLE = 11 +typelib_TypeClass_ENUM = 15 + +extrn __copyConstruct : proc +extrn __destruct : proc +extrn cpp_mediate: proc + +.code + +; First we have three code snippets that aren't real functions, but +; "naked" (in x86 calling convention parlance) functions jumped to +; from code generated in C++. + +; I think that for x64 Windows we shouldn't be jumping so wildly from +; generated code snippets into fixed code snippets here. "Procedures" +; should be continuous in memory, or the unwinding information will be +; broken. (For dynamically generated code, that is dynamically +; registered unwind information, obviously.) + +; So instead of generating jumps into here, we should just make the +; C++ code copy the machine code that these three "naked" functions +; compile after the snippet it is generating. Of course, that means +; the code here needs to be position independent, or (eek) that we +; would need to come up with some home-brewed minimal relocation +; mechanism. + +; Jumped to from code generated in except.cxx: ObjectFunction::ObjectFunction() + +copyConstruct proc + ; ObjectFunction this already on stack + push [rsp+8] ; source exc object this + push rcx ; exc object + call __copyConstruct + add rsp, 12 ; + ObjectFunction this + ret 4 +copyConstruct endp + +; Ditto + +destruct proc + ; ObjectFunction this already on stack + push rcx ; exc object + call __destruct + add rsp, 8 ; + ObjectFunction this + ret +destruct endp + +; Jumped to from code generated in cpp2uno.cxx:codeSnippet() + +cpp_vtable_call proc + sub rsp, 8 ; space for immediate return type + push rsp + push rdx ; vtable offset + push rax ; function index + mov rax, rsp + add rax, 20 + push rax ; original stack ptr + + call cpp_mediate + add rsp, 16 + + cmp rax, typelib_TypeClass_FLOAT + je Lfloat + cmp rax, typelib_TypeClass_DOUBLE + je Ldouble + cmp rax, typelib_TypeClass_HYPER + je Lhyper + cmp eax, typelib_TypeClass_UNSIGNED_HYPER + je Lhyper + ; rest is eax + pop rax + add rsp, 4 + ret +Lhyper: + pop rax + pop rdx + ret +Lfloat: + fld dword ptr [rsp] + add rsp, 8 + ret +Ldouble: + fld qword ptr [rsp] + add rsp, 8 + ret +cpp_vtable_call endp + +; Called from uno2cpp.cxx + +; This one is now hopefully proper x64 Windows code following the +; appropriate conventions and might actually work. + +; void callVirtualMethod( ; location on entry +; void * pAdjustedThisPtr, ; rcx +; sal_Int32 nVtableIndex, ; rdx +; void * pReturn, ; r8 +; typelib_TypeClass eReturnTypeClass, ; r9 +; sal_Int64 * pStack, ; ((4+1)*8)[rsp] +; sal_Int32 nStack ; ((5+1)*8)[rsp] +; sal_uInt64 *pGPR, ; ((6+1)*8)[rsp] +; double *pFPR) ; ((7+1)*8)[rsp] + +callVirtualMethod proc frame + ; Prologue + mov ((3+1)*8)[rsp], r9 + mov ((2+1)*8)[rsp], r8 + mov ((0+1)*8)[rsp], rcx + push rsi + .pushreg rsi + push rdi + .pushreg rdi + + ; Our stack frame size is 24 qwords (space for 20 parameters + ; to pass, plus the two pushed registers rsi and rdi, plus + ; return address, rounded up to 16 bytes) + + sub rsp, (20+1)*8 + .allocstack (20+1)*8 + .endprolog + + ; Stack parameters first + + ; nStack is number of qwords of stack space (including spilled + ; registers). If four or less, 4 is passed in anyway to make + ; code here simpler. + + mov rcx, ((24+5)*8)[rsp] ; nStack + sub rcx, 4 + jle Lxmmregs + + mov rsi, ((24+4)*8)[rsp] ; pStack + add rsi, 32 + lea rdi, 32[rsp] + rep movsq + +Lxmmregs: + ; Parameters passed in XMM registers + + ; We don't bother checking which actually needed, if any. + mov rax, ((24+7)*8)[rsp] ; pFPR + movsd xmm0, qword ptr [rax] + movsd xmm1, qword ptr 8[rax] + movsd xmm2, qword ptr 16[rax] + movsd xmm3, qword ptr 24[rax] + + ; Prepare pointer to function to call + mov rcx, ((24+0)*8)[rsp] + mov r12, [rcx] ; pAdjustedThisPtr->vtable + shl rdx, 3 ; nVtableIndex *= 8 + add r12, rdx + + ; Fill parameters passed in general purpose registers + mov rax, ((24+6)*8)[rsp] ; pGPR + mov rcx, (0*8)[rax] + mov rdx, (1*8)[rax] + mov r8, (2*8)[rax] + mov r9, (3*8)[rax] + + call qword ptr [r12] + + ; Test return type + mov r9, ((24+3)*8)[rsp] + cmp r9, typelib_TypeClass_VOID + je Lepilog + + ; int32 + cmp r9, typelib_TypeClass_LONG + je Lint32 + cmp r9, typelib_TypeClass_UNSIGNED_LONG + je Lint32 + cmp r9, typelib_TypeClass_ENUM + je Lint32 + + ; int8 + cmp r9, typelib_TypeClass_BOOLEAN + je Lint8 + cmp r9, typelib_TypeClass_BYTE + je Lint8 + + ; int16 + cmp r9, typelib_TypeClass_CHAR + je Lint16 + cmp r9, typelib_TypeClass_SHORT + je Lint16 + cmp r9, typelib_TypeClass_UNSIGNED_SHORT + je Lint16 + + ; int64 + cmp r9, typelib_TypeClass_HYPER + je Lint64 + cmp r9, typelib_TypeClass_UNSIGNED_HYPER + je Lint64 + + ; float + cmp r9, typelib_TypeClass_FLOAT + je Lfloat + + ; double + cmp r9, typelib_TypeClass_DOUBLE + je Ldouble + + jmp Lepilog ; no simple type + +Lint8: + mov byte ptr [r8], al + jmp Lepilog + +Lint16: + mov word ptr [r8], ax + jmp Lepilog + +Lint32: + mov dword ptr [r8], eax + jmp Lepilog + +Lint64: + mov qword ptr [r8], rax + jmp Lepilog + +Lfloat: + movss dword ptr [r8], xmm0 + jmp Lepilog + +Ldouble: + movsd qword ptr [r8], xmm0 + +Lepilog: + ; Epilogue + add rsp, (20+1)*8 + pop rdi + pop rsi + ret +callVirtualMethod endp + +end + +; vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx index b84da9e866ed..d3a445bed2c1 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx @@ -87,13 +87,11 @@ static inline typelib_TypeClass cpp2uno_call( } } - // stack space - OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); // parameters void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); void ** pCppArgs = pUnoArgs + nParams; // indizes of values this have to be converted (interface conversion cpp<=>uno) - sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); + sal_Int64 * pTempIndizes = (sal_Int64 *)(pUnoArgs + (2 * nParams)); // type descriptions for reconversions typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); @@ -116,7 +114,7 @@ static inline typelib_TypeClass cpp2uno_call( case typelib_TypeClass_HYPER: case typelib_TypeClass_UNSIGNED_HYPER: case typelib_TypeClass_DOUBLE: - pCppStack += sizeof(sal_Int32); // extra long + pCppStack += sizeof(sal_Int64); // extra qword break; default: break; @@ -155,7 +153,7 @@ static inline typelib_TypeClass cpp2uno_call( TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } } - pCppStack += sizeof(sal_Int32); // standard parameter length + pCppStack += sizeof(sal_Int64); // standard parameter length } // ExceptionHolder @@ -240,12 +238,10 @@ static inline typelib_TypeClass cpp2uno_call( } //================================================================================================== -static typelib_TypeClass __cdecl cpp_mediate( +typelib_TypeClass __cdecl cpp_mediate( void ** pCallStack, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, sal_Int64 * pRegisterReturn /* space for register return */ ) { - OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); - // pCallStack: ret adr, this, [ret *], params void * pThis = static_cast< char * >(pCallStack[1]) - nVtableOffset; bridges::cpp_uno::shared::CppInterfaceProxy * pCppI @@ -361,74 +357,28 @@ static typelib_TypeClass __cdecl cpp_mediate( return eRet; } -//================================================================================================== -/** - * is called on incoming vtable calls - * (called by asm snippets) - */ -static __declspec(naked) void __cdecl cpp_vtable_call(void) -{ -__asm - { - sub esp, 8 // space for immediate return type - push esp - push edx // vtable offset - push eax // function index - mov eax, esp - add eax, 20 - push eax // original stack ptr - - call cpp_mediate - add esp, 16 - - cmp eax, typelib_TypeClass_FLOAT - je Lfloat - cmp eax, typelib_TypeClass_DOUBLE - je Ldouble - cmp eax, typelib_TypeClass_HYPER - je Lhyper - cmp eax, typelib_TypeClass_UNSIGNED_HYPER - je Lhyper - // rest is eax - pop eax - add esp, 4 - ret -Lhyper: - pop eax - pop edx - ret -Lfloat: - fld dword ptr [esp] - add esp, 8 - ret -Ldouble: - fld qword ptr [esp] - add esp, 8 - ret - } -} +extern void *cpp_vtable_call; //================================================================================================== -int const codeSnippetSize = 16; +int const codeSnippetSize = 28; unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset) { unsigned char * p = code; - OSL_ASSERT(sizeof (sal_Int32) == 4); - // mov eax, functionIndex: + // mov rax, functionIndex: *p++ = 0xB8; - *reinterpret_cast< sal_Int32 * >(p) = functionIndex; - p += sizeof (sal_Int32); - // mov edx, vtableOffset: + *reinterpret_cast< sal_Int64 * >(p) = functionIndex; + p += sizeof (sal_Int64); + // mov rdx, vtableOffset: *p++ = 0xBA; - *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; - p += sizeof (sal_Int32); - // jmp rel32 cpp_vtable_call: + *reinterpret_cast< sal_Int64 * >(p) = vtableOffset; + p += sizeof (sal_Int64); + // jmp rel64 cpp_vtable_call: *p++ = 0xE9; - *reinterpret_cast< sal_Int32 * >(p) - = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32); - p += sizeof (sal_Int32); + *reinterpret_cast< sal_Int64 * >(p) + = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int64); + p += sizeof (sal_Int64); OSL_ASSERT(p - code <= codeSnippetSize); return code + codeSnippetSize; } diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx index 8894c5b1cbad..c7fea183d91f 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx @@ -238,9 +238,9 @@ ObjectFunction::ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpF *pCode++ = 0x68; *(void **)pCode = this; pCode += sizeof(void *); - // jmp rel32 fpFunc + // jmp rel64 fpFunc *pCode++ = 0xe9; - *(sal_Int32 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int32); + *(sal_Int64 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int64); } //__________________________________________________________________________________________________ ObjectFunction::~ObjectFunction() throw () @@ -249,47 +249,25 @@ ObjectFunction::~ObjectFunction() throw () } //================================================================================================== -static void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis ) +void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis ) throw () { ::uno_copyData( pExcThis, pSource, pThis->_pTypeDescr, cpp_acquire ); return pExcThis; } //================================================================================================== -static void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis ) +void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis ) throw () { ::uno_destructData( pExcThis, pThis->_pTypeDescr, cpp_release ); return pExcThis; } -// these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr -//================================================================================================== -static __declspec(naked) void copyConstruct() throw () -{ - __asm - { - // ObjectFunction this already on stack - push [esp+8] // source exc object this - push ecx // exc object - call __copyConstruct - add esp, 12 // + ObjectFunction this - ret 4 - } -} -//================================================================================================== -static __declspec(naked) void destruct() throw () -{ - __asm - { - // ObjectFunction this already on stack - push ecx // exc object - call __destruct - add esp, 8 // + ObjectFunction this - ret - } -} +// These are machine code snippets in asmbits.asm + +extern void *copyConstruct; +extern void *destruct; //================================================================================================== struct ExceptionType @@ -332,9 +310,6 @@ RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw () , _n3( 0 ) , _n4( 0 ) { - // a must be - OSL_ENSURE( sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer size differs from sal_Int32!" ); - typelib_CompoundTypeDescription * pCompTypeDescr; // info count @@ -346,10 +321,10 @@ RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw () } // info count accompanied by type info ptrs: type, base type, base base type, ... - _types = ::rtl_allocateMemory( sizeof(sal_Int32) + (sizeof(ExceptionType *) * nLen) ); - *(sal_Int32 *)_types = nLen; + _types = ::rtl_allocateMemory( sizeof(sal_Int64) + (sizeof(ExceptionType *) * nLen) ); + *(sal_Int64 *)_types = nLen; - ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1); + ExceptionType ** ppTypes = (ExceptionType **)((sal_Int64 *)_types + 1); sal_Int32 nPos = 0; for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr; @@ -361,8 +336,8 @@ RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw () //__________________________________________________________________________________________________ RaiseInfo::~RaiseInfo() throw () { - ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1); - for ( sal_Int32 nTypes = *(sal_Int32 *)_types; nTypes--; ) + ExceptionType ** ppTypes = (ExceptionType **)((sal_Int64 *)_types + 1); + for ( sal_Int32 nTypes = *(sal_Int64 *)_types; nTypes--; ) { delete ppTypes[nTypes]; } @@ -486,14 +461,10 @@ void mscx_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) void * pCppExc = alloca( pTypeDescr->nSize ); ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp ); - // a must be - OSL_ENSURE( - sizeof(sal_Int32) == sizeof(void *), - "### pointer size differs from sal_Int32!" ); - DWORD arFilterArgs[3]; + ULONG_PTR arFilterArgs[3]; arFilterArgs[0] = MSVC_magic_number; - arFilterArgs[1] = (DWORD)pCppExc; - arFilterArgs[2] = (DWORD)ExceptionInfos::getRaiseInfo( pTypeDescr ); + arFilterArgs[1] = (ULONG_PTR)pCppExc; + arFilterArgs[2] = (ULONG_PTR)ExceptionInfos::getRaiseInfo( pTypeDescr ); // destruct uno exception ::uno_any_destruct( pUnoExc, 0 ); @@ -514,13 +485,9 @@ int mscx_filterCppException( if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode) return EXCEPTION_CONTINUE_SEARCH; -#if _MSC_VER < 1300 // MSVC -6 - bool rethrow = (pRecord->NumberParameters < 3 || - pRecord->ExceptionInformation[ 2 ] == 0); -#else bool rethrow = __CxxDetectRethrow( &pRecord ); OSL_ASSERT( pRecord == pPointers->ExceptionRecord ); -#endif + if (rethrow && pRecord == pPointers->ExceptionRecord) { // hack to get msvcrt internal _curexception field: @@ -532,14 +499,12 @@ int mscx_filterCppException( // crt\src\mtdll.h: // offsetof (_tiddata, _curexception) - // offsetof (_tiddata, _tpxcptinfoptrs): -#if _MSC_VER < 1300 - 0x18 // msvcrt,dll -#elif _MSC_VER < 1310 - 0x20 // msvcr70.dll -#elif _MSC_VER < 1400 - 0x24 // msvcr71.dll +#if _MSC_VER < 1500 + error, this compiler version is not supported +#elif _MSC_VER < 1600 + 0x48 // msvcr90.dll #else - 0x28 // msvcr80.dll + error, please find value for this compiler version #endif ); } diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk index d8e760cb598c..44ea288e8cb5 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk @@ -54,7 +54,8 @@ SLOFILES= \ $(SLO)$/cpp2uno.obj \ $(SLO)$/uno2cpp.obj \ $(SLO)$/dllinit.obj \ - $(SLO)$/except.obj + $(SLO)$/except.obj \ + $(SLO)$/asmbits.obj NOOPTFILES= \ $(SLO)$/except.obj @@ -80,4 +81,3 @@ DEF1NAME=$(SHL1TARGET) # --- Targets ------------------------------------------------------ .INCLUDE : target.mk - diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx index f112b1a15f16..74b55397e6e8 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx @@ -47,106 +47,52 @@ using namespace ::com::sun::star::uno; namespace { +// As "long" is 32 bit also in x64 Windows we don't use "longs" in names +// to indicate pointer-sized stack slots etc like in the other x64 archs, +// but "qword" as in ml64. + //================================================================================================== -inline static void callVirtualMethod( +// In asmbits.asm +extern void callVirtualMethod( void * pAdjustedThisPtr, sal_Int32 nVtableIndex, - void * pRegisterReturn, typelib_TypeClass eReturnTypeClass, - sal_Int32 * pStackLongs, sal_Int32 nStackLongs ) -{ - // parameter list is mixed list of * and values - // reference parameters are pointers + void * pReturn, typelib_TypeClass eReturnTypeClass, + sal_Int64 * pStack, sal_Int32 nStack, + sal_uInt64 *pGPR, + double *pFPR); - OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); - OSL_ENSURE( (sizeof(void *) == 4) && - (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); - -__asm +#if OSL_DEBUG_LEVEL > 1 +inline void callVirtualMethodwrapper( + void * pAdjustedThisPtr, sal_Int32 nVtableIndex, + void * pReturn, typelib_TypeDescriptionReference * pReturnTypeRef, + sal_Int64 * pStack, sal_Int32 nStack, + sal_uInt64 *pGPR, sal_uInt32 nGPR, + double *pFPR, sal_uInt32 nFPR) +{ + // Let's figure out what is really going on here { - mov eax, nStackLongs - test eax, eax - je Lcall - // copy values - mov ecx, eax - shl eax, 2 // sizeof(sal_Int32) == 4 - add eax, pStackLongs // params stack space -Lcopy: sub eax, 4 - push dword ptr [eax] - dec ecx - jne Lcopy -Lcall: - // call - mov ecx, pAdjustedThisPtr - push ecx // this ptr - mov edx, [ecx] // pvft - mov eax, nVtableIndex - shl eax, 2 // sizeof(void *) == 4 - add edx, eax - call [edx] // interface method call must be __cdecl!!! - - // register return - mov ecx, eReturnTypeClass - cmp ecx, typelib_TypeClass_VOID - je Lcleanup - mov ebx, pRegisterReturn -// int32 - cmp ecx, typelib_TypeClass_LONG - je Lint32 - cmp ecx, typelib_TypeClass_UNSIGNED_LONG - je Lint32 - cmp ecx, typelib_TypeClass_ENUM - je Lint32 -// int8 - cmp ecx, typelib_TypeClass_BOOLEAN - je Lint8 - cmp ecx, typelib_TypeClass_BYTE - je Lint8 -// int16 - cmp ecx, typelib_TypeClass_CHAR - je Lint16 - cmp ecx, typelib_TypeClass_SHORT - je Lint16 - cmp ecx, typelib_TypeClass_UNSIGNED_SHORT - je Lint16 -// float - cmp ecx, typelib_TypeClass_FLOAT - je Lfloat -// double - cmp ecx, typelib_TypeClass_DOUBLE - je Ldouble -// int64 - cmp ecx, typelib_TypeClass_HYPER - je Lint64 - cmp ecx, typelib_TypeClass_UNSIGNED_HYPER - je Lint64 - jmp Lcleanup // no simple type -Lint8: - mov byte ptr [ebx], al - jmp Lcleanup -Lint16: - mov word ptr [ebx], ax - jmp Lcleanup -Lfloat: - fstp dword ptr [ebx] - jmp Lcleanup -Ldouble: - fstp qword ptr [ebx] - jmp Lcleanup -Lint64: - mov dword ptr [ebx], eax - mov dword ptr [ebx+4], edx - jmp Lcleanup -Lint32: - mov dword ptr [ebx], eax - jmp Lcleanup -Lcleanup: - // cleanup stack (obsolete though because of function) - mov eax, nStackLongs - shl eax, 2 // sizeof(sal_Int32) == 4 - add eax, 4 // this ptr - add esp, eax + fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR ); + for ( unsigned int i = 0; i < nGPR; ++i ) + fprintf( stderr, "0x%lx, ", pGPR[i] ); + fprintf( stderr, "\nFPR's (%d): ", nFPR ); + for ( unsigned int i = 0; i < nFPR; ++i ) + fprintf( stderr, "%f, ", pFPR[i] ); + fprintf( stderr, "\nStack (%d): ", nStack ); + for ( unsigned int i = 0; i < nStack; ++i ) + fprintf( stderr, "0x%lx, ", pStack[i] ); + fprintf( stderr, "\n" ); } + + callVirtualMethod( pAdjustedThisPtr, nVtableIndex, + pReturn, pReturnTypeRef->eTypeClass, + pStack, nStack, + pGPR, + pFPR); } +#define callVirtualMethod callVirtualMethodwrapper + +#endif + //================================================================================================== static void cpp_call( bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, @@ -156,16 +102,33 @@ static void cpp_call( void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) throw () { // max space for: [complex ret ptr], values|ptr ... - char * pCppStack = (char *)alloca( sizeof(sal_Int32) + (nParams * sizeof(sal_Int64)) ); + // (but will be used less - some of the values will be in pGPR and pFPR) + sal_uInt64 *pStack = (sal_uInt64 *) alloca( (nParams + 3) * sizeof(sal_uInt64) ); + sal_uInt64 *pStackStart = pStack; + + // Parameters to be passed in registers stored here + sal_uInt64 pGPR[4]; + sal_uInt32 nGPR = 0; + double pFPR[4]; + sal_uInt32 nFPR = 0; + + if (nParams > 20) + { + + } + + + char * pCppStack = (char *)alloca( sizeof(sal_Int64) + (nParams * sizeof(sal_Int64)) ); char * pCppStackStart = pCppStack; - // return + // 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 + bool bSimpleReturn = true; if (pReturnTypeDescr) { if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) @@ -186,15 +149,15 @@ static void cpp_call( // stack space - OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); + OSL_ENSURE( sizeof(void *) == sizeof(sal_Int64), "### unexpected size!" ); // args - void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); + void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); // indizes of values this have to be converted (interface conversion cpp<=>uno) sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); // type descriptions for reconversions typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); - sal_Int32 nTempIndizes = 0; + sal_Int32 nTempIndizes = 0; for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) { @@ -214,7 +177,7 @@ static void cpp_call( case typelib_TypeClass_HYPER: case typelib_TypeClass_UNSIGNED_HYPER: case typelib_TypeClass_DOUBLE: - pCppStack += sizeof(sal_Int32); // extra long + pCppStack += sizeof(sal_Int64); // extra qword break; default: break; @@ -254,7 +217,7 @@ static void cpp_call( TYPELIB_DANGER_RELEASE( pParamTypeDescr ); } } - pCppStack += sizeof(sal_Int32); // standard parameter length + pCppStack += sizeof(sal_Int64); // standard parameter length } __try @@ -264,8 +227,8 @@ static void cpp_call( reinterpret_cast< void ** >(pThis->getCppI()) + aVtableSlot.offset, aVtableSlot.index, pCppReturn, pReturnTypeDescr->eTypeClass, - (sal_Int32 *)pCppStackStart, - (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); + (sal_Int64 *)pCppStackStart, + (pCppStack - pCppStackStart) / sizeof(sal_Int64) ); } __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException( GetExceptionInformation(), -- cgit