Beispiel #1
0
        /// <summary>
        /// Do all registers of the given instruction fit in the size that is available for them?
        /// </summary>
        private static bool AllRegistersFit(Instruction ins)
        {
            var registers = ins.Registers;
            var count     = registers.Count;

            if (count == 0)
            {
                return(true);
            }
            var info = OpCodeInfo.Get(ins.OpCode);

            for (var i = 0; i < count; i++)
            {
                var size = info.GetUsage(i) & RegisterFlags.SizeMask;
                switch (size)
                {
                case RegisterFlags.Bits4:
                    if (!registers[i].IsBits4)
                    {
                        return(false);
                    }
                    break;

                case RegisterFlags.Bits8:
                    if (!registers[i].IsBits8)
                    {
                        return(false);
                    }
                    break;
                }
            }
            return(true);
        }
Beispiel #2
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();
     }
 }
            /// <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);
                }
            }
Beispiel #4
0
 /// <summary>
 /// Replace all occurrences of oldTarget with newTarget.
 /// </summary>
 public void ReplaceTarget(Instruction oldTarget, Instruction newTarget)
 {
     var keys = targets.Where(x => x.Value == oldTarget).Select(entry => entry.Key).ToList();
     foreach (var key in keys)
     {
         targets[key] = newTarget;
     }
 }
Beispiel #5
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);
            }
Beispiel #6
0
 /// <summary>
 /// Replace all occurrences of oldTarget with newTarget.
 /// </summary>
 public void ReplaceTarget(Instruction oldTarget, Instruction newTarget)
 {
     var count = targets.Count;
     for (var i = 0; i < count; i++)
     {
         if (targets[i] == oldTarget)
         {
             targets[i] = newTarget;
         }
     }
 }
Beispiel #7
0
 /// <summary>
 /// Convert the given instruction into 1 or more dex instructions.
 /// </summary>
 internal static IEnumerable<Instruction> Convert(RL.Instruction source, RegisterMapper regMapper)
 {
     var dexIns = new Instruction(source.Code.ToDex(), source.Operand) { SequencePoint = source.SequencePoint };
     var dexRegisters = dexIns.Registers;
     dexRegisters.AddRange(source.Registers.Select(x => regMapper[x]));
     if (!AllRegistersFit(dexIns) || dexIns.RequiresInvokeRange())
     {
         // At least 1 register does not fit.
         // Insert a NOP first so we do not have to re-route when we insert spilling code.
         yield return new Instruction(OpCodes.Nop);
     }
     yield return dexIns;
 }
Beispiel #8
0
 /// <summary>
 /// Get the instruction direct after the given instruction.
 /// </summary>
 internal static bool TryGetNext(this Instruction instruction, List<Instruction> instructions, out Instruction next)
 {
     next = null;
     for (var index = 0; index < instructions.Count; index++)
     {
         if (instructions[index] == instruction)
         {
             if (index == instructions.Count - 1)
                 return false;
             next = instructions[index + 1];
             return true;
         }
     }
     return false;
 }
Beispiel #9
0
            /// <summary>
            /// Gets all registers used in the given instruction, include "next" registers in case of wide operands.
            /// </summary>
            private HashSet <Register> GetAllUsedRegisters(Instruction ins)
            {
                var set = new HashSet <Register>();

                foreach (var r in ins.Registers)
                {
                    set.Add(r);
                    if (GetType(r) == RType.Wide)
                    {
                        // Include next register
                        var next = allRegisters.First(x => x.Index == r.Index + 1);
                        set.Add(next);
                    }
                }
                return(set);
            }
Beispiel #10
0
 /// <summary>
 /// Is the given register used as destination in the given instruction?
 /// </summary>
 public static bool IsDestinationIn(this Register register, Instruction ins)
 {
     var registers = ins.Registers;
     var count = registers.Count;
     if (count == 0)
         return false;
     var info = OpCodeInfo.Get(ins.OpCode);
     for (var i = 0; i < count; i++)
     {
         if (registers[i] == register)
         {
             if ((info.GetUsage(i) & RegisterFlags.Destination) == RegisterFlags.Destination)
                 return true;
         }
     }
     return false;
 }
Beispiel #11
0
        /// <summary>
        /// Convert the given instruction into 1 or more dex instructions.
        /// </summary>
        internal static IEnumerable <Instruction> Convert(RL.Instruction source, RegisterMapper regMapper)
        {
            var dexIns = new Instruction(source.Code.ToDex(), source.Operand)
            {
                SequencePoint = source.SequencePoint
            };
            var dexRegisters = dexIns.Registers;

            dexRegisters.AddRange(source.Registers.Select(x => regMapper[x]));
            if (!AllRegistersFit(dexIns) || dexIns.RequiresInvokeRange())
            {
                // At least 1 register does not fit.
                // Insert a NOP first so we do not have to re-route when we insert spilling code.
                yield return(new Instruction(OpCodes.Nop));
            }
            yield return(dexIns);
        }
Beispiel #12
0
 /// <summary>
 /// Is the given register used as source in the given instruction?
 /// </summary>
 public static bool IsSourceIn(this Register r, Instruction ins)
 {
     var registers = ins.Registers;
     var count = registers.Count;
     if (count == 0)
         return false;
     var info = OpCodeInfo.Get(ins.Code.ToDex());
     for (var i = 0; i < count; i++)
     {
         if (registers[i] == r)
         {
             if ((info.GetUsage(i) & RegisterFlags.Source) == RegisterFlags.Source)
                 return true;
         }
     }
     return false;
 }
Beispiel #13
0
        /// <summary>
        /// Reroute all old targets to the new targets.
        /// </summary>
        public void Reroute(Instruction oldTarget, Instruction newTarget)
        {
            if (branches != null)
            {
                var count = branches.Count;
                for (var i = 0; i < count; i++)
                {
                    var ins = branches[i];
                    if (ins.Operand == oldTarget)
                    {
                        ins.Operand = newTarget;
                    }
                    else if (ins.OpCode == OpCodes.Packed_switch || ins.OpCode== OpCodes.Sparse_switch)
                    {
                        var targets = (ISwitchData)ins.Operand;
                        targets.ReplaceTarget(oldTarget, newTarget);
                    }
                }
            }

            if (exceptionHandlers != null)
            {
                var count = exceptionHandlers.Length;
                for (var i = 0; i < count; i++)
                {
                    var eh = exceptionHandlers[i];
                    if (eh.CatchAll == oldTarget) { eh.CatchAll = newTarget; }
                    if (eh.TryEnd == oldTarget) { eh.TryEnd = GetPrevious(oldTarget); }
                    if (eh.TryStart == oldTarget) { eh.TryStart = newTarget; }
                    foreach (var c in eh.Catches)
                    {
                        if (c.Instruction == oldTarget) c.Instruction = newTarget;
                    }
                }
            }

            // Save PDB info
            /*if ((oldTarget.SequencePoint != null) && (newTarget.SequencePoint == null))
            {
                newTarget.SequencePoint = oldTarget.SequencePoint;
            }*/
        }
Beispiel #14
0
            /// <summary>
            /// Replace all occurrences of from to to in the register list of the given instruction.
            /// </summary>
            private static void ReplaceRegister(Instruction ins, Register from, Register to)
            {
                if (from == null)
                {
                    throw new ArgumentNullException("from");
                }
                if (to == null)
                {
                    throw new ArgumentNullException("to");
                }
                var registers = ins.Registers;
                var count     = registers.Count;

                for (var i = 0; i < count; i++)
                {
                    if (registers[i] == from)
                    {
                        registers[i] = to;
                    }
                }
            }
Beispiel #15
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;
            }
Beispiel #16
0
            /// <summary>
            /// Convert a normal invoke_x to invoke_x_range.
            /// </summary>
            private void ConvertInvoke(Instruction ins)
            {
                var registers = ins.Registers;
                var count     = registers.Count;

                if (count == 0)
                {
                    return;
                }

                // Replace all registers with their "spill" variant (if any)
                for (var i = 0; i < count; i++)
                {
                    Register         sReg;
                    LowRegisterState state;
                    if (TryGetLowRegister(registers[i], out sReg, out state))
                    {
                        ReplaceRegister(ins, registers[i], sReg);
                    }
                }

                // By replacing the registers, it it possible to avoid the invoke_x_range opcodes?
                if (!ins.RequiresInvokeRange())
                {
                    return;
                }

                if (!IsValidInvokeRange(registers))
                {
                    // Use invoke frame
                    for (var i = 0; i < count; i++)
                    {
                        var type = GetType(registers[i]);
                        block.InsertBefore(ins, CreateMove(registers[i], invokeFrame[i], type));
                        registers[i] = invokeFrame[i];
                    }
                }
                // Change opcode
                ins.OpCode = ins.OpCode.InvokeToRange();
            }
Beispiel #17
0
 /// <summary>
 /// Do all registers of the given instruction fit in the size that is available for them?
 /// </summary>
 private static bool AllRegistersFit(Instruction ins)
 {
     var registers = ins.Registers;
     var count = registers.Count;
     if (count == 0)
         return true;
     var info = OpCodeInfo.Get(ins.OpCode);
     for (var i = 0; i < count; i++)
     {
         var size = info.GetUsage(i) & RegisterFlags.SizeMask;
         switch (size)
         {
             case RegisterFlags.Bits4:
                 if (!registers[i].IsBits4)
                     return false;
                 break;
             case RegisterFlags.Bits8:
                 if (!registers[i].IsBits8)
                     return false;
                 break;
         }
     }
     return true;
 }
Beispiel #18
0
 /// <summary>
 /// Replace all occurrences of from to to in the register list of the given instruction.
 /// </summary>
 private static void ReplaceRegister(Instruction ins, Register from, Register to)
 {
     if (from == null)
         throw new ArgumentNullException("from");
     if (to == null)
         throw new ArgumentNullException("to");
     var registers = ins.Registers;
     var count = registers.Count;
     for (var i = 0; i < count; i++)
     {
         if (registers[i] == from)
         {
             registers[i] = to;
         }
     }
 }
Beispiel #19
0
 /// <summary>
 /// Gets all registers used in the given instruction, include "next" registers in case of wide operands.
 /// </summary>
 private HashSet<Register> GetAllUsedRegisters(Instruction ins)
 {
     var set = new HashSet<Register>();
     foreach (var r in ins.Registers)
     {
         set.Add(r);
         if (GetType(r) == RType.Wide)
         {
             // Include next register
             var next = allRegisters.First(x => x.Index == r.Index + 1);
             set.Add(next);
         }
     }
     return set;
 }
Beispiel #20
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;
            }
Beispiel #21
0
        private PackedSwitchData ExtractPackedSwitch(Instruction ins, int offset)
        {
            int baseOffset = offset;
            var result = new PackedSwitchData();
            ProcessPseudoCode(PseudoOpCodes.Packed_switch, ref offset);

            int targetcount = ReadShort(ref offset);
            result.FirstKey = ReadInt(ref offset);

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

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

            return result;
        }
Beispiel #22
0
        public string FormatAddress(Instruction ins)
        {
            var offset = ins.Offset.ToString("X3").PadLeft(4);

            if(Format.HasFlag(FormatOptions.ShowJumpTargets))
            {
                if (ExceptionHandlerOffsets.Contains(ins.Offset))
                    return offset + "!";
                if (JumpTargetOffsets.Contains(ins.Offset))
                    return offset + ":";
                else
                    return offset + " ";
            }
            return offset;
        }
Beispiel #23
0
 public string FormatOpCode(Instruction ins)
 {
     return OpCodesNames.GetName(ins.OpCode).ToLowerInvariant().PadLeft(20) + " ";
 }
Beispiel #24
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(")");
        }
 private static string Register(Instruction i)
 {
     return string.Join(", ", i.Registers.Select(x => string.Format("r{0}", x.Index)).ToArray());
 }
Beispiel #26
0
 private void ReadvB(Instruction ins)
 {
     ins.Registers.Add(methodDefinition.Body.Registers[upper[Ip++] >> 4]);
 }
Beispiel #27
0
 private void ReadvA(Instruction ins)
 {
     ins.Registers.Add(methodDefinition.Body.Registers[upper[Ip] & 0xF]);
 }
Beispiel #28
0
        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;
        }
Beispiel #29
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();
     }
 }
Beispiel #30
0
 public string FormatOperands(Instruction ins)
 {
     return FormatOperands(ins, _methodDef.Body, Format);
 }
Beispiel #31
0
 private void SetRegistersByMask(Instruction ins, int registerMask)
 {
     int registerCount = registerMask >> 20;
     for (int i = 0; i < registerCount; i++)
         ins.Registers.Add(methodDefinition.Body.Registers[(registerMask >> (i*4)) & 0xF]);
 }
Beispiel #32
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);
                }
            }
Beispiel #33
0
            /// <summary>
            /// Convert a normal invoke_x to invoke_x_range.
            /// </summary>
            private void ConvertInvoke(Instruction ins)
            {
                var registers = ins.Registers;
                var count = registers.Count;
                if (count == 0)
                    return;

                // Replace all registers with their "spill" variant (if any)
                for (var i = 0; i < count; i++)
                {
                    Register sReg;
                    LowRegisterState state;
                    if (TryGetLowRegister(registers[i], out sReg, out state))
                    {
                        ReplaceRegister(ins, registers[i], sReg);
                    }
                }

                // By replacing the registers, it it possible to avoid the invoke_x_range opcodes?
                if (!ins.RequiresInvokeRange())
                    return;

                if (!IsValidInvokeRange(registers))
                {
                    // Use invoke frame
                    for (var i = 0; i < count; i++)
                    {
                        var type = GetType(registers[i]);
                        block.InsertBefore(ins, CreateMove(registers[i], invokeFrame[i], type));
                        registers[i] = invokeFrame[i];
                    }
                }
                // Change opcode
                ins.OpCode = ins.OpCode.InvokeToRange();
            }
Beispiel #34
0
 public string FormatInstruction(Instruction ins)
 {
     return FormatAddress(ins) + " " + FormatOpCode(ins) + " " + FormatOperands(ins);
 }
Beispiel #35
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;
            }
Beispiel #36
0
 private void ReadvBBBB(Instruction ins)
 {
     ins.Registers.Add(methodDefinition.Body.Registers[Codes[Ip++]]);
 }
Beispiel #37
0
        public void ReadFrom(BinaryReader reader)
        {
            var registers = methodDefinition.Body.Registers;
            instructionsSize = reader.ReadUInt32();

            Codes = new int[instructionsSize];
            lower = new int[instructionsSize];
            upper = new int[instructionsSize];

            for (int i = 0; i < instructionsSize; i++)
            {
                Codes[i] = reader.ReadUInt16();
                lower[i] = Codes[i] & 0xFF;
                upper[i] = Codes[i] >> 8;
            }

            while (Ip < instructionsSize)
            {
                int offset;
                int registerCount;
                int registerMask;

                var ins = new Instruction();
                ins.OpCode = (OpCodes) lower[Ip];
                ins.Offset = Ip;

                Lookup.Add(Ip, ins);
                methodDefinition.Body.Instructions.Add(ins);

                switch (ins.OpCode)
                {
                    case OpCodes.Nop:
                    case OpCodes.Return_void:
                        Ip++;
                        break;
                    case OpCodes.Move_result:
                    case OpCodes.Move_result_wide:
                    case OpCodes.Move_result_object:
                    case OpCodes.Move_exception:
                    case OpCodes.Return:
                    case OpCodes.Return_wide:
                    case OpCodes.Return_object:
                    case OpCodes.Monitor_enter:
                    case OpCodes.Monitor_exit:
                    case OpCodes.Throw:
                        // vAA
                        ReadvAA(ins);
                        break;
                    case OpCodes.Move_object:
                    case OpCodes.Move_wide:
                    case OpCodes.Move:
                    case OpCodes.Array_length:
                    case OpCodes.Neg_int:
                    case OpCodes.Not_int:
                    case OpCodes.Neg_long:
                    case OpCodes.Not_long:
                    case OpCodes.Neg_float:
                    case OpCodes.Neg_double:
                    case OpCodes.Int_to_long:
                    case OpCodes.Int_to_float:
                    case OpCodes.Int_to_double:
                    case OpCodes.Long_to_int:
                    case OpCodes.Long_to_float:
                    case OpCodes.Long_to_double:
                    case OpCodes.Float_to_int:
                    case OpCodes.Float_to_long:
                    case OpCodes.Float_to_double:
                    case OpCodes.Double_to_int:
                    case OpCodes.Double_to_long:
                    case OpCodes.Double_to_float:
                    case OpCodes.Int_to_byte:
                    case OpCodes.Int_to_char:
                    case OpCodes.Int_to_short:
                    case OpCodes.Add_int_2addr:
                    case OpCodes.Sub_int_2addr:
                    case OpCodes.Mul_int_2addr:
                    case OpCodes.Div_int_2addr:
                    case OpCodes.Rem_int_2addr:
                    case OpCodes.And_int_2addr:
                    case OpCodes.Or_int_2addr:
                    case OpCodes.Xor_int_2addr:
                    case OpCodes.Shl_int_2addr:
                    case OpCodes.Shr_int_2addr:
                    case OpCodes.Ushr_int_2addr:
                    case OpCodes.Add_long_2addr:
                    case OpCodes.Sub_long_2addr:
                    case OpCodes.Mul_long_2addr:
                    case OpCodes.Div_long_2addr:
                    case OpCodes.Rem_long_2addr:
                    case OpCodes.And_long_2addr:
                    case OpCodes.Or_long_2addr:
                    case OpCodes.Xor_long_2addr:
                    case OpCodes.Shl_long_2addr:
                    case OpCodes.Shr_long_2addr:
                    case OpCodes.Ushr_long_2addr:
                    case OpCodes.Add_float_2addr:
                    case OpCodes.Sub_float_2addr:
                    case OpCodes.Mul_float_2addr:
                    case OpCodes.Div_float_2addr:
                    case OpCodes.Rem_float_2addr:
                    case OpCodes.Add_double_2addr:
                    case OpCodes.Sub_double_2addr:
                    case OpCodes.Mul_double_2addr:
                    case OpCodes.Div_double_2addr:
                    case OpCodes.Rem_double_2addr:
                        // vA, vB
                        ReadvA(ins);
                        ReadvB(ins);
                        break;
                    case OpCodes.Move_wide_from16:
                    case OpCodes.Move_from16:
                    case OpCodes.Move_object_from16:
                        // vAA, vBBBB
                        ReadvAA(ins);
                        ReadvBBBB(ins);
                        break;
                    case OpCodes.Move_16:
                    case OpCodes.Move_wide_16:
                    case OpCodes.Move_object_16:
                        // vAAAA, vBBBB
                        ReadvAAAA(ins);
                        ReadvBBBB(ins);
                        break;
                    case OpCodes.Const_4:
                        // vA, #+B
                        ReadvA(ins);
                        ins.Operand = (int) ReadNibble();
                        break;
                    case OpCodes.Const_16:
                        // vAA, #+BBBB
                        ReadvAA(ins);
                        ins.Operand = (int) ReadShort(ref Ip);
                        break;
                    case OpCodes.Const_wide_16:
                        // vAA, #+BBBB
                        ReadvAA(ins);
                        ins.Operand = (long) ReadShort(ref Ip);
                        break;
                    case OpCodes.Const:
                        // vAA, #+BBBBBBBB
                        ReadvAA(ins);
                        ins.Operand = (int) ReadInt(ref Ip);
                        break;
                    case OpCodes.Const_wide_32:
                        // vAA, #+BBBBBBBB
                        ReadvAA(ins);
                        ins.Operand = (long) ReadInt(ref Ip);
                        break;
                    case OpCodes.Fill_array_data:
                        // vAA, #+BBBBBBBB
                        ReadvAA(ins);
                        offset = ReadInt(ref Ip);
                        ins.Operand = ExtractArrayData(ins.Offset + offset);
                        break;
                    case OpCodes.Const_high16:
                        // vAA, #+BBBB0000
                        ReadvAA(ins);
                        ins.Operand = ((long) ReadShort(ref Ip)) << 16;
                        break;
                    case OpCodes.Const_wide:
                        // vAA, #+BBBBBBBBBBBBBBBB
                        ReadvAA(ins);
                        ins.Operand = ReadLong(ref Ip);
                        break;
                    case OpCodes.Const_wide_high16:
                        // vAA, #+BBBB000000000000
                        ReadvAA(ins);
                        ins.Operand = ((long) ReadShort(ref Ip)) << 48;
                        break;
                    case OpCodes.Const_string:
                        // vAA, string@BBBB
                        ReadvAA(ins);
                        ins.Operand = dexReader.GetString(ReadShort(ref Ip));
                        break;
                    case OpCodes.Const_string_jumbo:
                        // vAA, string@BBBBBBBB
                        ReadvAA(ins);
                        ins.Operand = dexReader.GetString(ReadInt(ref Ip));
                        break;
                    case OpCodes.Const_class:
                    case OpCodes.New_instance:
                    case OpCodes.Check_cast:
                        // vAA, type@BBBB
                        ReadvAA(ins);
                        ins.Operand = dexReader.GetTypeReference(ReadShort(ref Ip));
                        break;
                    case OpCodes.Instance_of:
                    case OpCodes.New_array:
                        // vA, vB, type@CCCC
                        ReadvA(ins);
                        ReadvB(ins);
                        ins.Operand = dexReader.GetTypeReference(ReadShort(ref Ip));
                        break;
                    case OpCodes.Filled_new_array:
                        // {vD, vE, vF, vG, vA}, type@CCCC
                        registerMask = upper[Ip++] << 16;
                        ins.Operand = dexReader.GetTypeReference(ReadShort(ref Ip));
                        registerMask |= Codes[Ip++];
                        SetRegistersByMask(ins, registerMask);
                        break;
                    case OpCodes.Filled_new_array_range:
                        // {vCCCC .. vNNNN}, type@BBBB
                        registerCount = upper[Ip++] << 16;
                        ins.Operand = dexReader.GetTypeReference(ReadShort(ref Ip));
                        ReadvBBBB(ins);
                        for (int i = 1; i < registerCount; i++)
                            ins.Registers.Add(registers[i + ins.Registers[0].Index]);
                        break;
                    case OpCodes.Goto:
                        // +AA
                        offset = (sbyte) ReadSByte(ref Ip);
                        lazyInstructionsSetters.Add(() => ins.Operand = Lookup[ins.Offset + offset]);
                        break;
                    case OpCodes.Goto_16:
                        // +AAAA
                        Ip++;
                        offset = (short) ReadShort(ref Ip);
                        lazyInstructionsSetters.Add(() => ins.Operand = Lookup[ins.Offset + offset]);
                        break;
                    case OpCodes.Goto_32:
                        // +AAAAAAAA
                        Ip++;
                        offset = ReadInt(ref Ip);
                        lazyInstructionsSetters.Add(() => ins.Operand = Lookup[ins.Offset + offset]);
                        break;
                    case OpCodes.Packed_switch:
                        // vAA, +BBBBBBBB
                        ReadvAA(ins);
                        offset = ReadInt(ref Ip);
                        ins.Operand = ExtractPackedSwitch(ins, ins.Offset + offset);
                        break;
                    case OpCodes.Sparse_switch:
                        // vAA, +BBBBBBBB
                        ReadvAA(ins);
                        offset = ReadInt(ref Ip);
                        ins.Operand = ExtractSparseSwitch(ins, ins.Offset + offset);
                        break;
                    case OpCodes.Cmpl_float:
                    case OpCodes.Cmpg_float:
                    case OpCodes.Cmpl_double:
                    case OpCodes.Cmpg_double:
                    case OpCodes.Cmp_long:
                    case OpCodes.Aget:
                    case OpCodes.Aget_wide:
                    case OpCodes.Aget_object:
                    case OpCodes.Aget_boolean:
                    case OpCodes.Aget_byte:
                    case OpCodes.Aget_char:
                    case OpCodes.Aget_short:
                    case OpCodes.Aput:
                    case OpCodes.Aput_wide:
                    case OpCodes.Aput_object:
                    case OpCodes.Aput_boolean:
                    case OpCodes.Aput_byte:
                    case OpCodes.Aput_char:
                    case OpCodes.Aput_short:
                    case OpCodes.Add_int:
                    case OpCodes.Sub_int:
                    case OpCodes.Mul_int:
                    case OpCodes.Div_int:
                    case OpCodes.Rem_int:
                    case OpCodes.And_int:
                    case OpCodes.Or_int:
                    case OpCodes.Xor_int:
                    case OpCodes.Shl_int:
                    case OpCodes.Shr_int:
                    case OpCodes.Ushr_int:
                    case OpCodes.Add_long:
                    case OpCodes.Sub_long:
                    case OpCodes.Mul_long:
                    case OpCodes.Div_long:
                    case OpCodes.Rem_long:
                    case OpCodes.And_long:
                    case OpCodes.Or_long:
                    case OpCodes.Xor_long:
                    case OpCodes.Shl_long:
                    case OpCodes.Shr_long:
                    case OpCodes.Ushr_long:
                    case OpCodes.Add_float:
                    case OpCodes.Sub_float:
                    case OpCodes.Mul_float:
                    case OpCodes.Div_float:
                    case OpCodes.Rem_float:
                    case OpCodes.Add_double:
                    case OpCodes.Sub_double:
                    case OpCodes.Mul_double:
                    case OpCodes.Div_double:
                    case OpCodes.Rem_double:
                        // vAA, vBB, vCC
                        ReadvAA(ins);
                        ReadvBB(ins);
                        ReadvCC(ins);
                        break;
                    case OpCodes.If_eq:
                    case OpCodes.If_ne:
                    case OpCodes.If_lt:
                    case OpCodes.If_ge:
                    case OpCodes.If_gt:
                    case OpCodes.If_le:
                        // vA, vB, +CCCC
                        ReadvA(ins);
                        ReadvB(ins);
                        offset = (short) ReadShort(ref Ip);
                        lazyInstructionsSetters.Add(() => ins.Operand = Lookup[ins.Offset + offset]);
                        break;
                    case OpCodes.If_eqz:
                    case OpCodes.If_nez:
                    case OpCodes.If_ltz:
                    case OpCodes.If_gez:
                    case OpCodes.If_gtz:
                    case OpCodes.If_lez:
                        // vAA, +BBBB
                        ReadvAA(ins);
                        offset = (short) ReadShort(ref Ip);
                        lazyInstructionsSetters.Add(() => ins.Operand = Lookup[ins.Offset + offset]);
                        break;
                    case OpCodes.Iget:
                    case OpCodes.Iget_wide:
                    case OpCodes.Iget_object:
                    case OpCodes.Iget_boolean:
                    case OpCodes.Iget_byte:
                    case OpCodes.Iget_char:
                    case OpCodes.Iget_short:
                    case OpCodes.Iput:
                    case OpCodes.Iput_wide:
                    case OpCodes.Iput_object:
                    case OpCodes.Iput_boolean:
                    case OpCodes.Iput_byte:
                    case OpCodes.Iput_char:
                    case OpCodes.Iput_short:
                        // vA, vB, field@CCCC
                        ReadvA(ins);
                        ReadvB(ins);
                        ins.Operand = dexReader.GetFieldReference(ReadShort(ref Ip));
                        break;
                    case OpCodes.Sget:
                    case OpCodes.Sget_wide:
                    case OpCodes.Sget_object:
                    case OpCodes.Sget_boolean:
                    case OpCodes.Sget_byte:
                    case OpCodes.Sget_char:
                    case OpCodes.Sget_short:
                    case OpCodes.Sput:
                    case OpCodes.Sput_wide:
                    case OpCodes.Sput_object:
                    case OpCodes.Sput_boolean:
                    case OpCodes.Sput_byte:
                    case OpCodes.Sput_char:
                    case OpCodes.Sput_short:
                        // vAA, field@BBBB
                        ReadvAA(ins);
                        ins.Operand = dexReader.GetFieldReference(ReadShort(ref Ip));
                        break;
                    case OpCodes.Invoke_virtual:
                    case OpCodes.Invoke_super:
                    case OpCodes.Invoke_direct:
                    case OpCodes.Invoke_static:
                    case OpCodes.Invoke_interface:
                        // {vD, vE, vF, vG, vA}, meth@CCCC
                        registerMask = upper[Ip++] << 16;
                        ins.Operand = dexReader.GetMethodReference(ReadShort(ref Ip));
                        registerMask |= Codes[Ip++];
                        SetRegistersByMask(ins, registerMask);
                        break;
                    case OpCodes.Invoke_virtual_range:
                    case OpCodes.Invoke_super_range:
                    case OpCodes.Invoke_direct_range:
                    case OpCodes.Invoke_static_range:
                    case OpCodes.Invoke_interface_range:
                        // {vCCCC .. vNNNN}, meth@BBBB
                        registerCount = ReadSByte(ref Ip);
                        ins.Operand = dexReader.GetMethodReference(ReadShort(ref Ip));
                        ReadvBBBB(ins);
                        for (int i = 1; i < registerCount; i++)
                            ins.Registers.Add(registers[i + ins.Registers[0].Index]);
                        break;
                    case OpCodes.Add_int_lit16:
                    case OpCodes.Rsub_int:
                    case OpCodes.Mul_int_lit16:
                    case OpCodes.Div_int_lit16:
                    case OpCodes.Rem_int_lit16:
                    case OpCodes.And_int_lit16:
                    case OpCodes.Or_int_lit16:
                    case OpCodes.Xor_int_lit16:
                        // vA, vB, #+CCCC
                        ReadvA(ins);
                        ReadvB(ins);
                        ins.Operand = (int) ReadShort(ref Ip);
                        break;
                    case OpCodes.Add_int_lit8:
                    case OpCodes.Rsub_int_lit8:
                    case OpCodes.Mul_int_lit8:
                    case OpCodes.Div_int_lit8:
                    case OpCodes.Rem_int_lit8:
                    case OpCodes.And_int_lit8:
                    case OpCodes.Or_int_lit8:
                    case OpCodes.Xor_int_lit8:
                    case OpCodes.Shl_int_lit8:
                    case OpCodes.Shr_int_lit8:
                    case OpCodes.Ushr_int_lit8:
                        // vAA, vBB, #+CC
                        ReadvAA(ins);
                        ReadvBB(ins);
                        ins.Operand = ReadSByte(ref Ip);
                        break;

                    default:
                        throw new NotImplementedException(string.Concat("Unknown opcode:", ins.OpCode));
                }

                LookupLast.Add(Ip - 1, ins);
            }

            if (Ip != instructionsSize)
                throw new MalformedException("Instruction pointer out of range");

            foreach (Action action in lazyInstructionsSetters)
                action();
        }
Beispiel #38
0
 private void ReadvBB(Instruction ins)
 {
     ins.Registers.Add(methodDefinition.Body.Registers[lower[Ip]]);
 }
Beispiel #39
0
 private void ReadvCC(Instruction ins)
 {
     ReadvAA(ins);
 }