Exemple #1
0
        /// <summary>
        /// Compile RL into Dex.
        /// </summary>
        public RegisterMapper Compile()
        {
            // Map registers
            var regMapper = new RegisterMapper(rlBody, frame);

            // Create instructions
            var maxOutgoingArguments = 0;
            var target = dexBody.Instructions;
            var insMap = new Dictionary<Instruction, Tuple<DexLib.Instructions.Instruction, DexLib.Instructions.Instruction>>();
            foreach (var ins in rlBody.Instructions)
            {
                DexLib.Instructions.Instruction first = null;
                DexLib.Instructions.Instruction last = null;
                foreach (var dexIns in RL2Dex.Convert(ins, regMapper))
                {
                    target.Add(dexIns);
                    if (first == null) first = dexIns;
                    last = dexIns;
                }
                if ((first == null) || (last == null))
                    throw new InvalidOperationException();
                insMap[ins] = Tuple.Create(first, last);

                // Gather statistics
                if (ins.Code.IsInvoke())
                {
                    maxOutgoingArguments = Math.Max(maxOutgoingArguments, ins.Registers.Count);
                }
            }

            // Update targets
            foreach (var dexIns in target)
            {
                var instruction = dexIns.Operand as Instruction;
                if (instruction != null)
                {
                    dexIns.Operand = insMap[instruction].Item1;
                }
                if (dexIns.OpCode == OpCodes.Packed_switch)
                {
                    var instructions = (Instruction[])dexIns.Operand;
                    dexIns.Operand = new PackedSwitchData(instructions.Select(x => insMap[x].Item1));
                }
                else if (dexIns.OpCode == OpCodes.Sparse_switch)
                {
                    var targetPairs = (Tuple<int, Instruction>[])dexIns.Operand;
                    var data = new SparseSwitchData();
                    foreach (var pair in targetPairs.OrderBy(x => x.Item1))
                    {
                        data.Targets.Add(pair.Item1, insMap[pair.Item2].Item1);
                    }
                    dexIns.Operand = data;
                }
            }

            // Create exception handlers 
            foreach (var handler in rlBody.Exceptions)
            {
                var dhandler = new ExceptionHandler();
                dhandler.TryStart = insMap[handler.TryStart].Item1;
                dhandler.TryEnd = insMap[handler.TryEnd].Item2;
                dhandler.CatchAll = (handler.CatchAll != null) ? insMap[handler.CatchAll].Item1 : null;
                dexBody.Exceptions.Add(dhandler);

                foreach (var catchBlock in handler.Catches)
                {
                    var dcatchBlock = new Catch();
                    dcatchBlock.Type = catchBlock.Type;
                    dcatchBlock.Instruction = insMap[catchBlock.Instruction].Item1;
                    dhandler.Catches.Add(dcatchBlock);
                }
            }

            // Add register spilling code (if needed)
            if (regMapper.SpillingRequired)
            {
                RegisterSpillingOptimizer.Transform(dexBody);
                RegisterSpilling.AddSpillingCode(dexBody, regMapper);
            }

            // Set statistics
            dexBody.Registers.AddRange(regMapper.All);
            dexBody.IncomingArguments = (ushort) regMapper.ArgumentCount;
            dexBody.OutgoingArguments = (ushort) maxOutgoingArguments;

            return regMapper;
        }
        private SparseSwitchData ExtractSparseSwitch(Instruction ins, int offset)
        {
            int baseOffset = offset;
            var result = new SparseSwitchData();
            ProcessPseudoCode(PseudoOpCodes.Sparse_switch, ref offset);

            int targetcount = ReadShort(ref offset);

            var keys = new int[targetcount];
            for (int i = 0; i < targetcount; i++)
                keys[i] = ReadInt(ref offset);

            for (int i = 0; i < targetcount; i++)
            {
                int index = i; // used for closure
                int target = ReadInt(ref offset);
                lazyInstructionsSetters.Add(() => result.Targets.Add(keys[index], Lookup[ins.Offset + target]));
            }

            if (offset - baseOffset != targetcount*4 + 2)
                throw new MalformedException("Unexpected Sparse switch blocksize");

            return result;
        }
        /// <summary>
        /// Note that referencing operands, i.e. TypeReferences, FieldReference or
        /// MethodRefrences are not cloned, but only shallow copied.
        /// If you indend to modify those operand values themself, be sure to clone
        /// them beforehand. 
        /// </summary>
        public static MethodBody Clone(MethodDefinition targetMethod, MethodDefinition sourceMethod)
        {
            var sourceBody = sourceMethod.Body;

            MethodBody body = new MethodBody(targetMethod, sourceBody.Registers.Count)
            {
                IncomingArguments = sourceBody.IncomingArguments,
                OutgoingArguments = sourceBody.OutgoingArguments
            };

            foreach (var sourceIns in sourceBody.Instructions)
            {
                var ins = new Instruction(sourceIns.OpCode);

                foreach (var r in sourceIns.Registers)
                    ins.Registers.Add(body.Registers[r.Index]);

                ins.Offset = sourceIns.Offset;
                ins.SequencePoint = ins.SequencePoint;

                ins.Operand = sourceIns.Operand;

                body.Instructions.Add(ins);
            }

            // fix instruction references

            var insByOffset = body.Instructions.ToDictionary(i => i.Offset);

            foreach (var ins in body.Instructions)
            {
                var targetIns = ins.Operand as Instruction;
                var packedSwitch = ins.Operand as PackedSwitchData;
                var sparseSwitch = ins.Operand as SparseSwitchData;

                if (targetIns != null)
                {
                    ins.Operand = insByOffset[targetIns.Offset];
                }
                else if (packedSwitch != null)
                {
                    var ps = new PackedSwitchData(packedSwitch.Targets.Select(si => insByOffset[si.Offset]));
                    ps.FirstKey = packedSwitch.FirstKey;
                    ins.Operand = ps;
                }
                else if (sparseSwitch != null)
                {
                    var ss = new SparseSwitchData();
                    foreach (var ssd in sparseSwitch.Targets)
                    {
                        ss.Targets.Add(ssd.Key, insByOffset[ssd.Value.Offset]);
                    }
                    ins.Operand = ss;
                }
            }


            foreach (var sourceEx in sourceBody.Exceptions)
            {
                var ex = new ExceptionHandler();
                if (sourceEx.TryStart != null)
                    ex.TryStart = insByOffset[sourceEx.TryStart.Offset];
                if (sourceEx.TryEnd != null)
                    ex.TryEnd   = insByOffset[sourceEx.TryEnd.Offset];
                if (sourceEx.CatchAll != null)
                    ex.CatchAll = insByOffset[sourceEx.CatchAll.Offset];

                foreach (var sourceCatch in sourceEx.Catches)
                {
                    var c = new Catch
                    {
                        Type = sourceCatch.Type,
                        Instruction = insByOffset[sourceCatch.Instruction.Offset]
                    };
                    ex.Catches.Add(c);
                }

                body.Exceptions.Add(ex);
            }

            if (sourceBody.DebugInfo != null)
            {
                var di = body.DebugInfo = new DebugInfo(body);

                di.LineStart = sourceBody.DebugInfo.LineStart;
                di.Parameters = sourceBody.DebugInfo.Parameters.ToList();

                foreach (var sourceInstruction in sourceBody.DebugInfo.DebugInstructions)
                {
                    di.DebugInstructions.Add(new DebugInstruction(sourceInstruction.OpCode,
                        sourceInstruction.Operands.ToList()));
                }
            }

            return body;
        }