oleaut32: Split DispCallFunc() into platform-specific functions.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-09-26 19:19:58 +02:00
parent 34e15e5a1d
commit 25d0c66238
1 changed files with 384 additions and 415 deletions

View File

@ -6345,6 +6345,114 @@ __ASM_GLOBAL_FUNC( call_method,
__ASM_GLOBAL_FUNC( call_double_method,
"jmp " __ASM_NAME("call_method") )
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
{
int argspos = 0, stack_offset;
void *func;
UINT i;
DWORD *args;
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;
}
/* maximum size for an argument is sizeof(VARIANT) */
args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
if (pvInstance)
{
const FARPROC *vtable = *(FARPROC **)pvInstance;
func = vtable[oVft/sizeof(void *)];
args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
}
else func = (void *)oVft;
switch (vtReturn)
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
break;
case VT_HRESULT:
WARN("invalid return type %u\n", vtReturn);
heap_free( args );
return E_INVALIDARG;
default:
break;
}
for (i = 0; i < cActuals; i++)
{
VARIANT *arg = prgpvarg[i];
switch (prgvt[i])
{
case VT_EMPTY:
break;
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_DATE:
case VT_CY:
memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
break;
case VT_DECIMAL:
case VT_VARIANT:
memcpy( &args[argspos], arg, sizeof(*arg) );
argspos += sizeof(*arg) / sizeof(DWORD);
break;
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
args[argspos++] = V_BOOL(arg);
break;
default:
args[argspos++] = V_UI4(arg);
break;
}
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
}
switch (vtReturn)
{
case VT_EMPTY:
case VT_DECIMAL:
case VT_VARIANT:
call_method( func, argspos, args, &stack_offset );
break;
case VT_R4:
V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
break;
case VT_I8:
case VT_UI8:
case VT_CY:
V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
break;
default:
V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
break;
}
heap_free( args );
if (stack_offset && cc == CC_STDCALL)
{
WARN( "stack pointer off by %d\n", stack_offset );
return DISP_E_BADCALLEE;
}
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
TRACE("retval: %s\n", debugstr_variant(pvargResult));
return S_OK;
}
#elif defined(__x86_64__)
extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
@ -6396,6 +6504,92 @@ __ASM_GLOBAL_FUNC( call_method,
__ASM_GLOBAL_FUNC( call_double_method,
"jmp " __ASM_NAME("call_method") )
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
{
int argspos = 0;
UINT i;
DWORD_PTR *args;
void *func;
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;
}
/* maximum size for an argument is sizeof(DWORD_PTR) */
args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
if (pvInstance)
{
const FARPROC *vtable = *(FARPROC **)pvInstance;
func = vtable[oVft/sizeof(void *)];
args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
}
else func = (void *)oVft;
switch (vtReturn)
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
break;
case VT_HRESULT:
WARN("invalid return type %u\n", vtReturn);
heap_free( args );
return E_INVALIDARG;
default:
break;
}
for (i = 0; i < cActuals; i++)
{
VARIANT *arg = prgpvarg[i];
switch (prgvt[i])
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (ULONG_PTR)arg;
break;
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
args[argspos++] = V_BOOL(arg);
break;
default:
args[argspos++] = V_UI8(arg);
break;
}
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
}
switch (vtReturn)
{
case VT_R4:
V_R4(pvargResult) = call_double_method( func, argspos, args );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args );
break;
case VT_DECIMAL:
case VT_VARIANT:
call_method( func, argspos, args );
break;
default:
V_UI8(pvargResult) = call_method( func, argspos, args );
break;
}
heap_free( args );
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
TRACE("retval: %s\n", debugstr_variant(pvargResult));
return S_OK;
}
#elif defined(__arm__)
extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
@ -6436,7 +6630,196 @@ __ASM_GLOBAL_FUNC( call_float_method,
__ASM_GLOBAL_FUNC( call_double_method,
"b " __ASM_NAME("call_method") )
#endif /* __arm__ */
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
{
int argspos;
void *func;
UINT i;
DWORD *args;
struct {
#ifndef __SOFTFP__
union {
float s[16];
double d[8];
} sd;
#endif
DWORD r[4];
} regs;
int rcount; /* 32-bit register index count */
#ifndef __SOFTFP__
int scount = 0; /* single-precision float register index count */
int dcount = 0; /* double-precision float register index count */
#endif
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;
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;
/* 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;
}
/* 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_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
case VT_DATE:
#ifndef __SOFTFP__
dcount = max( (scount + 1) / 2, dcount );
if (dcount < 8)
{
regs.sd.d[dcount++] = V_R8(arg);
}
else
{
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;
#endif
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( &regs.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;
case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
#ifndef __SOFTFP__
if (!(scount % 2)) scount = max( scount, dcount * 2 );
if (scount < 16)
regs.sd.s[scount++] = V_R4(arg);
else
args[argspos++] = V_UI4(arg);
break;
#endif
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 */
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*)&regs );
break;
case VT_R4:
V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)&regs );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)&regs );
break;
case VT_I8:
case VT_UI8:
case VT_CY:
V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
break;
default:
V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
break;
}
heap_free( args );
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
TRACE("retval: %s\n", debugstr_variant(pvargResult));
return S_OK;
}
#else /* __arm__ */
HRESULT WINAPI DispCallFunc( void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn,
UINT cActuals, VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult )
{
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));
return E_NOTIMPL;
}
#endif
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
{
@ -6625,420 +7008,6 @@ static HRESULT get_iface_guid(ITypeInfo *tinfo, HREFTYPE href, GUID *guid)
return hres;
}
/***********************************************************************
* DispCallFunc (OLEAUT32.@)
*
* Invokes a function of the specified calling convention, passing the
* specified arguments and returns the result.
*
* PARAMS
* pvInstance [I] Optional pointer to the instance whose function to invoke.
* oVft [I] The offset in the vtable. See notes.
* cc [I] Calling convention of the function to call.
* vtReturn [I] The return type of the function.
* cActuals [I] Number of parameters.
* prgvt [I] The types of the parameters to pass. This is used for sizing only.
* prgpvarg [I] The arguments to pass.
* pvargResult [O] The return value of the function. Can be NULL.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*
* NOTES
* The HRESULT return value of this function is not affected by the return
* value of the user supplied function, which is returned in pvargResult.
*
* If pvInstance is NULL then a non-object function is to be called and oVft
* is the address of the function to call.
*
* The cc parameter can be one of the following values:
*|CC_FASTCALL
*|CC_CDECL
*|CC_PASCAL
*|CC_STDCALL
*|CC_FPFASTCALL
*|CC_SYSCALL
*|CC_MPWCDECL
*|CC_MPWPASCAL
*
*/
HRESULT WINAPI
DispCallFunc(
void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
{
#ifdef __i386__
int argspos = 0, stack_offset;
void *func;
UINT i;
DWORD *args;
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;
}
/* maximum size for an argument is sizeof(VARIANT) */
args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
if (pvInstance)
{
const FARPROC *vtable = *(FARPROC **)pvInstance;
func = vtable[oVft/sizeof(void *)];
args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
}
else func = (void *)oVft;
switch (vtReturn)
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
break;
case VT_HRESULT:
WARN("invalid return type %u\n", vtReturn);
heap_free( args );
return E_INVALIDARG;
default:
break;
}
for (i = 0; i < cActuals; i++)
{
VARIANT *arg = prgpvarg[i];
switch (prgvt[i])
{
case VT_EMPTY:
break;
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_DATE:
case VT_CY:
memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
break;
case VT_DECIMAL:
case VT_VARIANT:
memcpy( &args[argspos], arg, sizeof(*arg) );
argspos += sizeof(*arg) / sizeof(DWORD);
break;
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
args[argspos++] = V_BOOL(arg);
break;
default:
args[argspos++] = V_UI4(arg);
break;
}
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
}
switch (vtReturn)
{
case VT_EMPTY:
case VT_DECIMAL:
case VT_VARIANT:
call_method( func, argspos, args, &stack_offset );
break;
case VT_R4:
V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
break;
case VT_I8:
case VT_UI8:
case VT_CY:
V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
break;
default:
V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
break;
}
heap_free( args );
if (stack_offset && cc == CC_STDCALL)
{
WARN( "stack pointer off by %d\n", stack_offset );
return DISP_E_BADCALLEE;
}
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
TRACE("retval: %s\n", debugstr_variant(pvargResult));
return S_OK;
#elif defined(__x86_64__)
int argspos = 0;
UINT i;
DWORD_PTR *args;
void *func;
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;
}
/* maximum size for an argument is sizeof(DWORD_PTR) */
args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
if (pvInstance)
{
const FARPROC *vtable = *(FARPROC **)pvInstance;
func = vtable[oVft/sizeof(void *)];
args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
}
else func = (void *)oVft;
switch (vtReturn)
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
break;
case VT_HRESULT:
WARN("invalid return type %u\n", vtReturn);
heap_free( args );
return E_INVALIDARG;
default:
break;
}
for (i = 0; i < cActuals; i++)
{
VARIANT *arg = prgpvarg[i];
switch (prgvt[i])
{
case VT_DECIMAL:
case VT_VARIANT:
args[argspos++] = (ULONG_PTR)arg;
break;
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
args[argspos++] = V_BOOL(arg);
break;
default:
args[argspos++] = V_UI8(arg);
break;
}
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
}
switch (vtReturn)
{
case VT_R4:
V_R4(pvargResult) = call_double_method( func, argspos, args );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args );
break;
case VT_DECIMAL:
case VT_VARIANT:
call_method( func, argspos, args );
break;
default:
V_UI8(pvargResult) = call_method( func, argspos, args );
break;
}
heap_free( args );
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
TRACE("retval: %s\n", debugstr_variant(pvargResult));
return S_OK;
#elif defined(__arm__)
int argspos;
void *func;
UINT i;
DWORD *args;
struct {
#ifndef __SOFTFP__
union {
float s[16];
double d[8];
} sd;
#endif
DWORD r[4];
} regs;
int rcount; /* 32-bit register index count */
#ifndef __SOFTFP__
int scount = 0; /* single-precision float register index count */
int dcount = 0; /* double-precision float register index count */
#endif
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;
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;
/* 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;
}
/* 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_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
case VT_DATE:
#ifndef __SOFTFP__
dcount = max( (scount + 1) / 2, dcount );
if (dcount < 8)
{
regs.sd.d[dcount++] = V_R8(arg);
}
else
{
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;
#endif
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( &regs.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;
case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
#ifndef __SOFTFP__
if (!(scount % 2)) scount = max( scount, dcount * 2 );
if (scount < 16)
regs.sd.s[scount++] = V_R4(arg);
else
args[argspos++] = V_UI4(arg);
break;
#endif
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 */
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*)&regs );
break;
case VT_R4:
V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)&regs );
break;
case VT_R8:
case VT_DATE:
V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)&regs );
break;
case VT_I8:
case VT_UI8:
case VT_CY:
V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
break;
default:
V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)&regs );
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));
return E_NOTIMPL;
#endif
}
static inline BOOL func_restricted( const FUNCDESC *desc )
{
return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);