Commit 00fb82c3 authored by Alexandre Julliard's avatar Alexandre Julliard

rpcrt4: Generate vtbl delegating thunks at compile time.

parent 439ce3a3
...@@ -39,7 +39,7 @@ typedef struct ...@@ -39,7 +39,7 @@ typedef struct
typedef struct typedef struct
{ {
IUnknownVtbl *base_obj; IUnknown base_obj;
IRpcStubBuffer *base_stub; IRpcStubBuffer *base_stub;
CStdStubBuffer stub_buffer; CStdStubBuffer stub_buffer;
} cstdstubbuffer_delegating_t; } cstdstubbuffer_delegating_t;
...@@ -69,8 +69,7 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN; ...@@ -69,8 +69,7 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN;
HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv) DECLSPEC_HIDDEN; HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv) DECLSPEC_HIDDEN;
HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub) DECLSPEC_HIDDEN; HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub) DECLSPEC_HIDDEN;
BOOL fill_stubless_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN; BOOL fill_stubless_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN;
IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) DECLSPEC_HIDDEN; const IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) DECLSPEC_HIDDEN;
void release_delegating_vtbl(IUnknownVtbl *vtbl) DECLSPEC_HIDDEN;
#define THUNK_ENTRY_FIRST_BLOCK() \ #define THUNK_ENTRY_FIRST_BLOCK() \
THUNK_ENTRY(3) \ THUNK_ENTRY(3) \
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "rpcproxy.h" #include "rpcproxy.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/asm.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "cpsf.h" #include "cpsf.h"
...@@ -101,26 +102,6 @@ HRESULT CStdStubBuffer_Construct(REFIID riid, ...@@ -101,26 +102,6 @@ HRESULT CStdStubBuffer_Construct(REFIID riid,
return S_OK; return S_OK;
} }
static CRITICAL_SECTION delegating_vtbl_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &delegating_vtbl_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": delegating_vtbl_section") }
};
static CRITICAL_SECTION delegating_vtbl_section = { &critsect_debug, -1, 0, 0, 0, 0 };
struct delegating_vtbl
{
DWORD ref;
DWORD size;
IUnknownVtbl vtbl;
const void *methods[];
};
static struct delegating_vtbl *current_vtbl;
static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv) static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv)
{ {
*ppv = pUnk; *ppv = pUnk;
...@@ -144,144 +125,78 @@ static ULONG WINAPI delegating_Release(IUnknown *pUnk) ...@@ -144,144 +125,78 @@ static ULONG WINAPI delegating_Release(IUnknown *pUnk)
*/ */
#ifdef __i386__ #ifdef __i386__
#include "pshpack1.h" #define THUNK_ENTRY_SIZE 20
typedef struct { #define THUNK_ENTRY(num) \
BYTE mov1[4]; /* mov 0x4(%esp),%eax 8b 44 24 04 */ ".balign 4\n\t" \
BYTE mov2[3]; /* mov 0x10(%eax),%eax 8b 40 10 */ "mov 4(%esp),%eax\n\t" \
BYTE mov3[4]; /* mov %eax,0x4(%esp) 89 44 24 04 */ "mov 0x10(%eax),%eax\n\t" \
BYTE mov4[2]; /* mov (%eax),%eax 8b 00 */ "mov %eax,4(%esp)\n\t" \
BYTE mov5[2]; /* jmp *offset(%eax) ff a0 offset */ "mov (%eax),%eax\n\t" \
DWORD offset; ".byte 0xff,0xa0\n\t" /* jmp *offset(%eax) */ \
BYTE pad[1]; /* nop 90 */ ".long 4*("#num")\n\t"
} vtbl_method_t;
#include "poppack.h"
static const BYTE opcodes[20] = { 0x8b, 0x44, 0x24, 0x04, 0x8b, 0x40, 0x10, 0x89, 0x44, 0x24, 0x04,
0x8b, 0x00, 0xff, 0xa0, 0, 0, 0, 0, 0x90 };
#elif defined(__x86_64__) #elif defined(__x86_64__)
#include "pshpack1.h" #define THUNK_ENTRY_SIZE 16
typedef struct #define THUNK_ENTRY(num) \
{ ".balign 4\n\t" \
BYTE mov1[4]; /* movq 0x20(%rcx),%rcx 48 8b 49 20 */ "movq 0x20(%rcx),%rcx\n\t" \
BYTE mov2[3]; /* movq (%rcx),%rax 48 8b 01 */ "movq (%rcx),%rax\n\t" \
BYTE jmp[2]; /* jmp *offset(%rax) ff a0 offset */ ".byte 0xff,0xa0\n\t" /* jmp *offset(%rax) */ \
DWORD offset; ".long 8*("#num")\n\t"
BYTE pad[3]; /* lea 0x0(%rsi),%rsi 48 8d 36 */
} vtbl_method_t;
#include "poppack.h"
static const BYTE opcodes[16] = { 0x48, 0x8b, 0x49, 0x20, 0x48, 0x8b, 0x01,
0xff, 0xa0, 0, 0, 0, 0, 0x48, 0x8d, 0x36 };
#elif defined(__arm__) #elif defined(__arm__)
static const DWORD opcodes[] = #define THUNK_ENTRY_SIZE 12
{ #define THUNK_ENTRY(num) \
0xe52d4004, /* push {r4} */ ".balign 4\n\t" \
0xe5900010, /* ldr r0, [r0, #16] */ "ldr r0, [r0, #0x10]\n\t" \
0xe5904000, /* ldr r4, [r0] */ "ldr ip, [r0]\n\t" \
0xe59fc008, /* ldr ip, [pc, #8] */ "ldr pc, [ip, #(4*("#num"))]\n\t"
0xe08cc004, /* add ip, ip, r4 */
0xe49d4004, /* pop {r4} */
0xe59cf000 /* ldr pc, [ip] */
};
typedef struct
{
DWORD opcodes[ARRAY_SIZE(opcodes)];
DWORD offset;
} vtbl_method_t;
#elif defined(__aarch64__) #elif defined(__aarch64__)
static const DWORD opcodes[] = #define THUNK_ENTRY_SIZE 20
{ #define THUNK_ENTRY(num) \
0xf9401000, /* ldr x0, [x0,#32] */ "ldr x0, [x0, #0x20]\n\t" \
0xf9400010, /* ldr x16, [x0] */ "ldr x16, [x0]\n\t" \
0x18000071, /* ldr w17, offset */ "mov x17, #("#num")\n\t" \
0xf8716a10, /* ldr x16, [x16,x17] */ "ldr x16, [x16, x17, lsl #3]\n\t" \
0xd61f0200 /* br x16 */ "br x16\n\t"
};
typedef struct
{
DWORD opcodes[ARRAY_SIZE(opcodes)];
DWORD offset;
} vtbl_method_t;
#else #else
#warning You must implement delegated proxies/stubs for your CPU #warning You must implement delegated proxies/stubs for your CPU
typedef struct #define THUNK_ENTRY_SIZE 0
{ #define THUNK_ENTRY(num) ""
DWORD offset;
} vtbl_method_t;
static const BYTE opcodes[1];
#endif #endif
#define BLOCK_SIZE 1024 extern void vtbl_thunks(void);
#define MAX_BLOCKS 64 /* 64k methods should be enough for anybody */ __ASM_GLOBAL_FUNC( vtbl_thunks, ALL_THUNK_ENTRIES )
#undef THUNK_ENTRY
static const vtbl_method_t *method_blocks[MAX_BLOCKS];
static const vtbl_method_t *allocate_block( unsigned int num ) static const struct
{ {
unsigned int i; IUnknownVtbl vtbl;
vtbl_method_t *prev, *block; const void *methods[NB_THUNK_ENTRIES - 3];
DWORD oldprot; } delegating_vtbl =
block = VirtualAlloc( NULL, BLOCK_SIZE * sizeof(*block),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
if (!block) return NULL;
for (i = 0; i < BLOCK_SIZE; i++)
{
memcpy( &block[i], opcodes, sizeof(opcodes) );
block[i].offset = (BLOCK_SIZE * num + i + 3) * sizeof(void *);
}
VirtualProtect( block, BLOCK_SIZE * sizeof(*block), PAGE_EXECUTE_READ, &oldprot );
prev = InterlockedCompareExchangePointer( (void **)&method_blocks[num], block, NULL );
if (prev) /* someone beat us to it */
{
VirtualFree( block, 0, MEM_RELEASE );
block = prev;
}
return block;
}
static BOOL init_delegating_vtbl(struct delegating_vtbl *table, DWORD num)
{ {
DWORD i, j; { delegating_QueryInterface, delegating_AddRef, delegating_Release },
table->ref = 0;
table->size = num;
if (num - 3 > BLOCK_SIZE * MAX_BLOCKS)
{
FIXME( "%lu methods not supported\n", num );
return FALSE;
}
table->vtbl.QueryInterface = delegating_QueryInterface;
table->vtbl.AddRef = delegating_AddRef;
table->vtbl.Release = delegating_Release;
for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++)
{ {
const vtbl_method_t *block = method_blocks[i]; #define THUNK_ENTRY(num) (char *)vtbl_thunks + ((num) - 3) * THUNK_ENTRY_SIZE,
if (!block && !(block = allocate_block( i ))) return FALSE; ALL_THUNK_ENTRIES
for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++) #undef THUNK_ENTRY
table->methods[j] = &block[j];
} }
return TRUE; };
}
BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num)
{ {
const void **entry = (const void **)(vtbl + 1); const void **entry = (const void **)(vtbl + 1);
DWORD i, j; DWORD i;
if (num - 3 > BLOCK_SIZE * MAX_BLOCKS) if (num > NB_THUNK_ENTRIES)
{ {
FIXME( "%lu methods not supported\n", num ); FIXME( "%lu methods not supported\n", num );
return FALSE; return FALSE;
...@@ -289,62 +204,19 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) ...@@ -289,62 +204,19 @@ BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num)
vtbl->QueryInterface = IUnknown_QueryInterface_Proxy; vtbl->QueryInterface = IUnknown_QueryInterface_Proxy;
vtbl->AddRef = IUnknown_AddRef_Proxy; vtbl->AddRef = IUnknown_AddRef_Proxy;
vtbl->Release = IUnknown_Release_Proxy; vtbl->Release = IUnknown_Release_Proxy;
for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) for (i = 0; i < num - 3; i++)
{ if (!entry[i]) entry[i] = delegating_vtbl.methods[i];
const vtbl_method_t *block = method_blocks[i];
if (!block && !(block = allocate_block( i ))) return FALSE;
for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++, entry++)
if (!*entry) *entry = &block[j];
}
return TRUE; return TRUE;
} }
IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) const IUnknownVtbl *get_delegating_vtbl(DWORD num)
{ {
IUnknownVtbl *ret; if (num > NB_THUNK_ENTRIES)
if (num_methods < 256) num_methods = 256; /* avoid frequent reallocations */
EnterCriticalSection(&delegating_vtbl_section);
if(!current_vtbl || num_methods > current_vtbl->size)
{ {
struct delegating_vtbl *table = malloc(FIELD_OFFSET(struct delegating_vtbl, methods[num_methods])); FIXME( "%lu methods not supported\n", num );
if (!table) return NULL;
{
LeaveCriticalSection(&delegating_vtbl_section);
return NULL;
}
init_delegating_vtbl(table, num_methods);
if (current_vtbl && current_vtbl->ref == 0)
{
TRACE("freeing old table\n");
free(current_vtbl);
}
current_vtbl = table;
}
current_vtbl->ref++;
ret = &current_vtbl->vtbl;
LeaveCriticalSection(&delegating_vtbl_section);
return ret;
}
void release_delegating_vtbl(IUnknownVtbl *vtbl)
{
struct delegating_vtbl *table = CONTAINING_RECORD(vtbl, struct delegating_vtbl, vtbl);
EnterCriticalSection(&delegating_vtbl_section);
table->ref--;
TRACE("ref now %ld\n", table->ref);
if(table->ref == 0 && table != current_vtbl)
{
TRACE("... and we're not current so free'ing\n");
free(table);
} }
LeaveCriticalSection(&delegating_vtbl_section); return &delegating_vtbl.vtbl;
} }
HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid, HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid,
...@@ -379,11 +251,10 @@ HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid, ...@@ -379,11 +251,10 @@ HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid,
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
This->base_obj = get_delegating_vtbl( vtbl->header.DispatchTableCount ); This->base_obj.lpVtbl = get_delegating_vtbl( vtbl->header.DispatchTableCount );
r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub); r = create_stub(delegating_iid, &This->base_obj, &This->base_stub);
if(FAILED(r)) if(FAILED(r))
{ {
release_delegating_vtbl(This->base_obj);
free(This); free(This);
IUnknown_Release(pvServer); IUnknown_Release(pvServer);
return r; return r;
...@@ -461,8 +332,6 @@ ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface, ...@@ -461,8 +332,6 @@ ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface,
IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer); IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer);
IRpcStubBuffer_Release(This->base_stub); IRpcStubBuffer_Release(This->base_stub);
release_delegating_vtbl(This->base_obj);
IPSFactoryBuffer_Release(pPSF); IPSFactoryBuffer_Release(pPSF);
free(This); free(This);
} }
......
...@@ -1465,7 +1465,6 @@ static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface) ...@@ -1465,7 +1465,6 @@ static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface)
if (stub->stub.base_stub) if (stub->stub.base_stub)
{ {
IRpcStubBuffer_Release(stub->stub.base_stub); IRpcStubBuffer_Release(stub->stub.base_stub);
release_delegating_vtbl(stub->stub.base_obj);
free(stub->dispatch_table); free(stub->dispatch_table);
} }
...@@ -1495,11 +1494,10 @@ static HRESULT typelib_stub_init(struct typelib_stub *stub, IUnknown *server, ...@@ -1495,11 +1494,10 @@ static HRESULT typelib_stub_init(struct typelib_stub *stub, IUnknown *server,
if (!IsEqualGUID(parentiid, &IID_IUnknown)) if (!IsEqualGUID(parentiid, &IID_IUnknown))
{ {
stub->stub.base_obj = get_delegating_vtbl(stub->stub_vtbl.header.DispatchTableCount); stub->stub.base_obj.lpVtbl = get_delegating_vtbl(stub->stub_vtbl.header.DispatchTableCount);
hr = create_stub(parentiid, (IUnknown *)&stub->stub.base_obj, &stub->stub.base_stub); hr = create_stub(parentiid, &stub->stub.base_obj, &stub->stub.base_stub);
if (FAILED(hr)) if (FAILED(hr))
{ {
release_delegating_vtbl(stub->stub.base_obj);
IUnknown_Release(stub->stub.stub_buffer.pvServerObject); IUnknown_Release(stub->stub.stub_buffer.pvServerObject);
return hr; return hr;
} }
......
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