1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /* Implement shared vtbl methods. */
7 
8 #include "xptcprivate.h"
9 
10 #if !defined(__arm__) && !(defined(LINUX) || defined(ANDROID) || defined(XP_DARWIN))
11 #error "This code is for Linux/iOS ARM only. Please check if it works for you, too.\nDepends strongly on gcc behaviour."
12 #endif
13 
14 #ifdef __ARM_EABI__
15 #define DOUBLEWORD_ALIGN(p) ((uint32_t *)((((uint32_t)(p)) + 7) & 0xfffffff8))
16 #else
17 #define DOUBLEWORD_ALIGN(p) (p)
18 #endif
19 
20 // Apple's iOS toolchain is lame.
21 #ifdef __APPLE__
22 #define GNU(str)
23 #define APPLE(str) str
24 #define UNDERSCORE "__"
25 #else
26 #define GNU(str) str
27 #define APPLE(str)
28 #define UNDERSCORE "_"
29 #endif
30 
31 #ifdef __thumb__
32 #define THUMB_FUNC ".thumb_func\n"
33 #else
34 #define THUMB_FUNC
35 #endif
36 
37 extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase * self,uint32_t methodIndex,uint32_t * args)38 PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
39 {
40 
41     nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
42     const nsXPTMethodInfo* info;
43     uint8_t paramCount;
44     uint8_t i;
45 
46     NS_ASSERTION(self,"no self");
47 
48     self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
49     paramCount = info->GetParamCount();
50 
51     const uint8_t indexOfJSContext = info->IndexOfJSContext();
52 
53     uint32_t* ap = args;
54     for(i = 0; i < paramCount; i++, ap++)
55     {
56         const nsXPTParamInfo& param = info->GetParam(i);
57         const nsXPTType& type = param.GetType();
58         nsXPTCMiniVariant* dp = &paramBuffer[i];
59 
60         if (i == indexOfJSContext)
61             ap++;
62 
63         if(param.IsOut() || !type.IsArithmetic())
64         {
65             dp->val.p = (void*) *ap;
66             continue;
67         }
68         // else
69         switch(type)
70         {
71         case nsXPTType::T_I8     : dp->val.i8  = *((int8_t*)  ap);       break;
72         case nsXPTType::T_I16    : dp->val.i16 = *((int16_t*) ap);       break;
73         case nsXPTType::T_I32    : dp->val.i32 = *((int32_t*) ap);       break;
74         case nsXPTType::T_I64    : ap = DOUBLEWORD_ALIGN(ap);
75 				   dp->val.i64 = *((int64_t*) ap); ap++; break;
76         case nsXPTType::T_U8     : dp->val.u8  = *((uint8_t*) ap);       break;
77         case nsXPTType::T_U16    : dp->val.u16 = *((uint16_t*)ap);       break;
78         case nsXPTType::T_U32    : dp->val.u32 = *((uint32_t*)ap);       break;
79         case nsXPTType::T_U64    : ap = DOUBLEWORD_ALIGN(ap);
80 				   dp->val.u64 = *((uint64_t*)ap); ap++; break;
81         case nsXPTType::T_FLOAT  : dp->val.f   = *((float*)   ap);       break;
82         case nsXPTType::T_DOUBLE : ap = DOUBLEWORD_ALIGN(ap);
83 				   dp->val.d   = *((double*)  ap); ap++; break;
84         case nsXPTType::T_BOOL   : dp->val.b   = *((bool*)  ap);       break;
85         case nsXPTType::T_CHAR   : dp->val.c   = *((char*)    ap);       break;
86         case nsXPTType::T_WCHAR  : dp->val.wc  = *((wchar_t*) ap);       break;
87         default:
88             NS_ERROR("bad type");
89             break;
90         }
91     }
92 
93     nsresult result = self->mOuter->CallMethod((uint16_t)methodIndex, info,
94                                                paramBuffer);
95 
96     return result;
97 }
98 
99 /*
100  * This is our shared stub.
101  *
102  * r0 = Self.
103  *
104  * The Rules:
105  *   We pass an (undefined) number of arguments into this function.
106  *   The first 3 C++ arguments are in r1 - r3, the rest are built
107  *   by the calling function on the stack.
108  *
109  *   We are allowed to corrupt r0 - r3, ip, and lr.
110  *
111  * Other Info:
112  *   We pass the stub number in using `ip'.
113  *
114  * Implementation:
115  * - We save r1 to r3 inclusive onto the stack, which will be
116  *   immediately below the caller saved arguments.
117  * - setup r2 (PrepareAndDispatch's args pointer) to point at
118  *   the base of all these arguments
119  * - Save LR (for the return address)
120  * - Set r1 (PrepareAndDispatch's methodindex argument) from ip
121  * - r0 is passed through (self)
122  * - Call PrepareAndDispatch
123  * - When the call returns, we return by loading the PC off the
124  *   stack, and undoing the stack (one instruction)!
125  *
126  */
127 __asm__ ("\n"
128          GNU(".text\n")
129          APPLE(".section __TEXT,__text\n")
130          THUMB_FUNC
131          ".align 2\n"
132          "SharedStub:\n"
133          GNU(".fnstart\n")
134          GNU(".cfi_startproc\n")
135          "stmfd	sp!, {r1, r2, r3}\n"
136          GNU(".save {r1, r2, r3}\n")
137          GNU(".cfi_def_cfa_offset 12\n")
138          GNU(".cfi_offset r3, -4\n")
139          GNU(".cfi_offset r2, -8\n")
140          GNU(".cfi_offset r1, -12\n")
141          "mov	r2, sp\n"
142          "str	lr, [sp, #-4]!\n"
143          GNU(".save	{lr}\n")
144          GNU(".cfi_def_cfa_offset 16\n")
145          GNU(".cfi_offset lr, -16\n")
146          "mov	r1, ip\n"
147          "bl	PrepareAndDispatch\n"
148          "ldr	pc, [sp], #16\n"
149          GNU(".cfi_endproc\n")
150          GNU(".fnend"));
151 
152 /*
153  * Create sets of stubs to call the SharedStub.
154  * We don't touch the stack here, nor any registers, other than IP.
155  * IP is defined to be corruptable by a called function, so we are
156  * safe to use it.
157  *
158  * This will work with or without optimisation.
159  */
160 
161 /*
162  * Note : As G++3 ABI contains the length of the functionname in the
163  *  mangled name, it is difficult to get a generic assembler mechanism like
164  *  in the G++ 2.95 case.
165  *  Create names would be like :
166  *    _ZN14nsXPTCStubBase5Stub9Ev
167  *    _ZN14nsXPTCStubBase6Stub13Ev
168  *    _ZN14nsXPTCStubBase7Stub144Ev
169  *  Use the assembler directives to get the names right...
170  */
171 
172 #define STUB_ENTRY(n)						\
173   __asm__(							\
174         GNU(".section \".text\"\n")                             \
175         APPLE(".section __TEXT,__text\n")                       \
176 "	.align 2\n"						\
177 "	.if ("#n" - 10) < 0\n"                                  \
178 "	.globl	" UNDERSCORE "ZN14nsXPTCStubBase5Stub"#n"Ev\n"	\
179         THUMB_FUNC                                              \
180         GNU(".type	_ZN14nsXPTCStubBase5Stub"#n"Ev,#function\n") \
181 UNDERSCORE "ZN14nsXPTCStubBase5Stub"#n"Ev:\n"			\
182 "	.else\n"                                                \
183 "	.if  ("#n" - 100) < 0\n"                                \
184 "	.globl	" UNDERSCORE "ZN14nsXPTCStubBase6Stub"#n"Ev\n"	\
185           THUMB_FUNC \
186           GNU(".type _ZN14nsXPTCStubBase6Stub"#n"Ev,#function\n") \
187 UNDERSCORE "ZN14nsXPTCStubBase6Stub"#n"Ev:\n"			\
188 "	.else\n"                                                \
189 "	.if ("#n" - 1000) < 0\n"                                \
190 "	.globl	" UNDERSCORE "ZN14nsXPTCStubBase7Stub"#n"Ev\n"	\
191         THUMB_FUNC                                              \
192         GNU(".type _ZN14nsXPTCStubBase7Stub"#n"Ev,#function\n") \
193 UNDERSCORE "ZN14nsXPTCStubBase7Stub"#n"Ev:\n"			\
194 "	.else\n"                                                \
195 "	.err \"stub number "#n"> 1000 not yet supported\"\n"    \
196 "	.endif\n"                                               \
197 "	.endif\n"                                               \
198 "	.endif\n"                                               \
199 "	mov	ip, #"#n"\n"					\
200 "	b	SharedStub\n\t");
201 
202 #if 0
203 /*
204  * This part is left in as comment : this is how the method definition
205  * should look like.
206  */
207 
208 #define STUB_ENTRY(n)  \
209 nsresult nsXPTCStubBase::Stub##n ()  \
210 { \
211   __asm__ (	  		        \
212 "	mov	ip, #"#n"\n"					\
213 "	b	SharedStub\n\t");                               \
214   return 0; /* avoid warnings */                                \
215 }
216 #endif
217 
218 
219 #define SENTINEL_ENTRY(n) \
220 nsresult nsXPTCStubBase::Sentinel##n() \
221 { \
222     NS_ERROR("nsXPTCStubBase::Sentinel called"); \
223     return NS_ERROR_NOT_IMPLEMENTED; \
224 }
225 
226 #include "xptcstubsdef.inc"
227