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
12 static uint32_t
invoke_count_words(uint32_t paramCount,nsXPTCVariant * s)13 invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
14 {
15 uint32_t overflow = 0, gpr = 1 /*this*/, fpr = 0;
16 for(uint32_t i = 0; i < paramCount; i++, s++)
17 {
18 if(s->IsPtrData())
19 {
20 if (gpr < 5) gpr++; else overflow++;
21 continue;
22 }
23 switch(s->type)
24 {
25 case nsXPTType::T_I8 :
26 case nsXPTType::T_I16 :
27 case nsXPTType::T_I32 :
28 if (gpr < 5) gpr++; else overflow++;
29 break;
30 case nsXPTType::T_I64 :
31 if (gpr < 4) gpr+=2; else gpr=5, overflow+=2;
32 break;
33 case nsXPTType::T_U8 :
34 case nsXPTType::T_U16 :
35 case nsXPTType::T_U32 :
36 if (gpr < 5) gpr++; else overflow++;
37 break;
38 case nsXPTType::T_U64 :
39 if (gpr < 4) gpr+=2; else gpr=5, overflow+=2;
40 break;
41 case nsXPTType::T_FLOAT :
42 if (fpr < 2) fpr++; else overflow++;
43 break;
44 case nsXPTType::T_DOUBLE :
45 if (fpr < 2) fpr++; else overflow+=2;
46 break;
47 case nsXPTType::T_BOOL :
48 case nsXPTType::T_CHAR :
49 case nsXPTType::T_WCHAR :
50 if (gpr < 5) gpr++; else overflow++;
51 break;
52 default:
53 // all the others are plain pointer types
54 if (gpr < 5) gpr++; else overflow++;
55 break;
56 }
57 }
58 /* Round up number of overflow words to ensure stack
59 stays aligned to 8 bytes. */
60 return (overflow + 1) & ~1;
61 }
62
63 static void
invoke_copy_to_stack(uint32_t paramCount,nsXPTCVariant * s,uint32_t * d_ov,uint32_t overflow)64 invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint32_t* d_ov, uint32_t overflow)
65 {
66 uint32_t *d_gpr = d_ov + overflow;
67 uint64_t *d_fpr = (uint64_t *)(d_gpr + 4);
68 uint32_t gpr = 1 /*this*/, fpr = 0;
69
70 for(uint32_t i = 0; i < paramCount; i++, s++)
71 {
72 if(s->IsPtrData())
73 {
74 if (gpr < 5)
75 *((void**)d_gpr) = s->ptr, d_gpr++, gpr++;
76 else
77 *((void**)d_ov ) = s->ptr, d_ov++;
78 continue;
79 }
80 switch(s->type)
81 {
82 case nsXPTType::T_I8 :
83 if (gpr < 5)
84 *((int32_t*) d_gpr) = s->val.i8, d_gpr++, gpr++;
85 else
86 *((int32_t*) d_ov ) = s->val.i8, d_ov++;
87 break;
88 case nsXPTType::T_I16 :
89 if (gpr < 5)
90 *((int32_t*) d_gpr) = s->val.i16, d_gpr++, gpr++;
91 else
92 *((int32_t*) d_ov ) = s->val.i16, d_ov++;
93 break;
94 case nsXPTType::T_I32 :
95 if (gpr < 5)
96 *((int32_t*) d_gpr) = s->val.i32, d_gpr++, gpr++;
97 else
98 *((int32_t*) d_ov ) = s->val.i32, d_ov++;
99 break;
100 case nsXPTType::T_I64 :
101 if (gpr < 4)
102 *((int64_t*) d_gpr) = s->val.i64, d_gpr+=2, gpr+=2;
103 else
104 *((int64_t*) d_ov ) = s->val.i64, d_ov+=2, gpr=5;
105 break;
106 case nsXPTType::T_U8 :
107 if (gpr < 5)
108 *((uint32_t*) d_gpr) = s->val.u8, d_gpr++, gpr++;
109 else
110 *((uint32_t*) d_ov ) = s->val.u8, d_ov++;
111 break;
112 case nsXPTType::T_U16 :
113 if (gpr < 5)
114 *((uint32_t*)d_gpr) = s->val.u16, d_gpr++, gpr++;
115 else
116 *((uint32_t*)d_ov ) = s->val.u16, d_ov++;
117 break;
118 case nsXPTType::T_U32 :
119 if (gpr < 5)
120 *((uint32_t*)d_gpr) = s->val.u32, d_gpr++, gpr++;
121 else
122 *((uint32_t*)d_ov ) = s->val.u32, d_ov++;
123 break;
124 case nsXPTType::T_U64 :
125 if (gpr < 4)
126 *((uint64_t*)d_gpr) = s->val.u64, d_gpr+=2, gpr+=2;
127 else
128 *((uint64_t*)d_ov ) = s->val.u64, d_ov+=2, gpr=5;
129 break;
130 case nsXPTType::T_FLOAT :
131 if (fpr < 2)
132 *((float*) d_fpr) = s->val.f, d_fpr++, fpr++;
133 else
134 *((float*) d_ov ) = s->val.f, d_ov++;
135 break;
136 case nsXPTType::T_DOUBLE :
137 if (fpr < 2)
138 *((double*) d_fpr) = s->val.d, d_fpr++, fpr++;
139 else
140 *((double*) d_ov ) = s->val.d, d_ov+=2;
141 break;
142 case nsXPTType::T_BOOL :
143 if (gpr < 5)
144 *((uint32_t*)d_gpr) = s->val.b, d_gpr++, gpr++;
145 else
146 *((uint32_t*)d_ov ) = s->val.b, d_ov++;
147 break;
148 case nsXPTType::T_CHAR :
149 if (gpr < 5)
150 *((uint32_t*)d_gpr) = s->val.c, d_gpr++, gpr++;
151 else
152 *((uint32_t*)d_ov ) = s->val.c, d_ov++;
153 break;
154 case nsXPTType::T_WCHAR :
155 if (gpr < 5)
156 *((uint32_t*)d_gpr) = s->val.wc, d_gpr++, gpr++;
157 else
158 *((uint32_t*)d_ov ) = s->val.wc, d_ov++;
159 break;
160 default:
161 // all the others are plain pointer types
162 if (gpr < 5)
163 *((void**) d_gpr) = s->val.p, d_gpr++, gpr++;
164 else
165 *((void**) d_ov ) = s->val.p, d_ov++;
166 break;
167 }
168 }
169 }
170
171 typedef nsresult (*vtable_func)(nsISupports *, uint32_t, uint32_t, uint32_t, uint32_t, double, double);
172
173 // Avoid AddressSanitizer instrumentation for the next function because it
174 // depends on __builtin_alloca behavior and alignment that cannot be relied on
175 // once the function is compiled with a version of ASan that has dynamic-alloca
176 // instrumentation enabled.
177
178 MOZ_ASAN_BLACKLIST
EXPORT_XPCOM_API(nsresult)179 EXPORT_XPCOM_API(nsresult)
180 NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
181 uint32_t paramCount, nsXPTCVariant* params)
182 {
183 vtable_func *vtable = *reinterpret_cast<vtable_func **>(that);
184 vtable_func method = vtable[methodIndex];
185 uint32_t overflow = invoke_count_words (paramCount, params);
186 uint32_t *stack_space = reinterpret_cast<uint32_t *>(__builtin_alloca((overflow + 8 /* 4 32-bits gpr + 2 64-bits fpr */) * 4));
187
188 invoke_copy_to_stack(paramCount, params, stack_space, overflow);
189
190 uint32_t *d_gpr = stack_space + overflow;
191 double *d_fpr = reinterpret_cast<double *>(d_gpr + 4);
192
193 return method(that, d_gpr[0], d_gpr[1], d_gpr[2], d_gpr[3], d_fpr[0], d_fpr[1]);
194 }
195