1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,207 @@ 1.4 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <stdio.h> 1.10 + 1.11 +typedef unsigned nsresult; 1.12 +typedef unsigned uint32_t; 1.13 +typedef unsigned nsXPCVariant; 1.14 + 1.15 + 1.16 +#if defined(WIN32) 1.17 +#define NS_IMETHOD virtual nsresult __stdcall 1.18 +#define NS_IMETHODIMP nsresult __stdcall 1.19 +#else 1.20 +#define NS_IMETHOD virtual nsresult 1.21 +#define NS_IMETHODIMP nsresult 1.22 +#endif 1.23 + 1.24 + 1.25 +class base{ 1.26 +public: 1.27 + NS_IMETHOD ignored() = 0; 1.28 +}; 1.29 + 1.30 +class foo : public base { 1.31 +public: 1.32 + NS_IMETHOD callme1(int i, int j) = 0; 1.33 + NS_IMETHOD callme2(int i, int j) = 0; 1.34 + NS_IMETHOD callme3(int i, int j) = 0; 1.35 +}; 1.36 + 1.37 +class bar : public foo{ 1.38 +public: 1.39 + NS_IMETHOD ignored(); 1.40 + NS_IMETHOD callme1(int i, int j); 1.41 + NS_IMETHOD callme2(int i, int j); 1.42 + NS_IMETHOD callme3(int i, int j); 1.43 +}; 1.44 + 1.45 +/* 1.46 +class baz : public base { 1.47 +public: 1.48 + NS_IMETHOD ignored(); 1.49 + NS_IMETHOD callme1(); 1.50 + NS_IMETHOD callme2(); 1.51 + NS_IMETHOD callme3(); 1.52 + void setfoo(foo* f) {other = f;} 1.53 + 1.54 + foo* other; 1.55 +}; 1.56 +NS_IMETHODIMP baz::ignored(){return 0;} 1.57 +*/ 1.58 + 1.59 +NS_IMETHODIMP bar::ignored(){return 0;} 1.60 + 1.61 +NS_IMETHODIMP bar::callme1(int i, int j) 1.62 +{ 1.63 + printf("called bar::callme1 with: %d %d\n", i, j); 1.64 + return 5; 1.65 +} 1.66 + 1.67 +NS_IMETHODIMP bar::callme2(int i, int j) 1.68 +{ 1.69 + printf("called bar::callme2 with: %d %d\n", i, j); 1.70 + return 5; 1.71 +} 1.72 + 1.73 +NS_IMETHODIMP bar::callme3(int i, int j) 1.74 +{ 1.75 + printf("called bar::callme3 with: %d %d\n", i, j); 1.76 + return 5; 1.77 +} 1.78 + 1.79 +void docall(foo* f, int i, int j){ 1.80 + f->callme1(i, j); 1.81 +} 1.82 + 1.83 +/***************************************************************************/ 1.84 +#if defined(WIN32) 1.85 + 1.86 +static uint32_t __stdcall 1.87 +invoke_count_words(uint32_t paramCount, nsXPCVariant* s) 1.88 +{ 1.89 + return paramCount; 1.90 +} 1.91 + 1.92 +static void __stdcall 1.93 +invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPCVariant* s) 1.94 +{ 1.95 + for(uint32_t i = 0; i < paramCount; i++, d++, s++) 1.96 + { 1.97 + *((uint32_t*)d) = *((uint32_t*)s); 1.98 + } 1.99 +} 1.100 + 1.101 +static nsresult __stdcall 1.102 +DoInvoke(void* that, uint32_t index, 1.103 + uint32_t paramCount, nsXPCVariant* params) 1.104 +{ 1.105 + __asm { 1.106 + push params 1.107 + push paramCount 1.108 + call invoke_count_words // stdcall, result in eax 1.109 + shl eax,2 // *= 4 1.110 + sub esp,eax // make space for params 1.111 + mov edx,esp 1.112 + push params 1.113 + push paramCount 1.114 + push edx 1.115 + call invoke_copy_to_stack // stdcall 1.116 + mov ecx,that // instance in ecx 1.117 + push ecx // push this 1.118 + mov edx,[ecx] // vtable in edx 1.119 + mov eax,index 1.120 + shl eax,2 // *= 4 1.121 + add edx,eax 1.122 + call [edx] // stdcall, i.e. callee cleans up stack. 1.123 + } 1.124 +} 1.125 + 1.126 +#else 1.127 +/***************************************************************************/ 1.128 +// just Linux_x86 now. Add other later... 1.129 + 1.130 +static uint32_t 1.131 +invoke_count_words(uint32_t paramCount, nsXPCVariant* s) 1.132 +{ 1.133 + return paramCount; 1.134 +} 1.135 + 1.136 +static void 1.137 +invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPCVariant* s) 1.138 +{ 1.139 + for(uint32_t i = 0; i < paramCount; i++, d++, s++) 1.140 + { 1.141 + *((uint32_t*)d) = *((uint32_t*)s); 1.142 + } 1.143 +} 1.144 + 1.145 +static nsresult 1.146 +DoInvoke(void* that, uint32_t index, 1.147 + uint32_t paramCount, nsXPCVariant* params) 1.148 +{ 1.149 + uint32_t result; 1.150 + void* fn_count = invoke_count_words; 1.151 + void* fn_copy = invoke_copy_to_stack; 1.152 + 1.153 + __asm__ __volatile__( 1.154 + "pushl %4\n\t" 1.155 + "pushl %3\n\t" 1.156 + "movl %5, %%eax\n\t" 1.157 + "call *%%eax\n\t" /* count words */ 1.158 + "addl $0x8, %%esp\n\t" 1.159 + "shl $2, %%eax\n\t" /* *= 4 */ 1.160 + "subl %%eax, %%esp\n\t" /* make room for params */ 1.161 + "movl %%esp, %%edx\n\t" 1.162 + "pushl %4\n\t" 1.163 + "pushl %3\n\t" 1.164 + "pushl %%edx\n\t" 1.165 + "movl %6, %%eax\n\t" 1.166 + "call *%%eax\n\t" /* copy params */ 1.167 + "addl $0xc, %%esp\n\t" 1.168 + "movl %1, %%ecx\n\t" 1.169 + "pushl %%ecx\n\t" 1.170 + "movl (%%ecx), %%edx\n\t" 1.171 + "movl %2, %%eax\n\t" /* function index */ 1.172 + "shl $2, %%eax\n\t" /* *= 4 */ 1.173 + "addl $8, %%eax\n\t" /* += 8 */ 1.174 + "addl %%eax, %%edx\n\t" 1.175 + "call *(%%edx)\n\t" /* safe to not cleanup esp */ 1.176 + "movl %%eax, %0" 1.177 + : "=g" (result) /* %0 */ 1.178 + : "g" (that), /* %1 */ 1.179 + "g" (index), /* %2 */ 1.180 + "g" (paramCount), /* %3 */ 1.181 + "g" (params), /* %4 */ 1.182 + "g" (fn_count), /* %5 */ 1.183 + "g" (fn_copy) /* %6 */ 1.184 + : "ax", "cx", "dx", "memory" 1.185 + ); 1.186 + 1.187 + return result; 1.188 +} 1.189 + 1.190 +#endif 1.191 +/***************************************************************************/ 1.192 + 1.193 +int main() 1.194 +{ 1.195 + nsXPCVariant params1[2] = {1,2}; 1.196 + nsXPCVariant params2[2] = {2,4}; 1.197 + nsXPCVariant params3[2] = {3,6}; 1.198 + 1.199 + foo* a = new bar(); 1.200 + 1.201 +// printf("calling via C++...\n"); 1.202 +// docall(a, 12, 24); 1.203 + 1.204 + printf("calling via ASM...\n"); 1.205 + DoInvoke(a, 1, 2, params1); 1.206 + DoInvoke(a, 2, 2, params2); 1.207 + DoInvoke(a, 3, 2, params3); 1.208 + 1.209 + return 0; 1.210 +}