michael@0: michael@0: #include michael@0: michael@0: typedef unsigned nsresult; michael@0: typedef unsigned uint32_t; michael@0: typedef unsigned nsXPCVariant; michael@0: michael@0: michael@0: #if defined(WIN32) michael@0: #define NS_IMETHOD virtual nsresult __stdcall michael@0: #define NS_IMETHODIMP nsresult __stdcall michael@0: #else michael@0: #define NS_IMETHOD virtual nsresult michael@0: #define NS_IMETHODIMP nsresult michael@0: #endif michael@0: michael@0: michael@0: class base{ michael@0: public: michael@0: NS_IMETHOD ignored() = 0; michael@0: }; michael@0: michael@0: class foo : public base { michael@0: public: michael@0: NS_IMETHOD callme1(int i, int j) = 0; michael@0: NS_IMETHOD callme2(int i, int j) = 0; michael@0: NS_IMETHOD callme3(int i, int j) = 0; michael@0: }; michael@0: michael@0: class bar : public foo{ michael@0: public: michael@0: NS_IMETHOD ignored(); michael@0: NS_IMETHOD callme1(int i, int j); michael@0: NS_IMETHOD callme2(int i, int j); michael@0: NS_IMETHOD callme3(int i, int j); michael@0: }; michael@0: michael@0: class baz : public base { michael@0: public: michael@0: NS_IMETHOD ignored(); michael@0: NS_IMETHOD callme1(); michael@0: NS_IMETHOD callme2(); michael@0: NS_IMETHOD callme3(); michael@0: void setfoo(foo* f) {other = f;} michael@0: michael@0: foo* other; michael@0: }; michael@0: NS_IMETHODIMP baz::ignored(){return 0;} michael@0: michael@0: NS_IMETHODIMP bar::ignored(){return 0;} michael@0: michael@0: NS_IMETHODIMP bar::callme1(int i, int j) michael@0: { michael@0: printf("called bar::callme1 with: %d %d\n", i, j); michael@0: return 15; michael@0: } michael@0: michael@0: NS_IMETHODIMP bar::callme2(int i, int j) michael@0: { michael@0: printf("called bar::callme2 with: %d %d\n", i, j); michael@0: return 25; michael@0: } michael@0: michael@0: NS_IMETHODIMP bar::callme3(int i, int j) michael@0: { michael@0: printf("called bar::callme3 with: %d %d\n", i, j); michael@0: return 35; michael@0: } michael@0: michael@0: void docall(foo* f, int i, int j){ michael@0: f->callme1(i, j); michael@0: } michael@0: michael@0: /***************************************************************************/ michael@0: #if defined(WIN32) michael@0: michael@0: static int __stdcall michael@0: PrepareAndDispatch(baz* self, uint32_t methodIndex, michael@0: uint32_t* args, uint32_t* stackBytesToPop) michael@0: { michael@0: fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n", michael@0: (void*)self, methodIndex, (void*)args); michael@0: foo* a = self->other; michael@0: int p1 = (int) *args; michael@0: int p2 = (int) *(args+1); michael@0: int out = 0; michael@0: switch(methodIndex) michael@0: { michael@0: case 1: out = a->callme1(p1, p2); break; michael@0: case 2: out = a->callme2(p1, p2); break; michael@0: case 3: out = a->callme3(p1, p2); break; michael@0: } michael@0: *stackBytesToPop = 2*4; michael@0: return out; michael@0: } michael@0: michael@0: #ifndef __GNUC__ michael@0: static __declspec(naked) void SharedStub(void) michael@0: { michael@0: __asm { michael@0: push ebp // set up simple stack frame michael@0: mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args michael@0: push ecx // make room for a ptr michael@0: lea eax, [ebp-4] // pointer to stackBytesToPop michael@0: push eax michael@0: lea ecx, [ebp+16] // pointer to args michael@0: push ecx michael@0: mov edx, [ebp+4] // vtbl_index michael@0: push edx michael@0: mov eax, [ebp+12] // this michael@0: push eax michael@0: call PrepareAndDispatch michael@0: mov edx, [ebp+8] // return address michael@0: mov ecx, [ebp-4] // stackBytesToPop michael@0: add ecx, 12 // for this, the index, and ret address michael@0: mov esp, ebp michael@0: pop ebp michael@0: add esp, ecx // fix up stack pointer michael@0: jmp edx // simulate __stdcall return michael@0: } michael@0: } michael@0: michael@0: // these macros get expanded (many times) in the file #included below michael@0: #define STUB_ENTRY(n) \ michael@0: __declspec(naked) nsresult __stdcall baz::callme##n() \ michael@0: { __asm push n __asm jmp SharedStub } michael@0: michael@0: #else /* __GNUC__ */ michael@0: michael@0: #define STUB_ENTRY(n) \ michael@0: nsresult __stdcall baz::callme##n() \ michael@0: { \ michael@0: uint32_t *args, stackBytesToPop; \ michael@0: int result = 0; \ michael@0: baz *obj; \ michael@0: __asm__ __volatile__ ( \ michael@0: "leal 0x0c(%%ebp), %0\n\t" /* args */ \ michael@0: "movl 0x08(%%ebp), %1\n\t" /* this */ \ michael@0: : "=r" (args), \ michael@0: "=r" (obj)); \ michael@0: result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \ michael@0: fprintf(stdout, "stub returning: %d\n", result); \ michael@0: fprintf(stdout, "bytes to pop: %d\n", stackBytesToPop); \ michael@0: return result; \ michael@0: } michael@0: michael@0: #endif /* ! __GNUC__ */ michael@0: michael@0: #else michael@0: /***************************************************************************/ michael@0: // just Linux_x86 now. Add other later... michael@0: michael@0: static int michael@0: PrepareAndDispatch(baz* self, uint32_t methodIndex, uint32_t* args) michael@0: { michael@0: foo* a = self->other; michael@0: int p1 = (int) *args; michael@0: int p2 = (int) *(args+1); michael@0: switch(methodIndex) michael@0: { michael@0: case 1: a->callme1(p1, p2); break; michael@0: case 2: a->callme2(p1, p2); break; michael@0: case 3: a->callme3(p1, p2); break; michael@0: } michael@0: return 1; michael@0: } michael@0: michael@0: #define STUB_ENTRY(n) \ michael@0: nsresult baz::callme##n() \ michael@0: { \ michael@0: void* method = PrepareAndDispatch; \ michael@0: nsresult result; \ michael@0: __asm__ __volatile__( \ michael@0: "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ michael@0: "pushl %%ecx\n\t" \ michael@0: "pushl $"#n"\n\t" /* method index */ \ michael@0: "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ michael@0: "pushl %%ecx\n\t" \ michael@0: "call *%%edx" /* PrepareAndDispatch */ \ michael@0: : "=a" (result) /* %0 */ \ michael@0: : "d" (method) /* %1 */ \ michael@0: : "memory" ); \ michael@0: return result; \ michael@0: } michael@0: michael@0: #endif michael@0: /***************************************************************************/ michael@0: michael@0: STUB_ENTRY(1) michael@0: STUB_ENTRY(2) michael@0: STUB_ENTRY(3) michael@0: michael@0: int main() michael@0: { michael@0: foo* a = new bar(); michael@0: baz* b = new baz(); michael@0: michael@0: /* here we make the global 'check for alloc failure' checker happy */ michael@0: if(!a || !b) michael@0: return 1; michael@0: michael@0: foo* c = (foo*)b; michael@0: michael@0: b->setfoo(a); michael@0: c->callme1(1,2); michael@0: c->callme2(2,4); michael@0: c->callme3(3,6); michael@0: michael@0: return 0; michael@0: }