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>
This commit is contained in:
parent
35719665d7
commit
0b393119bb
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user