/// <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; }
/// <summary> /// Transform the given body. /// </summary> public void 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; } } }