Skip to content

Commit

Permalink
Improvements to nullable / boxing (#1063)
Browse files Browse the repository at this point in the history
* Adding benchmarks for nullable

* Add some more benchmarks

* Specialize certain generics with conrete implementations

* Add delegate boxing test

* Add nullable delegate fix

* Add managed delegate unwrapping fix

* Fix unwrapping delegates

* Refactor

* Remove memory alloc

* Remove IDelegateVftbl from public API surface.

* Add some more benchmarks and tests

* Change handling of nullable type string delegate scenarios to return an nullable object instead with the actual object rather than calling value each time to allow for better caching.

* Fix build and minor comment change

* Remove lamda for creating delegate RCW

* spacing

* Adding get delegate benchmarks

* Add boxing tests and fix issue with Char

* Update testwinrt
  • Loading branch information
manodasanW authored Jan 21, 2022
1 parent 0b7b73f commit 38209f8
Show file tree
Hide file tree
Showing 21 changed files with 1,928 additions and 106 deletions.
92 changes: 92 additions & 0 deletions src/Benchmarks/ReflectionPerf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ public object ExecuteMarshalingForString()
public object ExecuteMarshalingForCustomObject()
{
return instance.NewWrappedClassObject;
}

[Benchmark]
public int ExecuteMarshalingForDelegate()
{
int y = 1;
instance.CallForInt(() => y);
return y;
}

[Benchmark]
Expand Down Expand Up @@ -120,6 +128,90 @@ public object ExistingDictionaryLookup3()
{
var dict = instance.ExistingDictionary;
return dict["a"];
}

[Benchmark]
public int GetNullableInt()
{
return instance.NullableInt.Value;
}

[Benchmark]
public void SetNullableInt()
{
instance.NullableInt = new Nullable<int>(4);
}

[Benchmark]
public object GetNullableBittableStruct()
{
return instance.NullableBlittableStruct.Value;
}

[Benchmark]
public void SetNullableBittableStruct()
{
BlittableStruct blittableStruct = new BlittableStruct() { i32 = 2 };
instance.NullableBlittableStruct = new Nullable<BlittableStruct>(blittableStruct);
}

[Benchmark]
public object GetNullableTimeSpan()
{
return instance.NullableTimeSpan.Value;
}

[Benchmark]
public void SetNullableTimeSpan()
{
TimeSpan timeSpan = new TimeSpan(100);
instance.NullableTimeSpan = new Nullable<TimeSpan>(timeSpan);
}

[Benchmark]
public object GetNullableNonBittableStruct()
{
return instance.NullableNonBlittableStruct.Value;
}

[Benchmark]
public void SetNullableNonBittableStruct()
{
NonBlittable nonBlittable = new NonBlittable() { A = true, C = "beta" };
instance.NullableNonBlittableStruct = new Nullable<NonBlittable>(nonBlittable);
}

[Benchmark]
public void SetNullableDelegate()
{
int z;
System.EventHandler<int> s = (object sender, int value) => z = value;
instance.NewTypeErasedNullableObject = s;
}

[Benchmark]
public void SetNullableIntDelegate()
{
ProvideInt s = () => 4;
instance.BoxedDelegate = s;
}

[Benchmark]
public object GetNullableIntDelegate()
{
return instance.BoxedDelegate as ProvideInt;
}

[Benchmark]
public object GetNewIntDelegate()
{
return instance.NewIntDelegate;
}

[Benchmark]
public object GetExistingIntDelegate()
{
return instance.ExistingIntDelegate;
}

[Benchmark]
Expand Down
11 changes: 11 additions & 0 deletions src/Tests/TestComponentCSharp/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,11 @@ namespace winrt::TestComponentCSharp::implementation
return winrt::unbox_value<hstring>(obj);
}

winrt::TestComponentCSharp::ProvideInt Class::UnboxDelegate(WF::IInspectable const& obj)
{
return winrt::unbox_value<TestComponentCSharp::ProvideInt>(obj);
}

com_array<int32_t> Class::UnboxInt32Array(WF::IInspectable const& obj)
{
return obj.as<IReferenceArray<int32_t>>().Value();
Expand Down Expand Up @@ -1462,6 +1467,12 @@ namespace winrt::TestComponentCSharp::implementation
return winrt::box_value(hstring{});
}

WF::IInspectable Class::BoxedDelegate()
{
TestComponentCSharp::ProvideUri handler = [] { return Windows::Foundation::Uri(L"http://microsoft.com"); };
return winrt::box_value(handler);
}

hstring Class::Catch(hstring const& /*params*/, hstring& /*lock*/)
{
// Compile-only test for keyword escaping
Expand Down
2 changes: 2 additions & 0 deletions src/Tests/TestComponentCSharp/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ namespace winrt::TestComponentCSharp::implementation
static int32_t UnboxInt32(IInspectable const& obj);
static bool UnboxBoolean(IInspectable const& obj);
static hstring UnboxString(IInspectable const& obj);
static TestComponentCSharp::ProvideInt UnboxDelegate(IInspectable const& obj);
static com_array<int32_t> UnboxInt32Array(IInspectable const& obj);
static com_array<bool> UnboxBooleanArray(IInspectable const& obj);
static com_array<hstring> UnboxStringArray(IInspectable const& obj);
Expand All @@ -368,6 +369,7 @@ namespace winrt::TestComponentCSharp::implementation
static hstring GetTypeNameForType(Windows::UI::Xaml::Interop::TypeName const& type);

static Windows::Foundation::IInspectable EmptyString();
static Windows::Foundation::IInspectable BoxedDelegate();

hstring Catch(hstring const& params, hstring& locks);

Expand Down
2 changes: 2 additions & 0 deletions src/Tests/TestComponentCSharp/TestComponentCSharp.idl
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,11 @@ namespace TestComponentCSharp
static Int32 UnboxInt32(Object obj);
static Boolean UnboxBoolean(Object obj);
static String UnboxString(Object obj);
static ProvideInt UnboxDelegate(Object obj);
static Int32[] UnboxInt32Array(Object obj);
static Boolean[] UnboxBooleanArray(Object obj);
static String[] UnboxStringArray(Object obj);
static Object BoxedDelegate{ get; };

// WUX.Interop.TypeName -> System.Type mapping
static Windows.UI.Xaml.Interop.TypeName Int32Type { get; };
Expand Down
12 changes: 12 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,9 @@ public void TestValueBoxing()

string s = "Hello World!";
Assert.Equal(s, Class.UnboxString(s));

ProvideInt intHandler = () => 42;
Assert.Equal(intHandler, Class.UnboxDelegate(intHandler));
}

[Fact]
Expand Down Expand Up @@ -2222,6 +2225,15 @@ public void TestStringUnboxing()
Assert.IsType<string>(str2);
Assert.Equal(string.Empty, (string)str1);
Assert.Equal(string.Empty, (string)str2);
}

[Fact]
public void TestDelegateUnboxing()
{
var del = Class.BoxedDelegate;
Assert.IsType<ProvideUri>(del);
var provideUriDel = (ProvideUri) del;
Assert.Equal(new Uri("http://microsoft.com"), provideUriDel());
}

internal class ManagedType { }
Expand Down
111 changes: 111 additions & 0 deletions src/Tests/UnitTest/TestComponent_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,117 @@ public void TestVectorGetMany()
Assert.True(composableObjects.GetRange(1, 3).SequenceEqual(interfaceSubset));
}

private void Box_type<T>(T val, Func<T, object, object> boxFunc)
{
var boxedVal = boxFunc(val, val);
Assert.IsType<T>(boxedVal);
Assert.Equal((T)boxedVal, val);
}

[Fact]
public void Box_Byte()
{
Box_type<byte>(4, Tests.Box1);
}

[Fact]
public void Box_UShort()
{
Box_type<ushort>(4, Tests.Box2);
}

[Fact]
public void Box_UInt()
{
Box_type<uint>(4, Tests.Box3);
}

[Fact]
public void Box_ULong()
{
Box_type<ulong>(4, Tests.Box4);
}

[Fact]
public void Box_Short()
{
Box_type<short>(4, Tests.Box5);
}

[Fact]
public void Box_Int()
{
Box_type(4, Tests.Box6);
}

[Fact]
public void Box_Long()
{
Box_type<long>(4, Tests.Box7);
}

[Fact]
public void Box_Bool()
{
Box_type(true, Tests.Box8);
}

[Fact]
public void Box_Float()
{
Box_type<float>(4, Tests.Box9);
}

[Fact]
public void Box_Double()
{
Box_type(4.0, Tests.Box10);
}

[Fact]
public void Box_Guid()
{
Box_type(Guid.NewGuid(), Tests.Box11);
}

[Fact]
public void Box_Char()
{
Box_type('c', Tests.Box12);
}

[Fact]
public void Box_String()
{
Box_type("test", Tests.Box13);
}

[Fact]
public void Box_Timespan()
{
Box_type(TimeSpan.FromMilliseconds(4), Tests.Box14);
}

[Fact]
public void Box_Blittable()
{
Blittable blittable = new Blittable(3, 4, 5, 6, 7, 8, 9, 10, 11, typeof(ITests).GUID);
Box_type(blittable, Tests.Box15);
}

[Fact]
public void Box_NonBittable()
{
NonBlittable nonBlittable = new NonBlittable(true, 'a', "one", 1);
Box_type(nonBlittable, Tests.Box16);
}

[Fact]
public void Box_DateTime()
{
Box_type(DateTimeOffset.Now, Tests.Box17);
}

// Nota Bene: this test case must always remain the final one
[Fact]
public void Z_Check_Coverage()
Expand Down
Loading

0 comments on commit 38209f8

Please sign in to comment.