Module: wine Branch: master Commit: 0b393119bb868dba303359ba6cbca2d2447a75d6 URL: http://source.winehq.org/git/wine.git/?a=commit;h=0b393119bb868dba303359ba6c...
Author: Donna Whisnant dewhisna@dewtronics.com Date: Sat Oct 28 13:00:32 2017 -0500
oleaut32: Add ARM support to DispCallFunc().
Signed-off-by: Donna Whisnant dewhisna@dewtronics.com Signed-off-by: André Hentschel nerv@dawncrow.de Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/oleaut32/typelib.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index ebf6d85..86da3e3 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -6422,6 +6422,41 @@ __ASM_GLOBAL_FUNC( call_method, /* same function but returning floating point */ static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
+#elif defined(__arm__) + +extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args ); +__ASM_GLOBAL_FUNC( call_method, + /* r0 = *func + * r1 = nb_stk_args + * r2 = *stk_args (pointer to 'nb_stk_args' DWORD values to push on stack) + * r3 = *reg_args (pointer to 8, 64-bit d0-d7 (double) values OR as 16, 32-bit s0-s15 (float) values, followed by 4, 32-bit (DWORD) r0-r3 values) + */ + + "push {fp, lr}\n\t" /* Save frame pointer and return address (stack still aligned to 8 bytes) */ + "mov fp, sp\n\t" /* Save stack pointer as our frame for cleaning the stack on return */ + + "lsls r1, r1, #2\n\t" /* r1 = nb_stk_args * sizeof(DWORD) */ + "beq 1f\n\t" /* Skip allocation if no stack args */ + "add r2, r2, r1\n" /* Calculate ending address of incoming stack data */ + "2:\tldr ip, [r2, #-4]!\n\t" /* Get next value */ + "str ip, [sp, #-4]!\n\t" /* Push it on the stack */ + "subs r1, r1, #4\n\t" /* Decrement count */ + "bgt 2b\n\t" /* Loop till done */ + + "1:\tvldm r3!, {s0-s15}\n\t" /* Load the s0-s15/d0-d7 arguments */ + "mov ip, r0\n\t" /* Save the function call address to ip before we nuke r0 with arguments to pass */ + "ldm r3, {r0-r3}\n\t" /* Load the r0-r3 arguments */ + + "blx ip\n\t" /* Call the target function */ + + "mov sp, fp\n\t" /* Clean the stack using fp */ + "pop {fp, pc}\n\t" /* Restore fp and return */ + ) + +/* same function but returning single/double floating point */ +static float (CDECL * const call_float_method)(void *, int, const DWORD *, const DWORD *) = (void *)call_method; +static double (CDECL * const call_double_method)(void *, int, const DWORD *, const DWORD *) = (void *)call_method; + #endif /* __x86_64__ */
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt) @@ -6813,6 +6848,177 @@ DispCallFunc( TRACE("retval: %s\n", debugstr_variant(pvargResult)); return S_OK;
+#elif defined(__arm__) + int argspos; + void *func; + UINT i; + DWORD *args; + struct { + union { + float s[16]; + double d[8]; + } sd; + DWORD r[4]; + } regs; + int rcount; /* 32-bit register index count */ + int scount; /* single-precision float register index count (will be incremented twice for doubles, plus alignment) */ + + TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n", + pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult)); + + if (cc != CC_STDCALL && cc != CC_CDECL) + { + FIXME("unsupported calling convention %d\n",cc); + return E_INVALIDARG; + } + + argspos = 0; + rcount = 0; + scount = 0; + + /* 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 'r' registers: */ + switch (vtReturn) + { + case VT_DECIMAL: + case VT_VARIANT: + regs.r[rcount++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */ + break; + case VT_HRESULT: + WARN("invalid return type %u\n", vtReturn); + return E_INVALIDARG; + default: /* And all others are in 'r', 's', or 'd' registers or have no return value */ + break; + } + + if (pvInstance) + { + const FARPROC *vtable = *(FARPROC **)pvInstance; + func = vtable[oVft/sizeof(void *)]; + regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */ + } + else func = (void *)oVft; + + /* maximum size for an argument is sizeof(VARIANT). Also allow for return pointer and stack alignment. */ + args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 ); + + for (i = 0; i < cActuals; i++) + { + VARIANT *arg = prgpvarg[i]; + DWORD *pdwarg = (DWORD *)(arg); /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */ + int ntemp; /* Used for counting words split between registers and stack */ + + switch (prgvt[i]) + { + case VT_EMPTY: + break; + case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */ + if (scount < 16) + regs.sd.s[scount++] = V_R4(arg); + else + args[argspos++] = V_UI4(arg); + break; + case VT_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */ + case VT_DATE: + if (scount < 15) + { + scount += (scount % 2); /* align scount to next whole double */ + regs.sd.d[scount/2] = V_R8(arg); + scount += 2; + } + else + { + scount = 16; /* Make sure we flag that all 's' regs are full */ + argspos += (argspos % 2); /* align argspos to 8-bytes */ + memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) ); + argspos += sizeof(V_R8(arg)) / sizeof(DWORD); + } + break; + case VT_I8: /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */ + case VT_UI8: + case VT_CY: + if (rcount < 3) + { + rcount += (rcount % 2); /* align rcount to 8-byte register pair */ + memcpy( ®s.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) ); + rcount += sizeof(V_UI8(arg)) / sizeof(DWORD); + } + else + { + rcount = 4; /* Make sure we flag that all 'r' regs are full */ + argspos += (argspos % 2); /* align argspos to 8-bytes */ + memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) ); + argspos += sizeof(V_UI8(arg)) / sizeof(DWORD); + } + break; + case VT_DECIMAL: /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */ + case VT_VARIANT: + /* 8-byte align 'r' and/or stack: */ + if (rcount < 3) + rcount += (rcount % 2); + else + { + rcount = 4; + argspos += (argspos % 2); + } + ntemp = sizeof(*arg) / sizeof(DWORD); + while (ntemp > 0) + { + if (rcount < 4) + regs.r[rcount++] = *pdwarg++; + else + args[argspos++] = *pdwarg++; + --ntemp; + } + break; + case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */ + if (rcount < 4) + regs.r[rcount++] = V_BOOL(arg); + else + args[argspos++] = V_BOOL(arg); + break; + default: + if (rcount < 4) + regs.r[rcount++] = V_UI4(arg); + else + args[argspos++] = V_UI4(arg); + break; + } + TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg)); + } + + argspos += (argspos % 2); /* Make sure stack function alignment is 8-byte */ + + TRACE("rcount: %d, scount: %d, argspos: %d\n", rcount, scount, argspos); + + switch (vtReturn) + { + 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*)®s ); + break; + case VT_R4: + V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)®s ); + break; + case VT_R8: + case VT_DATE: + V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)®s ); + break; + case VT_I8: + case VT_UI8: + case VT_CY: + V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)®s ); + break; + default: + V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)®s ); + break; + } + heap_free( args ); + if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn; + TRACE("retval: %s\n", debugstr_variant(pvargResult)); + return S_OK; + #else FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n", pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));