Merge pull request #1412 from esdrubal/stackframe
authorZoltan Varga <vargaz@gmail.com>
Sun, 30 Nov 2014 14:11:03 +0000 (15:11 +0100)
committerZoltan Varga <vargaz@gmail.com>
Sun, 30 Nov 2014 14:11:03 +0000 (15:11 +0100)
Release sequence points and Symbolicate tool

37 files changed:
mcs/class/corlib/System.Diagnostics/StackFrame.cs
mcs/class/corlib/System/Environment.cs
mcs/class/corlib/System/Exception.cs
mcs/tools/symbolicate/LocationProvider.cs [new file with mode: 0644]
mcs/tools/symbolicate/Makefile [new file with mode: 0644]
mcs/tools/symbolicate/symbolicate.cs [new file with mode: 0644]
mcs/tools/symbolicate/symbolicate.exe.sources [new file with mode: 0644]
mono/metadata/appdomain.c
mono/metadata/object-internals.h
mono/mini/Makefile.am.in
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/cpu-amd64.md
mono/mini/cpu-arm.md
mono/mini/cpu-arm64.md
mono/mini/cpu-mips.md
mono/mini/cpu-ppc.md
mono/mini/cpu-ppc64.md
mono/mini/cpu-s390x.md
mono/mini/cpu-x86.md
mono/mini/debugger-agent.c
mono/mini/debugger-agent.h
mono/mini/ir-emit.h
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-arm.c
mono/mini/mini-codegen.c
mono/mini/mini-exceptions.c
mono/mini/mini-mips.c
mono/mini/mini-ops.h
mono/mini/mini-ppc.c
mono/mini/mini-s390x.c
mono/mini/mini-x86.c
mono/mini/mini.c
mono/mini/mini.h
mono/mini/seq-points.c [new file with mode: 0644]
mono/mini/seq-points.h [new file with mode: 0644]

index 37a6c559fb32abf79851ef23a959877676ecaf6b..b6aa9d2ed3ec6e8ce49863ad12ee196739e5d8de 100644 (file)
@@ -49,6 +49,7 @@ namespace System.Diagnostics {
                #region Keep in sync with object-internals.h
                private int ilOffset = OFFSET_UNKNOWN;
                private int nativeOffset = OFFSET_UNKNOWN;
+               private long methodAddress;
                private MethodBase methodBase;
                private string fileName;
                private int lineNumber;
@@ -165,6 +166,11 @@ namespace System.Diagnostics {
                         return nativeOffset;                        
                 }
 
+               internal long GetMethodAddress ()
+               {
+                       return methodAddress;
+               }
+
                internal string GetInternalMethodName ()
                {
                        return internalMethodName;
index 21128defd9ba7b1b5b39dd2b99dacbdabb50f8bc..e216543aaac37c8834b5810ca738c3e01e1e356f 100644 (file)
@@ -56,7 +56,7 @@ namespace System {
                 * of icalls, do not require an increment.
                 */
 #pragma warning disable 169
-               private const int mono_corlib_version = 111;
+               private const int mono_corlib_version = 112;
 #pragma warning restore 169
 
                [ComVisible (true)]
index d5d81dcd73926ac2a74d7629de56fcbf51b79958..5ccf4bd494b6cbc7f3069b6a5c1bfde5aa20f22e 100644 (file)
@@ -208,12 +208,12 @@ namespace System
                                        if (internal_name != null)
                                                sb.Append (internal_name);
                                        else
-                                               sb.AppendFormat ("<0x{0:x5}> {1}", frame.GetNativeOffset (), unknown);
+                                               sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
                                } else {
                                        GetFullNameForStackTrace (sb, frame.GetMethod ());
 
                                        if (frame.GetILOffset () == -1)
-                                               sb.AppendFormat (" <0x{0:x5}> ", frame.GetNativeOffset ());
+                                               sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> ", frame.GetMethodAddress (), frame.GetNativeOffset ());
                                        else
                                                sb.AppendFormat (" [0x{0:x5}] ", frame.GetILOffset ());
 
diff --git a/mcs/tools/symbolicate/LocationProvider.cs b/mcs/tools/symbolicate/LocationProvider.cs
new file mode 100644 (file)
index 0000000..634915c
--- /dev/null
@@ -0,0 +1,144 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.CompilerServices.SymbolWriter;
+
+namespace Symbolicate
+{
+       struct Location {
+               public string FileName;
+               public int Line;
+       }
+
+       class LocationProvider {
+               class AssemblyLocationProvider {
+                       AssemblyDefinition assembly;
+                       MonoSymbolFile symbolFile;
+
+                       public AssemblyLocationProvider (AssemblyDefinition assembly, MonoSymbolFile symbolFile)
+                       {
+                               this.assembly = assembly;
+                               this.symbolFile = symbolFile;
+                       }
+
+                       public bool TryGetLocation (string methodFullName, string[] methodParamsTypes, int ilOffset, out Location location)
+                       {
+                               location = default (Location);
+                               if (symbolFile == null)
+                                       return false;
+
+                               var typeNameEnd = methodFullName.LastIndexOf (".");
+                               var typeName = methodFullName.Substring (0, typeNameEnd);
+                               var methodName = methodFullName.Substring (typeNameEnd + 1, methodFullName.Length - typeNameEnd - 1);
+
+                               var type = assembly.MainModule.Types.FirstOrDefault (t => t.FullName == typeName);
+                               if (type == null)
+                                       return false;
+
+                               var method = type.Methods.FirstOrDefault (m => {
+                                       if (m.Name != methodName)
+                                               return false;
+
+                                       if (m.Parameters.Count != methodParamsTypes.Length)
+                                               return false;
+
+                                       for (var i = 0; i < methodParamsTypes.Length; i++) {
+                                               var paramType = m.Parameters[i].ParameterType;
+                                               if (paramType.Name != methodParamsTypes[i])
+                                                       return false;
+                                       }
+
+                                       return true;
+                               });
+
+                               if (method == null)
+                                       return false;
+
+                               var methodSymbol = symbolFile.Methods [method.MetadataToken.RID-1];
+
+                               foreach (var lineNumber in methodSymbol.GetLineNumberTable ().LineNumbers) {
+                                       if (lineNumber.Offset < ilOffset)
+                                               continue;
+
+                                       location.FileName = symbolFile.Sources [lineNumber.File-1].FileName;
+                                       location.Line = lineNumber.Row;
+                                       return true;
+                               }
+
+                               return false;
+                       }
+               }
+
+               Dictionary<string, AssemblyLocationProvider> assemblies;
+               HashSet<string> directories;
+
+               public LocationProvider () {
+                       assemblies = new Dictionary<string, AssemblyLocationProvider> ();
+                       directories = new HashSet<string> ();
+               }
+
+               public void AddAssembly (string assemblyPath)
+               {
+                       assemblyPath = Path.GetFullPath (assemblyPath);
+                       if (assemblies.ContainsKey (assemblyPath))
+                               return;
+
+                       if (!File.Exists (assemblyPath))
+                               throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
+
+                       var assembly = AssemblyDefinition.ReadAssembly (assemblyPath);
+                       MonoSymbolFile symbolFile = null;
+
+                       var symbolPath = assemblyPath + ".mdb";
+                       if (!File.Exists (symbolPath))
+                               Debug.WriteLine (".mdb file was not found for " + assemblyPath);
+                       else
+                               symbolFile = MonoSymbolFile.ReadSymbolFile (assemblyPath + ".mdb");
+
+                       assemblies.Add (assemblyPath, new AssemblyLocationProvider (assembly, symbolFile));
+
+                       directories.Add (Path.GetDirectoryName (assemblyPath));
+
+                       foreach (var assemblyRef in assembly.MainModule.AssemblyReferences) {
+                               string refPath = null;
+                               foreach (var dir in directories) {
+                                       refPath = Path.Combine (dir, assemblyRef.Name);
+                                       if (File.Exists (refPath))
+                                               break;
+                                       refPath = Path.Combine (dir, assemblyRef.Name + ".dll");
+                                       if (File.Exists (refPath))
+                                               break;
+                                       refPath = Path.Combine (dir, assemblyRef.Name + ".exe");
+                                       if (File.Exists (refPath))
+                                               break;
+                                       refPath = null;
+                               }
+                               if (refPath != null)
+                                       AddAssembly (refPath);
+                       }
+               }
+
+               public void AddDirectory (string directory)
+               {
+                       if (Directory.Exists (directory))
+                               throw new ArgumentException ("Directory " + directory + " does not exist.");
+
+                       directories.Add (directory);
+               }
+
+               public bool TryGetLocation (string methodName, string[] methodParams, int ilOffset, out Location location)
+               {
+                       location = default (Location);
+                       foreach (var assembly in assemblies.Values) {
+                               if (assembly.TryGetLocation (methodName, methodParams, ilOffset, out location))
+                                       return true;
+                       }
+
+                       return false;
+               }
+       }
+}
+
diff --git a/mcs/tools/symbolicate/Makefile b/mcs/tools/symbolicate/Makefile
new file mode 100644 (file)
index 0000000..bd6f970
--- /dev/null
@@ -0,0 +1,12 @@
+thisdir = tools/symbolicate
+SUBDIRS =
+include ../../build/rules.make
+
+PROGRAM = symbolicate.exe
+
+LOCAL_MCS_FLAGS = \
+       /r:Mono.Cecil.dll       \
+       /r:Mono.CompilerServices.SymbolWriter.dll \
+       /r:System.Xml
+
+include ../../build/executable.make
diff --git a/mcs/tools/symbolicate/symbolicate.cs b/mcs/tools/symbolicate/symbolicate.cs
new file mode 100644 (file)
index 0000000..5df3b51
--- /dev/null
@@ -0,0 +1,69 @@
+using System;
+using System.IO;
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+namespace Symbolicate
+{
+       public class Program
+       {
+               static Regex regex = new Regex (@"\w*at (?<MethodName>.+) \((?<MethodParams>.*)\) \[0x(?<IL>.+)\] in <filename unknown>:0");
+
+               public static int Main (String[] args)
+               {
+                       if (args.Length < 2) {
+                               Console.Error.WriteLine ("Usage: symbolicate <assembly path> <input file> [lookup directories]");
+                               return 1;
+                       }
+
+                       var assemblyPath = args [0];
+                       var inputFile = args [1];
+
+                       var locProvider = new LocationProvider ();
+
+                       for (var i = 2; i < args.Length; i++)
+                               locProvider.AddDirectory (args [i]);
+
+                       locProvider.AddAssembly (assemblyPath);
+
+                       using (StreamReader r = new StreamReader (inputFile)) {
+                           for (var line = r.ReadLine (); line != null; line = r.ReadLine ()) {
+                                       line = SymbolicateLine (line, locProvider);
+                                       Console.WriteLine (line);
+                           }
+                       }
+
+                       return 0;
+               }
+
+               static string SymbolicateLine (string line, LocationProvider locProvider)
+               {
+                       var match = regex.Match (line);
+                       if (!match.Success)
+                               return line;
+
+                       var methodName = match.Groups ["MethodName"].Value;
+                       var methodParams = ParseParametersTypes (match.Groups ["MethodParams"].Value);
+                       var ilOffset = int.Parse (match.Groups ["IL"].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+
+                       Location location;
+                       if (!locProvider.TryGetLocation (methodName, methodParams, ilOffset, out location))
+                               return line;
+
+                       return line.Replace ("<filename unknown>:0", string.Format ("{0}:{1}", location.FileName, location.Line));
+               }
+
+               static string[] ParseParametersTypes (string parameters)
+               {
+                       if (string.IsNullOrEmpty (parameters))
+                               return new string [0];
+
+                       var paramsArray = parameters.Split (',');
+                       var paramsTypes = new string [paramsArray.Length];
+                       for (var i = 0; i < paramsArray.Length; i++)
+                               paramsTypes [i] = paramsArray [i].Trim ().Split (new char[]{' '}, 2)[0];
+
+                       return paramsTypes;
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/tools/symbolicate/symbolicate.exe.sources b/mcs/tools/symbolicate/symbolicate.exe.sources
new file mode 100644 (file)
index 0000000..968d028
--- /dev/null
@@ -0,0 +1,2 @@
+symbolicate.cs
+LocationProvider.cs
\ No newline at end of file
index c40af5a98f562911e5dd024c548c7faf35504e46..cbd481abeb387ed49459e9aa4bafa42e533a9fa1 100644 (file)
@@ -78,7 +78,7 @@
  * Changes which are already detected at runtime, like the addition
  * of icalls, do not require an increment.
  */
-#define MONO_CORLIB_VERSION 111
+#define MONO_CORLIB_VERSION 112
 
 typedef struct
 {
index 0e24c963d0c84b0bf5110eb3c89bf04b0db10299..11bb021a36f609702de4cd6d494c7017b22ed56d 100644 (file)
@@ -380,6 +380,7 @@ typedef struct {
        MonoObject obj;
        gint32 il_offset;
        gint32 native_offset;
+       gint64 method_address;
        MonoReflectionMethod *method;
        MonoString *filename;
        gint32 line;
index d43605ce620c8c9e472e83debd2a1451ae4b5356..04ac59db62041e7e50868241a50d0ed18b4e8cf9 100755 (executable)
@@ -289,6 +289,7 @@ endif
 
 genmdesc_SOURCES = \
        mini.h          \
+       seq-points.h    \
        genmdesc.c      \
        helpers.c       \
        ../metadata/opcodes.c
@@ -375,6 +376,8 @@ endif
 
 common_sources = \
        mini.c                  \
+       seq-points.c    \
+       seq-points.h    \
        ir-emit.h               \
        method-to-ir.c          \
        decompose.c             \
index bc9c01f401fc9f688c25190250d77ad4a934f8cd..283489f8d26dfafe23fa4ea3e3ba2906b7d57486 100644 (file)
@@ -52,6 +52,7 @@
 #include <mono/utils/mono-mmap.h>
 
 #include "mini.h"
+#include "seq-points.h"
 #include "image-writer.h"
 #include "dwarfwriter.h"
 #include "mini-gc.h"
@@ -5322,7 +5323,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 {
        MonoMethod *method;
        int i, k, buf_size, method_index;
-       guint32 debug_info_size;
+       guint32 debug_info_size, seq_points_size;
        guint8 *code;
        MonoMethodHeader *header;
        guint8 *p, *buf, *debug_info;
@@ -5346,7 +5347,9 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
 
        seq_points = cfg->seq_point_info;
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 2048 + (seq_points ? (seq_points->len * 128) : 0) + cfg->gc_map_size;
+       seq_points_size = seq_point_info_get_write_size (seq_points);
+
+       buf_size = header->num_clauses * 256 + debug_info_size + 2048 + seq_points_size + cfg->gc_map_size;
        p = buf = g_malloc (buf_size);
 
        use_unwind_ops = cfg->unwind_ops != NULL;
@@ -5552,27 +5555,9 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                }
        }
 
-       if (seq_points) {
-               int il_offset, native_offset, last_il_offset, last_native_offset, j;
-
-               encode_value (seq_points->len, p, &p);
-               last_il_offset = last_native_offset = 0;
-               for (i = 0; i < seq_points->len; ++i) {
-                       SeqPoint *sp = &seq_points->seq_points [i];
-                       il_offset = sp->il_offset;
-                       native_offset = sp->native_offset;
-                       encode_value (il_offset - last_il_offset, p, &p);
-                       encode_value (native_offset - last_native_offset, p, &p);
-                       last_il_offset = il_offset;
-                       last_native_offset = native_offset;
+       if (seq_points)
+               p += seq_point_info_write (seq_points, p);
 
-                       encode_value (sp->flags, p, &p);
-                       encode_value (sp->next_len, p, &p);
-                       for (j = 0; j < sp->next_len; ++j)
-                               encode_value (sp->next [j], p, &p);
-               }
-       }
-               
        g_assert (debug_info_size < buf_size);
 
        encode_value (debug_info_size, p, &p);
@@ -8855,7 +8840,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                MonoDebugOptions *opt = mini_get_debug_options ();
 
                opt->mdb_optimizations = TRUE;
-               opt->gen_seq_points = TRUE;
+               opt->gen_seq_points_debug_data = TRUE;
 
                if (!mono_debug_enabled ()) {
                        aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n");
index 757b730e655ab0cc3c9f95dfa3d87eda897f3d77..7158952a2ec6ca57bf03dc33978d6a317ef18b30 100644 (file)
@@ -58,6 +58,7 @@
 #include <mono/utils/mono-digest.h>
 
 #include "mini.h"
+#include "seq-points.h"
 #include "version.h"
 
 #ifndef DISABLE_AOT
@@ -2770,30 +2771,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
 
        if (method && has_seq_points) {
                MonoSeqPointInfo *seq_points;
-               int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
-               int len = decode_value (p, &p);
-
-               seq_points = g_malloc0 (sizeof (MonoSeqPointInfo) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
-               seq_points->len = len;
-               last_il_offset = last_native_offset = 0;
-               for (i = 0; i < len; ++i) {
-                       SeqPoint *sp = &seq_points->seq_points [i];
-                       il_offset = last_il_offset + decode_value (p, &p);
-                       native_offset = last_native_offset + decode_value (p, &p);
-
-                       sp->il_offset = il_offset;
-                       sp->native_offset = native_offset;
-                       
-                       sp->flags = decode_value (p, &p);
-                       sp->next_len = decode_value (p, &p);
-                       sp->next = g_new (int, sp->next_len);
-                       for (j = 0; j < sp->next_len; ++j)
-                               sp->next [j] = decode_value (p, &p);
-
-                       last_il_offset = il_offset;
-                       last_native_offset = native_offset;
-               }
+               p += seq_point_info_read (&seq_points, p, FALSE);
 
                mono_domain_lock (domain);
                g_hash_table_insert (domain_jit_info (domain)->seq_points, method, seq_points);
index be535210a6dea30087ad4d73e79db65b9748ffb8..ca62b660056ade35cb649dc15c7534e421c09d1a 100755 (executable)
@@ -66,6 +66,7 @@ tailcall: len:120 clob:c
 br: len:6
 label: len:0
 seq_point: len:31 clob:c
+il_seq_point: len:0
 
 long_add: dest:i src1:i src2:i len:3 clob:1 nacl:6
 long_sub: dest:i src1:i src2:i len:3 clob:1 nacl:6
index b31b368ec78550d7442a76009225d42d64bf7873..1ff8af77acb46825fae0cfeb0afbca416ffb8cc7 100644 (file)
@@ -58,6 +58,7 @@ switch: src1:i len:12
 # See the comment in resume_from_signal_handler, we can't copy the fp regs from sigctx to MonoContext on linux,
 # since the corresponding sigctx structures are not well defined.
 seq_point: len:38 clob:c
+il_seq_point: len:0
 
 throw: src1:i len:24
 rethrow: src1:i len:20
index f45b72123aa931454a7c95a8cbee92bbc789791e..482deb0daeae095357de3381ce452a932cd82a1a 100644 (file)
@@ -58,6 +58,7 @@ switch: src1:i len:12
 # See the comment in resume_from_signal_handler, we can't copy the fp regs from sigctx to MonoContext on linux,
 # since the corresponding sigctx structures are not well defined.
 seq_point: len:38 clob:c
+il_seq_point: len:0
 
 throw: src1:i len:24
 rethrow: src1:i len:20
index 0fd87c8973fe25fbe5fb5339bb198131affb60db..8d3447a7ee1cd5cd46119fb8c7b578922d79a4f0 100644 (file)
@@ -60,6 +60,7 @@ call: dest:v clob:c len:20
 br: len:16
 switch: src1:i len:40
 seq_point: len:24
+il_seq_point: len:0
 
 int_conv_to_r_un: dest:f src1:i len:32
 throw: src1:i len:24
index 44a482aad1318791135dfa69c99f0fb5d5fb1070..ba2ec60d3e727b0a74beeffeeb2126607abed162 100644 (file)
@@ -50,6 +50,7 @@ nop: len:4
 relaxed_nop: len:4
 break: len:32
 seq_point: len:24
+il_seq_point: len:0
 jmp: len:108
 tailcall: len:120 clob:c
 call: dest:a clob:c len:16
index c47c6e25b7b969d0dea0b177efa20c711a780e8a..dc6ac728ab435698dd1566cfae5513e96c9f5a36 100644 (file)
@@ -50,6 +50,7 @@ nop: len:4
 relaxed_nop: len:4
 break: len:40
 seq_point: len:48
+il_seq_point: len:0
 jmp: len:96
 call: dest:a clob:c len:36
 br: len:4
index 2eee2e4e57de2513cea47bc74092da93ed3c6aa0..96c218de52b61ddab6d2d2e22cff21de4306015f 100644 (file)
@@ -174,6 +174,7 @@ s390_setf4ret: dest:f src1:f len:4
 sbb: dest:i src1:i src2:i len:6
 sbb_imm: dest:i src1:i len:14
 seq_point: len:54
+il_seq_point: len:0
 sext_i4: dest:i src1:i len:4
 zext_i4: dest:i src1:i len:4
 shl_imm: dest:i src1:i len:10
index ca87f2fba43975024ef370c2b354e99cd5665240..0a2be606ea1d9db4c39834e01b353c6be4a4edc5 100644 (file)
@@ -67,6 +67,7 @@ call: dest:a clob:c len:17
 tailcall: len:120 clob:c
 br: len:5
 seq_point: len:17
+il_seq_point: len:0
 
 int_beq: len:6
 int_bge: len:6
index e2467da18f04e8e16a433d2134aca0c926838597..240f8419a4532cb81c55751c5b4f9965a4f7ac98 100644 (file)
@@ -84,6 +84,7 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
 #include <mono/utils/mono-threads.h>
 #include "debugger-agent.h"
 #include "mini.h"
+#include "seq-points.h"
 
 /*
 On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -1030,7 +1031,7 @@ mono_debugger_agent_init (void)
        breakpoints_init ();
        suspend_init ();
 
-       mini_get_debug_options ()->gen_seq_points = TRUE;
+       mini_get_debug_options ()->gen_seq_points_debug_data = TRUE;
        /* 
         * This is needed because currently we don't handle liveness info.
         */
@@ -3145,24 +3146,6 @@ is_suspended (void)
        return count_threads_to_wait_for () == 0;
 }
 
-static MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
-{
-       MonoSeqPointInfo *seq_points;
-
-       mono_domain_lock (domain);
-       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
-       if (!seq_points && method->is_inflated) {
-               /* generic sharing + aot */
-               seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
-               if (!seq_points)
-                       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
-       }
-       mono_domain_unlock (domain);
-
-       return seq_points;
-}
-
 static void
 no_seq_points_found (MonoMethod *method)
 {
@@ -3172,87 +3155,6 @@ no_seq_points_found (MonoMethod *method)
        printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
 }
 
-/*
- * find_next_seq_point_for_native_offset:
- *
- *   Find the first sequence point after NATIVE_OFFSET.
- */
-static SeqPoint*
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       seq_points = get_seq_points (domain, method);
-       if (!seq_points) {
-               if (info)
-                       *info = NULL;
-               return NULL;
-       }
-       g_assert (seq_points);
-       if (info)
-               *info = seq_points;
-
-       for (i = 0; i < seq_points->len; ++i) {
-               if (seq_points->seq_points [i].native_offset >= native_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
-/*
- * find_prev_seq_point_for_native_offset:
- *
- *   Find the first sequence point before NATIVE_OFFSET.
- */
-static SeqPoint*
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       seq_points = get_seq_points (domain, method);
-       if (info)
-               *info = seq_points;
-       if (!seq_points)
-               return NULL;
-
-       for (i = seq_points->len - 1; i >= 0; --i) {
-               if (seq_points->seq_points [i].native_offset <= native_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
-/*
- * find_seq_point:
- *
- *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
- * should be the location of a sequence point.
- */
-static G_GNUC_UNUSED SeqPoint*
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       *info = NULL;
-
-       seq_points = get_seq_points (domain, method);
-       if (!seq_points)
-               return NULL;
-       *info = seq_points;
-
-       for (i = 0; i < seq_points->len; ++i) {
-               if (seq_points->seq_points [i].il_offset == il_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
 typedef struct {
        DebuggerTlsData *tls;
        GSList *frames;
@@ -3264,7 +3166,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        ComputeFramesUserData *ud = user_data;
        StackFrame *frame;
        MonoMethod *method, *actual_method, *api_method;
-       SeqPoint *sp;
+       SeqPoint sp;
        int flags = 0;
 
        if (info->type != FRAME_TYPE_MANAGED) {
@@ -3292,9 +3194,8 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        if (info->il_offset == -1) {
                /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
                if (ud->frames == NULL) {
-                       sp = find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL);
-                       if (sp)
-                               info->il_offset = sp->il_offset;
+                       if (find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL, &sp))
+                               info->il_offset = sp.il_offset;
                }
                if (info->il_offset == -1)
                        info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
@@ -4286,7 +4187,6 @@ typedef struct {
        guint8 *ip;
        MonoJitInfo *ji;
        MonoDomain *domain;
-       SeqPoint *sp;
 } BreakpointInstance;
 
 /*
@@ -4331,38 +4231,44 @@ breakpoints_init (void)
 static void
 insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, MonoBreakpoint *bp, MonoError *error)
 {
-       int i, count;
+       int count;
        BreakpointInstance *inst;
-       SeqPoint *sp = NULL;
+       SeqPointIterator it;
+       gboolean it_has_sp = FALSE;
 
        if (error)
                mono_error_init (error);
 
-       for (i = 0; i < seq_points->len; ++i) {
-               sp = &seq_points->seq_points [i];
-
-               if (sp->il_offset == bp->il_offset)
+       seq_point_iterator_init (&it, seq_points);
+       while (seq_point_iterator_next (&it)) {
+               if (it.seq_point.il_offset == bp->il_offset) {
+                       it_has_sp = TRUE;
                        break;
+               }
        }
 
-       if (i == seq_points->len) {
+       if (!it_has_sp) {
                /*
                 * The set of IL offsets with seq points doesn't completely match the
                 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
                 */
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
-
-                       if (sp->il_offset != METHOD_ENTRY_IL_OFFSET && sp->il_offset != METHOD_EXIT_IL_OFFSET && sp->il_offset + 1 == bp->il_offset)
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it)) {
+                       if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET &&
+                               it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET &&
+                               it.seq_point.il_offset + 1 == bp->il_offset) {
+                               it_has_sp = TRUE;
                                break;
+                       }
                }
        }
 
-       if (i == seq_points->len) {
-               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset, seq_points->len);
+       if (!it_has_sp) {
+               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset);
 
-               for (i = 0; i < seq_points->len; ++i)
-                       DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it))
+                       DEBUG (1, fprintf (log_file, "%d\n", it.seq_point.il_offset));
 
                if (error) {
                        mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
@@ -4377,9 +4283,9 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        }
 
        inst = g_new0 (BreakpointInstance, 1);
-       inst->sp = sp;
-       inst->native_offset = sp->native_offset;
-       inst->ip = (guint8*)ji->code_start + sp->native_offset;
+       inst->il_offset = it.seq_point.il_offset;
+       inst->native_offset = it.seq_point.native_offset;
+       inst->ip = (guint8*)ji->code_start + it.seq_point.native_offset;
        inst->ji = ji;
        inst->domain = domain;
 
@@ -4394,7 +4300,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
        dbg_unlock ();
 
-       if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
+       if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
                DEBUG (1, fprintf (log_file, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset));
        } else if (count == 0) {
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
@@ -4404,7 +4310,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
 #endif
        }
 
-       DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)sp->il_offset, inst->ip, count));
+       DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, inst->ip, count));
 }
 
 static void
@@ -4776,7 +4682,8 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        MonoContext *ctx = &tls->restore_ctx;
        MonoMethod *method;
        MonoSeqPointInfo *info;
-       SeqPoint *sp;
+       SeqPoint sp;
+       gboolean found_sp;
 
        // FIXME: Speed this up
 
@@ -4806,12 +4713,14 @@ process_breakpoint_inner (DebuggerTlsData *tls)
         * The ip points to the instruction causing the breakpoint event, which is after
         * the offset recorded in the seq point map, so find the prev seq point before ip.
         */
-       sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info);
-       if (!sp)
+       found_sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp);
+
+       if (!found_sp)
                no_seq_points_found (method);
-       g_assert (sp);
 
-       DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp ? sp->il_offset : -1));
+       g_assert (found_sp);
+
+       DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp.il_offset));
 
        bp = NULL;
        for (i = 0; i < breakpoints->len; ++i) {
@@ -4822,7 +4731,7 @@ process_breakpoint_inner (DebuggerTlsData *tls)
 
                for (j = 0; j < bp->children->len; ++j) {
                        inst = g_ptr_array_index (bp->children, j);
-                       if (inst->ji == ji && inst->sp == sp) {
+                       if (inst->ji == ji && inst->il_offset == sp.il_offset && inst->native_offset == sp.native_offset) {
                                if (bp->req->event_kind == EVENT_KIND_STEP) {
                                        g_ptr_array_add (ss_reqs_orig, bp->req);
                                } else {
@@ -4833,9 +4742,9 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        }
        if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
                /* Maybe a method entry/exit event */
-               if (sp->il_offset == METHOD_ENTRY_IL_OFFSET)
+               if (sp.il_offset == METHOD_ENTRY_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_ENTRY;
-               else if (sp->il_offset == METHOD_EXIT_IL_OFFSET)
+               else if (sp.il_offset == METHOD_EXIT_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_EXIT;
        }
 
@@ -4848,12 +4757,12 @@ process_breakpoint_inner (DebuggerTlsData *tls)
                if (mono_thread_internal_current () != ss_req->thread)
                        continue;
 
-               hit = ss_update (ss_req, ji, sp, tls, ctx);
+               hit = ss_update (ss_req, ji, &sp, tls, ctx);
                if (hit)
                        g_ptr_array_add (ss_reqs, req);
 
                /* Start single stepping again from the current sequence point */
-               ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+               ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
        }
        
        if (ss_reqs->len > 0)
@@ -5014,7 +4923,7 @@ process_single_step_inner (DebuggerTlsData *tls)
        GSList *events;
        MonoContext *ctx = &tls->restore_ctx;
        MonoMethod *method;
-       SeqPoint *sp;
+       SeqPoint sp;
        MonoSeqPointInfo *info;
 
        ip = MONO_CONTEXT_GET_IP (ctx);
@@ -5060,16 +4969,16 @@ process_single_step_inner (DebuggerTlsData *tls)
         * The ip points to the instruction causing the single step event, which is before
         * the offset recorded in the seq point map, so find the next seq point after ip.
         */
-       sp = find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info);
-       if (!sp)
+       if (!find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
                return;
-       il_offset = sp->il_offset;
 
-       if (!ss_update (ss_req, ji, sp, tls, ctx))
+       il_offset = sp.il_offset;
+
+       if (!ss_update (ss_req, ji, &sp, tls, ctx))
                return;
 
        /* Start single stepping again from the current sequence point */
-       ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+       ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
 
        if ((ss_req->filter & STEP_FILTER_STATIC_CTOR) &&
                (method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
@@ -5243,10 +5152,12 @@ ss_stop (SingleStepReq *ss_req)
  * belong to the same thread as CTX.
  */
 static void
-ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPointsp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
 {
        int i, j, frame_index;
        SeqPoint *next_sp;
+       SeqPoint local_sp;
+       gboolean found_sp;
        MonoBreakpoint *bp;
        gboolean enable_global = FALSE;
 
@@ -5279,7 +5190,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                StackFrame *frame = tls->frames [frame_index];
 
                                method = frame->method;
-                               sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                               found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                               sp = (found_sp)? &local_sp : NULL;
                                frame_index ++;
                                if (sp && sp->next_len != 0)
                                        break;
@@ -5293,7 +5205,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                        StackFrame *frame = tls->frames [frame_index];
 
                                        method = frame->method;
-                                       sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                                       found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                                       sp = (found_sp)? &local_sp : NULL;
                                        if (sp && sp->next_len != 0)
                                                break;
                                        sp = NULL;
@@ -5303,12 +5216,16 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                }
 
                if (sp && sp->next_len > 0) {
-                       for (i = 0; i < sp->next_len; ++i) {
-                               next_sp = &info->seq_points [sp->next [i]];
+                       SeqPoint* next = g_new(SeqPoint, sp->next_len);
+
+                       seq_point_init_next (info, *sp, next);
+                       for (i = 0; i < sp->next_len; i++) {
+                               next_sp = &next[i];
 
                                bp = set_breakpoint (method, next_sp->il_offset, ss_req->req, NULL);
                                ss_req->bps = g_slist_append (ss_req->bps, bp);
                        }
+                       g_free (next);
                }
 
                if (ss_req->depth == STEP_DEPTH_OVER) {
@@ -5323,7 +5240,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                        for (j = 0; j < jinfo->num_clauses; ++j) {
                                                MonoJitExceptionInfo *ei = &jinfo->clauses [j];
 
-                                               sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL);
+                                               found_sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL, &local_sp);
+                                               sp = (found_sp)? &local_sp : NULL;
                                                if (sp) {
                                                        bp = set_breakpoint (frame->method, sp->il_offset, ss_req->req, NULL);
                                                        ss_req->bps = g_slist_append (ss_req->bps, bp);
@@ -5369,6 +5287,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
        DebuggerTlsData *tls;
        MonoSeqPointInfo *info = NULL;
        SeqPoint *sp = NULL;
+       SeqPoint local_sp;
+       gboolean found_sp;
        MonoMethod *method = NULL;
        MonoDebugMethodInfo *minfo;
        gboolean step_to_catch = FALSE;
@@ -5419,7 +5339,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
                 * Find the seq point corresponding to the landing site ip, which is the first seq
                 * point after ip.
                 */
-               sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info);
+               found_sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &local_sp);
+               sp = (found_sp)? &local_sp : NULL;
                if (!sp)
                        no_seq_points_found (frame.method);
                g_assert (sp);
@@ -5465,7 +5386,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
 
                        if (!method && frame->il_offset != -1) {
                                /* FIXME: Sort the table and use a binary search */
-                               sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                               found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                               sp = (found_sp)? &local_sp : NULL;
                                if (!sp)
                                        no_seq_points_found (frame->method);
                                g_assert (sp);
@@ -8856,9 +8778,9 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                MonoMethod *method;
                MonoDomain *domain;
                MonoSeqPointInfo *seq_points;
-               SeqPoint *sp = NULL;
+               SeqPoint sp;
+               gboolean found_sp;
                gint64 il_offset;
-               int i;
 
                method = decode_methodid (p, &p, end, &domain, &err);
                if (err)
@@ -8879,22 +8801,17 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
                        return ERR_INVALID_ARGUMENT;
 
-               seq_points = get_seq_points (domain, method);
-               g_assert (seq_points);
+               found_sp = find_seq_point (domain, method, il_offset, &seq_points, &sp);
 
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
+               g_assert (seq_points);
 
-                       if (sp->il_offset == il_offset)
-                               break;
-               }
-               if (i == seq_points->len)
+               if (!found_sp)
                        return ERR_INVALID_ARGUMENT;
 
                // FIXME: Check that the ip change is safe
 
-               DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp->il_offset, (int)sp->native_offset));
-               MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp->native_offset);
+               DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset));
+               MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
                break;
        }
        default:
@@ -9807,4 +9724,3 @@ mono_debugger_agent_unhandled_exception (MonoException *exc)
 }
 
 #endif
-
index 02853d0856b9bfe6f8e2b2ef3981272db236535c..63129c264831da75319e36aa3a13de46000d20ff 100644 (file)
@@ -3,13 +3,6 @@
 
 #include "mini.h"
 
-/* IL offsets used to mark the sequence points belonging to method entry/exit events */
-#define METHOD_ENTRY_IL_OFFSET -1
-#define METHOD_EXIT_IL_OFFSET 0xffffff
-
-/* Native offset used to mark seq points in dead code */
-#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1
-
 void
 mono_debugger_agent_parse_options (char *options) MONO_INTERNAL;
 
index 2bfd1ac51725410d5d3f9b3ce83fe19560bf3483..aac45186598af0c3295e282aca2433512024e1e9 100644 (file)
@@ -405,7 +405,7 @@ handle_gsharedvt_ldaddr (MonoCompile *cfg)
        } while (0)
 
 #define NEW_SEQ_POINT(cfg,dest,il_offset,intr_loc) do {         \
-       MONO_INST_NEW ((cfg), (dest), OP_SEQ_POINT); \
+       MONO_INST_NEW ((cfg), (dest), cfg->gen_seq_points_debug_data ? OP_SEQ_POINT : OP_IL_SEQ_POINT); \
        (dest)->inst_imm = (il_offset); \
        (dest)->flags = intr_loc ? MONO_INST_SINGLE_STEP_LOC : 0; \
        } while (0)
index 5504b8c5cd80d97cbd49b1412717e3a1cbbb1c1b..3e1a3554c836e6ce99c720541fbf0abed7fcc2c5 100755 (executable)
@@ -68,6 +68,7 @@
 #include "jit-icalls.h"
 #include "jit.h"
 #include "debugger-agent.h"
+#include "seq-points.h"
 
 #define BRANCH_COST 10
 #define INLINE_LENGTH_LIMIT 20
@@ -7135,7 +7136,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                seq_points = FALSE;
        }
 
-       if (cfg->gen_seq_points && cfg->method == method) {
+       if (cfg->gen_seq_points_debug_data && cfg->method == method) {
                minfo = mono_debug_lookup_method (method);
                if (minfo) {
                        int i, n_il_offsets;
index 23e70e0dcdf6a4b31afbfa5758b5a1be67964dbf..58e6ebecb8d28c6694e0e061a1e88d4e259e5153 100755 (executable)
@@ -4109,6 +4109,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_REACHED:
                case OP_NOT_NULL:
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
 
index 50aa640e8b48225e5c2bd6cab6ea6bdf7f1d689d..343cb49b8dc00e45f9b9df396c6d3c2259a37ddd 100644 (file)
@@ -4377,6 +4377,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_REACHED:
                case OP_NOT_NULL:
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
                        MonoInst *info_var = cfg->arch.seq_point_info_var;
index f4bdecb727a31a1b7c4598ea7bd658e5086e8f6b..cc603b8a9530467d8f9eb39dd46f2efbafd9cc9b 100644 (file)
@@ -686,6 +686,7 @@ mono_print_ins_index (int i, MonoInst *ins)
        case OP_GC_LIVENESS_USE:
                printf (" R%d", (int)ins->inst_c1);
                break;
+       case OP_IL_SEQ_POINT:
        case OP_SEQ_POINT:
                printf (" il: %x", (int)ins->inst_imm);
                break;
index 616ebc46bf363e6db420ffc14d4d0ce54be47bd8..56ff948213eee890999ecd65b02c51bac3e8f802 100644 (file)
@@ -52,6 +52,7 @@
 #include "mini.h"
 #include "trace.h"
 #include "debugger-agent.h"
+#include "seq-points.h"
 
 #ifndef MONO_ARCH_CONTEXT_DEF
 #define MONO_ARCH_CONTEXT_DEF
@@ -690,6 +691,7 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                }
                else
                        MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
+               sf->method_address = (gint64) ji->code_start;
                sf->native_offset = (char *)ip - (char *)ji->code_start;
 
                /*
@@ -698,10 +700,15 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                 * operation, so we shouldn't call this method twice.
                 */
                location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
-               if (location)
+               if (location) {
                        sf->il_offset = location->il_offset;
-               else
-                       sf->il_offset = 0;
+               } else {
+                       SeqPoint sp;
+                       if (find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
+                               sf->il_offset = sp.il_offset;
+                       else
+                               sf->il_offset = 0;
+               }
 
                if (need_file_info) {
                        if (location && location->source_file) {
@@ -852,7 +859,13 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
                        MonoDebugSourceLocation *source;
 
                        source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
-                       il_offset = source ? source->il_offset : -1;
+                       if (source) {
+                               il_offset = source->il_offset;
+                       } else {
+                               SeqPoint sp;
+                               if (find_prev_seq_point_for_native_offset (domain, jinfo_get_method (frame.ji), frame.native_offset, NULL, &sp))
+                                       il_offset = sp.il_offset;
+                       }
                        mono_debug_free_source_location (source);
                } else
                        il_offset = -1;
index 1eb61e9b20413c8771133920eb2971bf604f7051..277b4744a073964abae19a7f050016d450df3531 100644 (file)
@@ -3394,6 +3394,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_REACHED:
                case OP_NOT_NULL:
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
                                guint32 addr = (guint32)ss_trigger_page;
index e667a4c08f5050f328c1637ebfe03f84674cd5a8..cc8323a1eb7739b75fe29cbad51f0f806e844aca 100644 (file)
@@ -37,6 +37,7 @@ MINI_OP(OP_LOCALLOC, "localloc", IREG, IREG, NONE)
 MINI_OP(OP_LOCALLOC_IMM, "localloc_imm", IREG, NONE, NONE)
 MINI_OP(OP_CHECK_THIS, "checkthis", NONE, IREG, NONE)
 MINI_OP(OP_SEQ_POINT, "seq_point", NONE, NONE, NONE)
+MINI_OP(OP_IL_SEQ_POINT, "il_seq_point", NONE, NONE, NONE)
 MINI_OP(OP_IMPLICIT_EXCEPTION, "implicit_exception", NONE, NONE, NONE)
 
 MINI_OP(OP_VOIDCALL,   "voidcall", NONE, NONE, NONE)
index 594a72e06b10430a1967798a5203bdecf951dbfe..907fe766c9c1219742d862bc1844896111d358b8 100644 (file)
@@ -3104,6 +3104,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_REACHED:
                case OP_NOT_NULL:
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
 
index d84c87860d1f95b652405201c0823ed719a62097..a1618c932ebf84d95e0989029c0a4cdac80b0637 100644 (file)
@@ -4072,6 +4072,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL: {
                }
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
 
index 35f56d0f984fd50aba7cf01c9471fb046e95bf2a..e4415df43fafc31b378379671f8ff6abd6672305 100644 (file)
@@ -2761,6 +2761,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_REACHED:
                case OP_NOT_NULL:
                        break;
+               case OP_IL_SEQ_POINT:
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
+                       break;
                case OP_SEQ_POINT: {
                        int i;
 
index b642073e91ff5d3f86b0febabd82fbe90d58a08f..f876ce3ea5c5e30c9eff8506e15d0c87eca36806 100755 (executable)
@@ -64,6 +64,7 @@
 #include <mono/utils/mono-threads.h>
 
 #include "mini.h"
+#include "seq-points.h"
 #include "mini-llvm.h"
 #include "tasklets.h"
 #include <string.h>
@@ -76,6 +77,7 @@
 
 #include "mini-gc.h"
 #include "debugger-agent.h"
+#include "seq-points.h"
 
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
@@ -3921,159 +3923,6 @@ mono_postprocess_patches (MonoCompile *cfg)
        }
 }
 
-static void
-collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
-{
-       int i;
-       MonoBasicBlock *in_bb;
-       GSList *l;
-
-       for (i = 0; i < bb->in_count; ++i) {
-               in_bb = bb->in_bb [i];
-
-               if (in_bb->last_seq_point) {
-                       int src_index = in_bb->last_seq_point->backend.size;
-                       int dst_index = ins->backend.size;
-
-                       /* bb->in_bb might contain duplicates */
-                       for (l = next [src_index]; l; l = l->next)
-                               if (GPOINTER_TO_UINT (l->data) == dst_index)
-                                       break;
-                       if (!l)
-                               next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
-               } else {
-                       /* Have to look at its predecessors */
-                       if (depth < 5)
-                               collect_pred_seq_points (in_bb, ins, next, depth + 1);
-               }
-       }
-}
-
-static void
-mono_save_seq_point_info (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb;
-       GSList *bb_seq_points, *l;
-       MonoInst *last;
-       MonoDomain *domain = cfg->domain;
-       int i;
-       MonoSeqPointInfo *info;
-       GSList **next;
-
-       if (!cfg->seq_points)
-               return;
-
-       info = g_malloc0 (sizeof (MonoSeqPointInfo) + (cfg->seq_points->len * sizeof (SeqPoint)));
-       info->len = cfg->seq_points->len;
-       for (i = 0; i < cfg->seq_points->len; ++i) {
-               SeqPoint *sp = &info->seq_points [i];
-               MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
-
-               sp->il_offset = ins->inst_imm;
-               sp->native_offset = ins->inst_offset;
-               if (ins->flags & MONO_INST_NONEMPTY_STACK)
-                       sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
-
-               /* Used below */
-               ins->backend.size = i;
-       }
-
-       /*
-        * For each sequence point, compute the list of sequence points immediately
-        * following it, this is needed to implement 'step over' in the debugger agent.
-        */ 
-       next = g_new0 (GSList*, cfg->seq_points->len);
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               bb_seq_points = g_slist_reverse (bb->seq_points);
-               last = NULL;
-               for (l = bb_seq_points; l; l = l->next) {
-                       MonoInst *ins = l->data;
-
-                       if (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
-                               /* Used to implement method entry/exit events */
-                               continue;
-                       if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
-                               continue;
-
-                       if (last != NULL) {
-                               /* Link with the previous seq point in the same bb */
-                               next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
-                       } else {
-                               /* Link with the last bb in the previous bblocks */
-                               collect_pred_seq_points (bb, ins, next, 0);
-                       }
-
-                       last = ins;
-               }
-
-               if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
-                       MonoBasicBlock *bb2;
-                       MonoInst *endfinally_seq_point = NULL;
-
-                       /*
-                        * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
-                        */
-                       l = g_slist_last (bb->seq_points);
-                       if (l) {
-                               endfinally_seq_point = l->data;
-
-                               for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
-                                       GSList *l = g_slist_last (bb2->seq_points);
-
-                                       if (l) {
-                                               MonoInst *ins = l->data;
-
-                                               if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
-                                                       next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if (cfg->verbose_level > 2) {
-               printf ("\nSEQ POINT MAP: \n");
-       }
-
-       for (i = 0; i < cfg->seq_points->len; ++i) {
-               SeqPoint *sp = &info->seq_points [i];
-               GSList *l;
-               int j, next_index;
-
-               sp->next_len = g_slist_length (next [i]);
-               sp->next = g_new (int, sp->next_len);
-               j = 0;
-               if (cfg->verbose_level > 2 && next [i]) {
-                       printf ("\tIL0x%x ->", sp->il_offset);
-                       for (l = next [i]; l; l = l->next) {
-                               next_index = GPOINTER_TO_UINT (l->data);
-                               printf (" IL0x%x", info->seq_points [next_index].il_offset);
-                       }
-                       printf ("\n");
-               }
-               for (l = next [i]; l; l = l->next) {
-                       next_index = GPOINTER_TO_UINT (l->data);
-                       sp->next [j ++] = next_index;
-               }
-               g_slist_free (next [i]);
-       }
-       g_free (next);
-
-       cfg->seq_point_info = info;
-
-       // FIXME: dynamic methods
-       if (!cfg->compile_aot) {
-               mono_domain_lock (domain);
-               // FIXME: How can the lookup succeed ?
-               if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
-                       g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, info);
-               mono_domain_unlock (domain);
-       }
-
-       g_ptr_array_free (cfg->seq_points, TRUE);
-       cfg->seq_points = NULL;
-}
-
 void
 mono_codegen (MonoCompile *cfg)
 {
@@ -5001,7 +4850,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->full_aot = full_aot;
        cfg->skip_visibility = method->skip_visibility;
        cfg->orig_method = method;
-       cfg->gen_seq_points = debug_options.gen_seq_points;
+       cfg->gen_seq_points = TRUE;
+       cfg->gen_seq_points_debug_data = debug_options.gen_seq_points_debug_data;
+
        cfg->explicit_null_checks = debug_options.explicit_null_checks;
        cfg->soft_breakpoints = debug_options.soft_breakpoints;
        cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
@@ -7064,7 +6915,7 @@ mini_parse_debug_options (void)
                else if (!strcmp (arg, "explicit-null-checks"))
                        debug_options.explicit_null_checks = TRUE;
                else if (!strcmp (arg, "gen-seq-points"))
-                       debug_options.gen_seq_points = TRUE;
+                       debug_options.gen_seq_points_debug_data = TRUE;
                else if (!strcmp (arg, "init-stacks"))
                        debug_options.init_stacks = TRUE;
                else if (!strcmp (arg, "casts"))
@@ -7142,6 +6993,7 @@ register_jit_stats (void)
        mono_counters_register ("Allocated vars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocate_var);
        mono_counters_register ("Code reallocs", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.code_reallocs);
        mono_counters_register ("Allocated code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_code_size);
+       mono_counters_register ("Allocated seq points size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.allocated_seq_points_size);
        mono_counters_register ("Inlineable methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlineable_methods);
        mono_counters_register ("Inlined methods", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.inlined_methods);
        mono_counters_register ("Regvars", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.regvars);
@@ -7156,7 +7008,6 @@ register_jit_stats (void)
 }
 
 static void runtime_invoke_info_free (gpointer value);
-static void seq_point_info_free (gpointer value);
 
 static gint
 class_method_pair_equal (gconstpointer ka, gconstpointer kb)
@@ -7227,19 +7078,6 @@ runtime_invoke_info_free (gpointer value)
        g_free (info);
 }
 
-static void seq_point_info_free (gpointer value)
-{
-       int i = 0;
-       MonoSeqPointInfo* info = (MonoSeqPointInfo*)value;
-       
-       for (i = 0; i < info->len; ++i) {
-               SeqPoint *sp = &info->seq_points [i];
-               g_free (sp->next);
-       }
-
-       g_free (info);
-}
-
 static void
 mini_free_jit_domain_info (MonoDomain *domain)
 {
index cfd1053320746dbe7dc71be133f232f62413a561..2169a79423f1b5440e27fd30fd9736a56b807dc8 100755 (executable)
@@ -329,21 +329,6 @@ typedef struct {
  */
 typedef MonoStackFrameInfo StackFrameInfo;
 
-#define MONO_SEQ_POINT_FLAG_NONEMPTY_STACK 1
-
-typedef struct {
-       int il_offset, native_offset, flags;
-       /* Indexes of successor sequence points */
-       int *next;
-       /* Number of entries in next */
-       int next_len;
-} SeqPoint;
-
-typedef struct {
-       int len;
-       SeqPoint seq_points [MONO_ZERO_LEN_ARRAY];
-} MonoSeqPointInfo;
-
 #if 0
 #define mono_bitset_foreach_bit(set,b,n) \
        for (b = 0; b < n; b++)\
@@ -1488,6 +1473,7 @@ typedef struct {
        guint            uses_simd_intrinsics : 1;
        guint            keep_cil_nops : 1;
        guint            gen_seq_points : 1;
+       guint            gen_seq_points_debug_data : 1;
        guint            explicit_null_checks : 1;
        guint            compute_gc_maps : 1;
        guint            soft_breakpoints : 1;
@@ -1583,7 +1569,7 @@ typedef struct {
        GPtrArray *seq_points;
 
        /* The encoded sequence point info */
-       MonoSeqPointInfo *seq_point_info;
+       struct MonoSeqPointInfo *seq_point_info;
 
        /* Method headers which need to be freed after compilation */
        GSList *headers_to_free;
@@ -1666,6 +1652,7 @@ typedef struct {
        gint32 max_code_size_ratio;
        gint32 biggest_method_size;
        gint32 allocated_code_size;
+       gint32 allocated_seq_points_size;
        gint32 inlineable_methods;
        gint32 inlined_methods;
        gint32 basic_blocks;
@@ -1844,7 +1831,11 @@ typedef struct {
        gboolean suspend_on_unhandled;
        gboolean dyn_runtime_invoke;
        gboolean gdb;
-       gboolean gen_seq_points;
+       /*
+        * Whenever data such as next sequence points and flags is required.
+        * Next sequence points and flags are required by the debugger agent.
+        */
+       gboolean gen_seq_points_debug_data;
        gboolean explicit_null_checks;
        /*
         * Fill stack frames with 0x2a in method prologs. This helps with the
diff --git a/mono/mini/seq-points.c b/mono/mini/seq-points.c
new file mode 100644 (file)
index 0000000..dc1a40c
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * seq-points.c: Sequence Points functions
+ *
+ * Authors:
+ *   Marcos Henrich (marcos.henrich@xamarin.com)
+ *
+ * Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
+ */
+
+#include "mini.h"
+#include "seq-points.h"
+
+typedef struct {
+       guint8 *data;
+       int len;
+       /* When has_debug_data is set to false only il and native deltas are saved */
+       gboolean has_debug_data;
+       /* When alloc_data is set to true data allocation/deallocation is managed by this structure */
+       gboolean alloc_data;
+} SeqPointInfoInflated;
+
+static int
+encode_var_int (guint8 *buf, guint8 **out_buf, int val)
+{
+       guint8 size = 0;
+
+       do {
+               guint8 byte = val & 0x7f;
+               g_assert (size < 4 && "value has more than 28 bits");
+               val >>= 7;
+               if(val) byte |= 0x80;
+               *(buf++) = byte;
+               size++;
+       } while (val);
+
+       if (out_buf)
+               *out_buf = buf;
+
+       return size;
+}
+
+static int
+decode_var_int (guint8* buf, guint8 **out_buf)
+{
+       guint8* p = buf;
+
+       int low;
+       int b;
+       b = *(p++); low   = (b & 0x7f)      ; if(!(b & 0x80)) goto done;
+       b = *(p++); low  |= (b & 0x7f) <<  7; if(!(b & 0x80)) goto done;
+       b = *(p++); low  |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
+       b = *(p++); low  |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
+
+       g_assert (FALSE && "value has more than 28 bits");
+
+done:
+
+       if (out_buf)
+               *out_buf = p;
+
+       return low;
+}
+
+static guint32
+encode_zig_zag (int val)
+{
+       return (val << 1) ^ (val >> 31);
+}
+
+static int
+decode_zig_zag (guint32 val)
+{
+       int n = val;
+       return (n >> 1) ^ (-(n & 1));
+}
+
+static SeqPointInfoInflated
+seq_point_info_inflate (MonoSeqPointInfo *info)
+{
+       SeqPointInfoInflated info_inflated;
+       guint8 *ptr = (guint8*) info;
+       int value;
+
+       value = decode_var_int (ptr, &ptr);
+
+       info_inflated.len = value >> 2;
+       info_inflated.has_debug_data = (value & 1) != 0;
+       info_inflated.alloc_data = (value & 2) != 0;
+
+       if (info_inflated.alloc_data)
+               info_inflated.data = ptr;
+       else
+               memcpy (&info_inflated.data, ptr, sizeof (guint8*));
+
+       return info_inflated;
+}
+
+static MonoSeqPointInfo*
+seq_point_info_new (int len, gboolean alloc_data, guint8 *data, gboolean has_debug_data)
+{
+       MonoSeqPointInfo *info;
+       guint8 *info_ptr;
+       guint8 buffer[4];
+       int buffer_len;
+       int value;
+       int data_size;
+
+       value = len << 2;
+       if (has_debug_data)
+               value |= 1;
+       if (alloc_data)
+               value |= 2;
+
+       buffer_len = encode_var_int (buffer, NULL, value);
+
+       data_size = buffer_len + (alloc_data? len : sizeof (guint8*));
+       info_ptr = g_new0 (guint8, data_size);
+       info = (MonoSeqPointInfo*) info_ptr;
+
+       memcpy (info_ptr, buffer, buffer_len);
+       info_ptr += buffer_len;
+
+       if (alloc_data)
+               memcpy (info_ptr, data, len);
+       else
+               memcpy (info_ptr, &data, sizeof (guint8*));
+
+       mono_jit_stats.allocated_seq_points_size += data_size;
+
+       return info;
+}
+
+void
+seq_point_info_free (gpointer ptr)
+{
+       MonoSeqPointInfo* info = (MonoSeqPointInfo*) ptr;
+       g_free (info);
+}
+
+static int
+seq_point_read (SeqPoint* seq_point, guint8* ptr, guint8* buffer_ptr, gboolean has_debug_data)
+{
+       int value;
+       guint8* ptr0 = ptr;
+
+       value = decode_var_int (ptr, &ptr);
+       seq_point->il_offset += decode_zig_zag (value);
+
+       value = decode_var_int (ptr, &ptr);
+       seq_point->native_offset += decode_zig_zag (value);
+
+       if (has_debug_data) {
+               value = decode_var_int (ptr, &ptr);
+               seq_point->flags = value;
+
+               if (seq_point->flags & MONO_SEQ_POINT_FLAG_EXIT_IL)
+                       seq_point->il_offset = METHOD_EXIT_IL_OFFSET;
+
+               value = decode_var_int (ptr, &ptr);
+               seq_point->next_len = value;
+
+               if (seq_point->next_len) {
+                       // store next offset and skip it
+                       seq_point->next_offset = ptr - buffer_ptr;
+                       ptr += seq_point->next_len;
+               }
+       }
+
+       return ptr - ptr0;
+}
+
+static gboolean
+seq_point_info_add_seq_point (GByteArray* array, SeqPoint *sp, SeqPoint *last_seq_point, GSList *next, gboolean has_debug_data)
+{
+       int il_delta, native_delta;
+       GSList *l;
+       guint8 buffer[4];
+       guint8 len;
+       int flags;
+
+       if (!has_debug_data &&
+               (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET))
+               return FALSE;
+
+       il_delta = sp->il_offset - last_seq_point->il_offset;
+       native_delta = sp->native_offset - last_seq_point->native_offset;
+
+       flags = sp->flags;
+
+       if (has_debug_data && sp->il_offset == METHOD_EXIT_IL_OFFSET) {
+               il_delta = 0;
+               flags |= MONO_SEQ_POINT_FLAG_EXIT_IL;
+       }
+
+       len = encode_var_int (buffer, NULL, encode_zig_zag (il_delta));
+       g_byte_array_append (array, buffer, len);
+
+       len = encode_var_int (buffer, NULL, encode_zig_zag (native_delta));
+       g_byte_array_append (array, buffer, len);
+
+       if (has_debug_data) {
+               sp->next_offset = array->len;
+               sp->next_len = g_slist_length (next);
+
+               len = encode_var_int (buffer, NULL, flags);
+               g_byte_array_append (array, buffer, len);
+
+               len = encode_var_int (buffer, NULL, sp->next_len);
+               g_byte_array_append (array, buffer, len);
+
+               for (l = next; l; l = l->next) {
+                       int next_index = GPOINTER_TO_UINT (l->data);
+                       guint8 buffer[4];
+                       int len = encode_var_int (buffer, NULL, next_index);
+                       g_byte_array_append (array, buffer, len);
+               }
+       }
+
+       return TRUE;
+}
+
+static void
+collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
+{
+       int i;
+       MonoBasicBlock *in_bb;
+       GSList *l;
+
+       for (i = 0; i < bb->in_count; ++i) {
+               in_bb = bb->in_bb [i];
+
+               if (in_bb->last_seq_point) {
+                       int src_index = in_bb->last_seq_point->backend.size;
+                       int dst_index = ins->backend.size;
+
+                       /* bb->in_bb might contain duplicates */
+                       for (l = next [src_index]; l; l = l->next)
+                               if (GPOINTER_TO_UINT (l->data) == dst_index)
+                                       break;
+                       if (!l)
+                               next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
+               } else {
+                       /* Have to look at its predecessors */
+                       if (depth < 5)
+                               collect_pred_seq_points (in_bb, ins, next, depth + 1);
+               }
+       }
+}
+
+void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+       GSList *bb_seq_points, *l;
+       MonoInst *last;
+       MonoDomain *domain = cfg->domain;
+       int i;
+       GSList **next;
+       SeqPoint* seq_points;
+       GByteArray* array;
+       gboolean has_debug_data = cfg->gen_seq_points_debug_data;
+
+       if (!cfg->seq_points)
+               return;
+
+       seq_points = g_new0 (SeqPoint, cfg->seq_points->len);
+
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &seq_points [i];
+               MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
+
+               sp->il_offset = ins->inst_imm;
+               sp->native_offset = ins->inst_offset;
+               if (ins->flags & MONO_INST_NONEMPTY_STACK)
+                       sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
+
+               /* Used below */
+               ins->backend.size = i;
+       }
+
+       if (has_debug_data) {
+               /*
+                * For each sequence point, compute the list of sequence points immediately
+                * following it, this is needed to implement 'step over' in the debugger agent.
+                */
+               next = g_new0 (GSList*, cfg->seq_points->len);
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       bb_seq_points = g_slist_reverse (bb->seq_points);
+                       last = NULL;
+                       for (l = bb_seq_points; l; l = l->next) {
+                               MonoInst *ins = l->data;
+
+                               if (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
+                               /* Used to implement method entry/exit events */
+                                       continue;
+                               if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
+                                       continue;
+
+                               if (last != NULL) {
+                                       /* Link with the previous seq point in the same bb */
+                                       next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                               } else {
+                                       /* Link with the last bb in the previous bblocks */
+                                       collect_pred_seq_points (bb, ins, next, 0);
+                               }
+
+                               last = ins;
+                       }
+
+                       if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
+                               MonoBasicBlock *bb2;
+                               MonoInst *endfinally_seq_point = NULL;
+
+                               /*
+                                * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
+                                */
+                               l = g_slist_last (bb->seq_points);
+                               if (l) {
+                                       endfinally_seq_point = l->data;
+
+                                       for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
+                                               GSList *l = g_slist_last (bb2->seq_points);
+
+                                               if (l) {
+                                                       MonoInst *ins = l->data;
+
+                                                       if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
+                                                               next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (cfg->verbose_level > 2) {
+                       printf ("\nSEQ POINT MAP: \n");
+
+                       for (i = 0; i < cfg->seq_points->len; ++i) {
+                               SeqPoint *sp = &seq_points [i];
+                               GSList *l;
+
+                               if (!next [i])
+                                       continue;
+
+                               printf ("\tIL0x%x ->", sp->il_offset);
+                               for (l = next [i]; l; l = l->next) {
+                                       int next_index = GPOINTER_TO_UINT (l->data);
+                                       printf (" IL0x%x", seq_points [next_index].il_offset);
+                               }
+                               printf ("\n");
+                       }
+               }
+       }
+
+       array = g_byte_array_new ();
+
+       { /* Add sequence points to seq_point_info */
+               SeqPoint zero_seq_point = {0};
+               SeqPoint* last_seq_point = &zero_seq_point;
+
+               for (i = 0; i < cfg->seq_points->len; ++i) {
+                       SeqPoint *sp = &seq_points [i];
+                       GSList* next_list = NULL;
+
+                       if (has_debug_data)
+                               next_list = next[i];
+
+                       if (seq_point_info_add_seq_point (array, sp, last_seq_point, next_list, has_debug_data))
+                               last_seq_point = sp;
+
+                       if (has_debug_data)
+                               g_slist_free (next [i]);
+               }
+       }
+
+       if (has_debug_data)
+               g_free (next);
+
+       cfg->seq_point_info = seq_point_info_new (array->len, TRUE, array->data, has_debug_data);
+
+       g_byte_array_free (array, TRUE);
+
+       // FIXME: dynamic methods
+       if (!cfg->compile_aot) {
+               mono_domain_lock (domain);
+               // FIXME: How can the lookup succeed ?
+               if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
+                       g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, cfg->seq_point_info);
+               mono_domain_unlock (domain);
+       }
+
+       g_ptr_array_free (cfg->seq_points, TRUE);
+       cfg->seq_points = NULL;
+}
+
+MonoSeqPointInfo*
+get_seq_points (MonoDomain *domain, MonoMethod *method)
+{
+       MonoSeqPointInfo *seq_points;
+
+       mono_domain_lock (domain);
+       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       if (!seq_points && method->is_inflated) {
+               /* generic sharing + aot */
+               seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
+               if (!seq_points)
+                       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
+       }
+       mono_domain_unlock (domain);
+
+       return seq_points;
+}
+
+static gboolean
+seq_point_find_next_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
+{
+       SeqPointIterator it;
+       seq_point_iterator_init (&it, info);
+       while (seq_point_iterator_next (&it)) {
+               if (it.seq_point.native_offset >= native_offset) {
+                       memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static gboolean
+seq_point_find_prev_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
+{
+       SeqPoint prev_seq_point;
+       gboolean  is_first = TRUE;
+       SeqPointIterator it;
+       seq_point_iterator_init (&it, info);
+       while (seq_point_iterator_next (&it) && it.seq_point.native_offset <= native_offset) {
+               memcpy (&prev_seq_point, &it.seq_point, sizeof (SeqPoint));
+               is_first = FALSE;
+       }
+
+       if (!is_first && prev_seq_point.native_offset <= native_offset) {
+               memcpy (seq_point, &prev_seq_point, sizeof (SeqPoint));
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gboolean
+seq_point_find_by_il_offset (MonoSeqPointInfo* info, int il_offset, SeqPoint* seq_point)
+{
+       SeqPointIterator it;
+       seq_point_iterator_init (&it, info);
+       while (seq_point_iterator_next (&it)) {
+               if (it.seq_point.il_offset == il_offset) {
+                       memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+/*
+ * find_next_seq_point_for_native_offset:
+ *
+ *   Find the first sequence point after NATIVE_OFFSET.
+ */
+gboolean
+find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
+{
+       MonoSeqPointInfo *seq_points;
+
+       seq_points = get_seq_points (domain, method);
+       if (!seq_points) {
+               if (info)
+                       *info = NULL;
+               return FALSE;
+       }
+       if (info)
+               *info = seq_points;
+
+       return seq_point_find_next_by_native_offset (seq_points, native_offset, seq_point);
+}
+
+/*
+ * find_prev_seq_point_for_native_offset:
+ *
+ *   Find the first sequence point before NATIVE_OFFSET.
+ */
+gboolean
+find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
+{
+       MonoSeqPointInfo *seq_points;
+
+       seq_points = get_seq_points (domain, method);
+       if (!seq_points) {
+               if (info)
+                       *info = NULL;
+               return FALSE;
+       }
+       if (info)
+               *info = seq_points;
+
+       return seq_point_find_prev_by_native_offset (seq_points, native_offset, seq_point);
+}
+
+/*
+ * find_seq_point:
+ *
+ *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
+ * should be the location of a sequence point.
+ */
+gboolean
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point)
+{
+       MonoSeqPointInfo *seq_points;
+
+       seq_points = get_seq_points (domain, method);
+       if (!seq_points) {
+               if (info)
+                       *info = NULL;
+               return FALSE;
+       }
+       if (info)
+               *info = seq_points;
+
+       return seq_point_find_by_il_offset (seq_points, il_offset, seq_point);
+}
+
+void
+seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next)
+{
+       int i;
+       guint8* ptr;
+       SeqPointIterator it;
+       GArray* seq_points = g_array_new (FALSE, TRUE, sizeof (SeqPoint));
+       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
+
+       g_assert (info_inflated.has_debug_data);
+
+       seq_point_iterator_init (&it, info);
+       while (seq_point_iterator_next (&it))
+               g_array_append_vals (seq_points, &it.seq_point, 1);
+
+       ptr = info_inflated.data + sp.next_offset;
+       for (i = 0; i < sp.next_len; i++) {
+               int next_index;
+               next_index = decode_var_int (ptr, &ptr);
+               g_assert (next_index < seq_points->len);
+               memcpy (&next[i], seq_points->data + next_index * sizeof (SeqPoint), sizeof (SeqPoint));
+       }
+
+       g_array_free (seq_points, TRUE);
+}
+
+gboolean
+seq_point_iterator_next (SeqPointIterator* it)
+{
+       if (it->ptr >= it->end)
+               return FALSE;
+
+       it->ptr += seq_point_read (&it->seq_point, it->ptr, it->begin, it->has_debug_data);
+
+       return TRUE;
+}
+
+void
+seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info)
+{
+       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
+       it->ptr = info_inflated.data;
+       it->begin = info_inflated.data;
+       it->end = it->begin + info_inflated.len;
+       it->has_debug_data = info_inflated.has_debug_data;
+       memset(&it->seq_point, 0, sizeof(SeqPoint));
+}
+
+int
+seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer)
+{
+       guint8* buffer0 = buffer;
+       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
+
+       memcpy (buffer, &info_inflated.has_debug_data, 1);
+       buffer++;
+
+       //Write sequence points
+       encode_var_int (buffer, &buffer, info_inflated.len);
+       memcpy (buffer, info_inflated.data, info_inflated.len);
+       buffer += info_inflated.len;
+
+       return buffer - buffer0;
+}
+
+int
+seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy)
+{
+       guint8* buffer0 = buffer;
+       int size;
+       gboolean has_debug_data;
+
+       memcpy (&has_debug_data, buffer, 1);
+       buffer++;
+
+       size = decode_var_int (buffer, &buffer);
+       (*info) = seq_point_info_new (size, copy, buffer, has_debug_data);
+       buffer += size;
+
+       return buffer - buffer0;
+}
+
+/*
+ * Returns the maximum size of mono_seq_point_info_write.
+ */
+int
+seq_point_info_get_write_size (MonoSeqPointInfo* info)
+{
+       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
+
+       //4 is the maximum size required to store the size of the data.
+       //1 is the byte used to store has_debug_data.
+       int size = 4 + 1 + info_inflated.len;
+
+       return size;
+}
diff --git a/mono/mini/seq-points.h b/mono/mini/seq-points.h
new file mode 100644 (file)
index 0000000..76a7b73
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Xamarin Inc
+ */
+#ifndef __MONO_SEQ_POINTS_H__
+#define __MONO_SEQ_POINTS_H__
+
+#define MONO_SEQ_POINT_FLAG_NONEMPTY_STACK 1
+#define MONO_SEQ_POINT_FLAG_EXIT_IL 2
+
+/* IL offsets used to mark the sequence points belonging to method entry/exit events */
+#define METHOD_ENTRY_IL_OFFSET -1
+#define METHOD_EXIT_IL_OFFSET 0xffffff
+
+/* Native offset used to mark seq points in dead code */
+#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1
+
+typedef struct {
+       int il_offset, native_offset, flags;
+       /* Offset of indexes of successor sequence points on the compressed buffer */
+       int next_offset;
+       /* Number of entries in next */
+       int next_len;
+} SeqPoint;
+
+typedef struct MonoSeqPointInfo {
+} MonoSeqPointInfo;
+
+typedef struct {
+       SeqPoint seq_point;
+       guint8* ptr;
+       guint8* begin;
+       guint8* end;
+       gboolean has_debug_data;
+} SeqPointIterator;
+
+void
+seq_point_info_free (gpointer info);
+
+void
+mono_save_seq_point_info (MonoCompile *cfg);
+
+MonoSeqPointInfo*
+get_seq_points (MonoDomain *domain, MonoMethod *method);
+
+gboolean
+find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point);
+
+gboolean
+find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point);
+
+gboolean
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point);
+
+gboolean
+seq_point_iterator_next (SeqPointIterator* it);
+
+void
+seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info);
+
+void
+seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next);
+
+int
+seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer);
+
+int
+seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy);
+
+int
+seq_point_info_get_write_size (MonoSeqPointInfo* info);
+
+#endif /* __MONO_SEQ_POINTS_H__ */
\ No newline at end of file