Exemplo n.º 1
0
        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
        }
Exemplo n.º 2
0
        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
        }
Exemplo n.º 3
0
        private void WorkerLogic(CompilationContext ctx)
        {
#if TRACE
            var s_workingSet = 0L;
            var s_typesInDynamicAssembly = -1;
            var s_time = TimeSpan.Zero;
#endif

            try
            {
#if TRACE
                GC.Collect();
                s_workingSet = Process.GetCurrentProcess().WorkingSet64;
                s_typesInDynamicAssembly = _types.Count();
                s_time = Process.GetCurrentProcess().TotalProcessorTime;

                var firstLine = String.Format(
                    "Entering the worker thread: rev={0} ({1} mode)", ctx.Revision,
                     ctx.CompilingBaseline ? "baseline" : "cumulative");
                var secondLine = String.Format(
                    "The context is: revision={0}, seq={1}, lastSeq={2}",
                    ctx.Revision, ctx.WorkerSeq, ctx.LastSuccessfulWorkerSeq);
                var thirdLine = "Compilation mode: " + (ctx.CompilingBaseline ? "baseline" : "cumulative");
                var fourthLine = String.Format(
                    "The changeset is: [{0}]{1}",
                    ctx.Changeset.Length,
                    ctx.Changeset.Length == 0 ? String.Empty : Environment.NewLine +
                        ctx.Changeset.Select(e => String.Format("  *{0}: {1}", e.Reason, e.Subject)).StringJoin(Environment.NewLine));
                var fifthLine = String.Format(
                    "The normalized changeset is: [{0}]{1}",
                    ctx.NormalizedChangeSet.Count,
                    ctx.NormalizedChangeSet.Count == 0 ? String.Empty : Environment.NewLine +
                        ctx.NormalizedChangeSet.Select(kvp => String.Format("  *{0}: {1}", kvp.Value, kvp.Key)).StringJoin(Environment.NewLine));
                var finalMessage = String.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}", 
                    Environment.NewLine, firstLine, secondLine, thirdLine, fourthLine, fifthLine);
                MTLog.Say(finalMessage);
#endif

                // was used to test empty thread footprint: ~64k
//                var t_scenario = _asm.GetTypes().FirstOrDefault(t => typeof(ICompiledScenario).IsAssignableFrom(t));
//                t_scenario = t_scenario ?? CompileScenarioRecursively(ctx);

                var t_scenario = CompileScenarioRecursively(ctx);
                var pool = new CompiledScenarioCache(Vault, t_scenario);

                MTLog.Say("Waiting at the barrier, pending successfully completed");
                lock (_barrier)
                {
                    // final modification guard (btw, the compiler logic also has such guards: for every node being compiled)
                    // if we fail here during baseline compilation - sigh... so much memory is gonna to be wasted
                    if (!ctx.StillInTouch()) throw new CompilerOutOfTouchException();

                    MTLog.Say("Breached the barrier");
                    _isBroken = false;
                    _brokenChangeSet = null;
                    _isPermanentlyBroken = false;
                    _compilingBaseline = false;
                    _changeSet.Clear();
                    _lastResult = pool;
                    _lastSuccessfulWorkerSeq = ctx.WorkerSeq;
                    MTLog.Say("Successfully completed");
                }
            }
            catch (Exception ex)
            {
                MTLog.Say("Waiting at the barrier, pending error: " + ex);
                lock (_barrier)
                {
                    MTLog.Say("Breached the barrier");
                    _isBroken = true;
                    _brokenChangeSet = ctx.Changeset;
                    if (ctx.CompilingBaseline) _baselineCompilationFailures++;
                    _isPermanentlyBroken = _baselineCompilationFailures >= MaxBaselineCompilationFailures;
                    // don't touch _compilingBaseline -> it should remain unchanged
                    // don't touch _changeSet -> it should remain unchanged
                    _lastResult = null;
                    MTLog.Say("Error: " + ex);
                }
            }
            finally
            {
                try
                {
                    GC.Collect();

#if TRACE
                    var f_WorkingSet = Process.GetCurrentProcess().WorkingSet64;
                    var f_typesInDynamicAssembly = _types.Count();
                    var f_time = Process.GetCurrentProcess().TotalProcessorTime;

                    var memDelta = (f_WorkingSet - s_workingSet) / 1024;
                    var typesDelta = f_typesInDynamicAssembly - s_typesInDynamicAssembly;
                    var timeDelta_sec = (f_time - s_time).Seconds;
                    var timeDelta_ms = (f_time - s_time).Milliseconds;

                    MTLog.Say(String.Format("Leaving the worker thread.{0}"+
                        "Time delta: {1}.{2} sec, memory delta: {3} Kb ({4} Kb total), types generated: {5}, avg memory per type: {6} Kb",
                        Environment.NewLine,
                        timeDelta_sec, 
                        timeDelta_ms,
                        s_workingSet == 0 ? "??" : memDelta.ToString(),
                        f_WorkingSet,
                        s_typesInDynamicAssembly == -1 ? "??" : typesDelta.ToString(),
                        (s_typesInDynamicAssembly == -1 || s_workingSet == 0 || typesDelta == 0) ? "??" : (memDelta / typesDelta).ToString()));
#else
                    MTLog.Say("Leaving the worker thread");
#endif
                }
                finally
                {
                    _worker = null;
                    _flag.Set();
                }
            }
        }