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
;
10 namespace Mozilla
.XPCOM
13 public class BaseProxy
15 protected IntPtr thisptr
;
16 protected BaseProxy(IntPtr ptr
) { thisptr = ptr; }
21 void EmitPtrAndFlagsStore(int argnum
, IntPtr ptr
, sbyte flags
)
23 //= bufLocal[argnum].ptr = ptr;
24 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
25 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 8);
26 ilg
.Emit(OpCodes
.Add
);
27 ilg
.Emit(OpCodes
.Ldc_I4
, ptr
.ToInt32());
28 ilg
.Emit(OpCodes
.Stind_I4
);
30 //= bufLocal[argnum].flags = flags;
31 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
32 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 13);
33 ilg
.Emit(OpCodes
.Add
);
34 ilg
.Emit(OpCodes
.Ldc_I4
, (Int32
)flags
);
35 ilg
.Emit(OpCodes
.Stind_I1
);
38 void EmitTypeStore(TypeInfo
.TypeDescriptor t
, int argnum
)
40 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
41 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 12);
42 ilg
.Emit(OpCodes
.Add
);
43 ilg
.Emit(OpCodes
.Ldc_I4
, (Int32
)t
.tag
);
44 ilg
.Emit(OpCodes
.Stind_I4
);
47 void EmitComputeBufferLoc(int argnum
)
49 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
50 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
);
51 ilg
.Emit(OpCodes
.Add
);
54 void EmitPrepareArgStore(int argnum
)
56 EmitComputeBufferLoc(argnum
);
60 void EmitLoadArg(int argnum
)
64 ilg
.Emit(OpCodes
.Ldarg_1
);
67 ilg
.Emit(OpCodes
.Ldarg_2
);
70 ilg
.Emit(OpCodes
.Ldarg_3
);
74 ilg
.Emit(OpCodes
.Ldarg_S
, argnum
+ 1);
76 ilg
.Emit(OpCodes
.Ldarg
, argnum
+ 1);
81 void EmitLoadReturnSlot_1(int slotnum
)
83 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
84 ilg
.Emit(OpCodes
.Ldc_I4
, (slotnum
- 1) * VARIANT_SIZE
);
85 ilg
.Emit(OpCodes
.Add
);
86 ilg
.Emit(OpCodes
.Ldind_I4
);
89 void EmitOutParamPrep(TypeInfo
.TypeDescriptor type
, int argnum
)
91 ilg
.Emit(OpCodes
.Nop
);
92 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
93 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 13);
94 ilg
.Emit(OpCodes
.Add
);
95 ilg
.Emit(OpCodes
.Ldc_I4
, 1); // PTR_IS_DATA
96 ilg
.Emit(OpCodes
.Stind_I1
);
98 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
99 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 8); // offsetof(ptr)
100 ilg
.Emit(OpCodes
.Add
);
101 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
102 ilg
.Emit(OpCodes
.Ldc_I4
, argnum
* VARIANT_SIZE
+ 0); // offsetof(val)
103 ilg
.Emit(OpCodes
.Add
);
104 ilg
.Emit(OpCodes
.Stind_I4
); /* XXX 64-bitness! */
107 void EmitProxyConstructor()
109 ConstructorBuilder ctor
=
110 tb
.DefineConstructor(MethodAttributes
.Family
,
111 CallingConventions
.Standard
,
112 new Type
[1] { typeof(IntPtr) }
);
113 ILGenerator ilg
= ctor
.GetILGenerator();
114 ilg
.Emit(OpCodes
.Ldarg_0
);
115 ilg
.Emit(OpCodes
.Ldarg_1
);
116 ilg
.Emit(OpCodes
.Call
, baseProxyCtor
);
117 ilg
.Emit(OpCodes
.Ret
);
120 const int VARIANT_SIZE
= 16; // sizeof(XPTCVariant)
122 const PropertyAttributes PROPERTY_ATTRS
= PropertyAttributes
.None
;
124 PropertyBuilder lastProperty
;
126 Type
FixupInterfaceType(TypeInfo
.ParamDescriptor desc
)
129 return TypeInfo
.TypeForIID(desc
.GetIID());
130 } catch (Exception e
) {
131 // Console.WriteLine(e);
132 return typeof(object);
136 unsafe void GenerateProxyMethod(MethodDescriptor desc
)
138 if (!desc
.IsVisible()) {
139 Console
.WriteLine("HIDDEN: {0}", desc
);
142 MethodAttributes methodAttrs
=
143 MethodAttributes
.Public
| MethodAttributes
.Virtual
;
145 String methodName
= desc
.name
;
146 if (desc
.IsGetter()) {
147 methodName
= "get_" + desc
.name
;
148 methodAttrs
|= MethodAttributes
.SpecialName
;
149 } else if (desc
.IsSetter()) {
150 methodName
= "set_" + desc
.name
;
151 methodAttrs
|= MethodAttributes
.SpecialName
;
154 // Fix up interface types in parameters
155 Type ret
= desc
.resultType
;
156 if (ret
== typeof(object))
157 ret
= FixupInterfaceType(desc
.args
[desc
.args
.Length
- 1]);
158 Type
[] argTypes
= (Type
[])desc
.argTypes
.Clone();
159 for (int i
= 0; i
< argTypes
.Length
; i
++) {
160 if (argTypes
[i
] == typeof(object))
161 argTypes
[i
] = FixupInterfaceType(desc
.args
[i
]);
163 MethodBuilder meth
= tb
.DefineMethod(methodName
, methodAttrs
, ret
, argTypes
);
165 ilg
= meth
.GetILGenerator();
166 bufLocal
= ilg
.DeclareLocal(System
.Type
.GetType("System.Int32*"));
167 LocalBuilder guidLocal
= ilg
.DeclareLocal(typeof(System
.Guid
));
168 TypeInfo
.ParamDescriptor
[] args
= desc
.args
;
170 Type marshalType
= typeof(System
.Runtime
.InteropServices
.Marshal
);
172 // Marshal.AllocCoTaskMem(constify(argBufSize))
173 int argCount
= args
.Length
;
174 int argBufSize
= VARIANT_SIZE
* args
.Length
;
176 ilg
.Emit(OpCodes
.Ldc_I4
, argBufSize
);
177 ilg
.Emit(OpCodes
.Call
, marshalType
.GetMethod("AllocCoTaskMem"));
178 ilg
.Emit(OpCodes
.Stloc
, bufLocal
);
180 for (int i
= 0; i
< argCount
; i
++) {
181 TypeInfo
.ParamDescriptor param
= args
[i
];
182 TypeInfo
.TypeDescriptor type
= param
.type
;
183 IntPtr ptr
= IntPtr
.Zero
;
185 EmitTypeStore(type
, i
);
188 EmitOutParamPrep(type
, i
);
200 EmitPrepareArgStore(i
);
201 // XXX do I need to cast this?
202 ilg
.Emit(OpCodes
.Castclass
, typeof(Int32
));
203 ilg
.Emit(OpCodes
.Stind_I4
);
206 EmitPrepareArgStore(i
);
207 ilg
.Emit(OpCodes
.Stind_I4
);
209 case TypeTag
.NSIdPtr
:
210 EmitPrepareArgStore(i
);
211 ilg
.Emit(OpCodes
.Stind_I4
); // XXX 64-bitness
214 EmitPrepareArgStore(i
);
215 // the string arg is now on the stack
216 ilg
.Emit(OpCodes
.Call
,
217 marshalType
.GetMethod("StringToCoTaskMemAnsi"));
218 ilg
.Emit(OpCodes
.Stind_I4
);
220 case TypeTag
.Interface
:
221 EmitPrepareArgStore(i
);
222 // MRP is the object passed as this arg
223 ilg
.Emit(OpCodes
.Ldloca_S
, guidLocal
);
224 ilg
.Emit(OpCodes
.Ldstr
, param
.GetIID().ToString());
225 ilg
.Emit(OpCodes
.Call
, guidCtor
);
226 ilg
.Emit(OpCodes
.Ldloca_S
, guidLocal
);
227 // stack is now objarg, ref guid
228 ilg
.Emit(OpCodes
.Call
, typeof(CLRWrapper
).GetMethod("Wrap"));
229 // now stack has the IntPtr in position to be stored.
230 ilg
.Emit(OpCodes
.Stind_I4
);
234 String msg = String.Format("{0}: type {1} not supported",
235 param.Name(), type.tag.ToString());
236 throw new Exception(msg);
240 EmitPtrAndFlagsStore(i
, ptr
, flags
);
243 //= (void)XPTC_InvokeByIndex(thisptr, desc.index, length, bufLocal);
244 ilg
.Emit(OpCodes
.Ldarg_0
);
245 ilg
.Emit(OpCodes
.Ldfld
, thisField
);
246 ilg
.Emit(OpCodes
.Ldc_I4
, desc
.index
);
247 ilg
.Emit(OpCodes
.Ldc_I4
, args
.Length
);
248 ilg
.Emit(OpCodes
.Ldloc_0
);
249 ilg
.Emit(OpCodes
.Call
, typeof(Mozilla
.XPCOM
.Invoker
).
250 GetMethod("XPTC_InvokeByIndex",
251 BindingFlags
.Static
| BindingFlags
.NonPublic
));
252 ilg
.Emit(OpCodes
.Pop
);
254 if (ret
== typeof(string)) {
255 ilg
.Emit(OpCodes
.Ldstr
, "FAKE RETURN STRING");
256 } else if (ret
== typeof(object)) {
257 ilg
.Emit(OpCodes
.Newobj
,
258 typeof(object).GetConstructor(new Type
[0]));
259 } else if (ret
== typeof(int)) {
260 EmitLoadReturnSlot_1(args
.Length
);
261 } else if (ret
== typeof(void)) {
264 throw new Exception(String
.Format("return type {0} not " +
266 desc
.result
.type
.tag
));
269 //= Marshal.FreeCoTaskMem(bufLocal);
270 ilg
.Emit(OpCodes
.Ldloc
, bufLocal
);
271 ilg
.Emit(OpCodes
.Call
, marshalType
.GetMethod("FreeCoTaskMem"));
273 ilg
.Emit(OpCodes
.Ret
);
278 if (desc
.IsSetter()) {
279 if (lastProperty
!= null && lastProperty
.Name
== desc
.name
) {
280 lastProperty
.SetSetMethod(meth
);
282 tb
.DefineProperty(desc
.name
, PROPERTY_ATTRS
, desc
.resultType
,
283 new Type
[0]).SetSetMethod(meth
);
286 } else if (desc
.IsGetter()) {
287 lastProperty
= tb
.DefineProperty(desc
.name
, PROPERTY_ATTRS
,
288 desc
.resultType
, new Type
[0]);
289 lastProperty
.SetGetMethod(meth
);
296 static ModuleBuilder module
;
297 static AssemblyBuilder builder
;
298 static ConstructorInfo baseProxyCtor
;
299 static ConstructorInfo guidCtor
;
301 internal static AssemblyBuilder ProxyAssembly
{
302 get { return builder; }
305 static ProxyGenerator()
307 AssemblyName an
= new AssemblyName();
308 an
.Version
= new Version(1, 0, 0, 0);
309 an
.Name
= "Mozilla.XPCOM.Proxies";
311 AppDomain curDom
= AppDomain
.CurrentDomain
;
312 builder
= curDom
.DefineDynamicAssembly(an
, AssemblyBuilderAccess
.RunAndSave
);
315 System
.Environment
.GetEnvironmentVariable("XPCOM_DOTNET_SAVE_PROXIES");
316 if (proxyDll
!= null) {
317 module
= builder
.DefineDynamicModule(an
.Name
, proxyDll
);
319 module
= builder
.DefineDynamicModule(an
.Name
);
322 baseProxyCtor
= typeof(BaseProxy
).
323 GetConstructor(BindingFlags
.NonPublic
| BindingFlags
.Instance
,
324 null, new Type
[1] { typeof(IntPtr) }
, null);
325 guidCtor
= typeof(System
.Guid
).
326 GetConstructor(new Type
[1] {typeof(string)}
);
331 LocalBuilder bufLocal
;
336 internal ProxyGenerator(String name
)
341 internal Assembly
Generate()
343 if (module
.GetType(proxyName
) != null)
344 return module
.Assembly
;
346 String baseIfaceName
= proxyName
.Replace("Mozilla.XPCOM.Proxies.", "");
347 String ifaceName
= "Mozilla.XPCOM.Interfaces." + baseIfaceName
;
349 Type ifaceType
= System
.Type
.GetType(ifaceName
+
350 ",Mozilla.XPCOM.Interfaces", true);
352 ushort inheritedMethodCount
;
353 String parentName
= TypeInfo
.GetParentInfo(baseIfaceName
,
354 out inheritedMethodCount
);
357 if (parentName
== null) {
358 parentType
= typeof(BaseProxy
);
360 parentType
= System
.Type
.GetType("Mozilla.XPCOM.Proxies." +
362 ",Mozilla.XPCOM.Proxies");
365 Console
.WriteLine("Defining {0} (inherits {1}, impls {2})",
366 proxyName
, parentType
, ifaceName
);
367 tb
= module
.DefineType(proxyName
, TypeAttributes
.Class
, parentType
,
368 new Type
[1] { ifaceType }
);
370 thisField
= typeof(BaseProxy
).GetField("thisptr",
371 BindingFlags
.NonPublic
|
372 BindingFlags
.Instance
);
374 EmitProxyConstructor();
376 MethodDescriptor
[] descs
= TypeInfo
.GetMethodData(baseIfaceName
);
378 for (int i
= inheritedMethodCount
; i
< descs
.Length
; i
++) {
379 if (descs
[i
] != null)
380 GenerateProxyMethod(descs
[i
]);
388 return module
.Assembly
;