Alexandre Julliard : oleaut32: Implement DispCallFunc() for ARM64.

Alexandre Julliard julliard at winehq.org
Thu Sep 26 15:51:19 CDT 2019


Module: wine
Branch: master
Commit: 71ab74a11fc847850eed5c898b916cf3736ffa10
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=71ab74a11fc847850eed5c898b916cf3736ffa10

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Sep 26 19:25:33 2019 +0200

oleaut32: Implement DispCallFunc() for ARM64.

Signed-off-by: Alexandre Julliard <julliard at 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( &regs.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 *)&regs );
+        break;
+    case VT_R4:
+        V_R4(result) = call_float_method( func, argspos, args, (DWORD_PTR *)&regs );
+        break;
+    case VT_R8:
+    case VT_DATE:
+        V_R8(result) = call_double_method( func, argspos, args, (DWORD_PTR *)&regs );
+        break;
+    default:
+        V_UI8(result) = call_method( func, argspos, args, (DWORD_PTR *)&regs );
+        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 )




More information about the wine-cvs mailing list