Beispiel #1
0
        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));
            }
        }
Beispiel #2
0
        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);
        }