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 /* Platform specific code to invoke XPCOM methods on native objects */
7 
8 #include "xptcprivate.h"
9 
10 // Remember that these 'words' are 32bit DWORDS
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 result = 0;
16     for(uint32_t i = 0; i < paramCount; i++, s++)
17     {
18         if(s->IsPtrData())
19         {
20             result++;
21             continue;
22         }
23         switch(s->type)
24         {
25         case nsXPTType::T_I8     :
26         case nsXPTType::T_I16    :
27         case nsXPTType::T_I32    :
28             result++;
29             break;
30         case nsXPTType::T_I64    :
31             result+=2;
32             break;
33         case nsXPTType::T_U8     :
34         case nsXPTType::T_U16    :
35         case nsXPTType::T_U32    :
36             result++;
37             break;
38         case nsXPTType::T_U64    :
39             result+=2;
40             break;
41         case nsXPTType::T_FLOAT  :
42             result++;
43             break;
44         case nsXPTType::T_DOUBLE :
45             result+=2;
46             break;
47         case nsXPTType::T_BOOL   :
48         case nsXPTType::T_CHAR   :
49         case nsXPTType::T_WCHAR  :
50             result++;
51             break;
52         default:
53             // all the others are plain pointer types
54             result++;
55             break;
56         }
57     }
58     return result;
59 }
60 
61 static void
invoke_copy_to_stack(uint32_t * d,uint32_t paramCount,nsXPTCVariant * s)62 invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPTCVariant* s)
63 {
64     for(uint32_t i = 0; i < paramCount; i++, d++, s++)
65     {
66         if(s->IsPtrData())
67         {
68             *((void**)d) = s->ptr;
69             continue;
70         }
71         switch(s->type)
72         {
73         case nsXPTType::T_I8     : *((int8_t*)  d) = s->val.i8;          break;
74         case nsXPTType::T_I16    : *((int16_t*) d) = s->val.i16;         break;
75         case nsXPTType::T_I32    : *((int32_t*) d) = s->val.i32;         break;
76         case nsXPTType::T_I64    : *((int64_t*) d) = s->val.i64; d++;    break;
77         case nsXPTType::T_U8     : *((uint8_t*) d) = s->val.u8;          break;
78         case nsXPTType::T_U16    : *((uint16_t*)d) = s->val.u16;         break;
79         case nsXPTType::T_U32    : *((uint32_t*)d) = s->val.u32;         break;
80         case nsXPTType::T_U64    : *((uint64_t*)d) = s->val.u64; d++;    break;
81         case nsXPTType::T_FLOAT  : *((float*)   d) = s->val.f;           break;
82         case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
83         case nsXPTType::T_BOOL   : *((bool*)  d) = s->val.b;           break;
84         case nsXPTType::T_CHAR   : *((char*)    d) = s->val.c;           break;
85         case nsXPTType::T_WCHAR  : *((wchar_t*) d) = s->val.wc;          break;
86         default:
87             // all the others are plain pointer types
88             *((void**)d) = s->val.p;
89             break;
90         }
91     }
92 }
93 
94 extern "C" {
95     struct my_params_struct {
96         nsISupports* that;
97         uint32_t Index;
98         uint32_t Count;
99         nsXPTCVariant* params;
100         uint32_t fn_count;
101         uint32_t fn_copy;
102     };
103 }
104 
105 EXPORT_XPCOM_API(nsresult)
NS_InvokeByIndex(nsISupports * that,uint32_t methodIndex,uint32_t paramCount,nsXPTCVariant * params)106 NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
107                    uint32_t paramCount, nsXPTCVariant* params)
108 {
109     uint32_t result;
110     struct my_params_struct my_params;
111     my_params.that = that;
112     my_params.Index = methodIndex;
113     my_params.Count = paramCount;
114     my_params.params = params;
115     my_params.fn_copy = (uint32_t) &invoke_copy_to_stack;
116     my_params.fn_count = (uint32_t) &invoke_count_words;
117 
118 /* This is to call a given method of class that.
119  * The parameters are in params, the number is in paramCount.
120  * The routine will issue calls to count the number of words
121  * required for argument passing and to copy the arguments to
122  * the stack.
123  * Since APCS passes the first 3 params in r1-r3, we need to
124  * load the first three words from the stack and correct the stack
125  * pointer (sp) in the appropriate way. This means:
126  *
127  * 1.) more than 3 arguments: load r1-r3, correct sp and remember No.
128  *			      of bytes left on the stack in r4
129  *
130  * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope),
131  *		  restore sp as if nothing had happened and set the marker r4 to zero.
132  *
133  * Afterwards sp will be restored using the value in r4 (which is not a temporary register
134  * and will be preserved by the function/method called according to APCS [ARM Procedure
135  * Calling Standard]).
136  *
137  * !!! IMPORTANT !!!
138  * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented
139  * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])!
140  *
141  */
142 
143 #ifdef __GNUC__
144   __asm__ __volatile__(
145     "ldr	r1, [%1, #12]	\n\t"	/* prepare to call invoke_count_words	*/
146     "ldr	ip, [%1, #16]	\n\t"	/* r0=paramCount, r1=params		*/
147     "ldr	r0, [%1,  #8]	\n\t"
148     "mov	lr, pc		\n\t"	/* call it...				*/
149     "mov	pc, ip		\n\t"
150     "mov	r4, r0, lsl #2	\n\t"	/* This is the amount of bytes needed.	*/
151     "sub	sp, sp, r4	\n\t"	/* use stack space for the args...	*/
152     "mov	r0, sp		\n\t"	/* prepare a pointer an the stack	*/
153     "ldr	r1, [%1,  #8]	\n\t"	/* =paramCount				*/
154     "ldr	r2, [%1, #12]	\n\t"	/* =params				*/
155     "ldr	ip, [%1, #20]	\n\t"	/* =invoke_copy_to_stack		*/
156     "mov	lr, pc		\n\t"	/* copy args to the stack like the	*/
157     "mov	pc, ip		\n\t"	/* compiler would.			*/
158     "ldr	r0, [%1]	\n\t"	/* =that				*/
159     "ldr	r1, [r0, #0]	\n\t"	/* get that->vtable offset		*/
160     "ldr	r2, [%1, #4]	\n\t"
161     "mov	r2, r2, lsl #2	\n\t"	/* a vtable_entry(x)=8 + (4 bytes * x)	*/
162     "ldr        ip, [r1, r2]    \n\t"	/* get method adress from vtable        */
163     "cmp	r4, #12		\n\t"	/* more than 3 arguments???		*/
164     "ldmgtia	sp!, {r1, r2, r3}\n\t"	/* yes: load arguments for r1-r3	*/
165     "subgt	r4, r4, #12	\n\t"	/*      and correct the stack pointer	*/
166     "ldmleia	sp, {r1, r2, r3}\n\t"	/* no:  load r1-r3 from stack		*/
167     "addle	sp, sp, r4	\n\t"	/*      and restore stack pointer	*/
168     "movle	r4, #0		\n\t"	/*	a mark for restoring sp		*/
169     "ldr	r0, [%1, #0]	\n\t"	/* get (self)				*/
170     "mov	lr, pc		\n\t"	/* call mathod				*/
171     "mov	pc, ip		\n\t"
172     "add	sp, sp, r4	\n\t"	/* restore stack pointer		*/
173     "mov	%0, r0		\n\t"	/* the result...			*/
174     : "=r" (result)
175     : "r" (&my_params), "m" (my_params)
176     : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp"
177     );
178 #else
179 #error "Unsupported compiler. Use g++ >= 2.8 for OpenBSD/arm."
180 #endif /* G++ >= 2.8 */
181 
182   return result;
183 }
184