Exemplo n.º 1
0
        public ZCompilerResult Compile()
        {
            var sw = Stopwatch.StartNew();

            var dm = CreateDynamicMethod(routine);

            this.il = new ILBuilder(dm.GetILGenerator());

            this.calls = new List <ZRoutineCall>();

            Profiler_EnterRoutine();

            this.controlFlowGraph  = ControlFlowGraph.Build(this.routine);
            this.addressToLabelMap = new Dictionary <int, ILabel>(this.controlFlowGraph.CodeBlocks.Count());

            // Determine whether stack, memory, screen and outputStreams are used.
            foreach (var codeBlock in this.controlFlowGraph.CodeBlocks)
            {
                this.addressToLabelMap.Add(codeBlock.Address, il.NewLabel());

                foreach (var i in codeBlock.Instructions)
                {
                    if (!this.usesStack && i.UsesStack())
                    {
                        this.usesStack = true;
                    }

                    if (!this.usesMemory && i.UsesMemory())
                    {
                        this.usesMemory = true;
                    }
                }
            }

            var instructionStatistics = new List <InstructionStatistics>(this.routine.Instructions.Length);

            // Emit IL
            foreach (var codeBlock in this.controlFlowGraph.CodeBlocks)
            {
                var generators = codeBlock.Instructions
                                 .Select(i => OpcodeGenerator.GetGenerator(i, machine.Version))
                                 .ToList();

                Optimize(generators);

                foreach (var generator in generators)
                {
                    ILabel label;
                    if (this.addressToLabelMap.TryGetValue(generator.Instruction.Address, out label))
                    {
                        label.Mark();
                    }

                    if (machine.Debugging)
                    {
                        il.Arguments.LoadMachine();
                        il.Call(Reflection <CompiledZMachine> .GetMethod("Tick", @public: false));
                    }

                    Profiler_ExecutingInstruction(generator.Instruction);
                    il.DebugWrite(generator.Instruction.PrettyPrint(machine));

                    var offset = il.Size;

                    generator.Generate(il, this);

                    instructionStatistics.Add(new InstructionStatistics(generator.Instruction, offset, il.Size - offset));
                }
            }

            var code = (ZRoutineCode)dm.CreateDelegate(typeof(ZRoutineCode), machine);

            sw.Stop();

            var statistics = new RoutineCompilationStatistics(
                this.routine,
                il.OpcodeCount,
                il.LocalCount,
                il.Size,
                sw.Elapsed,
                calculatedLoadVariableCount,
                calculatedStoreVariableCount,
                instructionStatistics);

            return(new ZCompilerResult(this.routine, calls.ToArray(), code, statistics));
        }