コード例 #1
0
ファイル: Decoder.cs プロジェクト: dnmodder/Ryujinx
        public static Block[] DecodeFunction(MemoryManager memory, ulong address, ExecutionMode mode, bool highCq)
        {
            List <Block> blocks = new List <Block>();

            Queue <Block> workQueue = new Queue <Block>();

            Dictionary <ulong, Block> visited = new Dictionary <ulong, Block>();

            int opsCount = 0;

            int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq;

            Block GetBlock(ulong blkAddress)
            {
                if (!visited.TryGetValue(blkAddress, out Block block))
                {
                    if (opsCount > instructionLimit || !memory.IsMapped((long)blkAddress))
                    {
                        return(null);
                    }

                    block = new Block(blkAddress);

                    workQueue.Enqueue(block);

                    visited.Add(blkAddress, block);
                }

                return(block);
            }

            GetBlock(address);

            while (workQueue.TryDequeue(out Block currBlock))
            {
                // Check if the current block is inside another block.
                if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
                {
                    Block nBlock = blocks[nBlkIndex];

                    if (nBlock.Address == currBlock.Address)
                    {
                        throw new InvalidOperationException("Found duplicate block address on the list.");
                    }

                    nBlock.Split(currBlock);

                    blocks.Insert(nBlkIndex + 1, currBlock);

                    continue;
                }

                // If we have a block after the current one, set the limit address.
                ulong limitAddress = ulong.MaxValue;

                if (nBlkIndex != blocks.Count)
                {
                    Block nBlock = blocks[nBlkIndex];

                    int nextIndex = nBlkIndex + 1;

                    if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count)
                    {
                        limitAddress = blocks[nextIndex].Address;
                    }
                    else if (nBlock.Address > currBlock.Address)
                    {
                        limitAddress = blocks[nBlkIndex].Address;
                    }
                }

                FillBlock(memory, mode, currBlock, limitAddress);

                opsCount += currBlock.OpCodes.Count;

                if (currBlock.OpCodes.Count != 0)
                {
                    // 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.
                    OpCode lastOp = currBlock.GetLastOp();

                    bool isCall = IsCall(lastOp);

                    if (lastOp is IOpCodeBImm op && !isCall)
                    {
                        currBlock.Branch = GetBlock((ulong)op.Immediate);
                    }

                    if (!IsUnconditionalBranch(lastOp) || isCall)
                    {
                        currBlock.Next = GetBlock(currBlock.EndAddress);
                    }
                }

                // Insert the new block on the list (sorted by address).
                if (blocks.Count != 0)
                {
                    Block nBlock = blocks[nBlkIndex];

                    blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock);
                }
                else
                {
                    blocks.Add(currBlock);
                }
            }

            TailCallRemover.RunPass(address, blocks);

            return(blocks.ToArray());
        }
コード例 #2
0
ファイル: Decoder.cs プロジェクト: pokemium/Ryujinx
        // ブロック単位のデコード を繰り返して複数のブロックを返す
        //
        // Cq = Code quality
        public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, bool singleBlock)
        {
            // デコード処理したブロックが入っている これを返す
            List <Block> blocks = new List <Block>();

            // デコード処理をまっているブロックを入れておくキュー
            Queue <Block> workQueue = new Queue <Block>();

            Dictionary <ulong, Block> visited = new Dictionary <ulong, Block>();

            Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);

            int opsCount = 0;

            int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq;

            // blkAddressを先頭とするBlock構造体を返す
            // すでにBlock構造体を構築しているならそれを、そうでないなら新しく作ってworkQueueにpushしたあと返す
            Block GetBlock(ulong blkAddress)
            {
                if (!visited.TryGetValue(blkAddress, out Block block))
                {
                    block = new Block(blkAddress);

                    if ((singleBlock && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
                    {
                        block.Exit       = true;
                        block.EndAddress = blkAddress;
                    }

                    workQueue.Enqueue(block);

                    visited.Add(blkAddress, block);
                }

                return(block);
            }

            GetBlock(address);


            // キューに入ったブロックを順に処理していく
            while (workQueue.TryDequeue(out Block currBlock))
            {
                // 処理対象のブロックがとあるブロックの内側に含まれている
                // blocks[nBlkIndex].Address <= currBlock.Address < blocks[nBlkIndex].EndAddress
                // currBlock.EndAddress <= blocks[nBlkIndex].EndAddress は成り立っているのか?
                if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
                {
                    Block nBlock = blocks[nBlkIndex];

                    if (nBlock.Address == currBlock.Address)
                    {
                        throw new InvalidOperationException("Found duplicate block address on the list.");
                    }

                    currBlock.Exit = false; // ブロックの終端ではない

                    // nBlock を分割して間にcurrBlockを差し込む
                    nBlock.Split(currBlock);
                    blocks.Insert(nBlkIndex + 1, currBlock);

                    continue;
                }

                // NOTE: nBlkIndex = 新しいブロックが入るべきblocksのインデックス
                // Exit=false つまり現在のブロックの後にブロックがある場合は、リミットアドレスを設定する
                if (!currBlock.Exit)
                {
                    ulong limitAddress = ulong.MaxValue;

                    if (nBlkIndex != blocks.Count)   // 念の為処理対象のブロックがblocksの最後のブロックでないか確認
                    {
                        Block nBlock = blocks[nBlkIndex];

                        int nextIndex = nBlkIndex + 1;

                        if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count)
                        {
                            // nBlock <- currBlock <- blocks[nextIndex] の場合は blocks[nextIndex] まで
                            limitAddress = blocks[nextIndex].Address;
                        }
                        else if (nBlock.Address > currBlock.Address)
                        {
                            // 新しいブロック -> nBlock の場合は nBlockまで
                            limitAddress = blocks[nBlkIndex].Address;
                        }
                    }

                    FillBlock(memory, mode, currBlock, limitAddress);

                    opsCount += currBlock.OpCodes.Count;

                    if (currBlock.OpCodes.Count != 0)
                    {
                        // 分岐命令だった場合に子ブロックを設定する
                        // "Branch "は、分岐命令が指すブロック、"Next"は、分岐しなかった場合に実行される次のアドレスのブロックです
                        // 無条件分岐(関数コールであるBL/BLRを除く)や実行ファイルの終了の場合、Nextはnullです。
                        OpCode lastOp = currBlock.GetLastOp();

                        bool isCall = IsCall(lastOp);

                        if (lastOp is IOpCodeBImm op && !isCall)
                        {
                            currBlock.Branch = GetBlock((ulong)op.Immediate);
                        }

                        if (!IsUnconditionalBranch(lastOp) || isCall)
                        {
                            currBlock.Next = GetBlock(currBlock.EndAddress);
                        }
                    }
                }

                // Insert the new block on the list (sorted by address).
                if (blocks.Count != 0)
                {
                    Block nBlock = blocks[nBlkIndex];
                    blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock);
                }
                else
                {
                    blocks.Add(currBlock);
                }
            }

            if (blocks.Count == 1 && blocks[0].OpCodes.Count == 0)
            {
                Debug.Assert(blocks[0].Exit);
                Debug.Assert(blocks[0].Address == blocks[0].EndAddress);

                throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}.");
            }

            if (!singleBlock)
            {
                return(TailCallRemover.RunPass(address, blocks));
            }
            else
            {
                return(blocks.ToArray());
            }
        }