35944f86f2
this is smaller than firefox and has special handling for small screens which is useful for machines like the zaurus. unfortunately, it's not there yet, see the TODO. please don't add this to the www Makefile yet.
175 lines
5.6 KiB
C++
175 lines
5.6 KiB
C++
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
// Platform specific code to invoke XPCOM methods on native objects
|
|
|
|
#include "xptcprivate.h"
|
|
|
|
// 6 integral parameters are passed in registers
|
|
const PRUint32 GPR_COUNT = 6;
|
|
|
|
// 8 floating point parameters are passed in SSE registers
|
|
const PRUint32 FPR_COUNT = 8;
|
|
|
|
// Remember that these 'words' are 64-bit long
|
|
static inline void
|
|
invoke_count_words(PRUint32 paramCount, nsXPTCVariant * s,
|
|
PRUint32 & nr_gpr, PRUint32 & nr_fpr, PRUint32 & nr_stack)
|
|
{
|
|
nr_gpr = 1; // skip one GP register for 'that'
|
|
nr_fpr = 0;
|
|
nr_stack = 0;
|
|
|
|
/* Compute number of eightbytes of class MEMORY. */
|
|
for (uint32 i = 0; i < paramCount; i++, s++) {
|
|
if (!s->IsPtrData()
|
|
&& (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) {
|
|
if (nr_fpr < FPR_COUNT)
|
|
nr_fpr++;
|
|
else
|
|
nr_stack++;
|
|
}
|
|
else {
|
|
if (nr_gpr < GPR_COUNT)
|
|
nr_gpr++;
|
|
else
|
|
nr_stack++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
invoke_copy_to_stack(PRUint64 * d, PRUint32 paramCount, nsXPTCVariant * s,
|
|
PRUint64 * gpregs, double * fpregs)
|
|
{
|
|
PRUint32 nr_gpr = 1; // skip one GP register for 'that'
|
|
PRUint32 nr_fpr = 0;
|
|
PRUint64 value;
|
|
|
|
for (uint32 i = 0; i < paramCount; i++, s++) {
|
|
if (s->IsPtrData())
|
|
value = (PRUint64) s->ptr;
|
|
else {
|
|
switch (s->type) {
|
|
case nsXPTType::T_FLOAT: break;
|
|
case nsXPTType::T_DOUBLE: break;
|
|
case nsXPTType::T_I8: value = s->val.i8; break;
|
|
case nsXPTType::T_I16: value = s->val.i16; break;
|
|
case nsXPTType::T_I32: value = s->val.i32; break;
|
|
case nsXPTType::T_I64: value = s->val.i64; break;
|
|
case nsXPTType::T_U8: value = s->val.u8; break;
|
|
case nsXPTType::T_U16: value = s->val.u16; break;
|
|
case nsXPTType::T_U32: value = s->val.u32; break;
|
|
case nsXPTType::T_U64: value = s->val.u64; break;
|
|
case nsXPTType::T_BOOL: value = s->val.b; break;
|
|
case nsXPTType::T_CHAR: value = s->val.c; break;
|
|
case nsXPTType::T_WCHAR: value = s->val.wc; break;
|
|
default: value = (PRUint64) s->val.p; break;
|
|
}
|
|
}
|
|
|
|
if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) {
|
|
if (nr_fpr < FPR_COUNT)
|
|
fpregs[nr_fpr++] = s->val.d;
|
|
else {
|
|
*((double *)d) = s->val.d;
|
|
d++;
|
|
}
|
|
}
|
|
else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) {
|
|
if (nr_fpr < FPR_COUNT)
|
|
// The value in %xmm register is already prepared to
|
|
// be retrieved as a float. Therefore, we pass the
|
|
// value verbatim, as a double without conversion.
|
|
fpregs[nr_fpr++] = s->val.d;
|
|
else {
|
|
*((float *)d) = s->val.f;
|
|
d++;
|
|
}
|
|
}
|
|
else {
|
|
if (nr_gpr < GPR_COUNT)
|
|
gpregs[nr_gpr++] = value;
|
|
else
|
|
*d++ = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C"
|
|
XPTC_PUBLIC_API(nsresult)
|
|
XPTC_InvokeByIndex(nsISupports * that, PRUint32 methodIndex,
|
|
PRUint32 paramCount, nsXPTCVariant * params)
|
|
{
|
|
PRUint32 nr_gpr, nr_fpr, nr_stack;
|
|
invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack);
|
|
|
|
// Stack, if used, must be 16-bytes aligned
|
|
if (nr_stack)
|
|
nr_stack = (nr_stack + 1) & ~1;
|
|
|
|
// Load parameters to stack, if necessary
|
|
PRUint64 *stack = (PRUint64 *) __builtin_alloca(nr_stack * 8);
|
|
PRUint64 gpregs[GPR_COUNT];
|
|
double fpregs[FPR_COUNT];
|
|
invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs);
|
|
|
|
// Load FPR registers from fpregs[]
|
|
register double d0 asm("xmm0");
|
|
register double d1 asm("xmm1");
|
|
register double d2 asm("xmm2");
|
|
register double d3 asm("xmm3");
|
|
register double d4 asm("xmm4");
|
|
register double d5 asm("xmm5");
|
|
register double d6 asm("xmm6");
|
|
register double d7 asm("xmm7");
|
|
|
|
switch (nr_fpr) {
|
|
#define ARG_FPR(N) \
|
|
case N+1: d##N = fpregs[N];
|
|
ARG_FPR(7);
|
|
ARG_FPR(6);
|
|
ARG_FPR(5);
|
|
ARG_FPR(4);
|
|
ARG_FPR(3);
|
|
ARG_FPR(2);
|
|
ARG_FPR(1);
|
|
ARG_FPR(0);
|
|
case 0:;
|
|
#undef ARG_FPR
|
|
}
|
|
|
|
// Load GPR registers from gpregs[]
|
|
register PRUint64 a0 asm("rdi");
|
|
register PRUint64 a1 asm("rsi");
|
|
register PRUint64 a2 asm("rdx");
|
|
register PRUint64 a3 asm("rcx");
|
|
register PRUint64 a4 asm("r8");
|
|
register PRUint64 a5 asm("r9");
|
|
|
|
switch (nr_gpr) {
|
|
#define ARG_GPR(N) \
|
|
case N+1: a##N = gpregs[N];
|
|
ARG_GPR(5);
|
|
ARG_GPR(4);
|
|
ARG_GPR(3);
|
|
ARG_GPR(2);
|
|
ARG_GPR(1);
|
|
case 1: a0 = (PRUint64) that;
|
|
case 0:;
|
|
#undef ARG_GPR
|
|
}
|
|
|
|
// Ensure that assignments to SSE registers won't be optimized away
|
|
asm("" ::
|
|
"x" (d0), "x" (d1), "x" (d2), "x" (d3),
|
|
"x" (d4), "x" (d5), "x" (d6), "x" (d7));
|
|
|
|
// Get pointer to method
|
|
PRUint64 methodAddress = *((PRUint64 *)that);
|
|
methodAddress += 8 * methodIndex;
|
|
methodAddress = *((PRUint64 *)methodAddress);
|
|
|
|
typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64);
|
|
PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5);
|
|
return result;
|
|
}
|