Beispiel #1
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;
        }
Beispiel #2
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;
        }