private static void DefineMethod(TypeBuilder proxyTB, IPersistentVector sig) { Symbol mname = (Symbol)sig.nth(0); Type[] paramTypes = GenClass.CreateTypeArray((ISeq)sig.nth(1)); Type retType = (Type)sig.nth(2); ISeq pmetas = (ISeq)(sig.count() >= 4 ? sig.nth(3) : null); MethodBuilder mb = proxyTB.DefineMethod(mname.Name, MethodAttributes.Abstract | MethodAttributes.Public | MethodAttributes.Virtual, retType, paramTypes); SetCustomAttributes(mb, GenInterface.ExtractAttributes(RT.meta(mname))); int i = 1; for (ISeq s = pmetas; s != null; s = s.next(), i++) { IPersistentMap meta = GenInterface.ExtractAttributes((IPersistentMap)s.first()); if (meta != null && meta.count() > 0) { ParameterBuilder pb = mb.DefineParameter(i, ParameterAttributes.None, String.Format("p_{0}", i)); GenInterface.SetCustomAttributes(pb, meta); } } }
static void DefineCtors(TypeBuilder proxyTB, Type superClass, string initName, string postInitName, ISeq ctors, ISeq ctorTypes, FieldBuilder initFB, FieldBuilder postInitFB, FieldBuilder stateFB, string factoryName) { ISeq s1 = ctors; for (ISeq s = ctorTypes; s != null; s = s.next()) { // TODO: Get rid of this mess by making sure the metadata on the keys of the constructors map gets copied to the constructor-types map. Sigh. IPersistentMap ctorAttributes = GenInterface.ExtractAttributes(RT.meta(((IMapEntry)s1.first()).key())); s1 = s1.next(); IMapEntry me = (IMapEntry)s.first(); ISeq thisParamTypesV = (ISeq)me.key(); ISeq baseParamTypesV = (ISeq)me.val(); Type[] thisParamTypes = CreateTypeArray(thisParamTypesV); Type[] baseParamTypes = CreateTypeArray(baseParamTypesV); BindingFlags flags = BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; ConstructorInfo superCtor = superClass.GetConstructor(flags, null, baseParamTypes, null); if (superCtor == null || superCtor.IsPrivate) { throw new InvalidOperationException("Base class constructor missing or private"); } ConstructorBuilder cb = proxyTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, thisParamTypes); GenInterface.SetCustomAttributes(cb, ctorAttributes); CljILGen gen = new CljILGen(cb.GetILGenerator()); Label noInitLabel = gen.DefineLabel(); Label noPostInitLabel = gen.DefineLabel(); Label endPostInitLabel = gen.DefineLabel(); Label endLabel = gen.DefineLabel(); LocalBuilder locSuperArgs = gen.DeclareLocal(typeof(object)); LocalBuilder locInitVal = gen.DeclareLocal(typeof(object)); if (initFB != null) { // init supplied EmitGetVar(gen, initFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, noInitLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); // box init args for (int i = 0; i < thisParamTypes.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (thisParamTypes[i].IsValueType) { gen.Emit(OpCodes.Box, thisParamTypes[i]); } } gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length]); // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length]); // Expecting: [[super-ctor-args...] state] // store the init return in a local gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Stloc, locInitVal); // store the first element in a local gen.EmitInt(0); // gen.Emit(OpCodes.Ldc_I4_0); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); gen.Emit(OpCodes.Stloc, locSuperArgs); // Stack this + super-ctor-args + call base-class ctor. gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < baseParamTypes.Length; i++) { gen.Emit(OpCodes.Ldloc, locSuperArgs); gen.EmitInt(i); // gen.Emit(OpCodes.Ldc_I4, i); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); if (baseParamTypes[i].IsValueType) { gen.Emit(OpCodes.Unbox_Any, baseParamTypes[i]); } else { gen.Emit(OpCodes.Castclass, baseParamTypes[i]); } } gen.Emit(OpCodes.Call, superCtor); if (stateFB != null) { gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldloc, locInitVal); gen.EmitInt(1); // gen.Emit(OpCodes.Ldc_I4_1); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); gen.Emit(OpCodes.Castclass, typeof(object)); gen.EmitFieldSet(stateFB); // gen.Emit(OpCodes.Stfld, stateFB); } gen.Emit(OpCodes.Br_S, endLabel); // No init found gen.MarkLabel(noInitLabel); gen.Emit(OpCodes.Pop); EmitUnsupported(gen, initName); gen.MarkLabel(endLabel); } else // no InitFB supplied. { bool ok = thisParamTypes.Length == baseParamTypes.Length; for (int i = 0; ok && i < thisParamTypes.Length; i++) { ok = baseParamTypes[i].IsAssignableFrom(thisParamTypes[i]); } if (!ok) { throw new InvalidOperationException(":init not specified, but ctor and super ctor args differ"); } gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < thisParamTypes.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (baseParamTypes[i] != thisParamTypes[i]) { gen.Emit(OpCodes.Castclass, baseParamTypes[i]); } } gen.Emit(OpCodes.Call, superCtor); } if (postInitFB != null) { // post-init supplied EmitGetVar(gen, postInitFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, noPostInitLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); // box init args gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < thisParamTypes.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (thisParamTypes[i].IsValueType) { gen.Emit(OpCodes.Box, thisParamTypes[i]); } gen.Emit(OpCodes.Castclass, thisParamTypes[i]); } gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]); // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]); gen.Emit(OpCodes.Pop); gen.Emit(OpCodes.Br_S, endPostInitLabel); // no post-init found gen.MarkLabel(noPostInitLabel); gen.Emit(OpCodes.Pop); EmitUnsupported(gen, postInitName + " not defined"); gen.MarkLabel(endPostInitLabel); } gen.Emit(OpCodes.Ret); if (!String.IsNullOrEmpty(factoryName)) { MethodBuilder factoryMB = proxyTB.DefineMethod(factoryName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, proxyTB, thisParamTypes); CljILGen genf = new CljILGen(factoryMB.GetILGenerator()); LocalBuilder[] locals = new LocalBuilder[thisParamTypes.Length]; for (int i = 0; i < thisParamTypes.Length; i++) { locals[i] = genf.DeclareLocal(thisParamTypes[i]); genf.EmitLoadArg(i); // genf.Emit(OpCodes.Ldarg, i); genf.Emit(OpCodes.Stloc, locals[i]); } for (int i = 0; i < thisParamTypes.Length; i++) { genf.EmitLoadArg(i); // genf.Emit(OpCodes.Ldarg, i); } genf.EmitNew(cb); // genf.Emit(OpCodes.Newobj, cb); genf.Emit(OpCodes.Ret); } } }