Пример #1
0
        public void Transform(MethodBody body)
        {
#if DEBUG
            //return;
#endif
            var instructions = body.Instructions;
            var hasNops = instructions.Any(x => x.OpCode == OpCodes.Nop);
            if (!hasNops)
                return;

            var rerouter = new BranchReRouter(body);
            var i = 0;
            while (i < instructions.Count - 1)
            {
                var inst = instructions[i];
                if (inst.OpCode != OpCodes.Nop)
                {
                    i++;
                    continue;
                }

                if (body.Exceptions.Any(x => (x.TryEnd == inst) /*|| (x.TryStart == inst)*/))
                {
                    i++;
                    continue;
                }

                var next = instructions[i + 1];
                rerouter.Reroute(inst, next);
                instructions.RemoveAt(i);
            }
        }
Пример #2
0
 /// <summary>
 /// Optimize the given body
 /// </summary>
 internal static void Optimize(MethodBody body)
 {
     foreach (var transformation in optimizations)
     {
         transformation.Transform(body);
     }            
 }
Пример #3
0
            /// <summary>
            /// Add code to save low register to their original registers if needed.
            /// </summary>
            public void FinalizeBlock(MethodBody body)
            {
                // no need to restore registers after return or throw.
                if (block.Exit.OpCode.IsReturn() || block.Exit.OpCode == OpCodes.Throw)
                {
                    return;
                }

                Instruction endingNop = null;

                foreach (var lowRegState in lowRegisters.Where(x => x.SaveToOriginalNeeded))
                {
                    if (endingNop == null)
                    {
                        endingNop = new Instruction(OpCodes.Nop);
                        // Block exit can never be a branch target, so no need to reroute.
                        if (block.Exit.OpCode.IsBranch())
                        {
                            block.InsertBefore(block.Exit, endingNop);
                        }
                        else
                        {
                            block.InsertAfter(block.Exit, endingNop);
                        }
                    }
                    // Add move instruction to save low register to original
                    lowRegState.SaveToOriginalAndClear(endingNop, block, body, mapper.RegisterSpillingMap);
                }
            }
Пример #4
0
 public static string FormatRegister(Register r, MethodBody body)
 {
     if (body.IsComing(r))
     {
         int parameterIdx = r.Index - body.Registers.Count + body.IncomingArguments;
         return "p" + parameterIdx;
     }
     return "r" + r.Index;
 }
Пример #5
0
            /// <summary>
            /// Add instructions that spill registers (when needed).
            /// </summary>
            internal void Generate(MethodBody body)
            {
                // Go over each instruction in the block.
                var instructions = block.Instructions.ToList();

                foreach (var ins in instructions)
                {
                    var registers = ins.Registers;
                    var count     = registers.Count;
                    if (count == 0)
                    {
                        // No registers, so no spilling
                        continue;
                    }

                    var isInvoke = ins.OpCode.IsInvoke();
                    if (isInvoke)
                    {
                        if (ins.RequiresInvokeRange())
                        {
                            ConvertInvoke(ins);
                        }
                    }
                    else
                    {
                        var info = OpCodeInfo.Get(ins.OpCode);
                        for (var i = 0; i < count; i++)
                        {
                            Register         r;
                            LowRegisterState state;
                            var spill = TryGetLowRegister(registers[i], out r, out state);
                            if (!spill)
                            {
                                var size = info.GetUsage(i) & RegisterFlags.SizeMask;
                                switch (size)
                                {
                                case RegisterFlags.Bits4:
                                    spill = !registers[i].IsBits4;
                                    break;

                                case RegisterFlags.Bits8:
                                    spill = !registers[i].IsBits8;
                                    break;
                                }
                            }
                            if (spill)
                            {
                                // Insert spilling code
                                AddCode(ins, registers[i], body);
                            }
                        }
                    }
                }
            }
Пример #6
0
        public void Transform(MethodBody body)
        {
            // Prefix all aligned opcodes with a nop.
            // We'll decide later if we want to remove them.
            var instructions = body.Instructions;
            /*for (var i = 0; i < instructions.Count; i++ )
            {
                switch(instructions[i].OpCode)
                {
                    case OpCodes.Packed_switch:
                        instructions.Insert(i++, new Instruction(OpCodes.Nop));
                        break;
                }
            }*/

            body.UpdateInstructionOffsets();
            for (var i = 0; i < instructions.Count; i++)
            {
                var ins = instructions[i];
                switch (ins.OpCode)
                {
                    /*case OpCodes.Packed_switch:
                        if ((ins.Offset % 2) == 0)
                        {
                            instructions.RemoveAt(i - 1);
                        }
                        break;*/
                    case OpCodes.Goto:
                    case OpCodes.Goto_16:
                    case OpCodes.Goto_32:
                        var offset = (ins.Operand as Instruction).Offset - ins.Offset;
                        OpCodes opcode;
                        if (IsI8(offset))
                        {
                            opcode = OpCodes.Goto;
                        }
                        else if (IsI16(offset))
                        {
                            opcode = OpCodes.Goto_16;
                        } 
                        else
                        {
                            opcode = OpCodes.Goto_32;
                        }
                        if (ins.OpCode != opcode)
                        {
                            ins.OpCode = opcode;
                            body.UpdateInstructionOffsets();
                        }
                        break;
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Add instructions that spill registers (when needed).
        /// </summary>
        internal static void AddSpillingCode(MethodBody body, RegisterMapper mapper)
        {
            // Calculate the basic blocks
            var basicBlocks = BasicBlock.Find(body);
            var spillRegisters = mapper.SpillRegisters.ToList();
            var invokeFrame = mapper.InvocationFrameRegisters.ToList();
            var allRegisters = mapper.All.ToList();

            foreach (var block in basicBlocks)
            {
                var generator = new BlockSpillCodeGenerator(block, mapper, spillRegisters, invokeFrame, allRegisters);
                generator.Generate(body);
                generator.FinalizeBlock(body);
            }
        }
Пример #8
0
        /// <summary>
        /// Add instructions that spill registers (when needed).
        /// </summary>
        internal static void AddSpillingCode(MethodBody body, RegisterMapper mapper)
        {
            // Calculate the basic blocks
            var basicBlocks    = BasicBlock.Find(body);
            var spillRegisters = mapper.SpillRegisters.ToList();
            var invokeFrame    = mapper.InvocationFrameRegisters.ToList();
            var allRegisters   = mapper.All.ToList();

            foreach (var block in basicBlocks)
            {
                var generator = new BlockSpillCodeGenerator(block, mapper, spillRegisters, invokeFrame, allRegisters);
                generator.Generate(body);
                generator.FinalizeBlock(body);
            }
        }
Пример #9
0
        /// <summary>
        /// Replace all references to oldRegister with newRegister in the given instruction set.
        /// </summary>
        public static void ReplaceRegisterWith(this IEnumerable<Instruction> instructions, Register oldRegister, Register newRegister, MethodBody body)
        {
            var oldRegister2 = (oldRegister.Type == RType.Wide) ? body.GetNext(oldRegister) : null;
            var newRegister2 = (newRegister.Type == RType.Wide) ? body.GetNext(newRegister) : null;

            if (oldRegister.IsKeepWithNext != newRegister.IsKeepWithNext)
                throw new ArgumentException("New register has different keep-with-next value");

            foreach (var ins in instructions)
            {
                ins.ReplaceRegisterWith(oldRegister, newRegister);
                if (oldRegister2 != null)
                    ins.ReplaceRegisterWith(oldRegister2, newRegister2);
            }
        }
Пример #10
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public BranchReRouter(MethodBody body)
 {
     this.body = body;
     List<Instruction> list = null;
     // Record instructions with branch targets
     foreach (var inst in body.Instructions)
     {
         if (inst.OpCode.IsBranch())
         {
             list = list ?? new List<Instruction>();
             list.Add(inst);
         }
     }
     branches = list;
     exceptionHandlers = body.Exceptions.Any() ? body.Exceptions.ToArray() : null;
 }
Пример #11
0
            /// <summary>
            /// Add instructions that spill the given register.
            /// </summary>
            private void AddCode(Instruction ins, Register register, MethodBody body)
            {
                // Try to find an earlier map for the register
                {
                    Register         sReg;
                    LowRegisterState state;
                    if (TryGetLowRegister(register, out sReg, out state))
                    {
                        // Already mapped, just replace.
                        ReplaceRegister(ins, register, sReg);

                        // Should we save the low register now?
                        if ((!state.SaveToOriginalNeeded) && (sReg.IsDestinationIn(ins)))
                        {
                            state.SaveToOriginalNeeded = true;
                        }
                        return;
                    }
                }

                // Allocate low register
                var sRegState = AllocateLowRegister(ins, register, body);

                // We can now use sReg as replacement for register.
                // Add move (only if the register is a source of the instruction)
                if (register.IsSourceIn(ins))
                {
                    block.InsertBefore(ins, CreateMove(register, sRegState.LowRegister, GetType(register)));
                }
                // See if we need to save the low register afterwards
                if ((!sRegState.SaveToOriginalNeeded) && (register.IsDestinationIn(ins)))
                {
                    sRegState.SaveToOriginalNeeded = true;
                }
                // Replace the register
                ReplaceRegister(ins, register, sRegState.LowRegister);

                // Record start point in mapping
                sRegState.Mapping.FirstInstruction = ins;
            }
Пример #12
0
        public void Transform(MethodBody body)
        {
#if DEBUG
            //return;
#endif
            var instructions = body.Instructions;
            var hasNops = instructions.Any(x => x.OpCode == OpCodes.Nop);
            if (!hasNops)
                return;

            var rerouter = new BranchReRouter(body);
            var i = 0;
            while (i < instructions.Count - 1)
            {
                var inst = instructions[i];
                if (inst.OpCode != OpCodes.Nop)
                {
                    i++;
                    continue;
                }

                if (body.Exceptions.Any(x => (x.TryEnd == inst) /*|| (x.TryStart == inst)*/))
                {
                    i++;
                    continue;
                }

                var next = instructions[i + 1];

                // TODO: prevent removal of nop if the next instruction branches to this nop,
                //       (i.e. a spin loop); or, better, handle this case in the RL to dex compiler.

                rerouter.Reroute(inst, next);
                instructions.RemoveAt(i);
            }
        }
Пример #13
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public DexCompiler(RL.MethodBody rlBody, MethodBody dexBody, InvocationFrame frame)
 {
     this.rlBody  = rlBody;
     this.dexBody = dexBody;
     this.frame   = frame;
 }
Пример #14
0
        /// <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;
        }
Пример #15
0
            /// <summary>
            /// Add instructions that spill registers (when needed).
            /// </summary>
            internal void Generate(MethodBody body)
            {
                // Go over each instruction in the block.
                var instructions = block.Instructions.ToList();
                foreach (var ins in instructions)
                {
                    var registers = ins.Registers;
                    var count = registers.Count;
                    if (count == 0)
                    {
                        // No registers, so no spilling
                        continue;
                    }

                    var isInvoke = ins.OpCode.IsInvoke();
                    if (isInvoke)
                    {
                        if (ins.RequiresInvokeRange())
                        {
                            ConvertInvoke(ins);
                        }
                    }
                    else
                    {
                        var info = OpCodeInfo.Get(ins.OpCode);
                        for (var i = 0; i < count; i++)
                        {
                            Register r;
                            LowRegisterState state;
                            var spill = TryGetLowRegister(registers[i], out r, out state);
                            if (!spill)
                            {
                                var size = info.GetUsage(i) & RegisterFlags.SizeMask;
                                switch (size)
                                {
                                    case RegisterFlags.Bits4:
                                        spill = !registers[i].IsBits4;
                                        break;
                                    case RegisterFlags.Bits8:
                                        spill = !registers[i].IsBits8;
                                        break;
                                }
                            }
                            if (spill)
                            {
                                // Insert spilling code
                                AddCode(ins, registers[i], body);
                            }
                        }
                    }
                }
            }
Пример #16
0
 /// <summary>
 /// Save the state in the low register back to the original register when a save is needed.
 /// The save code is inserted directly before the given target instruction.
 /// </summary>
 public void SaveToOriginalAndClear(Instruction target, BasicBlock block, MethodBody body, RegisterSpillingMap map)
 {
     if (wideStart != null)
     {
         wideStart.SaveToOriginalAndClear(target, block, body, map);
     }
     else
     {
         if (SaveToOriginalNeeded)
         {
             var original = OriginalRegister;
             // Fix target to insert before
             if (target.OpCode.IsMoveResult())
             {
                 do
                 {
                     target = target.GetPrevious(body.Instructions);
                 } while (target.OpCode == OpCodes.Nop);
             }
             // Insert save code
             var move = CreateMove(LowRegister, original, type);
             block.InsertBefore(target, move);
             // Save end in mapping
             Mapping.LastInstruction = move;
             // Record mapping
             map.Add(Mapping);
         }
         Clear();
     }
 }
Пример #17
0
            /// <summary>
            /// Allocate a low register and map it to the given original register.
            /// </summary>
            private LowRegisterState AllocateLowRegister(Instruction ins, Register register, MethodBody body)
            {
                // Prepare
                var type = GetType(register);
                var isWide = (type == RType.Wide);
                var regsNeeded = isWide ? 2 : 1;

                LowRegisterState regState = null;
                HashSet<Register> allRegistersUsedInIns = null;
                while (true)
                {
                    // Try to allocate free spilling register
                    regState = lowRegisters.FirstOrDefault(x => x.IsFreeFor(type));
                    if (regState != null)
                        break; // Found a free low register

                    // No spilling register is available.
                    // Free another register first
                    // If wide, free 2 registers
                    if (nextSpillIndex + regsNeeded > lowRegisters.Length) nextSpillIndex = 0;
                    regState = lowRegisters[nextSpillIndex];
                    var regStateNext = isWide ? lowRegisters[nextSpillIndex + 1] : null;

                    // Update index so we take another the next time
                    nextSpillIndex = (nextSpillIndex + regsNeeded) % (lowRegisters.Length - 1);

                    // Do not allocate registers already used in the current instruction
                    allRegistersUsedInIns = allRegistersUsedInIns ?? GetAllUsedRegisters(ins);
                    if (allRegistersUsedInIns.Contains(regState.LowRegister))
                        continue;
                    if ((regStateNext != null) && allRegistersUsedInIns.Contains(regStateNext.LowRegister))
                        continue;
             
                    // Save sReg back to original register
                    var map = mapper.RegisterSpillingMap;
                    regState.SaveToOriginalAndClear(ins, block, body, map);
                    if (regStateNext != null) regStateNext.SaveToOriginalAndClear(ins, block, body, map);
                }
                // Add mapping
                regState.SetInUseBy(register, type);
                return regState;
            }
Пример #18
0
            /// <summary>
            /// Add instructions that spill the given register.
            /// </summary>
            private void AddCode(Instruction ins, Register register, MethodBody body)
            {
                // Try to find an earlier map for the register
                {
                    Register sReg;
                    LowRegisterState state;
                    if (TryGetLowRegister(register, out sReg, out state))
                    {
                        // Already mapped, just replace.
                        ReplaceRegister(ins, register, sReg);

                        // Should we save the low register now?
                        if ((!state.SaveToOriginalNeeded) && (sReg.IsDestinationIn(ins)))
                        {
                            state.SaveToOriginalNeeded = true;
                        }
                        return;
                    }
                }

                // Allocate low register
                var sRegState = AllocateLowRegister(ins, register, body);

                // We can now use sReg as replacement for register.
                // Add move (only if the register is a source of the instruction)
                if (register.IsSourceIn(ins))
                {
                    block.InsertBefore(ins, CreateMove(register, sRegState.LowRegister, GetType(register)));
                }
                // See if we need to save the low register afterwards
                if ((!sRegState.SaveToOriginalNeeded) && (register.IsDestinationIn(ins)))
                {
                    sRegState.SaveToOriginalNeeded = true;
                }
                // Replace the register
                ReplaceRegister(ins, register, sRegState.LowRegister);

                // Record start point in mapping
                sRegState.Mapping.FirstInstruction = ins;
            }
Пример #19
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public DexCompiler(RL.MethodBody rlBody, MethodBody dexBody, InvocationFrame frame)
 {
     this.rlBody = rlBody;
     this.dexBody = dexBody;
     this.frame = frame;
 }
Пример #20
0
            /// <summary>
            /// Add code to save low register to their original registers if needed.
            /// </summary>
            public void FinalizeBlock(MethodBody body)
            {
                // no need to restore registers after return or throw.
                if (block.Exit.OpCode.IsReturn() || block.Exit.OpCode == OpCodes.Throw)
                    return;

                Instruction endingNop = null;
                
                foreach (var lowRegState in lowRegisters.Where(x => x.SaveToOriginalNeeded))
                {
                    if (endingNop == null)
                    {
                        endingNop = new Instruction(OpCodes.Nop);
                        // Block exit can never be a branch target, so no need to reroute.
                        if (block.Exit.OpCode.IsBranch())
                            block.InsertBefore(block.Exit, endingNop);
                        else
                            block.InsertAfter(block.Exit, endingNop);
                    }
                    // Add move instruction to save low register to original
                    lowRegState.SaveToOriginalAndClear(endingNop, block, body, mapper.RegisterSpillingMap);
                }
            }
Пример #21
0
        /// <summary>
        /// Find all basic blocks in the given body.
        /// </summary>
        public static List<BasicBlock> Find(MethodBody body)
        {
            var instructions = body.Instructions;
            if (instructions.Count == 0)
                return new List<BasicBlock>();

            var targetInstructions = body.Instructions.Select(x => x.Operand).OfType<Instruction>().ToList();
            targetInstructions.AddRange(instructions.Select(x => x.Operand).OfType<ISwitchData>().SelectMany(x => x.GetTargets()));
            targetInstructions.AddRange(instructions.Where(x => x.OpCode.IsBranch()).Select(x => GetNextOrDefault(instructions, x)));
            targetInstructions.AddRange(body.Exceptions.Select(x => x.TryStart));
            targetInstructions.AddRange(body.Exceptions.Select(x => GetNextOrDefault(instructions, x.TryEnd)));
            targetInstructions.AddRange(body.Exceptions.SelectMany(x => x.Catches, (h, y) => y.Instruction));
            targetInstructions.AddRange(body.Exceptions.Select(x => x.CatchAll));
            targetInstructions.Add(body.Instructions[0]);

            // Get sorted list with duplicates removed.
            var startInstructions = targetInstructions.Where(x => x != null).Distinct().OrderBy(instructions.IndexOf).ToList();
            var result = new List<BasicBlock>();
            for (var i = 0; i < startInstructions.Count; i++)
            {
                var entry = startInstructions[i];
                var exit = (i + 1 < startInstructions.Count)
                               ? GetPrevious(instructions, startInstructions[i + 1])
                               : body.Instructions[body.Instructions.Count - 1];
                result.Add(new BasicBlock(body.Instructions, entry, exit));
            }
            return result;
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public bool Transform(Dex target, MethodBody body)
        {
            // Build the control flow graph
            var cfg = new ControlFlowGraph(body);

            // Go over each block to find registers that are initialized and may need initialization
            foreach (var iterator in cfg)
            {
                var block = iterator;
                var data = new BasicBlockData(block);
                block.Tag = data;

                // Go over all instructions in the block, finding source/destination registers
                foreach (var ins in block.Instructions)
                {
                    var info = OpCodeInfo.Get(ins.Code.ToDex());
                    var count = ins.Registers.Count;
                    for (var i = 0; i < count; i++)
                    {
                        var reg = ins.Registers[i];
                        if (reg.Category != RCategory.Argument)
                        {
                            var flags = info.GetUsage(i);
                            if (flags.HasFlag(RegisterFlags.Source))
                            {
                                // Must be initialize
                                if (!data.Initialized.Contains(reg))
                                {
                                    data.MayNeedInitialization.Add(reg);
                                }
                            }
                            if (flags.HasFlag(RegisterFlags.Destination))
                            {
                                // Destination
                                data.Initialized.Add(reg);
                            }
                        }
                    }
                }

            }

            // Go over all blocks to collect the register that really need initialization
            var needInitialization = new HashSet<Register>();
            foreach (var iterator in cfg)
            {
                var block = iterator;
                var data = (BasicBlockData)block.Tag;

                foreach (var regIterator in data.MayNeedInitialization)
                {
                    // Short cut
                    var reg = regIterator;
                    if (needInitialization.Contains(reg))
                        continue;

                    // If the register is initialized in all entry blocks, we do not need to initialize it
                    if (block.EntryBlocks.Select(x => (BasicBlockData) x.Tag).Any(x => !x.IsInitialized(reg)))
                    {
                        // There is an entry block that does not initialize the register, so we have to initialize it
                        needInitialization.Add(reg);
                    }
                }
            }

            var index = 0;
            Register valueReg = null;
            Register objectReg = null;
            Register wideReg = null;
            var firstSourceLocation = body.Instructions[0].SequencePoint;
            foreach (var reg in needInitialization.OrderBy(x => x.Index))
            {
                switch (reg.Type)
                {
                    case RType.Value:
                        if (valueReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] {reg}) { SequencePoint = firstSourceLocation });
                            valueReg = reg;
                        }
                        else if (valueReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move, reg, valueReg) { SequencePoint = firstSourceLocation });                            
                        }
                        break;
                    case RType.Object:
                        if (objectReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] { reg }) { SequencePoint = firstSourceLocation });
                            objectReg = reg;
                        }
                        else if (objectReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move_object, reg, objectReg) { SequencePoint = firstSourceLocation });
                        }
                        break;
                    case RType.Wide:
                        if (wideReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const_wide, 0, new[] { reg }) { SequencePoint = firstSourceLocation });
                            wideReg = reg;
                        }
                        else if (wideReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move_wide, reg, wideReg) { SequencePoint = firstSourceLocation });
                        }
                        break;
                }
            }

            return false;
        }
Пример #23
0
        public static void Transform(MethodBody body)
        {
            //Debugger.Launch();
            foreach (var ins in body.Instructions)
            {
                switch (ins.OpCode)
                {
                    case OpCodes.Add_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Add_int);
                        break;
                    case OpCodes.Sub_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Sub_int);
                        break;
                    case OpCodes.Mul_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Mul_int);
                        break;
                    case OpCodes.Div_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Div_int);
                        break;
                    case OpCodes.Rem_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Rem_int);
                        break;
                    case OpCodes.And_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.And_int);
                        break;
                    case OpCodes.Or_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Or_int);
                        break;
                    case OpCodes.Xor_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Xor_int);
                        break;
                    case OpCodes.Shl_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Shl_int);
                        break;
                    case OpCodes.Shr_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Shr_int);
                        break;
                    case OpCodes.Ushr_int_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Ushr_int);
                        break;

                    case OpCodes.Add_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Add_long);
                        break;
                    case OpCodes.Sub_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Sub_long);
                        break;
                    case OpCodes.Mul_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Mul_long);
                        break;
                    case OpCodes.Div_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Div_long);
                        break;
                    case OpCodes.Rem_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Rem_long);
                        break;
                    case OpCodes.And_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.And_long);
                        break;
                    case OpCodes.Or_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Or_long);
                        break;
                    case OpCodes.Xor_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Xor_long);
                        break;
                    case OpCodes.Shl_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Shl_long);
                        break;
                    case OpCodes.Shr_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Shr_long);
                        break;
                    case OpCodes.Ushr_long_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Ushr_long);
                        break;

                    case OpCodes.Add_float_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Add_float);
                        break;
                    case OpCodes.Sub_float_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Sub_float);
                        break;
                    case OpCodes.Mul_float_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Mul_float);
                        break;
                    case OpCodes.Div_float_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Div_float);
                        break;
                    case OpCodes.Rem_float_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Rem_float);
                        break;

                    case OpCodes.Add_double_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Add_double);
                        break;
                    case OpCodes.Sub_double_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Sub_double);
                        break;
                    case OpCodes.Mul_double_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Mul_double);
                        break;
                    case OpCodes.Div_double_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Div_double);
                        break;
                    case OpCodes.Rem_double_2addr:
                        OptimizeBinOp2Addr(ins, OpCodes.Rem_double);
                        break;
                }
            }
        }
Пример #24
0
 public DebugInfo(MethodBody body)
 {
     Owner = body;
     Parameters = new List<string>();
     DebugInstructions = new List<DebugInstruction>();
 }
Пример #25
0
            /// <summary>
            /// Allocate a low register and map it to the given original register.
            /// </summary>
            private LowRegisterState AllocateLowRegister(Instruction ins, Register register, MethodBody body)
            {
                // Prepare
                var type       = GetType(register);
                var isWide     = (type == RType.Wide);
                var regsNeeded = isWide ? 2 : 1;

                LowRegisterState   regState = null;
                HashSet <Register> allRegistersUsedInIns = null;

                while (true)
                {
                    // Try to allocate free spilling register
                    regState = lowRegisters.FirstOrDefault(x => x.IsFreeFor(type));
                    if (regState != null)
                    {
                        break; // Found a free low register
                    }
                    // No spilling register is available.
                    // Free another register first
                    // If wide, free 2 registers
                    if (nextSpillIndex + regsNeeded > lowRegisters.Length)
                    {
                        nextSpillIndex = 0;
                    }
                    regState = lowRegisters[nextSpillIndex];
                    var regStateNext = isWide ? lowRegisters[nextSpillIndex + 1] : null;

                    // Update index so we take another the next time
                    nextSpillIndex = (nextSpillIndex + regsNeeded) % (lowRegisters.Length - 1);

                    // Do not allocate registers already used in the current instruction
                    allRegistersUsedInIns = allRegistersUsedInIns ?? GetAllUsedRegisters(ins);
                    if (allRegistersUsedInIns.Contains(regState.LowRegister))
                    {
                        continue;
                    }
                    if ((regStateNext != null) && allRegistersUsedInIns.Contains(regStateNext.LowRegister))
                    {
                        continue;
                    }

                    // Save sReg back to original register
                    var map = mapper.RegisterSpillingMap;
                    regState.SaveToOriginalAndClear(ins, block, body, map);
                    if (regStateNext != null)
                    {
                        regStateNext.SaveToOriginalAndClear(ins, block, body, map);
                    }
                }
                // Add mapping
                regState.SetInUseBy(register, type);
                return(regState);
            }
Пример #26
0
        private static void FormatOperand_Instruction(StringBuilder ops, Instruction ins, MethodBody body, Instruction target, bool compact)
        {
            ops.Append(JumpMarker);
            ops.Append(" ");
            ops.Append(target.Offset.ToString("X3"));

                int targetIdx = body.Instructions.IndexOf(target);
                int myIdx = body.Instructions.IndexOf(ins);

            ops.Append(!compact ? " ; " : "(");

            int offset = (targetIdx - myIdx);
            ops.Append(offset.ToString("+0;-0;+0"));

            if (compact)
                ops.Append(")");
        }
Пример #27
0
        public static string FormatOperands(Instruction ins, MethodBody body, FormatOptions options = FormatOptions.Default)
        {
            StringBuilder ops = new StringBuilder();

            bool fullTypeNames = options.HasFlag(FormatOptions.FullTypeNames);

            foreach (var r in ins.Registers)
            {
                if (ops.Length > 0)
                {
                    ops.Append(",");
                    Align(ops, 4);
                }
                ops.Append(FormatRegister(r, body));
            }
            if (ops.Length == 0)
                ops.Append(" ");

            if (ins.Operand != null)
            {
                Align(ops, 12);

                if (ins.Operand is string)
                {
                    ops.Append("\"");
                    ops.Append(ins.Operand);
                    ops.Append("\"");
                }
                else if (ins.Operand is sbyte)
                {
                    FormatOperand_Integer(ops, (int)(byte)(sbyte)ins.Operand, "X2");
                }
                else if (ins.Operand is short)
                {
                    FormatOperand_Integer(ops, (int) (short) ins.Operand);
                }
                else if (ins.Operand is int)
                {
                    FormatOperand_Integer(ops, (int) ins.Operand);
                }
                else if (ins.Operand is long)
                {
                    var l = (long) ins.Operand;
                    ops.Append(l);

                    ops.Append(" (0x");
                    ops.Append(l.ToString("X8"));
                    ops.Append(")");
                }
                else if (ins.Operand is Instruction)
                {
                    var target = (Instruction) ins.Operand;
                    FormatOperand_Instruction(ops, ins, body, target, false);
                }
                else if (ins.Operand is ClassReference)
                {
                    var m = (ClassReference) ins.Operand;
                    ops.Append(fullTypeNames ? m.ToString() : m.Name);
                }
                else if (ins.Operand is MethodReference)
                {
                    var m = (MethodReference) ins.Operand;
                    var owner = fullTypeNames || !(m.Owner is ClassReference)
                        ? m.ToString()
                        : ((ClassReference) m.Owner).Name;
                    ops.Append(owner + "::" + m.Name + m.Prototype);
                }
                else if (ins.Operand is FieldReference)
                {
                    var m = (FieldReference) ins.Operand;
                    ops.Append(fullTypeNames ? m.ToString() : m.Owner.Name + "::" + m.Name + " : " + m.Type);
                }
                else if (ins.Operand is PackedSwitchData)
                {
                    var d = (PackedSwitchData) ins.Operand;
                    FormatOperand_Integer(ops, d.FirstKey);
                    ops.Append(":");
                    foreach (var target in d.Targets)
                    {
                        ops.Append(" ");
                        FormatOperand_Instruction(ops, ins, body, target, true);
                    }
                }
                else if (ins.Operand is SparseSwitchData)
                {
                    var d = (SparseSwitchData) ins.Operand;
                    bool isFirst = true;
                    foreach (var target in d.Targets)
                    {
                        if (!isFirst)
                            ops.Append(" ");
                        ops.Append(target.Key);
                        ops.Append(": ");
                        FormatOperand_Instruction(ops, ins, body, target.Value, true);
                        isFirst = false;
                    }
                }
                else
                {
                    ops.Append(ins.Operand);
                }

                if (options.HasFlag(FormatOptions.DebugOperandTypes))
                    ops.AppendFormat(" [{0}]", ins.Operand.GetType().Name);
            }

            var bstrOperands = ops.ToString();
            return bstrOperands;
        }
Пример #28
0
 /// <summary>
 /// Save the state in the low register back to the original register when a save is needed.
 /// The save code is inserted directly before the given target instruction.
 /// </summary>
 public void SaveToOriginalAndClear(Instruction target, BasicBlock block, MethodBody body, RegisterSpillingMap map)
 {
     if (wideStart != null)
     {
         wideStart.SaveToOriginalAndClear(target, block, body, map);
     }
     else
     {
         if (SaveToOriginalNeeded)
         {
             var original = OriginalRegister;
             // Fix target to insert before
             if (target.OpCode.IsMoveResult())
             {
                 do
                 {
                     target = target.GetPrevious(body.Instructions);
                 } while (target.OpCode == OpCodes.Nop);
             }
             // Insert save code
             var move = CreateMove(LowRegister, original, type);
             block.InsertBefore(target, move);
             // Save end in mapping
             Mapping.LastInstruction = move;
             // Record mapping
             map.Add(Mapping);
         }
         Clear();
     }
 }
Пример #29
0
        /// <summary>
        /// Create debug info for the given (otherwise completed) body.
        /// </summary>
        internal void CreateDebugInfo(MethodBody dbody, RegisterMapper regMapper, DexTargetPackage targetPackage)
        {
            var source = compiledMethod.ILSource;
            if ((source == null) || !source.HasBody || (source.Body.Instructions.Count == 0))
                return;

            // Initialize
            var info = new DebugInfo(dbody);
            info.Parameters.AddRange(dbody.Owner.Prototype.Parameters.Select(x => x.Name ?? "?"));

            // Should be at a better location perhaps
            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.SetPrologueEnd));

            // Get instructions with valid sequence points
            var validTuples = dbody.Instructions.Select(x => Tuple.Create(x, x.SequencePoint as ISourceLocation)).Where(x => x.Item2 != null && !x.Item2.IsSpecial).ToList();

            // Assign line numbers
            var lineNumbers = AssignLineNumbers(validTuples.Select(x => x.Item2));

            // Set default document
            string lastUrl = null;
            var setLineStart = true;
            int lastLine = 0;
            int lastOffset = 0;                      
            var firstDocument = validTuples.Select(x => x.Item2).FirstOrDefault(x => x != null && x.Document != null);
            if (firstDocument != null)
            {
                lastUrl = firstDocument.Document;
                lastLine = firstDocument.StartLine;
                info.LineStart = (uint) lastLine;
                setLineStart = false;

                // Set on type or when different in debug info.
                var type = dbody.Owner.Owner;
                if (string.IsNullOrEmpty(type.SourceFile))
                    type.SourceFile = lastUrl;

                if (type.SourceFile != lastUrl)
                {
                    // Make sure the file is set when needed
                    lastUrl = null;
                }
            }

            // Build intermediate list
            var entries = new List<Entry>();

            // Add line numbers
            foreach (var tuple in validTuples)
            {
                var ins = tuple.Item1;
                var seqp = tuple.Item2;
                var lineNumber = GetLineNumber(seqp, lineNumbers);

                // Line number
                if (setLineStart)
                {
                    info.LineStart = (uint)lineNumber;
                    setLineStart = false;
                }

                var url = seqp.Document;
                entries.Add(new PositionEntry(ins.Offset, lineNumber, url));
            }

            // Add variables
            ControlFlowGraph cfg = null;
            foreach (var tuple in regMapper.VariableRegisters)
            {
                var reg = tuple.Register;
                var variable = tuple.Variable;
                if (variable.IsCompilerGenerated)
                    continue;
                var dexType = variable.GetType(targetPackage);
                if (dexType == null)
                    continue;

                // Find out in which basic blocks the variable is live
                cfg = cfg ?? new ControlFlowGraph(dbody);
                var startMap = new Dictionary<BasicBlock, Instruction>();
                foreach (var block in cfg)
                {
                    // First instruction from that first writes to the register.
                    var firstWrite = block.Instructions.FirstOrDefault(reg.IsDestinationIn);
                    if (firstWrite == null)
                        continue;

                    // The variable is valid the first instruction after the first write.
                    Instruction start;
                    if (!firstWrite.TryGetNext(dbody.Instructions, out start))
                        continue;
                    startMap.Add(block, start);
                    block.AddLiveRegisterAtExit(reg);                    
                }

                if (startMap.Count == 0)
                    continue;

                // Generate start-restart-end entries
                VariableEndEntry lastBlockEndEntry = null;
                foreach (var block in cfg)
                {
                    Instruction start;
                    var started = false;
                    if (block.IsLiveAtEntry(reg))
                    {
                        // Live in the entire block
                        if (lastBlockEndEntry == null)
                        {
                            // We have to start/restart
                            entries.Add(new VariableStartEntry(block.Entry.Offset, reg, variable, dexType));
                        }
                        else
                        {
                            // Remove the end-entry of the previous block
                            entries.Remove(lastBlockEndEntry);
                        }
                        started = true;
                    }
                    else if (startMap.TryGetValue(block, out start))
                    {
                        // Live from "start"
                        entries.Add(new VariableStartEntry(start.Offset, reg, variable, dexType));
                        started = true;
                    }

                    Instruction next;
                    lastBlockEndEntry = null;
                    if (started && block.Exit.TryGetNext(dbody.Instructions, out next))
                    {
                        // Add end block
                        entries.Add(lastBlockEndEntry = new VariableEndEntry(next.Offset, reg, variable));
                    }
                }

                // Weave in splilling info
                var spillMappings = regMapper.RegisterSpillingMap.Find(reg).ToList();
                if (spillMappings.Count > 0)
                {
                    foreach (var mapping in spillMappings)
                    {
                        var alreadyStarted = IsStartedAt(entries, variable, mapping.FirstInstruction.Offset);
                        if (alreadyStarted)
                        {
                            // Stop now
                            var prev = mapping.FirstInstruction.GetPrevious(dbody.Instructions);
                            entries.Add(new VariableEndEntry(prev.Offset, mapping.HighRegister, variable));
                        }

                        // Add mappings for low register
                        entries.Add(new VariableStartEntry(mapping.FirstInstruction.Offset, mapping.LowRegister, variable, dexType));
                        entries.Add(new VariableEndEntry(mapping.LastInstruction.Offset, mapping.LowRegister, variable));

                        if (alreadyStarted)
                        {
                            // Restart on high register
                            Instruction next;
                            if (mapping.LastInstruction.TryGetNext(dbody.Instructions, out next))
                            {
                                entries.Add(new VariableStartEntry(next.Offset, mapping.HighRegister, variable, dexType));
                            }
                        }
                    }
                }
            }

            // Generate instructions
            entries.Sort();
            var firstPositionEntry = true;
            var startedVarirables = new HashSet<Register>();
            foreach (var entry in entries)
            {
                entry.Generate(info, ref lastLine, ref lastOffset, ref lastUrl, ref firstPositionEntry, startedVarirables);
            }

            // Terminate
            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.EndSequence));

            // Attached
            dbody.DebugInfo = info;
        }
Пример #30
0
 public void Transform(MethodBody body)
 {
     //Debugger.Launch();
     foreach (var ins in body.Instructions)
     {
         switch (ins.OpCode)
         {
             case OpCodes.Const:
             case OpCodes.Const_4:
             case OpCodes.Const_16:
             case OpCodes.Const_high16:
                 if (IsI4(ins.Operand) && Is4Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Const_4;
                 }
                 else if (IsI16(ins.Operand) && Is8Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Const_16;
                 }
                 else if (IsIHigh16(ins.Operand) && Is8Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Const_high16;
                 }
                 else
                 {
                     ins.OpCode = OpCodes.Const;
                 }
                 break;
             case OpCodes.Const_wide:
             case OpCodes.Const_wide_16:
             case OpCodes.Const_wide_32:
             case OpCodes.Const_wide_high16:
                 {
                     // Convert int to long
                     if (ins.Operand is int)
                     {
                         ins.Operand = (long) ((int) ins.Operand);
                     }
                 }
                 break;
             case OpCodes.Move:
             case OpCodes.Move_16:
             case OpCodes.Move_from16:
                 if (Is4Bits(ins.Registers[0]) && Is4Bits(ins.Registers[1]))
                 {
                     ins.OpCode = OpCodes.Move;
                 }
                 else if (Is8Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Move_from16;
                 }
                 else
                 {
                     ins.OpCode = OpCodes.Move_16;
                 }
                 break;
             case OpCodes.Move_wide:
             case OpCodes.Move_wide_16:
             case OpCodes.Move_wide_from16:
                 if (Is4Bits(ins.Registers[0]) && Is4Bits(ins.Registers[1]))
                 {
                     ins.OpCode = OpCodes.Move_wide;
                 }
                 else if (Is8Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Move_wide_from16;
                 }
                 else
                 {
                     ins.OpCode = OpCodes.Move_wide_16;                            
                 }
                 break;
             case OpCodes.Move_object:
             case OpCodes.Move_object_16:
             case OpCodes.Move_object_from16:
                 if (Is4Bits(ins.Registers[0]) && Is4Bits(ins.Registers[1]))
                 {
                     ins.OpCode = OpCodes.Move_object;
                 }
                 else if (Is8Bits(ins.Registers[0]))
                 {
                     ins.OpCode = OpCodes.Move_object_from16;
                 }
                 else
                 {
                     ins.OpCode = OpCodes.Move_object_16;
                 }
                 break;
         }
     }
 }
Пример #31
0
 public RegisterNames(MethodBody body, bool hasMethodParametersInLastRegister)
 {
     _body = body;
     _hasMethodParametersInLastRegister = hasMethodParametersInLastRegister;
 }