Import 1.9b4 extra tag from cvs
[mozilla-extra.git] / extensions / mono / test / generate-assembly.cs
bloba90fc0f4a2c4c625001eb87e7beacb75736d9c60
1 using System;
2 using System.Runtime.InteropServices;
3 using System.Reflection;
4 using System.Reflection.Emit;
5 using Mozilla.XPCOM;
6 using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
7 using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
8 using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
10 public class Test
12 [DllImport("xpcom-dotnet.so")]
13 static extern int StartXPCOM(out IntPtr srvmgr);
15 static IntPtr srvmgr;
17 [DllImport("test.so", EntryPoint="GetImpl")]
18 public static extern IntPtr GetTestImpl();
20 static void GenerateInterfaceMethod(TypeBuilder tb, MethodDescriptor desc)
22 if (!desc.IsVisible()) {
23 Console.WriteLine("HIDDEN: {0}", desc);
24 return;
26 const MethodAttributes attrs = MethodAttributes.Public |
27 MethodAttributes.Abstract | MethodAttributes.Virtual;
28 tb.DefineMethod(desc.name, attrs, desc.resultType, desc.argTypes);
29 Console.WriteLine("\t{0}", desc);
32 static void EmitPtrAndFlagsStore(ILGenerator ilg, LocalBuilder bufLocal,
33 int argnum, IntPtr ptr, sbyte flags)
35 //= bufLocal[argnum].ptr = ptr;
36 ilg.Emit(OpCodes.Ldloc, bufLocal);
37 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 8);
38 ilg.Emit(OpCodes.Add);
39 ilg.Emit(OpCodes.Ldc_I4, ptr.ToInt32());
40 ilg.Emit(OpCodes.Stind_I4);
42 //= bufLocal[argnum].flags = flags;
43 ilg.Emit(OpCodes.Ldloc, bufLocal);
44 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 13);
45 ilg.Emit(OpCodes.Add);
46 ilg.Emit(OpCodes.Ldc_I4, (Int32)flags);
47 ilg.Emit(OpCodes.Stind_I1);
50 static void EmitTypeStore(ILGenerator ilg, LocalBuilder bufLocal,
51 TypeInfo.TypeDescriptor t, int argnum)
53 ilg.Emit(OpCodes.Ldloc, bufLocal);
54 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 12);
55 ilg.Emit(OpCodes.Add);
56 ilg.Emit(OpCodes.Ldc_I4, (Int32)t.tag);
57 ilg.Emit(OpCodes.Stind_I4);
60 static void EmitComputeBufferLoc(ILGenerator ilg, LocalBuilder bufLocal,
61 int argnum)
63 ilg.Emit(OpCodes.Ldloc, bufLocal);
64 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE);
65 ilg.Emit(OpCodes.Add);
68 static void EmitPrepareArgStore(ILGenerator ilg, LocalBuilder bufLocal,
69 int argnum)
71 EmitComputeBufferLoc(ilg, bufLocal, argnum);
72 EmitLoadArg(ilg, argnum);
75 static void EmitLoadArg(ILGenerator ilg, int argnum)
77 switch (argnum) {
78 case 0:
79 ilg.Emit(OpCodes.Ldarg_1);
80 break;
81 case 1:
82 ilg.Emit(OpCodes.Ldarg_2);
83 break;
84 case 2:
85 ilg.Emit(OpCodes.Ldarg_3);
86 break;
87 default:
88 if (argnum < 254)
89 ilg.Emit(OpCodes.Ldarg_S, argnum + 1);
90 else
91 ilg.Emit(OpCodes.Ldarg, argnum + 1);
92 break;
96 static void EmitLoadReturnSlot_1(ILGenerator ilg, LocalBuilder bufLocal,
97 int slotnum)
99 ilg.Emit(OpCodes.Ldloc, bufLocal);
100 ilg.Emit(OpCodes.Ldc_I4, (slotnum - 1) * VARIANT_SIZE);
101 ilg.Emit(OpCodes.Add);
102 ilg.Emit(OpCodes.Ldind_I4);
105 static void EmitOutParamPrep(ILGenerator ilg, LocalBuilder bufLocal,
106 TypeInfo.TypeDescriptor type, int argnum)
108 ilg.Emit(OpCodes.Nop);
109 ilg.Emit(OpCodes.Ldloc, bufLocal);
110 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 13);
111 ilg.Emit(OpCodes.Add);
112 ilg.Emit(OpCodes.Ldc_I4, 1); // PTR_IS_DATA
113 ilg.Emit(OpCodes.Stind_I1);
115 ilg.Emit(OpCodes.Ldloc, bufLocal);
116 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 8); // offsetof(ptr)
117 ilg.Emit(OpCodes.Add);
118 ilg.Emit(OpCodes.Ldloc, bufLocal);
119 ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 0); // offsetof(val)
120 ilg.Emit(OpCodes.Add);
121 ilg.Emit(OpCodes.Stind_I4); /* XXX 64-bitness! */
124 static void EmitProxyConstructor(TypeBuilder tb, FieldInfo thisField)
126 ConstructorBuilder ctor =
127 tb.DefineConstructor(MethodAttributes.Public,
128 CallingConventions.Standard,
129 new Type[1] { typeof(IntPtr) });
130 ILGenerator ilg = ctor.GetILGenerator();
131 ilg.Emit(OpCodes.Ldarg_0);
132 ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));
133 ilg.Emit(OpCodes.Ldarg_0);
134 ilg.Emit(OpCodes.Ldarg_1);
135 ilg.Emit(OpCodes.Stfld, thisField);
136 ilg.Emit(OpCodes.Ret);
139 const int VARIANT_SIZE = 16; /* sizeof(XPTCVariant) */
141 unsafe static void GenerateProxyMethod(TypeBuilder tb,
142 MethodDescriptor desc,
143 FieldInfo thisField)
145 if (!desc.IsVisible()) {
146 Console.WriteLine("HIDDEN: {0}", desc);
147 return;
149 const MethodAttributes attrs =
150 MethodAttributes.Public | MethodAttributes.Virtual;
151 Type ret = desc.resultType;
152 MethodBuilder meth =
153 tb.DefineMethod(desc.name, attrs, ret, desc.argTypes);
154 ILGenerator ilg = meth.GetILGenerator();
155 TypeInfo.ParamDescriptor[] args = desc.args;
157 LocalBuilder bufLocal =
158 ilg.DeclareLocal(System.Type.GetType("System.Int32*"));
160 Type marshalType = typeof(System.Runtime.InteropServices.Marshal);
162 // Marshal.AllocCoTaskMem(constify(argBufSize))
163 int argCount = args.Length;
164 int argBufSize = VARIANT_SIZE * args.Length;
166 ilg.Emit(OpCodes.Ldc_I4, argBufSize);
167 ilg.Emit(OpCodes.Call, marshalType.GetMethod("AllocCoTaskMem"));
168 ilg.Emit(OpCodes.Stloc, bufLocal);
170 for (int i = 0; i < argCount; i++) {
171 TypeInfo.ParamDescriptor param = args[i];
172 TypeInfo.TypeDescriptor type = param.type;
173 IntPtr ptr = IntPtr.Zero;
174 sbyte flags = 0;
175 EmitTypeStore(ilg, bufLocal, type, i);
177 if ((param.flags & ParamFlags.Out) != 0) {
178 EmitOutParamPrep(ilg, bufLocal, type, i);
179 continue;
181 switch (type.tag) {
182 case TypeTag.Int8:
183 case TypeTag.Int16:
184 case TypeTag.UInt8:
185 case TypeTag.UInt16:
186 case TypeTag.Char:
187 case TypeTag.WChar:
188 case TypeTag.UInt32:
189 EmitPrepareArgStore(ilg, bufLocal, i);
190 // XXX do I need to cast this?
191 ilg.Emit(OpCodes.Castclass, typeof(Int32));
192 ilg.Emit(OpCodes.Stind_I4);
193 break;
194 case TypeTag.Int32:
195 EmitPrepareArgStore(ilg, bufLocal, i);
196 ilg.Emit(OpCodes.Stind_I4);
197 break;
198 case TypeTag.String:
199 EmitPrepareArgStore(ilg, bufLocal, i);
200 // the string arg is now on the stack
201 ilg.Emit(OpCodes.Call,
202 marshalType.GetMethod("StringToCoTaskMemAnsi"));
203 ilg.Emit(OpCodes.Stind_I4);
204 break;
205 default:
207 String msg = String.Format("{0}: type {1} not supported",
208 param.Name(), type.tag.ToString());
209 throw new Exception(msg);
211 break;
213 EmitPtrAndFlagsStore(ilg, bufLocal, i, ptr, flags);
216 //= (void)XPTC_InvokeByIndex(thisptr, desc.index, length, bufLocal);
217 ilg.Emit(OpCodes.Ldarg_0);
218 ilg.Emit(OpCodes.Ldfld, thisField);
219 ilg.Emit(OpCodes.Ldc_I4, desc.index);
220 ilg.Emit(OpCodes.Ldc_I4, args.Length);
221 ilg.Emit(OpCodes.Ldloc_0);
222 ilg.Emit(OpCodes.Call, typeof(Mozilla.XPCOM.Invoker).
223 GetMethod("XPTC_InvokeByIndex",
224 BindingFlags.Static | BindingFlags.NonPublic));
225 ilg.Emit(OpCodes.Pop);
227 if (ret == typeof(string)) {
228 ilg.Emit(OpCodes.Ldstr, "FAKE RETURN STRING");
229 } else if (ret == typeof(object)) {
230 ilg.Emit(OpCodes.Newobj,
231 typeof(object).GetConstructor(new Type[0]));
232 } else if (ret == typeof(int)) {
233 EmitLoadReturnSlot_1(ilg, bufLocal, args.Length);
234 } else if (ret == typeof(void)) {
235 // Nothing
236 } else {
237 throw new Exception(String.Format("return type {0} not " +
238 "supported yet",
239 desc.result.type.tag));
242 //= Marshal.FreeCoTaskMem(bufLocal);
243 ilg.Emit(OpCodes.Ldloc, bufLocal);
244 ilg.Emit(OpCodes.Call, marshalType.GetMethod("FreeCoTaskMem"));
246 ilg.Emit(OpCodes.Ret);
247 Console.WriteLine("$\t{0}", desc);
250 public static void Main(string[] args)
252 int res = StartXPCOM(out srvmgr);
254 if (res != 0) {
255 Console.WriteLine("StartXPCOM failed: {0:X2}", res);
256 return;
259 string ifaceName = args[0];
261 MethodDescriptor[] descs = TypeInfo.GetMethodData(ifaceName);
262 Console.WriteLine("Interface {0}:", ifaceName);
264 AssemblyName an = new AssemblyName();
265 an.Version = new Version(1, 0, 0, 0);
266 an.Name = "Mozilla.XPCOM.Interfaces." + ifaceName;
268 AppDomain currentDomain = AppDomain.CurrentDomain;
270 AssemblyBuilderAccess access;
271 if (args.Length > 1)
272 access = AssemblyBuilderAccess.RunAndSave;
273 else
274 access = AssemblyBuilderAccess.Run;
275 AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(an, access);
277 ModuleBuilder mb;
278 if (args.Length > 1)
279 mb = ab.DefineDynamicModule(an.Name, args[1]);
280 else
281 mb = ab.DefineDynamicModule(an.Name);
283 TypeBuilder ifaceTb = mb.DefineType(ifaceName, (TypeAttributes.Public |
284 TypeAttributes.Interface));
286 for (int i = 3; i < descs.Length; i++) {
287 GenerateInterfaceMethod(ifaceTb, descs[i]);
290 ifaceTb.CreateType();
292 TypeBuilder proxyTb = mb.DefineType(ifaceName + "$Proxy",
293 (TypeAttributes.Class),
294 typeof(object),
295 new Type[1] { ifaceTb } );
296 FieldBuilder thisField = proxyTb.DefineField("this", typeof(IntPtr),
297 FieldAttributes.Private);
298 EmitProxyConstructor(proxyTb, thisField);
300 for (int i = 3; i < descs.Length; i++) {
301 GenerateProxyMethod(proxyTb, descs[i], thisField);
304 if (args.Length > 1)
305 ab.Save(args[1]);
307 Type proxyType = proxyTb.CreateType();
308 Console.WriteLine("proxyType: {0}", proxyType);
309 ConstructorInfo proxyCtor =
310 proxyType.GetConstructor(new Type[1] { typeof(IntPtr) });
311 Console.WriteLine("proxyCtor: {0}", proxyCtor);
313 IntPtr impl = GetTestImpl();
314 Console.WriteLine("proxyThis: {0:X2}", impl.ToInt32());
315 object proxy = proxyCtor.Invoke(new object[] { impl });
317 MethodInfo proxyAdd = proxyType.GetMethod("add");
318 Console.WriteLine("proxyAdd: {0}", proxyAdd);
319 object proxyRet = proxyAdd.Invoke(proxy, new object[] { 3, 5 });
320 Console.WriteLine("proxyRet: {0}", (int)proxyRet);
322 MethodInfo proxySay = proxyType.GetMethod("say");
323 Console.WriteLine("proxySay: {0}", proxySay);
324 proxySay.Invoke(proxy, new object[] { "holy cow!" });
326 PropertyInfo proxyIntProp = proxyType.GetProperty("intProp");
327 Console.WriteLine("proxyIntProp: {0}", proxyIntProp);
328 Console.WriteLine("proxyIntProp(get): {0}",
329 proxyIntProp.GetValue(proxy, null));
330 proxyIntProp.SetValue(proxy, 31337, null);
331 Console.WriteLine("proxyIntProp(get): {0}",
332 proxyIntProp.GetValue(proxy, null));