static private Action <CpuThreadState> _CreateDelegateForPC(CpuProcessor CpuProcessor, Stream MemoryStream, uint EntryPC, out int InstructionsProcessed) { InstructionsProcessed = 0; if (EntryPC == 0) { if (MemoryStream is PspMemoryStream) { throw (new InvalidOperationException("EntryPC can't be NULL")); } } if (CpuProcessor.PspConfig.TraceJIT) { Console.WriteLine("Emiting EntryPC=0x{0:X}", EntryPC); } MemoryStream.Position = EntryPC; if ((MemoryStream.Length >= 8) && new BinaryReader(MemoryStream).ReadUInt64() == 0x0000000003E00008) { Console.WriteLine("NullSub detected at 0x{0:X}!", EntryPC); } var InstructionReader = new InstructionReader(MemoryStream); var MipsMethodEmiter = new MipsMethodEmiter(MipsEmiter, CpuProcessor); var ILGenerator = MipsMethodEmiter.ILGenerator; var CpuEmiter = new CpuEmiter(MipsMethodEmiter, InstructionReader, MemoryStream, CpuProcessor); uint PC; uint EndPC = (uint)MemoryStream.Length; uint MinPC = uint.MaxValue, MaxPC = uint.MinValue; var Labels = new SortedDictionary <uint, Label>(); var BranchesToAnalyze = new Queue <uint>(); var AnalyzedPC = new HashSet <uint>(); Labels[EntryPC] = ILGenerator.DefineLabel(); BranchesToAnalyze.Enqueue(EntryPC); // PASS1: Analyze and find labels. PC = EntryPC; //Debug.WriteLine("PASS1: (PC={0:X}, EndPC={1:X})", PC, EndPC); var GlobalInstructionStats = CpuProcessor.GlobalInstructionStats; var InstructionStats = new Dictionary <string, uint>(); var NewInstruction = new Dictionary <string, bool>(); int MaxNumberOfInstructions = 8 * 1024; //int MaxNumberOfInstructions = 60; while (BranchesToAnalyze.Count > 0) { bool EndOfBranchFound = false; for (PC = BranchesToAnalyze.Dequeue(); PC < EndPC; PC += 4) { // If already analyzed, stop scanning this branch. if (AnalyzedPC.Contains(PC)) { break; } AnalyzedPC.Add(PC); //Console.WriteLine("%08X".Sprintf(PC)); if (AnalyzedPC.Count > MaxNumberOfInstructions) { throw (new InvalidDataException("Code sequence too long: >= " + MaxNumberOfInstructions + "")); } MinPC = Math.Min(MinPC, PC); MaxPC = Math.Max(MaxPC, PC); //Console.WriteLine(" PC:{0:X}", PC); CpuEmiter.LoadAT(PC); var BranchInfo = GetBranchInfo(CpuEmiter.Instruction.Value); if (CpuProcessor.PspConfig.LogInstructionStats) { var InstructionName = GetInstructionName(CpuEmiter.Instruction.Value, null); if (!InstructionStats.ContainsKey(InstructionName)) { InstructionStats[InstructionName] = 0; } InstructionStats[InstructionName]++; if (!GlobalInstructionStats.ContainsKey(InstructionName)) { NewInstruction[InstructionName] = true; GlobalInstructionStats[InstructionName] = 0; } GlobalInstructionStats[InstructionName]++; //var GlobalInstructionStats = CpuProcessor.GlobalInstructionStats; //var InstructionStats = new Dictionary<string, uint>(); //var NewInstruction = new Dictionary<string, bool>(); } // Branch instruction. if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpInstruction) != 0) { //Console.WriteLine("Instruction"); EndOfBranchFound = true; continue; } else if ((BranchInfo & CpuBranchAnalyzer.Flags.BranchOrJumpInstruction) != 0) { var BranchAddress = CpuEmiter.Instruction.GetBranchAddress(PC); Labels[BranchAddress] = ILGenerator.DefineLabel(); BranchesToAnalyze.Enqueue(BranchAddress); // Jump Always performed. /* * if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpAlways) != 0) * { * EndOfBranchFound = true; * continue; * } */ } else if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0) { // On this special Syscall if (CpuEmiter.Instruction.CODE == FunctionGenerator.NativeCallSyscallCode) { //PC += 4; break; } } // A Jump Always found. And we have also processed the delayed branch slot. End the branch. if (EndOfBranchFound) { EndOfBranchFound = false; break; } } } // PASS2: Generate code and put labels; Action <uint> _EmitCpuInstructionAT = (_PC) => { if (CpuProcessor.PspConfig.TraceJIT) { ILGenerator.Emit(OpCodes.Ldarg_0); ILGenerator.Emit(OpCodes.Ldc_I4, _PC); ILGenerator.Emit(OpCodes.Call, typeof(CpuThreadState).GetMethod("Trace")); Console.WriteLine(" PC=0x{0:X}", _PC); } CpuEmiter.LoadAT(_PC); CpuEmiterInstruction(CpuEmiter.Instruction.Value, CpuEmiter); }; uint InstructionsEmitedSinceLastWaypoint = 0; Action StorePC = () => { MipsMethodEmiter.SavePC(PC); }; Action <bool> EmitInstructionCountIncrement = (bool CheckForYield) => { if (!CpuProcessor.PspConfig.CountInstructionsAndYield) { return; } //Console.WriteLine("EmiteInstructionCountIncrement: {0},{1}", InstructionsEmitedSinceLastWaypoint, CheckForYield); if (InstructionsEmitedSinceLastWaypoint > 0) { MipsMethodEmiter.SaveStepInstructionCount(() => { MipsMethodEmiter.LoadStepInstructionCount(); ILGenerator.Emit(OpCodes.Ldc_I4, InstructionsEmitedSinceLastWaypoint); //ILGenerator.Emit(OpCodes.Add); ILGenerator.Emit(OpCodes.Sub); }); //ILGenerator.Emit(OpCodes.Ldc_I4, 100); //ILGenerator.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine"), new Type[] { typeof(int) }); InstructionsEmitedSinceLastWaypoint = 0; } if (CheckForYield) { if (!CpuProcessor.PspConfig.BreakInstructionThreadSwitchingForSpeed) { var NoYieldLabel = ILGenerator.DefineLabel(); MipsMethodEmiter.LoadStepInstructionCount(); ILGenerator.Emit(OpCodes.Ldc_I4_0); ILGenerator.Emit(OpCodes.Bgt, NoYieldLabel); //ILGenerator.Emit(OpCodes.Ldc_I4, 1000000); //ILGenerator.Emit(OpCodes.Blt, NoYieldLabel); MipsMethodEmiter.SaveStepInstructionCount(() => { ILGenerator.Emit(OpCodes.Ldc_I4_0); }); StorePC(); ILGenerator.Emit(OpCodes.Ldarg_0); ILGenerator.Emit(OpCodes.Call, typeof(CpuThreadState).GetMethod("Yield")); //ILGenerator.Emit(OpCodes.Call, typeof(GreenThread).GetMethod("Yield")); ILGenerator.MarkLabel(NoYieldLabel); } } }; Action EmitCpuInstruction = () => { if (CpuProcessor.NativeBreakpoints.Contains(PC)) { ILGenerator.Emit(OpCodes.Call, typeof(DebugUtils).GetMethod("IsDebuggerPresentDebugBreak")); } // Marks label. if (Labels.ContainsKey(PC)) { EmitInstructionCountIncrement(false); ILGenerator.MarkLabel(Labels[PC]); } _EmitCpuInstructionAT(PC); PC += 4; InstructionsEmitedSinceLastWaypoint++; }; //Debug.WriteLine("PASS2: MinPC:{0:X}, MaxPC:{1:X}", MinPC, MaxPC); // Jumps to the entry point. ILGenerator.Emit(OpCodes.Br, Labels[EntryPC]); for (PC = MinPC; PC <= MaxPC;) { uint CurrentInstructionPC = PC; Instruction CurrentInstruction = InstructionReader[PC]; InstructionsProcessed++; /* * if (!AnalyzedPC.Contains(CurrentInstructionPC)) * { * // Marks label. * if (Labels.ContainsKey(PC)) * { * ILGenerator.MarkLabel(Labels[PC]); * } * * * PC += 4; * continue; * } */ var BranchInfo = GetBranchInfo(CurrentInstruction.Value); // Delayed branch instruction. if ((BranchInfo & CpuBranchAnalyzer.Flags.BranchOrJumpInstruction) != 0) { InstructionsEmitedSinceLastWaypoint += 2; EmitInstructionCountIncrement(true); var BranchAddress = CurrentInstruction.GetBranchAddress(PC); if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpInstruction) != 0) { // Marks label. if (Labels.ContainsKey(PC)) { ILGenerator.MarkLabel(Labels[PC]); } _EmitCpuInstructionAT(PC + 4); _EmitCpuInstructionAT(PC + 0); PC += 8; } else { // Branch instruction. EmitCpuInstruction(); //if ((BranchInfo & CpuBranchAnalyzer.Flags.Likely) != 0) if (BranchInfo.HasFlag(CpuBranchAnalyzer.Flags.Likely)) { //Console.WriteLine("Likely"); // Delayed instruction. CpuEmiter._branch_likely(() => { EmitCpuInstruction(); }); } else { //Console.WriteLine("Not Likely"); // Delayed instruction. EmitCpuInstruction(); } if (CurrentInstructionPC + 4 != BranchAddress) { if (Labels.ContainsKey(BranchAddress)) { CpuEmiter._branch_post(Labels[BranchAddress]); } // Code not reached. else { } } } } // Normal instruction. else { // Syscall instruction. if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0) { StorePC(); } EmitCpuInstruction(); if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0) { // On this special Syscall if (CurrentInstruction.CODE == FunctionGenerator.NativeCallSyscallCode) { //PC += 4; break; } } } } if (CpuProcessor.PspConfig.ShowInstructionStats) { Console.Error.WriteLine("-------------------------- {0:X}-{1:X} ", MinPC, MaxPC); foreach (var Pair in InstructionStats.OrderByDescending(Item => Item.Value)) { Console.Error.Write("{0} : {1}", Pair.Key, Pair.Value); if (NewInstruction.ContainsKey(Pair.Key)) { Console.Error.Write(" <-- NEW!"); } Console.Error.WriteLine(""); } } //if (BreakPoint) IsDebuggerPresentDebugBreak(); Action <CpuThreadState> Delegate = MipsMethodEmiter.CreateDelegate(); return(Delegate); }