Skip to content
This repository has been archived by the owner on Sep 24, 2021. It is now read-only.

Unload types on domain unload #2

Merged
merged 6 commits into from
Sep 4, 2015
89 changes: 68 additions & 21 deletions Mono.Debugging.Soft/SoftDebuggerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class SoftDebuggerSession : DebuggerSession
{
readonly Dictionary<Tuple<TypeMirror, string>, MethodMirror[]> overloadResolveCache = new Dictionary<Tuple<TypeMirror, string>, MethodMirror[]> ();
readonly Dictionary<string, List<TypeMirror>> source_to_type = new Dictionary<string, List<TypeMirror>> (PathComparer);
readonly Dictionary<AppDomainMirror, AssemblyMirror[]> domainAssemblies = new Dictionary<AppDomainMirror, AssemblyMirror[]>();
readonly Dictionary<long,ObjectMirror> activeExceptionsByThread = new Dictionary<long, ObjectMirror> ();
readonly Dictionary<EventRequest, BreakInfo> breakpoints = new Dictionary<EventRequest, BreakInfo> ();
readonly Dictionary<string, MonoSymbolFile> symbolFiles = new Dictionary<string, MonoSymbolFile> ();
Expand Down Expand Up @@ -417,8 +418,8 @@ void ConnectionStarted (VirtualMachine machine)
ConnectOutput (machine.StandardError, true);

HideConnectionDialog ();
machine.EnableEvents (EventType.AssemblyLoad, EventType.ThreadStart, EventType.ThreadDeath,

machine.EnableEvents (EventType.AppDomainCreate, EventType.AppDomainUnload, EventType.AssemblyLoad, EventType.ThreadStart, EventType.ThreadDeath,
EventType.AssemblyUnload, EventType.UserBreak, EventType.UserLog);
try {
unhandledExceptionRequest = machine.CreateExceptionRequest (null, false, true);
Expand Down Expand Up @@ -1455,6 +1456,12 @@ void HandleEventSet (EventSet es)
}

switch (type) {
case EventType.AppDomainCreate:
HandleAppDomainCreateEvents (Array.ConvertAll(es.Events, item => (AppDomainCreateEvent)item));
break;
case EventType.AppDomainUnload:
HandleAppDomainUnloadEvents (Array.ConvertAll(es.Events, item => (AppDomainUnloadEvent)item));
break;
case EventType.AssemblyLoad:
HandleAssemblyLoadEvents (Array.ConvertAll (es.Events, item => (AssemblyLoadEvent)item));
break;
Expand Down Expand Up @@ -1789,6 +1796,59 @@ void HandleBreakEventSet (Event[] es, bool dequeuing)
}
}

void RemoveUnloadedAssemblyTypes(AssemblyMirror asm)
{
// Remove affected types from the loaded types list
var affectedTypes = new List<string>(from pair in types
where PathComparer.Equals(pair.Value.Assembly.Location, asm.Location)
select pair.Key);

foreach (string typeName in affectedTypes)
{
TypeMirror tm;

if (types.TryGetValue(typeName, out tm))
{
if (tm.IsNested)
aliases.Remove(NestedTypeNameToAlias(typeName));

types.Remove(typeName);
}
}

foreach (var pair in source_to_type)
{
pair.Value.RemoveAll(m => PathComparer.Equals(m.Assembly.Location, asm.Location));
}
}

void HandleAppDomainCreateEvents(AppDomainCreateEvent[] events)
{
var domain = events[0].Domain;
if (events.Length > 1)
throw new InvalidOperationException("Simultaneous AppDomainCreateEvent for multiple domains");

if(!domainAssemblies.ContainsKey(domain))
domainAssemblies[domain] = null;
}

void HandleAppDomainUnloadEvents(AppDomainUnloadEvent[] events)
{
var domain = events[0].Domain;
if (events.Length > 1)
throw new InvalidOperationException("Simultaneous AppDomainUnloadEvent for multiple domains");

if (!domainAssemblies.ContainsKey(domain))
return;

var assemblies = domainAssemblies[domain];

foreach (var asm in assemblies)
RemoveUnloadedAssemblyTypes(asm);

domainAssemblies.Remove(domain);
}

void HandleAssemblyLoadEvents (AssemblyLoadEvent[] events)
{
var asm = events [0].Assembly;
Expand All @@ -1802,6 +1862,11 @@ void HandleAssemblyLoadEvents (AssemblyLoadEvent[] events)

string flagExt = isExternal ? " [External]" : "";
OnDebuggerOutput (false, string.Format ("Loaded assembly: {0}{1}\n", asm.Location, flagExt));

// Update loaded assemblies for each domain
var domains = new List<AppDomainMirror>(domainAssemblies.Keys);
foreach (var domain in domains)
domainAssemblies[domain] = domain.GetAssemblies();
}

void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events)
Expand Down Expand Up @@ -1829,25 +1894,7 @@ void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events)
pending_bes.Add (breakpoint.Value);
}

// Remove affected types from the loaded types list
var affectedTypes = new List<string> (from pair in types
where PathComparer.Equals (pair.Value.Assembly.Location, asm.Location)
select pair.Key);

foreach (string typeName in affectedTypes) {
TypeMirror tm;

if (types.TryGetValue (typeName, out tm)) {
if (tm.IsNested)
aliases.Remove (NestedTypeNameToAlias (typeName));

types.Remove (typeName);
}
}

foreach (var pair in source_to_type) {
pair.Value.RemoveAll (m => PathComparer.Equals (m.Assembly.Location, asm.Location));
}
RemoveUnloadedAssemblyTypes(asm);
}
OnDebuggerOutput (false, string.Format ("Unloaded assembly: {0}\n", asm.Location));
}
Expand Down