public AILEmitterCtx( ATranslatorCache Cache, ABlock[] Graph, ABlock Root, string SubName) { this.Cache = Cache ?? throw new ArgumentNullException(nameof(Cache)); this.Graph = Graph ?? throw new ArgumentNullException(nameof(Graph)); this.Root = Root ?? throw new ArgumentNullException(nameof(Root)); Labels = new Dictionary <long, AILLabel>(); Emitter = new AILEmitter(Graph, Root, SubName); ILBlock = Emitter.GetILBlock(0); OpcIndex = -1; if (Graph.Length == 0 || !AdvanceOpCode()) { throw new ArgumentException(nameof(Graph)); } }
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine( ATranslatorCache Cache, AThreadState State, AMemory Memory, long Start) { Dictionary <long, ABlock> Visited = new Dictionary <long, ABlock>(); Dictionary <long, ABlock> VisitedEnd = new Dictionary <long, ABlock>(); Queue <ABlock> Blocks = new Queue <ABlock>(); ABlock Enqueue(long Position) { if (!Visited.TryGetValue(Position, out ABlock Output)) { Output = new ABlock(Position); Blocks.Enqueue(Output); Visited.Add(Position, Output); } return(Output); } ABlock Root = Enqueue(Start); while (Blocks.Count > 0) { ABlock Current = Blocks.Dequeue(); FillBlock(State, Memory, Current); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, //executed when the branch is not taken. For Unconditional Branches //(except BL/BLR that are sub calls) or end of executable, Next is null. if (Current.OpCodes.Count > 0) { bool HasCachedSub = false; AOpCode LastOp = Current.GetLastOp(); if (LastOp is AOpCodeBImm Op) { if (Op.Emitter == AInstEmit.Bl) { HasCachedSub = Cache.HasSubroutine(Op.Imm); } else { Current.Branch = Enqueue(Op.Imm); } } if (!((LastOp is AOpCodeBImmAl) || (LastOp is AOpCodeBReg)) || HasCachedSub) { Current.Next = Enqueue(Current.EndPosition); } } //If we have on the graph two blocks with the same end position, //then we need to split the bigger block and have two small blocks, //the end position of the bigger "Current" block should then be == to //the position of the "Smaller" block. while (VisitedEnd.TryGetValue(Current.EndPosition, out ABlock Smaller)) { if (Current.Position > Smaller.Position) { ABlock Temp = Smaller; Smaller = Current; Current = Temp; } Current.EndPosition = Smaller.Position; Current.Next = Smaller; Current.Branch = null; Current.OpCodes.RemoveRange( Current.OpCodes.Count - Smaller.OpCodes.Count, Smaller.OpCodes.Count); VisitedEnd[Smaller.EndPosition] = Smaller; } VisitedEnd.Add(Current.EndPosition, Current); } //Make and sort Graph blocks array by position. ABlock[] Graph = new ABlock[Visited.Count]; while (Visited.Count > 0) { ulong FirstPos = ulong.MaxValue; foreach (ABlock Block in Visited.Values) { if (FirstPos > (ulong)Block.Position) { FirstPos = (ulong)Block.Position; } } ABlock Current = Visited[(long)FirstPos]; do { Graph[Graph.Length - Visited.Count] = Current; Visited.Remove(Current.Position); Current = Current.Next; }while (Current != null); } return(Graph, Root); }