xpcom/reflect/xptcall/src/md/test/stub_test.cpp

changeset 0
6474c204b198
     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 +}

mercurial