// ReSharper restore UnusedParameter.Local private SparseSwitchData ExtractSparseSwitch(Instruction ins, int offset) { int baseOffset = offset; var result = new SparseSwitchData(); ProcessPseudoCode(PseudoOpCodes.SparseSwitch, ref offset); int targetcount = ReadShort(ref offset); var keys = new int[targetcount]; for (var i = 0; i < targetcount; i++) { keys[i] = ReadInt(ref offset); } for (var i = 0; i < targetcount; i++) { var index = i; // used for closure var target = ReadInt(ref offset); LazyInstructionsSetters.Add(() => result.Targets.Add(keys[index], Lookup[ins.Offset + target])); } if (offset - baseOffset != targetcount * 4 + 2) { throw new MalformedException("Unexpected Sparse switch blocksize"); } return(result); }
/// <summary> /// Compile RL into Dex. /// </summary> public RegisterMapper Compile() { // Map registers var regMapper = new RegisterMapper(rlBody, frame); // Create instructions var maxOutgoingArguments = 0; var target = dexBody.Instructions; var insMap = new Dictionary <Instruction, Tuple <DexLib.Instructions.Instruction, DexLib.Instructions.Instruction> >(); foreach (var ins in rlBody.Instructions) { DexLib.Instructions.Instruction first = null; DexLib.Instructions.Instruction last = null; foreach (var dexIns in RL2Dex.Convert(ins, regMapper)) { target.Add(dexIns); if (first == null) { first = dexIns; } last = dexIns; } if ((first == null) || (last == null)) { throw new InvalidOperationException(); } insMap[ins] = Tuple.Create(first, last); // Gather statistics if (ins.Code.IsInvoke()) { maxOutgoingArguments = Math.Max(maxOutgoingArguments, ins.Registers.Count); } } // Update targets foreach (var dexIns in target) { var instruction = dexIns.Operand as Instruction; if (instruction != null) { dexIns.Operand = insMap[instruction].Item1; } if (dexIns.OpCode == OpCodes.Packed_switch) { var instructions = (Instruction[])dexIns.Operand; dexIns.Operand = new PackedSwitchData(instructions.Select(x => insMap[x].Item1)); } else if (dexIns.OpCode == OpCodes.Sparse_switch) { var targetPairs = (Tuple <int, Instruction>[])dexIns.Operand; var data = new SparseSwitchData(); foreach (var pair in targetPairs.OrderBy(x => x.Item1)) { data.Targets.Add(pair.Item1, insMap[pair.Item2].Item1); } dexIns.Operand = data; } } // Create exception handlers foreach (var handler in rlBody.Exceptions) { var dhandler = new ExceptionHandler(); dhandler.TryStart = insMap[handler.TryStart].Item1; dhandler.TryEnd = insMap[handler.TryEnd].Item2; dhandler.CatchAll = (handler.CatchAll != null) ? insMap[handler.CatchAll].Item1 : null; dexBody.Exceptions.Add(dhandler); foreach (var catchBlock in handler.Catches) { var dcatchBlock = new Catch(); dcatchBlock.Type = catchBlock.Type; dcatchBlock.Instruction = insMap[catchBlock.Instruction].Item1; dhandler.Catches.Add(dcatchBlock); } } // Add register spilling code (if needed) if (regMapper.SpillingRequired) { RegisterSpillingOptimizer.Transform(dexBody); RegisterSpilling.AddSpillingCode(dexBody, regMapper); } // Set statistics dexBody.Registers.AddRange(regMapper.All); dexBody.IncomingArguments = (ushort)regMapper.ArgumentCount; dexBody.OutgoingArguments = (ushort)maxOutgoingArguments; return(regMapper); }
/// <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); }