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 }