private void GenerateAssemblyLookup(ModuleBuilder module) { if (_embeddedAssemblies.Count == 0) { return; } foreach (Assembly ass in _embeddedAssemblies) { string shortname = ass.FullName.Substring(0, ass.FullName.IndexOf(",")); string tempfile = Path.GetTempFileName(); File.Copy(new Uri(ass.EscapedCodeBase).LocalPath, tempfile, true); MemoryStream ms = new MemoryStream(File.ReadAllBytes(tempfile)); ms.Seek(0, SeekOrigin.Begin); module.DefineManifestResource(shortname, ms, ResourceAttributes.Public); File.Delete(tempfile); } MethodBuilder resolveAssemblyMethod = module.DefineGlobalMethod("ResolveAssembly", MethodAttributes.Public | MethodAttributes.Static, typeof(Assembly), new Type[] { typeof(object), typeof(System.ResolveEventArgs) }); ILGenerator ilResolve = resolveAssemblyMethod.GetILGenerator(); CompileContext resolvecontext = new CompileContext(); resolvecontext.PushIL(ilResolve); LocalBuilder localStream = ilResolve.DeclareLocal(typeof(Stream)); LocalBuilder localBuf = ilResolve.DeclareLocal(typeof(byte[])); LocalBuilder localName = ilResolve.DeclareLocal(typeof(string)); ilResolve.Emit(OpCodes.Ldarg_1); ilResolve.Emit(OpCodes.Call, typeof(ResolveEventArgs).GetMethod("get_Name")); ilResolve.Emit(OpCodes.Stloc, localName); ilResolve.Emit(OpCodes.Ldloc, localName); ilResolve.Emit(OpCodes.Ldc_I4_0); ilResolve.Emit(OpCodes.Ldloc, localName); ilResolve.Emit(OpCodes.Ldstr, ","); ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) })); ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("Substring", new Type[] { typeof(int), typeof(int) })); ilResolve.Emit(OpCodes.Stloc, localName); Assign(localStream, Call(Call(typeof(Assembly), "GetExecutingAssembly", false), "GetManifestResourceStream", false, localName), resolvecontext); Label notNull = ilResolve.DefineLabel(); ilResolve.Emit(OpCodes.Ldloc, localStream); ilResolve.Emit(OpCodes.Brtrue, notNull); { //Not found, just return null ilResolve.Emit(OpCodes.Ldnull); ilResolve.Emit(OpCodes.Ret); } ilResolve.MarkLabel(notNull); Call(localStream, "get_Length", false).Compile(resolvecontext); ilResolve.Emit(OpCodes.Conv_Ovf_I); ilResolve.Emit(OpCodes.Newarr, typeof(System.Byte)); ilResolve.Emit(OpCodes.Stloc, localBuf); ilResolve.Emit(OpCodes.Ldloc, localStream); ilResolve.Emit(OpCodes.Ldloc, localBuf); ilResolve.Emit(OpCodes.Ldc_I4_0); ilResolve.Emit(OpCodes.Ldloc, localBuf); ilResolve.Emit(OpCodes.Ldlen); ilResolve.Emit(OpCodes.Conv_I4); ilResolve.Emit(OpCodes.Callvirt, typeof(Stream).GetMethod("Read", new Type[] { typeof(byte[]), typeof(int), typeof(int) })); ilResolve.Emit(OpCodes.Pop); //Notify that we loaded this embedded... ilResolve.Emit(OpCodes.Ldarg_1); ilResolve.Emit(OpCodes.Call, typeof(ResolveEventArgs).GetMethod("get_Name")); ilResolve.Emit(OpCodes.Ldstr, " was not found externally, loading embedded version..."); ilResolve.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) })); ilResolve.Emit(OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(string) })); Call(typeof(Assembly), "Load", false, localBuf).Compile(resolvecontext); ilResolve.Emit(OpCodes.Ret); resolvecontext.PopIL(); MethodBuilder moduleInitializer = module.DefineGlobalMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.RTSpecialName, null, new Type[] { }); ILGenerator ilStartup = moduleInitializer.GetILGenerator(); ilStartup.Emit(OpCodes.Call, typeof(System.AppDomain).GetMethod("get_CurrentDomain")); ilStartup.Emit(OpCodes.Ldnull); ilStartup.Emit(OpCodes.Ldftn, resolveAssemblyMethod); ilStartup.Emit(OpCodes.Newobj, MethodResolver.GetConstructor(typeof(System.ResolveEventHandler))); ilStartup.Emit(OpCodes.Callvirt, MethodResolver.GetMethod(typeof(System.AppDomain), "add_AssemblyResolve")); ilStartup.Emit(OpCodes.Ret); }
public void Compile(CompileOptions options) { string absolutePath = Path.Combine(Environment.CurrentDirectory, options.OutputFile); string filename = Path.GetFileName(absolutePath); string folder = Path.GetDirectoryName(absolutePath); AssemblyName name = new AssemblyName(filename); AssemblyBuilder assembly = Thread.GetDomain().DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, folder); ModuleBuilder module = assembly.DefineDynamicModule(options.OutputFile, filename, options.Debug); if (options.EmbedPLR) { EmbedAssembly(Assembly.GetExecutingAssembly()); } if (_embeddedAssemblies.Count > 0) { GenerateAssemblyLookup(module); } CompileContext context = new CompileContext(); context.Options = options; context.Module = module; MethodBuilder mainMethod = module.DefineGlobalMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { }); if (options.Debug) { context.DebugWriter = module.DefineDocument(options.Arguments[0], Guid.Empty, Guid.Empty, SymDocumentType.Text); module.SetUserEntryPoint(mainMethod); } context.Module = module; context.ImportedClasses = _importedClasses; if (BeforeCompile != null) { BeforeCompile(context); } foreach (ProcessDefinition procdef in this) { procdef.CompileSignature(module, context); } if (!context.ImportedClasses.Contains(typeof(PLR.Runtime.BuiltIns).FullName)) { context.ImportedClasses.Add(typeof(PLR.Runtime.BuiltIns).FullName); } context.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly()); if (options.References != "") { foreach (string assemblyName in options.References.Split(',')) { string absoluteAssemblyPath = Path.Combine(Directory.GetCurrentDirectory(), assemblyName); if (!File.Exists(absoluteAssemblyPath)) { Console.Error.WriteLine("Assembly '{0}' does not exist!", absoluteAssemblyPath); Environment.Exit(1); } context.ReferencedAssemblies.Add(Assembly.LoadFile(absoluteAssemblyPath)); } } foreach (ProcessDefinition procdef in this) { context.CurrentMasterType = null; procdef.Compile(context); context.CurrentMasterType = null; } List<LocalBuilder> initial = new List<LocalBuilder>(); context.PushIL(mainMethod.GetILGenerator()); if (MainMethodStart != null) { MainMethodStart(context); } foreach (ProcessDefinition procdef in this) { if (procdef.EntryProc) { TypeInfo startProc = context.GetType(procdef.FullName); LocalBuilder loc = context.ILGenerator.DeclareLocal(startProc.Builder); context.ILGenerator.Emit(OpCodes.Newobj, startProc.Constructor); context.ILGenerator.Emit(OpCodes.Stloc, loc); } } //Run Scheduler, who now knows all the new Processes CallScheduler("Run", true, context); if (MainMethodEnd!= null) { MainMethodEnd(context); } //return 0; context.ILGenerator.Emit(OpCodes.Ldc_I4_0); context.ILGenerator.Emit(OpCodes.Ret); if (AfterCompile != null) { AfterCompile(context); } module.CreateGlobalFunctions(); assembly.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); assembly.Save(filename); }
/// <summary> /// Compiles the start block of /// </summary> /// <param name="context"></param> public TypeInfo CompileNewProcessStart(CompileContext context, string name) { try { //Get this before we push a new type on the stack, we are going to need it... Dictionary<string, LocalBuilder> currentLocals = null; if (context.Type != null) { currentLocals = context.Type.Locals; } if (context.CurrentMasterType != null) { //Are in a type, so let's create a nested one TypeInfo nestedType = new TypeInfo(); nestedType.Builder = context.Type.Builder.DefineNestedType(name, TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.BeforeFieldInit, typeof(ProcessBase)); context.PushType(nestedType); } else { context.PushType(context.GetType(name)); context.CurrentMasterType = context.Type; } Type baseType = typeof(ProcessBase); if (this.PreProcessActions != null) { this.PreProcessActions.Compile(context); context.Type.IsPreProcessed = true; } if (this.ActionRestrictions != null) { this.ActionRestrictions.Compile(context); context.Type.IsRestricted = true; } MethodBuilder methodStart = context.Type.Builder.DefineMethod("RunProcess", MethodAttributes.Public | MethodAttributes.Virtual); context.Type.Builder.DefineMethodOverride(methodStart, baseType.GetMethod("RunProcess")); context.PushIL(methodStart.GetILGenerator()); Call(new ThisPointer(typeof(ProcessBase)), "InitSetID", true).Compile(context); if (this.WrapInTryCatch) { context.ILGenerator.BeginExceptionBlock(); } if (context.Type.Constructor == null) { //Nested type which hasn't defined its constructor yet VariableCollection col = new VariableCollection(); col.Start(this); List<Type> paramTypes = new List<Type>(); List<Variable> constructorParams = new List<Variable>(); foreach (Variable v in col.Variables) { if (currentLocals != null && currentLocals.ContainsKey(v.Name)) { //We have defined this local variable and so should pass it to the new process paramTypes.Add(typeof(object)); constructorParams.Add(v); context.Type.ConstructorParameters.Add(v.Name); //Needed to pass the right parameters along later context.Type.Fields.Add(context.Type.Builder.DefineField(v.Name, typeof(object), FieldAttributes.Private)); } } context.Type.Constructor = context.Type.Builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, paramTypes.ToArray()); ILGenerator ilCon = context.Type.Constructor.GetILGenerator(); ilCon.Emit(OpCodes.Ldarg_0); ilCon.Emit(OpCodes.Call, typeof(ProcessBase).GetConstructor(new Type[] { })); for (int i = 0; i < constructorParams.Count; i++) { context.Type.Constructor.DefineParameter(i + 1, ParameterAttributes.None, constructorParams[i].Name); //save the variables argument we got passed in ilCon.Emit(OpCodes.Ldarg_0); ilCon.Emit(OpCodes.Ldarg, i + 1); ilCon.Emit(OpCodes.Stfld, context.Type.GetField(constructorParams[i].Name)); } ilCon.Emit(OpCodes.Ret); } //Do this after the constructor has been defined, because the fields //of the object are defined in the constructor... foreach (FieldBuilder field in context.Type.Fields) { LocalBuilder local = context.ILGenerator.DeclareLocal(typeof(object)); if (context.Options.Debug) { local.SetLocalSymInfo(field.Name); } context.Type.Locals.Add(field.Name, local); //Add the field value to the local variable, so we can concentrate on only local vars context.ILGenerator.Emit(OpCodes.Ldarg_0); context.ILGenerator.Emit(OpCodes.Ldfld, field); context.ILGenerator.Emit(OpCodes.Stloc, local); } return context.Type; } catch (Exception) { return null; } }