generator: Dispose ownable method parameters in VM callback (bxc#237)
Some virtual methods are passed a native object that is wrapped in an IDisposable managed object, which is then passed on to the managed overrides. We need to dispose those objects as soon as possible, otherwise their native counterpart will not be freed until the next garbage collection. Requiring the overrides to dispose them would be cumbersome and error-prone. Those parameters will now be disposed in a finally {...} block, after the virtual method has returned. This means that overrides should not keep a reference to such a parameter outside of the scope of the method, as it will be diposed when the method returns. This change only affects Cairo.Context parameter for now, but it was particularly needed for them, as they could happily hold on to tens of MBs of memory until the next garbage collection.
This commit is contained in:
parent
2967482762
commit
e48ac63d54
3 changed files with 57 additions and 5 deletions
|
@ -28,6 +28,7 @@ namespace GtkSharp.Generation {
|
|||
public class ManagedCallString {
|
||||
|
||||
IDictionary<Parameter, bool> parms = new Dictionary<Parameter, bool> ();
|
||||
IList<Parameter> dispose_params = new List<Parameter> ();
|
||||
string error_param = null;
|
||||
string user_data_param = null;
|
||||
string destroy_param = null;
|
||||
|
@ -57,6 +58,10 @@ namespace GtkSharp.Generation {
|
|||
special = true;
|
||||
|
||||
this.parms.Add (p, special);
|
||||
|
||||
if (p.IsOwnable) {
|
||||
dispose_params.Add (p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,10 +75,18 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
public bool HasDisposeParam {
|
||||
get { return dispose_params.Count > 0; }
|
||||
}
|
||||
|
||||
public string Unconditional (string indent) {
|
||||
string ret = "";
|
||||
if (error_param != null)
|
||||
ret = indent + error_param + " = IntPtr.Zero;\n";
|
||||
|
||||
foreach (Parameter p in dispose_params) {
|
||||
ret += indent + p.CSType + " my" + p.Name + " = null;\n";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -103,6 +116,10 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
foreach (Parameter p in dispose_params) {
|
||||
ret += indent + "my" + p.Name + " = " + p.FromNative (p.Name) + ";\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -119,7 +136,12 @@ namespace GtkSharp.Generation {
|
|||
if (p.Generatable is CallbackGen) {
|
||||
result [i] += p.Name + "_invoker.Handler";
|
||||
} else {
|
||||
result [i] += (parms [p]) ? "my" + p.Name : p.FromNative (p.Name);
|
||||
if (parms [p] || dispose_params.Contains(p)) {
|
||||
// Parameter was declared and marshalled earlier
|
||||
result [i] += "my" + p.Name;
|
||||
} else {
|
||||
result [i] += p.FromNative (p.Name);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -150,6 +172,22 @@ namespace GtkSharp.Generation {
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public string DisposeParams (string indent)
|
||||
{
|
||||
string ret = "";
|
||||
|
||||
foreach (Parameter p in dispose_params) {
|
||||
string name = "my" + p.Name;
|
||||
string disp_name = "disposable_" + p.Name;
|
||||
|
||||
ret += indent + "var " + disp_name + " = " + name + " as IDisposable;\n";
|
||||
ret += indent + "if (" + disp_name + " != null)\n";
|
||||
ret += indent + "\t" + disp_name + ".Dispose ();\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,12 @@ namespace GtkSharp.Generation {
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsOwnable {
|
||||
get {
|
||||
return this.Generatable is OwnableGen;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Owned {
|
||||
get {
|
||||
return elem.GetAttribute ("owned") == "true";
|
||||
|
|
|
@ -98,14 +98,17 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine ("\t\t\t\t{0} __obj = GLib.Object.GetObject (inst, false) as {0};", type);
|
||||
}
|
||||
|
||||
sw.Write (call.Setup ("\t\t\t\t"));
|
||||
sw.Write ("\t\t\t\t");
|
||||
string indent = "\t\t\t\t";
|
||||
if (!retval.IsVoid)
|
||||
sw.Write (retval.CSType + " __result = ");
|
||||
sw.WriteLine (indent + retval.CSType + " __result;");
|
||||
sw.Write (call.Setup (indent));
|
||||
sw.Write (indent);
|
||||
if (!retval.IsVoid)
|
||||
sw.Write ("__result = ");
|
||||
if (!this.IsStatic)
|
||||
sw.Write ("__obj.");
|
||||
sw.WriteLine (this.CallString + ";");
|
||||
sw.Write (call.Finish ("\t\t\t\t"));
|
||||
sw.Write (call.Finish (indent));
|
||||
if (!retval.IsVoid)
|
||||
sw.WriteLine ("\t\t\t\treturn " + retval.ToNative ("__result") + ";");
|
||||
|
||||
|
@ -116,6 +119,11 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine ("\t\t\t\t// NOTREACHED: above call does not return.");
|
||||
sw.WriteLine ("\t\t\t\tthrow e;");
|
||||
}
|
||||
|
||||
if (call.HasDisposeParam) {
|
||||
sw.WriteLine ("\t\t\t} finally {");
|
||||
sw.Write (call.DisposeParams (indent));
|
||||
}
|
||||
sw.WriteLine ("\t\t\t}");
|
||||
sw.WriteLine ("\t\t}");
|
||||
sw.WriteLine ();
|
||||
|
|
Loading…
Reference in a new issue