|
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 // Platform specific code to invoke XPCOM methods on native objects |
|
8 |
|
9 #include "xptcprivate.h" |
|
10 |
|
11 // 6 integral parameters are passed in registers |
|
12 const uint32_t GPR_COUNT = 6; |
|
13 |
|
14 // 8 floating point parameters are passed in SSE registers |
|
15 const uint32_t FPR_COUNT = 8; |
|
16 |
|
17 // Remember that these 'words' are 64-bit long |
|
18 static inline void |
|
19 invoke_count_words(uint32_t paramCount, nsXPTCVariant * s, |
|
20 uint32_t & nr_gpr, uint32_t & nr_fpr, uint32_t & nr_stack) |
|
21 { |
|
22 nr_gpr = 1; // skip one GP register for 'that' |
|
23 nr_fpr = 0; |
|
24 nr_stack = 0; |
|
25 |
|
26 /* Compute number of eightbytes of class MEMORY. */ |
|
27 for (uint32_t i = 0; i < paramCount; i++, s++) { |
|
28 if (!s->IsPtrData() |
|
29 && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { |
|
30 if (nr_fpr < FPR_COUNT) |
|
31 nr_fpr++; |
|
32 else |
|
33 nr_stack++; |
|
34 } |
|
35 else { |
|
36 if (nr_gpr < GPR_COUNT) |
|
37 nr_gpr++; |
|
38 else |
|
39 nr_stack++; |
|
40 } |
|
41 } |
|
42 } |
|
43 |
|
44 static void |
|
45 invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s, |
|
46 uint64_t * gpregs, double * fpregs) |
|
47 { |
|
48 uint32_t nr_gpr = 1; // skip one GP register for 'that' |
|
49 uint32_t nr_fpr = 0; |
|
50 uint64_t value; |
|
51 |
|
52 for (uint32_t i = 0; i < paramCount; i++, s++) { |
|
53 if (s->IsPtrData()) |
|
54 value = (uint64_t) s->ptr; |
|
55 else { |
|
56 switch (s->type) { |
|
57 case nsXPTType::T_FLOAT: break; |
|
58 case nsXPTType::T_DOUBLE: break; |
|
59 case nsXPTType::T_I8: value = s->val.i8; break; |
|
60 case nsXPTType::T_I16: value = s->val.i16; break; |
|
61 case nsXPTType::T_I32: value = s->val.i32; break; |
|
62 case nsXPTType::T_I64: value = s->val.i64; break; |
|
63 case nsXPTType::T_U8: value = s->val.u8; break; |
|
64 case nsXPTType::T_U16: value = s->val.u16; break; |
|
65 case nsXPTType::T_U32: value = s->val.u32; break; |
|
66 case nsXPTType::T_U64: value = s->val.u64; break; |
|
67 case nsXPTType::T_BOOL: value = s->val.b; break; |
|
68 case nsXPTType::T_CHAR: value = s->val.c; break; |
|
69 case nsXPTType::T_WCHAR: value = s->val.wc; break; |
|
70 default: value = (uint64_t) s->val.p; break; |
|
71 } |
|
72 } |
|
73 |
|
74 if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { |
|
75 if (nr_fpr < FPR_COUNT) |
|
76 fpregs[nr_fpr++] = s->val.d; |
|
77 else { |
|
78 *((double *)d) = s->val.d; |
|
79 d++; |
|
80 } |
|
81 } |
|
82 else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { |
|
83 if (nr_fpr < FPR_COUNT) |
|
84 // The value in %xmm register is already prepared to |
|
85 // be retrieved as a float. Therefore, we pass the |
|
86 // value verbatim, as a double without conversion. |
|
87 fpregs[nr_fpr++] = s->val.d; |
|
88 else { |
|
89 *((float *)d) = s->val.f; |
|
90 d++; |
|
91 } |
|
92 } |
|
93 else { |
|
94 if (nr_gpr < GPR_COUNT) |
|
95 gpregs[nr_gpr++] = value; |
|
96 else |
|
97 *d++ = value; |
|
98 } |
|
99 } |
|
100 } |
|
101 |
|
102 EXPORT_XPCOM_API(nsresult) |
|
103 NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex, |
|
104 uint32_t paramCount, nsXPTCVariant * params) |
|
105 { |
|
106 uint32_t nr_gpr, nr_fpr, nr_stack; |
|
107 invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack); |
|
108 |
|
109 // Stack, if used, must be 16-bytes aligned |
|
110 if (nr_stack) |
|
111 nr_stack = (nr_stack + 1) & ~1; |
|
112 |
|
113 // Load parameters to stack, if necessary |
|
114 uint64_t *stack = (uint64_t *) __builtin_alloca(nr_stack * 8); |
|
115 uint64_t gpregs[GPR_COUNT]; |
|
116 double fpregs[FPR_COUNT]; |
|
117 invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); |
|
118 |
|
119 // Load FPR registers from fpregs[] |
|
120 register double d0 asm("xmm0"); |
|
121 register double d1 asm("xmm1"); |
|
122 register double d2 asm("xmm2"); |
|
123 register double d3 asm("xmm3"); |
|
124 register double d4 asm("xmm4"); |
|
125 register double d5 asm("xmm5"); |
|
126 register double d6 asm("xmm6"); |
|
127 register double d7 asm("xmm7"); |
|
128 |
|
129 switch (nr_fpr) { |
|
130 #define ARG_FPR(N) \ |
|
131 case N+1: d##N = fpregs[N]; |
|
132 ARG_FPR(7); |
|
133 ARG_FPR(6); |
|
134 ARG_FPR(5); |
|
135 ARG_FPR(4); |
|
136 ARG_FPR(3); |
|
137 ARG_FPR(2); |
|
138 ARG_FPR(1); |
|
139 ARG_FPR(0); |
|
140 case 0:; |
|
141 #undef ARG_FPR |
|
142 } |
|
143 |
|
144 // Load GPR registers from gpregs[] |
|
145 register uint64_t a0 asm("rdi"); |
|
146 register uint64_t a1 asm("rsi"); |
|
147 register uint64_t a2 asm("rdx"); |
|
148 register uint64_t a3 asm("rcx"); |
|
149 register uint64_t a4 asm("r8"); |
|
150 register uint64_t a5 asm("r9"); |
|
151 |
|
152 switch (nr_gpr) { |
|
153 #define ARG_GPR(N) \ |
|
154 case N+1: a##N = gpregs[N]; |
|
155 ARG_GPR(5); |
|
156 ARG_GPR(4); |
|
157 ARG_GPR(3); |
|
158 ARG_GPR(2); |
|
159 ARG_GPR(1); |
|
160 case 1: a0 = (uint64_t) that; |
|
161 case 0:; |
|
162 #undef ARG_GPR |
|
163 } |
|
164 |
|
165 // Ensure that assignments to SSE registers won't be optimized away |
|
166 asm("" :: |
|
167 "x" (d0), "x" (d1), "x" (d2), "x" (d3), |
|
168 "x" (d4), "x" (d5), "x" (d6), "x" (d7)); |
|
169 |
|
170 // Get pointer to method |
|
171 uint64_t methodAddress = *((uint64_t *)that); |
|
172 methodAddress += 8 * methodIndex; |
|
173 methodAddress = *((uint64_t *)methodAddress); |
|
174 |
|
175 typedef nsresult (*Method)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); |
|
176 nsresult result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5); |
|
177 return result; |
|
178 } |