Exemple #1
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;
 }
Exemple #2
0
 /// <summary>
 /// Default ctor.
 /// </summary>
 internal BlockSpillCodeGenerator(BasicBlock block, RegisterMapper mapper, List<Register> lowRegisters, List<Register> invokeFrame, List<Register> allRegisters)
 {
     this.block = block;
     this.mapper = mapper;
     this.lowRegisters = new LowRegisterState[lowRegisters.Count];
     LowRegisterState next = null;
     for (var i = lowRegisters.Count - 1; i >= 0; i--)
     {
         this.lowRegisters[i] = new LowRegisterState(lowRegisters[i], next);
         next = this.lowRegisters[i];
     }
     this.invokeFrame = invokeFrame;
     this.allRegisters = allRegisters;
 }
            /// <summary>
            /// Default ctor.
            /// </summary>
            internal BlockSpillCodeGenerator(BasicBlock block, RegisterMapper mapper, List <Register> lowRegisters, List <Register> invokeFrame, List <Register> allRegisters)
            {
                this.block        = block;
                this.mapper       = mapper;
                this.lowRegisters = new LowRegisterState[lowRegisters.Count];
                LowRegisterState next = null;

                for (var i = lowRegisters.Count - 1; i >= 0; i--)
                {
                    this.lowRegisters[i] = new LowRegisterState(lowRegisters[i], next);
                    next = this.lowRegisters[i];
                }
                this.invokeFrame  = invokeFrame;
                this.allRegisters = allRegisters;
            }
        /// <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);
            }
        }
Exemple #5
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);
            }
        }
Exemple #6
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);
        }
Exemple #7
0
        /// <summary>
        /// Compile RL into the Dex method body.
        /// </summary>
        private void CompileToDex(DexTargetPackage targetPackage, bool generateDebugInfo, MapFile mapFile)
        {
            var dmethod = DexMethod;
            if (dmethod == null)
                throw new ArgumentException("No DexMethod set");
            if ((dmethod.IsAbstract) || (dmethod.IsNative))
                return;
            var rlBody = RLBody;
            if (rlBody == null)
                throw new ArgumentException("No RL body set");

            // Ensure RL is optimized
            OptimizeRL(targetPackage.DexFile);

            // Compile to Dex
            var dbody = new Dot42.DexLib.Instructions.MethodBody(dmethod, 0);
            var dexCompiler = new DexCompiler(rlBody, dbody, InvocationFrame);
            regMapper = dexCompiler.Compile();

            // Optimize code
            //dbody.UpdateInstructionOffsets();
            DexOptimizer.DexOptimizer.Optimize(dbody);

            // Ensure correct offsets
            dbody.UpdateInstructionOffsets();
            dmethod.Body = dbody;

            if (generateDebugInfo || (mapFile != null))
            {
                // Add debug info
                var debugInfoBuilder = new DebugInfoBuilder(this);
                if (generateDebugInfo)
                    debugInfoBuilder.CreateDebugInfo(dbody, regMapper, targetPackage);
                if (mapFile != null)
                    debugInfoBuilder.AddDocumentMapping(mapFile);
            }
        }
Exemple #8
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 (!type.SetSourceFile(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;
        }
Exemple #9
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;
        }
Exemple #10
0
        /// <summary>
        /// Compile RL into Dex.
        /// </summary>
        public RegisterMapper Compile()
        {
            // Map registers
            var regMapper = new RegisterMapper(rlBody, frame);

            // Create instructions
            var maxOutgoingArguments = 0;
            var target = dexBody.Instructions;
            var insMap = new Dictionary <Instruction, Tuple <DexLib.Instructions.Instruction, DexLib.Instructions.Instruction> >();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return regMapper;
        }
Exemple #12
0
        /// <summary>
        /// Compile RL into the Dex method body.
        /// </summary>
        private void CompileToDex(DexTargetPackage targetPackage, bool generateDebugInfo, MapFile mapFile)
        {
            var dmethod = DexMethod;
            if (dmethod == null)
                throw new ArgumentException("No DexMethod set");
            if ((dmethod.IsAbstract) || (dmethod.IsNative))
                return;

            var rlBody = RLBody;

            if (rlBody == null && dmethod.Body != null) // already satisfied from the cache?
                return;

            if (rlBody == null)
                throw new ArgumentException(string.Format("internal compiler error: No RL body set on method '{2}'.'{3}' => '{0}'.'{1}'", dmethod.Owner.Name, dmethod.Name, method == null ? null : method.DeclaringType.FullName, method == null ? null : method.Name));

            // Ensure RL is optimized
            OptimizeRL(targetPackage.DexFile);

            // Compile to Dex
            var dbody = new Dot42.DexLib.Instructions.MethodBody(dmethod, 0);
            var dexCompiler = new DexCompiler(rlBody, dbody, InvocationFrame);
            regMapper = dexCompiler.Compile();

            // Optimize code
            //dbody.UpdateInstructionOffsets();
            DexOptimizer.DexOptimizer.Optimize(dbody);

            // Ensure correct offsets
            dbody.UpdateInstructionOffsets();
            dmethod.Body = dbody;

            if (generateDebugInfo || (mapFile != null))
            {
                // Add debug info
                var debugInfoBuilder = new DebugInfoBuilder(this);
                if (generateDebugInfo)
                    debugInfoBuilder.CreateDebugInfo(dbody, regMapper, targetPackage);
                if (mapFile != null && dmethod.MapFileId != 0)
                    debugInfoBuilder.AddDocumentMapping(mapFile);
            }
        }