This repository has been archived by the owner on Apr 10, 2024. It is now read-only.
/
xptcinvoke_x86_64_solaris.cpp
143 lines (127 loc) · 5.3 KB
/
xptcinvoke_x86_64_solaris.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Platform specific code to invoke XPCOM methods on native objects
#include "xptcprivate.h"
#include "alloca.h"
// 6 integral parameters are passed in registers
const uint32_t GPR_COUNT = 6;
// 8 floating point parameters are passed in SSE registers
const uint32_t FPR_COUNT = 8;
// Remember that these 'words' are 64-bit long
static inline void
invoke_count_words(uint32_t paramCount, nsXPTCVariant * s,
uint32_t & nr_gpr, uint32_t & nr_fpr, uint32_t & 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_t 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(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s,
uint64_t * gpregs, double * fpregs)
{
uint32_t nr_gpr = 1; // skip one GP register for 'that'
uint32_t nr_fpr = 0;
uint64_t value;
for (uint32_t i = 0; i < paramCount; i++, s++) {
if (s->IsPtrData())
value = (uint64_t) 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 = (uint64_t) 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;
}
}
}
EXPORT_XPCOM_API(nsresult)
NS_InvokeByIndex_P(nsISupports * that, uint32_t methodIndex,
uint32_t paramCount, nsXPTCVariant * params)
{
uint32_t 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
uint64_t *stack = (uint64_t *) __builtin_alloca(nr_stack * 8);
uint64_t gpregs[GPR_COUNT];
double fpregs[FPR_COUNT];
invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs);
switch (nr_fpr) {
case 8: asm("movupd %0, %xmm7" : : "xmm7" (fpregs[7]));
case 7: asm("movupd %0, %xmm6" : : "xmm6" (fpregs[6]));
case 6: asm("movupd %0, %xmm5" : : "xmm5" (fpregs[5]));
case 5: asm("movupd %0, %xmm4" : : "xmm4" (fpregs[4]));
case 4: asm("movupd %0, %xmm3" : : "xmm3" (fpregs[3]));
case 3: asm("movupd %0, %xmm2" : : "xmm2" (fpregs[2]));
case 2: asm("movupd %0, %xmm1" : : "xmm1" (fpregs[1]));
case 1: asm("movupd %0, %xmm0" : : "xmm0" (fpregs[0]));
case 0:;
}
// Ensure that assignments to SSE registers won't be optimized away
asm("" ::: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7");
// Get pointer to method
uint64_t methodAddress = *((uint64_t *)that);
methodAddress += 16 + 8 * methodIndex;
methodAddress = *((uint64_t *)methodAddress);
typedef uint32_t (*Method)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
uint32_t result = ((Method)methodAddress)((uint64_t)that, gpregs[1], gpregs[2], gpregs[3], gpregs[4], gpregs[5]);
return result;
}