void EmitTypeStore(TypeInfo.TypeDescriptor t, int argnum) { ilg.Emit(OpCodes.Ldloc, bufLocal); ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 12); ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Ldc_I4, (Int32)t.tag); ilg.Emit(OpCodes.Stind_I4); }
void EmitOutParamPrep(TypeInfo.TypeDescriptor type, int argnum) { ilg.Emit(OpCodes.Nop); ilg.Emit(OpCodes.Ldloc, bufLocal); ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 13); ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Ldc_I4, 1); // PTR_IS_DATA ilg.Emit(OpCodes.Stind_I1); ilg.Emit(OpCodes.Ldloc, bufLocal); ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 8); // offsetof(ptr) ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Ldloc, bufLocal); ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 0); // offsetof(val) ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Stind_I4); /* XXX 64-bitness! */ }
unsafe void GenerateProxyMethod(MethodDescriptor desc) { if (!desc.IsVisible()) { Console.WriteLine("HIDDEN: {0}", desc); return; } MethodAttributes methodAttrs = MethodAttributes.Public | MethodAttributes.Virtual; String methodName = desc.name; if (desc.IsGetter()) { methodName = "get_" + desc.name; methodAttrs |= MethodAttributes.SpecialName; } else if (desc.IsSetter()) { methodName = "set_" + desc.name; methodAttrs |= MethodAttributes.SpecialName; } // Fix up interface types in parameters Type ret = desc.resultType; if (ret == typeof(object)) { ret = FixupInterfaceType(desc.args[desc.args.Length - 1]); } Type[] argTypes = (Type[])desc.argTypes.Clone(); for (int i = 0; i < argTypes.Length; i++) { if (argTypes[i] == typeof(object)) { argTypes[i] = FixupInterfaceType(desc.args[i]); } } MethodBuilder meth = tb.DefineMethod(methodName, methodAttrs, ret, argTypes); ilg = meth.GetILGenerator(); bufLocal = ilg.DeclareLocal(System.Type.GetType("System.Int32*")); LocalBuilder guidLocal = ilg.DeclareLocal(typeof(System.Guid)); TypeInfo.ParamDescriptor[] args = desc.args; Type marshalType = typeof(System.Runtime.InteropServices.Marshal); // Marshal.AllocCoTaskMem(constify(argBufSize)) int argCount = args.Length; int argBufSize = VARIANT_SIZE * args.Length; ilg.Emit(OpCodes.Ldc_I4, argBufSize); ilg.Emit(OpCodes.Call, marshalType.GetMethod("AllocCoTaskMem")); ilg.Emit(OpCodes.Stloc, bufLocal); for (int i = 0; i < argCount; i++) { TypeInfo.ParamDescriptor param = args[i]; TypeInfo.TypeDescriptor type = param.type; IntPtr ptr = IntPtr.Zero; sbyte flags = 0; EmitTypeStore(type, i); if (param.IsOut()) { EmitOutParamPrep(type, i); if (!param.IsIn()) { continue; } } switch (type.tag) { case TypeTag.Int8: case TypeTag.Int16: case TypeTag.UInt8: case TypeTag.UInt16: case TypeTag.Char: case TypeTag.WChar: case TypeTag.UInt32: EmitPrepareArgStore(i); // XXX do I need to cast this? ilg.Emit(OpCodes.Castclass, typeof(Int32)); ilg.Emit(OpCodes.Stind_I4); break; case TypeTag.Int32: EmitPrepareArgStore(i); ilg.Emit(OpCodes.Stind_I4); break; case TypeTag.NSIdPtr: EmitPrepareArgStore(i); ilg.Emit(OpCodes.Stind_I4); // XXX 64-bitness break; case TypeTag.String: EmitPrepareArgStore(i); // the string arg is now on the stack ilg.Emit(OpCodes.Call, marshalType.GetMethod("StringToCoTaskMemAnsi")); ilg.Emit(OpCodes.Stind_I4); break; case TypeTag.Interface: EmitPrepareArgStore(i); // MRP is the object passed as this arg ilg.Emit(OpCodes.Ldloca_S, guidLocal); ilg.Emit(OpCodes.Ldstr, param.GetIID().ToString()); ilg.Emit(OpCodes.Call, guidCtor); ilg.Emit(OpCodes.Ldloca_S, guidLocal); // stack is now objarg, ref guid ilg.Emit(OpCodes.Call, typeof(CLRWrapper).GetMethod("Wrap")); // now stack has the IntPtr in position to be stored. ilg.Emit(OpCodes.Stind_I4); break; default: /* * String msg = String.Format("{0}: type {1} not supported", * param.Name(), type.tag.ToString()); * throw new Exception(msg); */ break; } EmitPtrAndFlagsStore(i, ptr, flags); } //= (void)XPTC_InvokeByIndex(thisptr, desc.index, length, bufLocal); ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Ldfld, thisField); ilg.Emit(OpCodes.Ldc_I4, desc.index); ilg.Emit(OpCodes.Ldc_I4, args.Length); ilg.Emit(OpCodes.Ldloc_0); ilg.Emit(OpCodes.Call, typeof(Mozilla.XPCOM.Invoker). GetMethod("XPTC_InvokeByIndex", BindingFlags.Static | BindingFlags.NonPublic)); ilg.Emit(OpCodes.Pop); if (ret == typeof(string)) { ilg.Emit(OpCodes.Ldstr, "FAKE RETURN STRING"); } else if (ret == typeof(object)) { ilg.Emit(OpCodes.Newobj, typeof(object).GetConstructor(new Type[0])); } else if (ret == typeof(int)) { EmitLoadReturnSlot_1(args.Length); } else if (ret == typeof(void)) { // Nothing } else { throw new Exception(String.Format("return type {0} not " + "supported yet", desc.result.type.tag)); } //= Marshal.FreeCoTaskMem(bufLocal); ilg.Emit(OpCodes.Ldloc, bufLocal); ilg.Emit(OpCodes.Call, marshalType.GetMethod("FreeCoTaskMem")); ilg.Emit(OpCodes.Ret); ilg = null; bufLocal = null; if (desc.IsSetter()) { if (lastProperty != null && lastProperty.Name == desc.name) { lastProperty.SetSetMethod(meth); } else { tb.DefineProperty(desc.name, PROPERTY_ATTRS, desc.resultType, new Type[0]).SetSetMethod(meth); } lastProperty = null; } else if (desc.IsGetter()) { lastProperty = tb.DefineProperty(desc.name, PROPERTY_ATTRS, desc.resultType, new Type[0]); lastProperty.SetGetMethod(meth); } else { lastProperty = null; } }