private Type CompileNode(CompilationContext ctx, IBranch b) { #if FORCE_SINGLE_THREADED Application.DoEvents(); #endif // vault modifications guard if (!ctx.StillInTouch()) throw new CompilerOutOfTouchException(); // type var t_parent = ctx.PrevSuccessfulType(b.VPath) ?? typeof(CompiledNode); (t_parent == typeof(CompiledNode) ^ (ctx.CumulativeCompilation && ctx.ScheduledCumulations.ContainsKey(b))).AssertTrue(); var t = _mod.DefineType(ctx.RequestName(b.GetClassName()), TA.Public, t_parent); #if TRACE try { #endif // constructor var ctor = t.DefineConstructor(MA.PublicCtor, CallingConventions.Standard, typeof(CompiledNode).MkArray()); ctor.DefineParameter(1, ParmA.None, "parent"); ctor.il().ld_args(2).basector(typeof(CompiledNode), typeof(CompiledNode)).ret(); // the [VPath(...)] attribute for reflection-based analysis t.SetCustomAttribute(new CustomAttributeBuilder( typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()), b.VPath.ToString().MkArray())); // the [Revision(...)] attribute for reflection-based analysis t.SetCustomAttribute(new CustomAttributeBuilder( typeof(RevisionAttribute).GetConstructor(new[] { typeof(ulong) }), new object[] { Vault.Revision })); // the [Seq(...)] attribute for synchronization and namespacing purposes t.SetCustomAttribute(new CustomAttributeBuilder( typeof(SeqAttribute).GetConstructor(new[] { typeof(int) }), new object[] { ctx.WorkerSeq })); // trivial overrides t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name")) .il() .ldstr(b.GetClassName() + "_seq" + ctx.WorkerSeq) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath")) .il() .ldstr(b.VPath) .newobj(typeof(VPath), typeof(String)) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision")) .il() .ldc_i8(Vault.Revision) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq")) .il() .ldc_i4(ctx.WorkerSeq) .ret(); ImplementCreateChildren(ctx, t, b); ImplementCreateProperties(ctx, t, b); // finalize the type var t_created = t.CreateType(); _types.Add(t_created); // create a factory method for this class var factoryName = b.GetClassName().Substring(b.GetClassName().LastIndexOf(".") + 1); var factoryMethod = ctx.FactoryType.DefineMethod("Create_" + ctx.RequestName(factoryName), MA.PublicStatic, typeof(CompiledNode), typeof(CompiledNode).MkArray()); factoryMethod.SetCustomAttribute(new CustomAttributeBuilder( typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()), b.VPath.ToString().MkArray())); factoryMethod.il().ldarg(0).newobj(t_created, typeof(CompiledNode).MkArray()).ret(); // register self within the factory ctx.Factory.il() .ldarg(0) .ldstr(b.VPath.ToString()) .newobj(typeof(VPath), typeof(String)) .ldnull() .ldftn(factoryMethod) .newobj(typeof(Func<CompiledNode, CompiledNode>), typeof(Object), typeof(IntPtr)) .callvirt(typeof(NodeFactory).GetMethod("Register", BF.All)); return t_created; #if TRACE } finally { // attempts to finalize the type so that we can dump an assembly to disk after certain exceptions if (!t.IsCreated()) { Action<Action> neverFail = code => {try{code();}catch{}}; neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name")).il().ldnull().ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath")).il().ldnull().ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision")).il().ldc_i8(0).ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq")).il().ldc_i4(0).ret()); neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateChildren", BF.All)).il().ret()); neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateProperties", BF.All)).il().ret()); neverFail(() => ctx.CCs[t].il().ret()); neverFail(() => ctx.CPs[t].il().ret()); neverFail(() => t.CreateType()); } } #endif }
private Type CompileScenarioRecursively(CompilationContext ctx) { #if FORCE_SINGLE_THREADED Application.DoEvents(); #endif // vault modifications guard if (!ctx.StillInTouch()) throw new CompilerOutOfTouchException(); // type var t_parent = ctx.PrevSuccessfulType("scenario") ?? typeof(CompiledScenario); (t_parent == typeof(CompiledScenario) ^ ctx.CumulativeCompilation).AssertTrue(); var t = _mod.DefineType(ctx.RequestName(Vault.GetClassName()), TA.Public, t_parent); #if TRACE try { #endif // constructors var ctorDesignMode = t.DefineConstructor(MA.PublicCtor, CallingConventions.Standard, new[] { typeof(IVault) }); ctorDesignMode.DefineParameter(1, ParmA.None, "scenario"); ctorDesignMode.il().ld_args(2).basector(typeof(CompiledScenario), typeof(IVault)).ret(); var ctorRuntimeMode = t.DefineConstructor(MA.PublicCtor, CallingConventions.Standard, new[] { typeof(IVault), typeof(IVault) }); ctorRuntimeMode.DefineParameter(1, ParmA.None, "scenario"); ctorRuntimeMode.DefineParameter(2, ParmA.None, "repository"); ctorRuntimeMode.il().ld_args(3).basector(typeof(CompiledScenario), typeof(IVault), typeof(IVault)).ret(); // the [Version(...)] attribute for reflection-based analysis t.SetCustomAttribute(new CustomAttributeBuilder( typeof(VersionAttribute).GetConstructor(new[] { typeof(String), typeof(ulong) }), new object[] { Vault.Id.ToString(), Vault.Revision })); // the [Seq(...)] attribute for synchronization and namespacing purposes t.SetCustomAttribute(new CustomAttributeBuilder( typeof(SeqAttribute).GetConstructor(new[] { typeof(int) }), new object[] { ctx.WorkerSeq })); // trivial overrides t.DefineOverrideReadonly(typeof(CompiledScenario).GetProperty("Version")) .il() .ldstr(Vault.Id.ToString()) .newobj(typeof(Guid), typeof(String)) .ldc_i8(Vault.Revision) .newobj(typeof(Version), typeof(Guid), typeof(ulong)) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name")) .il() .ldstr(Vault.GetClassName() + "_seq" + ctx.WorkerSeq) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath")) .il() .call(typeof(VPath).GetProperty("Empty").GetGetMethod()) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision")) .il() .ldc_i8(Vault.Revision) .ret(); t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq")) .il() .ldc_i4(ctx.WorkerSeq) .ret(); // factory initialization var parentFactory = ctx.PrevSuccessfulType("factory") ?? typeof(NodeFactory); ctx.FactoryType = _mod.DefineType(ctx.RequestName(t.Name + "_factory"), TA.Public, parentFactory); ctx.FactoryType.SetCustomAttribute(new CustomAttributeBuilder( typeof(SeqAttribute).GetConstructor(new[] { typeof(int) }), new object[] { ctx.WorkerSeq })); // setting up the factory method ctx.Factory = ctx.FactoryType.DefineConstructor(MA.PublicCtor, CallingConventions.Standard, new Type[0]); ctx.Factory.il().ldarg(0).basector(parentFactory); // complex overrides (the main work is here, below the stack) if (ctx.CompilingBaseline) { // baseline compilation involves creating classes and properties // for every single node and svd/fla in the scenario ImplementCreateChildren(ctx, t, Vault); ImplementCreateProperties(ctx, t, Vault); } else { var cum = ctx.ScheduledCumulations; MTLog.Say(String.Format("Scheduled cumulations: [{0}]{1}", cum.Count, cum.Count == 0 ? String.Empty : Environment.NewLine + cum.Select(kvp => String.Format("[{0}] {1}{2}", kvp.Value.Length, kvp.Key, cum.Count == 0 ? String.Empty : Environment.NewLine + kvp.Value.Select(co => String.Format(">>{0}: {1}", co.Reason, co.Subject) ).StringJoin(Environment.NewLine)) ).StringJoin(Environment.NewLine))); // cumulative compilation only should regenerate pieces of code // that are affected by events mentioned in ctx.NormalizedChangeSet cum.Keys.ForEach(host => CompileNode(ctx, host)); } // factory finalization ctx.Factory.il().ret(); var t_factory_created = ctx.FactoryType.CreateType(); _types.Add(t_factory_created); var createNodeFactory = t.DefineOverride(typeof(CompiledScenario).GetMethod("CreateNodeFactory", BF.All)); createNodeFactory.il().newobj(t_factory_created).ret(); // finalize the type var t_created = t.CreateType(); _types.Add(t_created); return t_created; #if TRACE } finally { // attempts to finalize the type so that we can dump an assembly to disk even after exceptions if (!t.IsCreated()) { Action<Action> neverFail = code => {try{code();}catch{}}; neverFail(() => t.DefineOverrideReadonly(typeof(CompiledScenario).GetProperty("Version")).il().ldc_i4(0).ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Name")).il().ldnull().ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("VPath")).il().ldnull().ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Revision")).il().ldc_i8(0).ret()); neverFail(() => t.DefineOverrideReadonly(typeof(CompiledNode).GetProperty("Seq")).il().ldc_i4(0).ret()); neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateChildren", BF.All)).il().ret()); neverFail(() => t.DefineOverride(typeof(CompiledNode).GetMethod("CreateProperties", BF.All)).il().ret()); neverFail(() => ctx.CCs[t].il().ret()); neverFail(() => ctx.CPs[t].il().ret()); neverFail(() => t.DefineOverride(typeof(CompiledScenario).GetMethod("CreateNodeFactory", BF.All)).il().ldnull().ret()); neverFail(() => t.CreateType()); } if (!ctx.FactoryType.IsCreated()) { Action<Action> neverFail = code => {try{code();}catch{}}; neverFail(() => ctx.Factory.il().ret()); neverFail(() => ctx.FactoryType.CreateType()); } } #endif }