// Return the assembly locations that need to be verified private string[] SaveAssemblies() { if (!SaveSnippets) { return(new string[0]); } List <string> assemlyLocations = new List <string>(); // first save all assemblies to disk: if (_assembly != null) { string assemblyLocation = _assembly.SaveAssembly(); if (assemblyLocation != null) { assemlyLocations.Add(assemblyLocation); } _assembly = null; } if (_debugAssembly != null) { string debugAssemblyLocation = _debugAssembly.SaveAssembly(); if (debugAssemblyLocation != null) { assemlyLocations.Add(debugAssemblyLocation); } _debugAssembly = null; } return(assemlyLocations.ToArray()); }
/// <summary> /// This takes an assembly name including extension and saves the provided ScriptCode objects into the assembly. /// /// The provided script codes can constitute code from multiple languages. The assemblyName can be either a fully qualified /// or a relative path. The DLR will simply save the assembly to the desired location. The assembly is created by the DLR and /// if a file already exists than an exception is raised. /// /// The DLR determines the internal format of the ScriptCode and the DLR can feel free to rev this as appropriate. /// </summary> public static void SaveToAssembly(string assemblyName, params SavableScriptCode[] codes) { ContractUtils.RequiresNotNull(assemblyName, "assemblyName"); ContractUtils.RequiresNotNullItems(codes, "codes"); // break the assemblyName into it's dir/name/extension string dir = Path.GetDirectoryName(assemblyName); if (String.IsNullOrEmpty(dir)) { dir = Environment.CurrentDirectory; } string name = Path.GetFileNameWithoutExtension(assemblyName); string ext = Path.GetExtension(assemblyName); // build the assembly & type gen that all the script codes will live in... AssemblyGen ag = new AssemblyGen(new AssemblyName(name), dir, ext, /*emitSymbols*/false); TypeBuilder tb = ag.DefinePublicType("DLRCachedCode", typeof(object), true); TypeGen tg = new TypeGen(ag, tb); var symbolDict = new Dictionary<SymbolId, FieldBuilder>(); // then compile all of the code Dictionary<Type, List<CodeInfo>> langCtxBuilders = new Dictionary<Type, List<CodeInfo>>(); foreach (SavableScriptCode sc in codes) { List<CodeInfo> builders; if (!langCtxBuilders.TryGetValue(sc.LanguageContext.GetType(), out builders)) { langCtxBuilders[sc.LanguageContext.GetType()] = builders = new List<CodeInfo>(); } KeyValuePair<MethodBuilder, Type> compInfo = sc.CompileForSave(tg, symbolDict); builders.Add(new CodeInfo(compInfo.Key, sc, compInfo.Value)); } MethodBuilder mb = tb.DefineMethod( "GetScriptCodeInfo", MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.Static, typeof(MutableTuple<Type[], Delegate[][], string[][], string[][]>), Type.EmptyTypes); ILGen ilgen = new ILGen(mb.GetILGenerator()); var langsWithBuilders = langCtxBuilders.ToArray(); // lang ctx array ilgen.EmitArray(typeof(Type), langsWithBuilders.Length, (index) => { ilgen.Emit(OpCodes.Ldtoken, langsWithBuilders[index].Key); ilgen.EmitCall(typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) })); }); // builders array of array ilgen.EmitArray(typeof(Delegate[]), langsWithBuilders.Length, (index) => { List<CodeInfo> builders = langsWithBuilders[index].Value; ilgen.EmitArray(typeof(Delegate), builders.Count, (innerIndex) => { ilgen.EmitNull(); ilgen.Emit(OpCodes.Ldftn, builders[innerIndex].Builder); ilgen.EmitNew( builders[innerIndex].DelegateType, new[] { typeof(object), typeof(IntPtr) } ); }); }); // paths array of array ilgen.EmitArray(typeof(string[]), langsWithBuilders.Length, (index) => { List<CodeInfo> builders = langsWithBuilders[index].Value; ilgen.EmitArray(typeof(string), builders.Count, (innerIndex) => { ilgen.EmitString(builders[innerIndex].Code.SourceUnit.Path); }); }); // 4th element in tuple - custom per-language data ilgen.EmitArray(typeof(string[]), langsWithBuilders.Length, (index) => { List<CodeInfo> builders = langsWithBuilders[index].Value; ilgen.EmitArray(typeof(string), builders.Count, (innerIndex) => { ICustomScriptCodeData data = builders[innerIndex].Code as ICustomScriptCodeData; if (data != null) { ilgen.EmitString(data.GetCustomScriptCodeData()); } else { ilgen.Emit(OpCodes.Ldnull); } }); }); ilgen.EmitNew( typeof(MutableTuple<Type[], Delegate[][], string[][], string[][]>), new[] { typeof(Type[]), typeof(Delegate[][]), typeof(string[][]), typeof(string[][]) } ); ilgen.Emit(OpCodes.Ret); mb.SetCustomAttribute(new CustomAttributeBuilder( typeof(DlrCachedCodeAttribute).GetConstructor(Type.EmptyTypes), ArrayUtils.EmptyObjects )); tg.FinishType(); ag.SaveAssembly(); }
public static void SaveNewTypes(string assemblyName, IList<PythonTuple> types) { Assert.NotNull(assemblyName, types); AssemblyGen ag = new AssemblyGen(new AssemblyName(assemblyName), ".", ".dll", false); TypeBuilder tb = ag.DefinePublicType(_constructorTypeName, typeof(object), true); tb.SetCustomAttribute(typeof(PythonCachedTypeInfoAttribute).GetConstructor(Type.EmptyTypes), new byte[0]); MethodBuilder mb = tb.DefineMethod(_constructorMethodName, MethodAttributes.Public | MethodAttributes.Static, typeof(CachedNewTypeInfo[]), Type.EmptyTypes); ILGenerator ilg = mb.GetILGenerator(); // new CachedTypeInfo[types.Count] // we leave this on the stack (duping it) and storing into it. EmitInt(ilg, types.Count); ilg.Emit(OpCodes.Newarr, typeof(CachedNewTypeInfo)); int curType = 0; foreach (var v in types) { NewTypeInfo nti = NewTypeInfo.GetTypeInfo(String.Empty, v); var typeInfos = new NewTypeMaker(nti).SaveType(ag, "Python" + _typeCount++ + "$" + nti.BaseType.Name); // prepare for storing the element into our final array ilg.Emit(OpCodes.Dup); EmitInt(ilg, curType++); // new CachedNewTypeInfo(type, specialNames, interfaceTypes): // load the type ilg.Emit(OpCodes.Ldtoken, typeInfos.Key); ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // create the dictionary<str, str[]> of special names ilg.Emit(OpCodes.Newobj, typeof(Dictionary<string, string[]>).GetConstructor(new Type[0])); foreach (var specialName in typeInfos.Value) { // dup dict ilg.Emit(OpCodes.Dup); // emit key ilg.Emit(OpCodes.Ldstr, specialName.Key); // emit value int iVal = specialName.Value.Length; EmitInt(ilg, iVal); ilg.Emit(OpCodes.Newarr, typeof(string)); for (int i = 0; i < specialName.Value.Length; i++) { ilg.Emit(OpCodes.Dup); EmitInt(ilg, i); ilg.Emit(OpCodes.Ldstr, specialName.Value[0]); ilg.Emit(OpCodes.Stelem_Ref); } // assign to dict ilg.Emit(OpCodes.Call, typeof(Dictionary<string, string[]>).GetMethod("set_Item")); } // emit the interface types (if any) if (nti.InterfaceTypes.Count != 0) { EmitInt(ilg, nti.InterfaceTypes.Count); ilg.Emit(OpCodes.Newarr, typeof(Type)); for (int i = 0; i < nti.InterfaceTypes.Count; i++) { ilg.Emit(OpCodes.Dup); EmitInt(ilg, i); ilg.Emit(OpCodes.Ldtoken, nti.InterfaceTypes[i]); ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); ilg.Emit(OpCodes.Stelem_Ref); } } else { ilg.Emit(OpCodes.Ldnull); } // crated the CachedNewTypeInfo and store it in the array ilg.Emit(OpCodes.Newobj, typeof(CachedNewTypeInfo).GetConstructors()[0]); ilg.Emit(OpCodes.Stelem_Ref); } ilg.Emit(OpCodes.Ret); tb.CreateType(); ag.SaveAssembly(); }