Module: wine Branch: master Commit: 71ab74a11fc847850eed5c898b916cf3736ffa10 URL: https://source.winehq.org/git/wine.git/?a=commit;h=71ab74a11fc847850eed5c898...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Sep 26 19:25:33 2019 +0200
oleaut32: Implement DispCallFunc() for ARM64.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/oleaut32/typelib.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 374eb5a38b..d40c0efb0f 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -6809,7 +6809,165 @@ HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VART return S_OK; }
-#else /* __arm__ */ +#elif defined(__aarch64__) + +extern DWORD_PTR CDECL call_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args ); +extern float CDECL call_float_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args ); +extern double CDECL call_double_method( void *func, int nb_stk_args, const DWORD_PTR *stk_args, const DWORD_PTR *reg_args ); +__ASM_GLOBAL_FUNC( call_method, + "stp x29, x30, [sp, #-16]!\n\t" + "mov x29, sp\n\t" + "sub sp, sp, x1, lsl #3\n\t" + "cbz x1, 2f\n" + "1:\tsub x1, x1, #1\n\t" + "ldr x4, [x2, x1, lsl #3]\n\t" + "str x4, [sp, x1, lsl #3]\n\t" + "cbnz x1, 1b\n" + "2:\tmov x8, x0\n\t" + "mov x9, x3\n\t" + "ldp d0, d1, [x9]\n\t" + "ldp d2, d3, [x9, #0x10]\n\t" + "ldp d4, d5, [x9, #0x20]\n\t" + "ldp d6, d7, [x9, #0x30]\n\t" + "ldp x0, x1, [x9, #0x40]\n\t" + "ldp x2, x3, [x9, #0x50]\n\t" + "ldp x4, x5, [x9, #0x60]\n\t" + "ldp x6, x7, [x9, #0x70]\n\t" + "blr x8\n\t" + "mov sp, x29\n\t" + "ldp x29, x30, [sp], #16\n\t" + "ret" ) +__ASM_GLOBAL_FUNC( call_float_method, + "b " __ASM_NAME("call_method") ) +__ASM_GLOBAL_FUNC( call_double_method, + "b " __ASM_NAME("call_method") ) + +HRESULT WINAPI DispCallFunc( void *instance, ULONG_PTR offset, CALLCONV cc, VARTYPE ret_type, UINT count, + VARTYPE *types, VARIANTARG **vargs, VARIANT *result ) +{ + int argspos; + void *func; + UINT i; + DWORD_PTR *args; + struct + { + union + { + float f; + double d; + } fp[8]; + DWORD_PTR x[8]; + } regs; + int rcount; /* 64-bit register index count */ + int fpcount = 0; /* float register index count */ + + TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n", + instance, offset, cc, ret_type, count, types, vargs, result, V_VT(result)); + + if (cc != CC_STDCALL && cc != CC_CDECL) + { + FIXME("unsupported calling convention %d\n",cc); + return E_INVALIDARG; + } + + argspos = 0; + rcount = 0; + + if (instance) + { + const FARPROC *vtable = *(FARPROC **)instance; + func = vtable[offset/sizeof(void *)]; + regs.x[rcount++] = (DWORD_PTR)instance; /* the This pointer is always the first parameter */ + } + else func = (void *)offset; + + /* Determine if we need to pass a pointer for the return value as arg 0. If so, do that */ + /* first as it will need to be in the 'x' registers: */ + switch (ret_type) + { + case VT_DECIMAL: + case VT_VARIANT: + regs.x[rcount++] = (DWORD_PTR)result; /* arg 0 is a pointer to the result */ + break; + case VT_HRESULT: + WARN("invalid return type %u\n", ret_type); + return E_INVALIDARG; + default: + break; + } + + /* maximum size for an argument is sizeof(VARIANT). Also allow for return pointer and stack alignment. */ + args = heap_alloc( sizeof(VARIANT) * count + sizeof(DWORD_PTR) * 4 ); + + for (i = 0; i < count; i++) + { + VARIANT *arg = vargs[i]; + + switch (types[i]) + { + case VT_EMPTY: + break; + case VT_R4: + if (fpcount < 8) regs.fp[fpcount++].f = V_R4(arg); + else *(float *)&args[argspos++] = V_R4(arg); + break; + case VT_R8: + case VT_DATE: + if (fpcount < 8) regs.fp[fpcount++].d = V_R8(arg); + else *(double *)&args[argspos++] = V_R8(arg); + break; + case VT_DECIMAL: + case VT_VARIANT: + if (rcount < 7) + { + memcpy( ®s.x[rcount], arg, sizeof(*arg) ); + rcount += 2; + } + else + { + memcpy( &args[argspos], arg, sizeof(*arg) ); + argspos += 2; + } + break; + case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */ + if (rcount < 8) regs.x[rcount++] = V_BOOL(arg); + else args[argspos++] = V_BOOL(arg); + break; + default: + if (rcount < 8) regs.x[rcount++] = V_UI8(arg); + else args[argspos++] = V_UI8(arg); + break; + } + TRACE("arg %u: type %s %s\n", i, debugstr_vt(types[i]), debugstr_variant(arg)); + } + + argspos += (argspos % 2); /* Make sure stack function alignment is 16-byte */ + + switch (ret_type) + { + case VT_EMPTY: /* EMPTY = no return value */ + case VT_DECIMAL: /* DECIMAL and VARIANT already have a pointer argument passed (see above) */ + case VT_VARIANT: + call_method( func, argspos, args, (DWORD_PTR *)®s ); + break; + case VT_R4: + V_R4(result) = call_float_method( func, argspos, args, (DWORD_PTR *)®s ); + break; + case VT_R8: + case VT_DATE: + V_R8(result) = call_double_method( func, argspos, args, (DWORD_PTR *)®s ); + break; + default: + V_UI8(result) = call_method( func, argspos, args, (DWORD_PTR *)®s ); + break; + } + heap_free( args ); + if (ret_type != VT_VARIANT) V_VT(result) = ret_type; + TRACE("retval: %s\n", debugstr_variant(result)); + return S_OK; +} + +#else /* __aarch64__ */
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )