Skip to content

Commit

Permalink
Fix GC issues with static events. (#759)
Browse files Browse the repository at this point in the history
  • Loading branch information
manodasanW authored Mar 11, 2021
1 parent 0e66e66 commit 006ad4e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
22 changes: 22 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,28 @@ public void TestCovariance()
Assert.True(TestObject.IterableOfObjectIterablesProperty.SequenceEqual(listOfListOfUris));
}

[Fact]
public void TestStaticEventWithGC()
{
bool eventCalled = false;
void Class_StaticIntPropertyChanged(object sender, int e)
{
eventCalled = (e == 3);
}

Class.StaticIntPropertyChanged += Class_StaticIntPropertyChanged;
GC.Collect(2, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
Class.StaticIntPropertyChanged -= Class_StaticIntPropertyChanged;
Class.StaticIntProperty = 3;
Assert.False(eventCalled);
Class.StaticIntPropertyChanged += Class_StaticIntPropertyChanged;
GC.Collect(2, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
Class.StaticIntProperty = 3;
Assert.True(eventCalled);
}

#if NET5_0
[TestComponentCSharp.Warning] // NO warning CA1416
class WarningManaged { };
Expand Down
40 changes: 30 additions & 10 deletions src/cswinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1545,9 +1545,29 @@ remove => %.% -= value;

std::string write_static_cache_object(writer& w, std::string_view cache_type_name, TypeDef const& class_type)
{
if (settings.netstandard_compat)
bool hasStaticEvent = false;
for (auto&& evt : class_type.EventList())
{

auto [add, _] = get_event_methods(evt);
if (add.Flags().Static())
{
hasStaticEvent = true;
break;
}
}

auto instance = hasStaticEvent ?
w.write_temp(
"private static readonly _% _instance = new _%();",
cache_type_name,
cache_type_name) :
w.write_temp(
"private static readonly WeakLazy<_%> _instance = new WeakLazy<_%>();",
cache_type_name,
cache_type_name);

if (settings.netstandard_compat)
{
auto cache_vftbl_type = w.write_temp("ABI.%.%.Vftbl",
class_type.TypeNamespace(),
cache_type_name);
Expand All @@ -1562,18 +1582,18 @@ remove => %.% -= value;
internal class _% : ABI.%.%
{
public _%() : base(%()) { }
private static WeakLazy<_%> _instance = new WeakLazy<_%>();
internal static % Instance => _instance.Value;
%
internal static % Instance => %;
}
)",
cache_type_name,
class_type.TypeNamespace(),
cache_type_name,
cache_type_name,
cache_interface,
instance,
cache_type_name,
cache_type_name,
cache_type_name);
hasStaticEvent ? "_instance" : "_instance.Value");
}
else
{
Expand All @@ -1586,8 +1606,8 @@ public _%()
_obj = (new BaseActivationFactory("%", "%.%"))._As(GuidGenerator.GetIID(typeof(%.%).GetHelperType()));
}
private static WeakLazy<_%> _instance = new WeakLazy<_%>();
internal static % Instance => (%)_instance.Value;
%
internal static % Instance => (%)%;
IObjectReference IWinRTObject.NativeObject => _obj;
bool IWinRTObject.HasUnwrappableNativeObject => false;
Expand All @@ -1602,10 +1622,10 @@ global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, ob
class_type.TypeName(),
class_type.TypeNamespace(),
cache_type_name,
instance,
cache_type_name,
cache_type_name,
cache_type_name,
cache_type_name);
hasStaticEvent ? "_instance" : "_instance.Value");
}

return w.write_temp("_%.Instance", cache_type_name);
Expand Down

0 comments on commit 006ad4e

Please sign in to comment.