2 using System
.Runtime
.InteropServices
;
3 using System
.Reflection
;
4 using System
.Reflection
.Emit
;
6 using MethodDescriptor
= Mozilla
.XPCOM
.TypeInfo
.MethodDescriptor
;
7 using TypeTag
= Mozilla
.XPCOM
.TypeInfo
.TypeTag
;
8 using ParamFlags
= Mozilla
.XPCOM
.TypeInfo
.ParamFlags
;
12 [DllImport("xpcom-dotnet.so")]
13 static extern int StartXPCOM(out 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
);
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
,
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
,
71 EmitComputeBufferLoc(ilg
, bufLocal
, argnum
);
72 EmitLoadArg(ilg
, argnum
);
75 static void EmitLoadArg(ILGenerator ilg
, int argnum
)
79 ilg
.Emit(OpCodes
.Ldarg_1
);
82 ilg
.Emit(OpCodes
.Ldarg_2
);
85 ilg
.Emit(OpCodes
.Ldarg_3
);
89 ilg
.Emit(OpCodes
.Ldarg_S
, argnum
+ 1);
91 ilg
.Emit(OpCodes
.Ldarg
, argnum
+ 1);
96 static void EmitLoadReturnSlot_1(ILGenerator ilg
, LocalBuilder bufLocal
,
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
,
145 if (!desc
.IsVisible()) {
146 Console
.WriteLine("HIDDEN: {0}", desc
);
149 const MethodAttributes attrs
=
150 MethodAttributes
.Public
| MethodAttributes
.Virtual
;
151 Type ret
= desc
.resultType
;
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
;
175 EmitTypeStore(ilg
, bufLocal
, type
, i
);
177 if ((param
.flags
& ParamFlags
.Out
) != 0) {
178 EmitOutParamPrep(ilg
, bufLocal
, type
, i
);
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
);
195 EmitPrepareArgStore(ilg
, bufLocal
, i
);
196 ilg
.Emit(OpCodes
.Stind_I4
);
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
);
207 String msg = String.Format("{0}: type {1} not supported",
208 param.Name(), type.tag.ToString());
209 throw new Exception(msg);
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)) {
237 throw new Exception(String
.Format("return type {0} not " +
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
);
255 Console
.WriteLine("StartXPCOM failed: {0:X2}", res
);
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
;
272 access
= AssemblyBuilderAccess
.RunAndSave
;
274 access
= AssemblyBuilderAccess
.Run
;
275 AssemblyBuilder ab
= currentDomain
.DefineDynamicAssembly(an
, access
);
279 mb
= ab
.DefineDynamicModule(an
.Name
, args
[1]);
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
),
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
);
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));