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