summaryrefslogtreecommitdiff
path: root/bridges
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@novell.com>2011-01-28 18:24:01 +0200
committerTor Lillqvist <tlillqvist@novell.com>2011-01-28 18:41:07 +0200
commit75e02ab302970290758f121364b96cdafdc95b2e (patch)
tree469c08e94264565acb8dbe0e43097f6e6e25aa39 /bridges
parent96b1611644da542b23eb0a78744be320eb2e8b54 (diff)
Let's use a shared privateSnippetExecutor() approach as on x64 Linux
It simplifies function table and unwinding info management, as those are now static for the privateSnippetExecutor() function in call.asm. Even if it is slightly ugly to have to poke in more instructions in codeSnippet(). Out privateSnippetExecutor() is much simpler than the x64 Linux one, thanks to the simpler calling convention.
Diffstat (limited to 'bridges')
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/call.asm (renamed from bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm)124
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx135
-rw-r--r--bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk2
-rw-r--r--bridges/source/cpp_uno/shared/vtablefactory.cxx24
4 files changed, 89 insertions, 196 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
index 8d76b2f8a521..ae514fd065e2 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm
@@ -29,15 +29,18 @@
;; in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
;; instead of those above.
-;; This is the template source code for the trampoline generated by
-;; codeSnippet() in cpp2uno.cxx. codeSnippet() copies the code from
-;; this function, modifying it as necessary in a few places. The
-;; generated trampoline calls cpp_vtable_call() which then calls the
-;; actual UNO function.
+;; This is the function jumped to from the trampoline generated by
+;; codeSnippet() in cpp2uno.cxx. Here we call cpp_vtable_call() which
+;; then calls the actual UNO function.
-;; We keep this as a separate .asm file here so that it is easy to
-;; modify, and we don't need to laborously enter machine code into
-;; codeSnippet().
+;; The code snippet generated is called from "normal" C++ code which
+;; has no idea that it is calling dynamically generated code.
+
+;; The generated short code snippet is not covered by any function
+;; table and unwind info, but that doesn't matter, as the instructions
+;; in it are not really going to cause any exception. Once it jumps
+;; here it is covered by a function table, and the calls further down
+;; through cpp_vtable_call() can be unwound cleanly.
;; This is in a separate file for x86-64 as MSVC doesn't have in-line
;; assembly for x64.
@@ -73,9 +76,6 @@
;; information, for instance:
;; http://www.nynaeve.net/?p=11
-;; The code snippet generated is called from "normal" C++ code which
-;; has no idea that it is calling dynamically generated code.
-
typelib_TypeClass_FLOAT equ 10
typelib_TypeClass_DOUBLE equ 11
@@ -83,28 +83,7 @@ extern cpp_vtable_call: proc
.code
-;; Single instruction templates. For each register paramter, which can
-;; be either in an integer or floating-point register, either of two
-;; instruction sequences are used, either:
-;; mov qword ptr offset[rsp], reg
-;; nop
-;; or:
-;; movsd qwort ptr offset[rsp], xmmreg
-;;
-;; The nop in the integer case is so that both are of equal length
-
-fp_spill_templates:
-public fp_spill_templates
- movsd qword ptr (40+8)[rsp], xmm0
- movsd qword ptr (40+16)[rsp], xmm1
- movsd qword ptr (40+24)[rsp], xmm2
- movsd qword ptr (40+32)[rsp], xmm3
-fp_spill_templates_end:
-public fp_spill_templates_end
-
-;; The actual template function code here
-
-trampoline_template proc
+privateSnippetExecutor proc frame
;; Make stack frame. Re-align RSP at 16 bytes. We need just one
;; qword of stack for our own purposes: Where cpp_vtable_call()
@@ -113,76 +92,20 @@ trampoline_template proc
;; cpp_vtable_call()) to spill their register parameters.
sub rsp, 40
-trampoline_template_prolog_end:
-
- jmp trampoline_template_spill_params
-
- ;; We store the function table (with just one entry, for this function) and
- ;; the associated unwind info here at a known offset from the function start
- ;; so that we don't have to know separately where it is when we need to unregister it, but
- ;; can just use the known offset from the function start.
-
- align 4
- ;; See http://msdn.microsoft.com/en-us/library/ssa62fwe%28v=VS.90%29.aspx
-trampoline_template_function_table::
-public trampoline_template_function_table
- dword 0
- dword trampoline_template_end - trampoline_template
- dword unwind_info - trampoline_template
-unwind_info:
- byte 1
- byte trampoline_template_prolog_end - trampoline_template
- byte 1
- byte 0
- byte trampoline_template_prolog_end - trampoline_template
- byte 42h
-
-trampoline_template_spill_params::
-public trampoline_template_spill_params
-
- ;; Spill our register parameters. In the x64 Windows calling
- ;; convention the caller always has stack space allocated
- ;; where the callee can spill register parameters.
-
- ;; The default is integer moves, that are replaced in the
- ;; generated code snippet with floating-point moves for
- ;; floating-point parameters.
-
- mov qword ptr (40+8)[rsp], rcx
- nop
- mov qword ptr (40+16)[rsp], rdx
- nop
- mov qword ptr (40+24)[rsp], r8
- nop
- mov qword ptr (40+32)[rsp], r9
- nop
-trampoline_template_spill_params_end::
-public trampoline_template_spill_params_end
-
- ;; Call cpp_vtable_call() with 3 parameters:
-
- ;; 1 (rcx): nFunctionIndex
- ;; 2 (rdx): nVtableOffset
- ;; 3 (r8): pointer to where to store return value, followed by our
+ .allocstack (40)
+ .endprolog
+
+ ;; Call cpp_vtable_call() with 2 parameters:
+
+ ;; 1 (rcx): nOffsetAndIndex (already put there in code generated by codeSnippet)
+ ;; 2 (rdx): pointer to where to store return value, followed by our
;; return address (uninteresting to cpp_vtable_call()), followed
;; by our spilled register parameters, as stored above, followed
;; by the rest of our parameters, if any.
- mov rcx, 12345467890abcdeh ;; nFunctionIndex, actual value generated from
- ;; parameter to codeSnippet()
-trampoline_template_function_index::
-public trampoline_template_function_index
+ lea rdx, 32[rsp]
- mov rdx, 12345467890abcdeh ;; nVtableOffset, ditto
-trampoline_template_vtable_offset::
-public trampoline_template_vtable_offset
-
- lea r8, 32[rsp] ;; Where cpp_vtable_call() will store the return value
-
- mov rax, 12345467890abcdeh ;; cpp_vtable_call address, filled in by codeSnippet()
-trampoline_template_cpp_vtable_call::
-public trampoline_template_cpp_vtable_call
- call rax
+ call cpp_vtable_call
;; cpp_vtable_call() returns the typelib_TypeClass type of the
;; return value of the called UNO function
@@ -202,10 +125,7 @@ Lfloat:
Lepilogue:
add rsp, 40
ret
-trampoline_template_end::
-public trampoline_template_end
-
-trampoline_template endp
+privateSnippetExecutor endp
end
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 22e0c7467e15..38d48241d02c 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx
@@ -228,10 +228,12 @@ static inline typelib_TypeClass cpp2uno_call(
//==================================================================================================
extern "C" typelib_TypeClass cpp_vtable_call(
- sal_Int32 nFunctionIndex,
- sal_Int32 nVtableOffset,
+ sal_Int64 nOffsetAndIndex,
void ** pStack )
{
+ sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF);
+ sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF);
+
// pStack points to space for return value, after which
// follows our return address (uninteresting) then the spilled
// integer or floating-point register parameters from the call to
@@ -372,89 +374,84 @@ extern "C" typelib_TypeClass cpp_vtable_call(
}
//==================================================================================================
-extern "C" {
-
-// These are actually addresses in the code compiled from codeSnippet.asm
-extern char
- fp_spill_templates,
- fp_spill_templates_end,
- trampoline_template,
- trampoline_template_function_table,
- trampoline_template_spill_params,
- trampoline_template_spill_params_end,
- trampoline_template_function_index,
- trampoline_template_vtable_offset,
- trampoline_template_cpp_vtable_call,
- trampoline_template_end;
-}
-// Just the code
-int const codeSnippetSize =
- (int) (&trampoline_template_end - &trampoline_template);
+int const codeSnippetSize = 48;
+
+extern "C" char privateSnippetExecutor;
// This function generates the code that acts as a proxy for the UNO function to be called.
// The generated code does the following:
-// - Save register parametrs.
+// - Spills register parameters on stack
+// - Loads functionIndex and vtableOffset into scratch registers
+// - Jumps to privateSnippetExecutor
unsigned char * codeSnippet(
unsigned char * code,
char param_kind[4],
- sal_Int32 functionIndex,
- sal_Int32 vtableOffset,
+ sal_Int32 nFunctionIndex,
+ sal_Int32 nVtableOffset,
bool bHasHiddenParam )
{
- OSL_ASSERT( (&fp_spill_templates_end - &fp_spill_templates) ==
- (&trampoline_template_spill_params_end - &trampoline_template_spill_params) );
-
- OSL_ASSERT( ((&fp_spill_templates_end - &fp_spill_templates) / 4) * 4 ==
- (&fp_spill_templates_end - &fp_spill_templates) );
+ sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
+ unsigned char *p = code;
if ( bHasHiddenParam )
- functionIndex |= 0x80000000;
-
- int const one_spill_instruction_size =
- (int) ((&fp_spill_templates_end - &fp_spill_templates)) / 4;
+ nOffsetAndIndex |= 0x80000000;
- memcpy( code, &trampoline_template, codeSnippetSize );
-
- for (int i = 0; i < 4; ++i)
+ // Spill parameters
+ if ( param_kind[0] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
{
- if ( param_kind[i] == CPPU_CURRENT_NAMESPACE::REGPARAM_FLT )
- {
- memcpy (&trampoline_template_spill_params + i*one_spill_instruction_size,
- &fp_spill_templates + i*one_spill_instruction_size,
- one_spill_instruction_size);
- }
+ // mov qword ptr 8[rsp], rcx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x08;
+ }
+ else
+ {
+ // movsd qword ptr 8[rsp], xmm0
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08;
+ }
+ if ( param_kind[1] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 16[rsp], rdx
+ *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
}
+ else
+ {
+ // movsd qword ptr 16[rsp], xmm1
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x10;
+ }
+ if ( param_kind[2] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 24[rsp], r8
+ *p++ = 0x4C; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18;
+ }
+ else
+ {
+ // movsd qword ptr 24[rsp], xmm2
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18;
+ }
+ if ( param_kind[3] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT )
+ {
+ // mov qword ptr 32[rsp], r9
+ *p++ = 0x4C;*p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x20;
+ }
+ else
+ {
+ // movsd qword ptr 32[rsp], xmm3
+ *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x5C; *p++ = 0x24; *p++ = 0x20;
+ }
+
+ // mov rcx, nOffsetAndIndex
+ *p++ = 0x48; *p++ = 0xB9;
+ *((sal_uInt64 *)p) = nOffsetAndIndex; p += 8;
+
+ // mov r11, privateSnippetExecutor
+ *p++ = 0x49; *p++ = 0xBB;
+ *((void **)p) = &privateSnippetExecutor; p += 8;
+
+ // jmp r11
+ *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
- ((sal_uInt64*) (code + (&trampoline_template_function_index
- - &trampoline_template)))[-1] =
- functionIndex;
- ((sal_uInt64*) (code + (&trampoline_template_vtable_offset
- - &trampoline_template)))[-1] =
- vtableOffset;
- ((void**) (code + (&trampoline_template_cpp_vtable_call
- - &trampoline_template)))[-1] =
- cpp_vtable_call;
-
- // Add unwind data for the dynamically generated function by
- // calling RtlAddFunctionTable().
-
- // The unwind data is inside the function code, at a fixed offset
- // from the function start. See codeSnippet.asm. Actually this is
- // unnecessarily complex, we could as well just allocate the
- // function table dynamically. But it doesn't hurt either, I
- // think.
-
- // The real problem now is that we need to remove the unwind data
- // with RtlDeleteFunctionTable() in freeExec() in
- // vtablefactory.cxx. See comment there.
-
- RUNTIME_FUNCTION *pFunTable =
- (RUNTIME_FUNCTION *) (code + (&trampoline_template_function_table
- - &trampoline_template));
-
- RtlAddFunctionTable( pFunTable, 1, (DWORD64) code );
+ OSL_ASSERT( p < code + codeSnippetSize );
return code + codeSnippetSize;
}
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 e813fad0c4cc..7f73ebe4bba2 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk
@@ -55,7 +55,7 @@ SLOFILES= \
$(SLO)$/uno2cpp.obj \
$(SLO)$/dllinit.obj \
$(SLO)$/except.obj \
- $(SLO)$/codeSnippet.obj
+ $(SLO)$/call.obj
NOOPTFILES= \
$(SLO)$/except.obj
diff --git a/bridges/source/cpp_uno/shared/vtablefactory.cxx b/bridges/source/cpp_uno/shared/vtablefactory.cxx
index f589c295f3a7..4b819632c863 100644
--- a/bridges/source/cpp_uno/shared/vtablefactory.cxx
+++ b/bridges/source/cpp_uno/shared/vtablefactory.cxx
@@ -125,14 +125,6 @@ extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) {
return p;
}
-#if defined SAL_W32
-extern "C" {
-extern char
- trampoline_template,
- trampoline_template_function_table;
-}
-#endif
-
extern "C" void SAL_CALL freeExec(
rtl_arena_type *, void * address, sal_Size size)
{
@@ -140,22 +132,6 @@ extern "C" void SAL_CALL freeExec(
munmap(static_cast< char * >(address), size);
#elif defined SAL_W32
(void) size; // unused
-
- // Remove the function table for the dynamically generated
- // function that was added in codeSnippet() in cpp2uno.cxx.
-
-#if 0
- // This is broken. address is not the address of a code
- // snippet. Each virtual memory region alocated with
- // VirtualAlloc() contains multiple generated code snippets. We
- // need to have a hash table from the base addresses of the region
- // to the function tables inside it.
-
- RUNTIME_FUNCTION *pFunTable =
- (RUNTIME_FUNCTION *) ((char *) address + (&trampoline_template_function_table - &trampoline_template));
- RtlDeleteFunctionTable( pFunTable );
-#endif
-
VirtualFree(address, 0, MEM_RELEASE);
#elif defined(SAL_OS2)
(void) DosFreeMem( address);