1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/reflect/xptcall/src/md/test/stub_test.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,210 @@ 1.4 + 1.5 +#include <stdio.h> 1.6 + 1.7 +typedef unsigned nsresult; 1.8 +typedef unsigned uint32_t; 1.9 +typedef unsigned nsXPCVariant; 1.10 + 1.11 + 1.12 +#if defined(WIN32) 1.13 +#define NS_IMETHOD virtual nsresult __stdcall 1.14 +#define NS_IMETHODIMP nsresult __stdcall 1.15 +#else 1.16 +#define NS_IMETHOD virtual nsresult 1.17 +#define NS_IMETHODIMP nsresult 1.18 +#endif 1.19 + 1.20 + 1.21 +class base{ 1.22 +public: 1.23 + NS_IMETHOD ignored() = 0; 1.24 +}; 1.25 + 1.26 +class foo : public base { 1.27 +public: 1.28 + NS_IMETHOD callme1(int i, int j) = 0; 1.29 + NS_IMETHOD callme2(int i, int j) = 0; 1.30 + NS_IMETHOD callme3(int i, int j) = 0; 1.31 +}; 1.32 + 1.33 +class bar : public foo{ 1.34 +public: 1.35 + NS_IMETHOD ignored(); 1.36 + NS_IMETHOD callme1(int i, int j); 1.37 + NS_IMETHOD callme2(int i, int j); 1.38 + NS_IMETHOD callme3(int i, int j); 1.39 +}; 1.40 + 1.41 +class baz : public base { 1.42 +public: 1.43 + NS_IMETHOD ignored(); 1.44 + NS_IMETHOD callme1(); 1.45 + NS_IMETHOD callme2(); 1.46 + NS_IMETHOD callme3(); 1.47 + void setfoo(foo* f) {other = f;} 1.48 + 1.49 + foo* other; 1.50 +}; 1.51 +NS_IMETHODIMP baz::ignored(){return 0;} 1.52 + 1.53 +NS_IMETHODIMP bar::ignored(){return 0;} 1.54 + 1.55 +NS_IMETHODIMP bar::callme1(int i, int j) 1.56 +{ 1.57 + printf("called bar::callme1 with: %d %d\n", i, j); 1.58 + return 15; 1.59 +} 1.60 + 1.61 +NS_IMETHODIMP bar::callme2(int i, int j) 1.62 +{ 1.63 + printf("called bar::callme2 with: %d %d\n", i, j); 1.64 + return 25; 1.65 +} 1.66 + 1.67 +NS_IMETHODIMP bar::callme3(int i, int j) 1.68 +{ 1.69 + printf("called bar::callme3 with: %d %d\n", i, j); 1.70 + return 35; 1.71 +} 1.72 + 1.73 +void docall(foo* f, int i, int j){ 1.74 + f->callme1(i, j); 1.75 +} 1.76 + 1.77 +/***************************************************************************/ 1.78 +#if defined(WIN32) 1.79 + 1.80 +static int __stdcall 1.81 +PrepareAndDispatch(baz* self, uint32_t methodIndex, 1.82 + uint32_t* args, uint32_t* stackBytesToPop) 1.83 +{ 1.84 + fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n", 1.85 + (void*)self, methodIndex, (void*)args); 1.86 + foo* a = self->other; 1.87 + int p1 = (int) *args; 1.88 + int p2 = (int) *(args+1); 1.89 + int out = 0; 1.90 + switch(methodIndex) 1.91 + { 1.92 + case 1: out = a->callme1(p1, p2); break; 1.93 + case 2: out = a->callme2(p1, p2); break; 1.94 + case 3: out = a->callme3(p1, p2); break; 1.95 + } 1.96 + *stackBytesToPop = 2*4; 1.97 + return out; 1.98 +} 1.99 + 1.100 +#ifndef __GNUC__ 1.101 +static __declspec(naked) void SharedStub(void) 1.102 +{ 1.103 + __asm { 1.104 + push ebp // set up simple stack frame 1.105 + mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args 1.106 + push ecx // make room for a ptr 1.107 + lea eax, [ebp-4] // pointer to stackBytesToPop 1.108 + push eax 1.109 + lea ecx, [ebp+16] // pointer to args 1.110 + push ecx 1.111 + mov edx, [ebp+4] // vtbl_index 1.112 + push edx 1.113 + mov eax, [ebp+12] // this 1.114 + push eax 1.115 + call PrepareAndDispatch 1.116 + mov edx, [ebp+8] // return address 1.117 + mov ecx, [ebp-4] // stackBytesToPop 1.118 + add ecx, 12 // for this, the index, and ret address 1.119 + mov esp, ebp 1.120 + pop ebp 1.121 + add esp, ecx // fix up stack pointer 1.122 + jmp edx // simulate __stdcall return 1.123 + } 1.124 +} 1.125 + 1.126 +// these macros get expanded (many times) in the file #included below 1.127 +#define STUB_ENTRY(n) \ 1.128 +__declspec(naked) nsresult __stdcall baz::callme##n() \ 1.129 +{ __asm push n __asm jmp SharedStub } 1.130 + 1.131 +#else /* __GNUC__ */ 1.132 + 1.133 +#define STUB_ENTRY(n) \ 1.134 +nsresult __stdcall baz::callme##n() \ 1.135 +{ \ 1.136 + uint32_t *args, stackBytesToPop; \ 1.137 + int result = 0; \ 1.138 + baz *obj; \ 1.139 + __asm__ __volatile__ ( \ 1.140 + "leal 0x0c(%%ebp), %0\n\t" /* args */ \ 1.141 + "movl 0x08(%%ebp), %1\n\t" /* this */ \ 1.142 + : "=r" (args), \ 1.143 + "=r" (obj)); \ 1.144 + result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \ 1.145 + fprintf(stdout, "stub returning: %d\n", result); \ 1.146 + fprintf(stdout, "bytes to pop: %d\n", stackBytesToPop); \ 1.147 + return result; \ 1.148 +} 1.149 + 1.150 +#endif /* ! __GNUC__ */ 1.151 + 1.152 +#else 1.153 +/***************************************************************************/ 1.154 +// just Linux_x86 now. Add other later... 1.155 + 1.156 +static int 1.157 +PrepareAndDispatch(baz* self, uint32_t methodIndex, uint32_t* args) 1.158 +{ 1.159 + foo* a = self->other; 1.160 + int p1 = (int) *args; 1.161 + int p2 = (int) *(args+1); 1.162 + switch(methodIndex) 1.163 + { 1.164 + case 1: a->callme1(p1, p2); break; 1.165 + case 2: a->callme2(p1, p2); break; 1.166 + case 3: a->callme3(p1, p2); break; 1.167 + } 1.168 + return 1; 1.169 +} 1.170 + 1.171 +#define STUB_ENTRY(n) \ 1.172 +nsresult baz::callme##n() \ 1.173 +{ \ 1.174 + void* method = PrepareAndDispatch; \ 1.175 + nsresult result; \ 1.176 + __asm__ __volatile__( \ 1.177 + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ 1.178 + "pushl %%ecx\n\t" \ 1.179 + "pushl $"#n"\n\t" /* method index */ \ 1.180 + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ 1.181 + "pushl %%ecx\n\t" \ 1.182 + "call *%%edx" /* PrepareAndDispatch */ \ 1.183 + : "=a" (result) /* %0 */ \ 1.184 + : "d" (method) /* %1 */ \ 1.185 + : "memory" ); \ 1.186 + return result; \ 1.187 +} 1.188 + 1.189 +#endif 1.190 +/***************************************************************************/ 1.191 + 1.192 +STUB_ENTRY(1) 1.193 +STUB_ENTRY(2) 1.194 +STUB_ENTRY(3) 1.195 + 1.196 +int main() 1.197 +{ 1.198 + foo* a = new bar(); 1.199 + baz* b = new baz(); 1.200 + 1.201 + /* here we make the global 'check for alloc failure' checker happy */ 1.202 + if(!a || !b) 1.203 + return 1; 1.204 + 1.205 + foo* c = (foo*)b; 1.206 + 1.207 + b->setfoo(a); 1.208 + c->callme1(1,2); 1.209 + c->callme2(2,4); 1.210 + c->callme3(3,6); 1.211 + 1.212 + return 0; 1.213 +}