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