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)); }