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