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); } } }
Type Generate(Type superclass, ISeq interfaces, IPersistentMap attributes, string className) { // define the class List <Type> interfaceTypes = new List <Type> { typeof(IProxy) }; for (ISeq s = interfaces; s != null; s = s.next()) { interfaceTypes.Add((Type)s.first()); } TypeBuilder proxyTB = _context.ModuleBuilder.DefineType( className, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, superclass, interfaceTypes.ToArray()); GenInterface.SetCustomAttributes(proxyTB, attributes); DefineCtors(proxyTB, superclass); MaybeImplementISerializable(proxyTB, interfaceTypes); FieldBuilder mapField = AddIProxyMethods(proxyTB); HashSet <Type> allInterfaces = GetAllInterfaces(interfaces); HashSet <MethodBuilder> specialMethods = new HashSet <MethodBuilder>(); AddInterfaceMethods(proxyTB, mapField, superclass, allInterfaces, specialMethods); AddInterfaceProperties(proxyTB, superclass, allInterfaces, specialMethods); // Must follow AddInterfaceMethods Type t = proxyTB.CreateType(); //if (Compiler.IsCompiling) // SaveProxyContext(); return(t); }
public static Type GenerateClass(string className, Type superclass, ISeq interfaces, // of Types ISeq ctors, ISeq ctorTypes, ISeq methods, IPersistentMap exposesFields, IPersistentMap exposesMethods, string prefix, bool hasMain, string factoryName, string stateName, string initName, string postInitName, string implCname, string implNamespace, bool loadImplNamespace, IPersistentMap attributes) { className = className.Replace('-', '_'); string path = (string)Compiler.CompilePathVar.deref(); if (path == null) { throw new InvalidOperationException("*compile-path* not set"); } string extension = hasMain ? ".exe" : ".dll"; GenContext context = GenContext.CreateWithExternalAssembly(Compiler.munge(className), extension, true); // define the class List <Type> interfaceTypes = new List <Type>(); for (ISeq s = interfaces; s != null; s = s.next()) { interfaceTypes.Add((Type)s.first()); } TypeBuilder proxyTB = context.ModuleBuilder.DefineType( className, TypeAttributes.Class | TypeAttributes.Public, superclass, interfaceTypes.ToArray()); GenInterface.SetCustomAttributes(proxyTB, attributes); List <MethodSignature> sigs = GetAllSignatures(superclass, interfaceTypes, methods); Dictionary <string, List <MethodSignature> > overloads = ComputeOverloads(sigs); HashSet <string> varNames = ComputeOverloadNames(overloads); foreach (MethodSignature sig in sigs) { varNames.Add(sig.Name); } if (!String.IsNullOrEmpty(initName)) { varNames.Add(initName); } if (!String.IsNullOrEmpty(postInitName)) { varNames.Add(postInitName); } if (hasMain) { varNames.Add(_mainName); } Dictionary <string, FieldBuilder> varMap = DefineStaticFields(proxyTB, varNames); FieldBuilder stateFB = String.IsNullOrEmpty(stateName) ? null : DefineStateField(proxyTB, stateName); DefineStaticCtor(proxyTB, prefix, varMap, loadImplNamespace, implNamespace, implCname); varMap.TryGetValue(initName, out FieldBuilder initFB); varMap.TryGetValue(postInitName, out FieldBuilder postInitFB); varMap.TryGetValue(_mainName, out FieldBuilder mainFB); DefineCtors(proxyTB, superclass, implNamespace + "." + prefix + initName, implNamespace + "." + prefix + postInitName, ctors, ctorTypes, initFB, postInitFB, stateFB, factoryName); EmitMethods(proxyTB, sigs, overloads, varMap, exposesMethods); EmitExposers(proxyTB, superclass, exposesFields); if (hasMain) { EmitMain(context, proxyTB, implNamespace + "." + prefix + _mainName, mainFB); } Type t = proxyTB.CreateType(); context.SaveAssembly(); return(t); }
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); } } }