|
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 #include <stdio.h> |
|
7 |
|
8 typedef unsigned nsresult; |
|
9 typedef unsigned uint32_t; |
|
10 typedef unsigned nsXPCVariant; |
|
11 |
|
12 |
|
13 #if defined(WIN32) |
|
14 #define NS_IMETHOD virtual nsresult __stdcall |
|
15 #define NS_IMETHODIMP nsresult __stdcall |
|
16 #else |
|
17 #define NS_IMETHOD virtual nsresult |
|
18 #define NS_IMETHODIMP nsresult |
|
19 #endif |
|
20 |
|
21 |
|
22 class base{ |
|
23 public: |
|
24 NS_IMETHOD ignored() = 0; |
|
25 }; |
|
26 |
|
27 class foo : public base { |
|
28 public: |
|
29 NS_IMETHOD callme1(int i, int j) = 0; |
|
30 NS_IMETHOD callme2(int i, int j) = 0; |
|
31 NS_IMETHOD callme3(int i, int j) = 0; |
|
32 }; |
|
33 |
|
34 class bar : public foo{ |
|
35 public: |
|
36 NS_IMETHOD ignored(); |
|
37 NS_IMETHOD callme1(int i, int j); |
|
38 NS_IMETHOD callme2(int i, int j); |
|
39 NS_IMETHOD callme3(int i, int j); |
|
40 }; |
|
41 |
|
42 /* |
|
43 class baz : public base { |
|
44 public: |
|
45 NS_IMETHOD ignored(); |
|
46 NS_IMETHOD callme1(); |
|
47 NS_IMETHOD callme2(); |
|
48 NS_IMETHOD callme3(); |
|
49 void setfoo(foo* f) {other = f;} |
|
50 |
|
51 foo* other; |
|
52 }; |
|
53 NS_IMETHODIMP baz::ignored(){return 0;} |
|
54 */ |
|
55 |
|
56 NS_IMETHODIMP bar::ignored(){return 0;} |
|
57 |
|
58 NS_IMETHODIMP bar::callme1(int i, int j) |
|
59 { |
|
60 printf("called bar::callme1 with: %d %d\n", i, j); |
|
61 return 5; |
|
62 } |
|
63 |
|
64 NS_IMETHODIMP bar::callme2(int i, int j) |
|
65 { |
|
66 printf("called bar::callme2 with: %d %d\n", i, j); |
|
67 return 5; |
|
68 } |
|
69 |
|
70 NS_IMETHODIMP bar::callme3(int i, int j) |
|
71 { |
|
72 printf("called bar::callme3 with: %d %d\n", i, j); |
|
73 return 5; |
|
74 } |
|
75 |
|
76 void docall(foo* f, int i, int j){ |
|
77 f->callme1(i, j); |
|
78 } |
|
79 |
|
80 /***************************************************************************/ |
|
81 #if defined(WIN32) |
|
82 |
|
83 static uint32_t __stdcall |
|
84 invoke_count_words(uint32_t paramCount, nsXPCVariant* s) |
|
85 { |
|
86 return paramCount; |
|
87 } |
|
88 |
|
89 static void __stdcall |
|
90 invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPCVariant* s) |
|
91 { |
|
92 for(uint32_t i = 0; i < paramCount; i++, d++, s++) |
|
93 { |
|
94 *((uint32_t*)d) = *((uint32_t*)s); |
|
95 } |
|
96 } |
|
97 |
|
98 static nsresult __stdcall |
|
99 DoInvoke(void* that, uint32_t index, |
|
100 uint32_t paramCount, nsXPCVariant* params) |
|
101 { |
|
102 __asm { |
|
103 push params |
|
104 push paramCount |
|
105 call invoke_count_words // stdcall, result in eax |
|
106 shl eax,2 // *= 4 |
|
107 sub esp,eax // make space for params |
|
108 mov edx,esp |
|
109 push params |
|
110 push paramCount |
|
111 push edx |
|
112 call invoke_copy_to_stack // stdcall |
|
113 mov ecx,that // instance in ecx |
|
114 push ecx // push this |
|
115 mov edx,[ecx] // vtable in edx |
|
116 mov eax,index |
|
117 shl eax,2 // *= 4 |
|
118 add edx,eax |
|
119 call [edx] // stdcall, i.e. callee cleans up stack. |
|
120 } |
|
121 } |
|
122 |
|
123 #else |
|
124 /***************************************************************************/ |
|
125 // just Linux_x86 now. Add other later... |
|
126 |
|
127 static uint32_t |
|
128 invoke_count_words(uint32_t paramCount, nsXPCVariant* s) |
|
129 { |
|
130 return paramCount; |
|
131 } |
|
132 |
|
133 static void |
|
134 invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPCVariant* s) |
|
135 { |
|
136 for(uint32_t i = 0; i < paramCount; i++, d++, s++) |
|
137 { |
|
138 *((uint32_t*)d) = *((uint32_t*)s); |
|
139 } |
|
140 } |
|
141 |
|
142 static nsresult |
|
143 DoInvoke(void* that, uint32_t index, |
|
144 uint32_t paramCount, nsXPCVariant* params) |
|
145 { |
|
146 uint32_t result; |
|
147 void* fn_count = invoke_count_words; |
|
148 void* fn_copy = invoke_copy_to_stack; |
|
149 |
|
150 __asm__ __volatile__( |
|
151 "pushl %4\n\t" |
|
152 "pushl %3\n\t" |
|
153 "movl %5, %%eax\n\t" |
|
154 "call *%%eax\n\t" /* count words */ |
|
155 "addl $0x8, %%esp\n\t" |
|
156 "shl $2, %%eax\n\t" /* *= 4 */ |
|
157 "subl %%eax, %%esp\n\t" /* make room for params */ |
|
158 "movl %%esp, %%edx\n\t" |
|
159 "pushl %4\n\t" |
|
160 "pushl %3\n\t" |
|
161 "pushl %%edx\n\t" |
|
162 "movl %6, %%eax\n\t" |
|
163 "call *%%eax\n\t" /* copy params */ |
|
164 "addl $0xc, %%esp\n\t" |
|
165 "movl %1, %%ecx\n\t" |
|
166 "pushl %%ecx\n\t" |
|
167 "movl (%%ecx), %%edx\n\t" |
|
168 "movl %2, %%eax\n\t" /* function index */ |
|
169 "shl $2, %%eax\n\t" /* *= 4 */ |
|
170 "addl $8, %%eax\n\t" /* += 8 */ |
|
171 "addl %%eax, %%edx\n\t" |
|
172 "call *(%%edx)\n\t" /* safe to not cleanup esp */ |
|
173 "movl %%eax, %0" |
|
174 : "=g" (result) /* %0 */ |
|
175 : "g" (that), /* %1 */ |
|
176 "g" (index), /* %2 */ |
|
177 "g" (paramCount), /* %3 */ |
|
178 "g" (params), /* %4 */ |
|
179 "g" (fn_count), /* %5 */ |
|
180 "g" (fn_copy) /* %6 */ |
|
181 : "ax", "cx", "dx", "memory" |
|
182 ); |
|
183 |
|
184 return result; |
|
185 } |
|
186 |
|
187 #endif |
|
188 /***************************************************************************/ |
|
189 |
|
190 int main() |
|
191 { |
|
192 nsXPCVariant params1[2] = {1,2}; |
|
193 nsXPCVariant params2[2] = {2,4}; |
|
194 nsXPCVariant params3[2] = {3,6}; |
|
195 |
|
196 foo* a = new bar(); |
|
197 |
|
198 // printf("calling via C++...\n"); |
|
199 // docall(a, 12, 24); |
|
200 |
|
201 printf("calling via ASM...\n"); |
|
202 DoInvoke(a, 1, 2, params1); |
|
203 DoInvoke(a, 2, 2, params2); |
|
204 DoInvoke(a, 3, 2, params3); |
|
205 |
|
206 return 0; |
|
207 } |