Back to index

lightning-sunbird  0.9+nobinonly
stub_test.cpp
Go to the documentation of this file.
00001 
00002 #include <stdio.h>
00003 
00004 typedef unsigned nsresult;
00005 typedef unsigned PRUint32;
00006 typedef unsigned nsXPCVariant;
00007 
00008 
00009 #if defined(WIN32)
00010 #define NS_IMETHOD virtual nsresult __stdcall
00011 #define NS_IMETHODIMP nsresult __stdcall
00012 #else
00013 #define NS_IMETHOD virtual nsresult
00014 #define NS_IMETHODIMP nsresult
00015 #endif
00016 
00017 
00018 class base{
00019 public:
00020   NS_IMETHOD ignored() = 0;
00021 };
00022 
00023 class foo : public base {
00024 public:
00025   NS_IMETHOD callme1(int i, int j) = 0;
00026   NS_IMETHOD callme2(int i, int j) = 0;
00027   NS_IMETHOD callme3(int i, int j) = 0;
00028 };
00029 
00030 class bar : public foo{
00031 public:
00032   NS_IMETHOD ignored();
00033   NS_IMETHOD callme1(int i, int j);
00034   NS_IMETHOD callme2(int i, int j);
00035   NS_IMETHOD callme3(int i, int j);
00036 };
00037 
00038 class baz : public base {
00039 public:
00040   NS_IMETHOD ignored();
00041   NS_IMETHOD callme1();
00042   NS_IMETHOD callme2();
00043   NS_IMETHOD callme3();
00044   void setfoo(foo* f) {other = f;}
00045 
00046   foo* other;
00047 };
00048 NS_IMETHODIMP baz::ignored(){return 0;}
00049 
00050 NS_IMETHODIMP bar::ignored(){return 0;}
00051 
00052 NS_IMETHODIMP bar::callme1(int i, int j)
00053 {
00054   printf("called bar::callme1 with: %d %d\n", i, j);
00055   return 15;
00056 }
00057 
00058 NS_IMETHODIMP bar::callme2(int i, int j)
00059 {
00060   printf("called bar::callme2 with: %d %d\n", i, j);
00061   return 25;
00062 }
00063 
00064 NS_IMETHODIMP bar::callme3(int i, int j)
00065 {
00066   printf("called bar::callme3 with: %d %d\n", i, j);
00067   return 35;
00068 }
00069 
00070 void docall(foo* f, int i, int j){
00071   f->callme1(i, j); 
00072 }
00073 
00074 /***************************************************************************/
00075 #if defined(WIN32)
00076 
00077 static int __stdcall
00078 PrepareAndDispatch(baz* self, PRUint32 methodIndex,
00079                    PRUint32* args, PRUint32* stackBytesToPop)
00080 {
00081     fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n",
00082         (void*)self, methodIndex, (void*)args);
00083     foo* a = self->other;
00084     int p1 = (int) *args;
00085     int p2 = (int) *(args+1);
00086     int out = 0;
00087     switch(methodIndex)
00088     {
00089     case 1: out = a->callme1(p1, p2); break;
00090     case 2: out = a->callme2(p1, p2); break;
00091     case 3: out = a->callme3(p1, p2); break;
00092     }
00093     *stackBytesToPop = 2*4;
00094     return out;
00095 }
00096 
00097 #ifndef __GNUC__
00098 static __declspec(naked) void SharedStub(void)
00099 {
00100     __asm {
00101         push ebp            // set up simple stack frame
00102         mov  ebp, esp       // stack has: ebp/vtbl_index/retaddr/this/args
00103         push ecx            // make room for a ptr
00104         lea  eax, [ebp-4]   // pointer to stackBytesToPop
00105         push eax
00106         lea  ecx, [ebp+16]  // pointer to args
00107         push ecx
00108         mov  edx, [ebp+4]   // vtbl_index
00109         push edx
00110         mov  eax, [ebp+12]  // this
00111         push eax
00112         call PrepareAndDispatch
00113         mov  edx, [ebp+8]   // return address
00114         mov  ecx, [ebp-4]   // stackBytesToPop
00115         add  ecx, 12        // for this, the index, and ret address
00116         mov  esp, ebp
00117         pop  ebp
00118         add  esp, ecx       // fix up stack pointer
00119         jmp  edx            // simulate __stdcall return
00120     }
00121 }
00122 
00123 // these macros get expanded (many times) in the file #included below
00124 #define STUB_ENTRY(n) \
00125 __declspec(naked) nsresult __stdcall baz::callme##n() \
00126 { __asm push n __asm jmp SharedStub }
00127 
00128 #else /* __GNUC__ */
00129 
00130 #define STUB_ENTRY(n) \
00131 nsresult __stdcall baz::callme##n() \
00132 { \
00133   PRUint32 *args, stackBytesToPop; \
00134   int result = 0; \
00135   baz *obj; \
00136   __asm__ __volatile__ ( \
00137     "leal   0x0c(%%ebp), %0\n\t"    /* args */ \
00138     "movl   0x08(%%ebp), %1\n\t"    /* this */ \
00139     : "=r" (args), \
00140       "=r" (obj)); \
00141   result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \
00142     fprintf(stdout, "stub returning: %d\n", result); \
00143     fprintf(stdout, "bytes to pop:  %d\n", stackBytesToPop); \
00144     return result; \
00145 }
00146 
00147 #endif /* ! __GNUC__ */
00148 
00149 #else
00150 /***************************************************************************/
00151 // just Linux_x86 now. Add other later...
00152 
00153 static int
00154 PrepareAndDispatch(baz* self, PRUint32 methodIndex, PRUint32* args)
00155 {
00156     foo* a = self->other;
00157     int p1 = (int) *args;
00158     int p2 = (int) *(args+1);
00159     switch(methodIndex)
00160     {
00161     case 1: a->callme1(p1, p2); break;
00162     case 2: a->callme2(p1, p2); break;
00163     case 3: a->callme3(p1, p2); break;
00164     }
00165     return 1;
00166 }
00167 
00168 #define STUB_ENTRY(n) \
00169 nsresult baz::callme##n() \
00170 { \
00171   register void* method = PrepareAndDispatch; \
00172   register nsresult result; \
00173   __asm__ __volatile__( \
00174     "leal   0x0c(%%ebp), %%ecx\n\t"    /* args */ \
00175     "pushl  %%ecx\n\t" \
00176     "pushl  $"#n"\n\t"                 /* method index */ \
00177     "movl   0x08(%%ebp), %%ecx\n\t"    /* this */ \
00178     "pushl  %%ecx\n\t" \
00179     "call   *%%edx"                    /* PrepareAndDispatch */ \
00180     : "=a" (result)     /* %0 */ \
00181     : "d" (method)      /* %1 */ \
00182     : "memory" ); \
00183     return result; \
00184 }
00185 
00186 #endif
00187 /***************************************************************************/
00188 
00189 STUB_ENTRY(1)
00190 STUB_ENTRY(2)
00191 STUB_ENTRY(3)
00192 
00193 int main()
00194 {
00195   foo* a = new bar();
00196   baz* b = new baz();
00197 
00198   /* here we make the global 'check for alloc failure' checker happy */
00199   if(!a || !b)
00200     return 1;
00201   
00202   foo* c = (foo*)b;
00203 
00204   b->setfoo(a);
00205   c->callme1(1,2);
00206   c->callme2(2,4);
00207   c->callme3(3,6);
00208 
00209   return 0;
00210 }