Skip to content

Commit

Permalink
perf: Don't rely on reflection for Marshal.PtrToStructure
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Apr 9, 2021
1 parent e820c2b commit 20ea231
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Runtime.InteropServices;
using System.Text;
using Uno.Extensions;
Expand All @@ -18,6 +19,17 @@ internal static class TSInteropMarshaller

public const UnmanagedType LPUTF8Str = (UnmanagedType)48;

[StructLayout(LayoutKind.Sequential)]
public class WrapperBoolean_Return
{
public static WrapperBoolean_Return Instance { get; } = new WrapperBoolean_Return();

private WrapperBoolean_Return() { }

public bool Value;
}


public static void InvokeJS(
string methodName,
object paramStruct,
Expand Down Expand Up @@ -54,14 +66,15 @@ public static void InvokeJS(
}
}

public static object InvokeJS(
public static void InvokeJS(
string methodName,
object paramStruct,
Type retStructType,
object retStruct,
[System.Runtime.CompilerServices.CallerMemberName] string? memberName = null
)
{
var paramStructType = paramStruct.GetType();
var retStructType = retStruct.GetType();

var returnSize = MarshalSizeOfHelper.SizeOf(retStructType);
var paramSize = MarshalSizeOfHelper.SizeOf(paramStructType);
Expand All @@ -83,8 +96,7 @@ public static object InvokeJS(

var ret = WebAssemblyRuntime.InvokeJSUnmarshalled(methodName, pParms, pReturnValue);

var returnValue = Marshal.PtrToStructure(pReturnValue, retStructType);
return returnValue!;
Marshal.PtrToStructure(pReturnValue, retStruct);
}
catch (Exception e)
{
Expand Down
61 changes: 39 additions & 22 deletions src/Uno.UI.Wasm.Tests/Tests/TSBindingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ public void When_IntPtr()
Id = (IntPtr)42
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_IntPtr", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_IntPtr", param, ret);

Assert.AreEqual("42", ret.Value);
Assert.AreEqual("42", ret.Value.Value);
}

[TestMethod]
Expand All @@ -36,9 +37,10 @@ public void When_IntPtr_Zero()
Id = (IntPtr)0
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_IntPtr_Zero", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_IntPtr_Zero", param, ret);

Assert.AreEqual("0", ret.Value);
Assert.AreEqual("0", ret.Value.Value);
}

[TestMethod]
Expand All @@ -49,9 +51,10 @@ public void When_SingleString()
MyString = "This is 42"
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_SingleString", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_SingleString", param, ret);

Assert.AreEqual(param.MyString, ret.Value);
Assert.AreEqual(param.MyString, ret.Value.Value);
}

[TestMethod]
Expand All @@ -62,9 +65,10 @@ public void When_SingleUnicodeString()
MyString = "This is 🤣 🎉"
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_SingleUnicodeString", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_SingleUnicodeString", param, ret);

Assert.AreEqual(param.MyString, ret.Value);
Assert.AreEqual(param.MyString, ret.Value.Value);
}

[TestMethod]
Expand All @@ -75,9 +79,10 @@ public void When_NullString()
MyString = null
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullString", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullString", param, ret);

Assert.AreEqual("true", ret.Value);
Assert.AreEqual("true", ret.Value.Value);
}

[TestMethod]
Expand All @@ -89,9 +94,10 @@ public void When_ArrayOfInt()
MyArray = new[] { 1, 2, 3, 42 }
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfInt", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfInt", param, ret);

Assert.AreEqual("1;2;3;42", ret.Value);
Assert.AreEqual("1;2;3;42", ret.Value.Value);
}

[TestMethod]
Expand All @@ -103,9 +109,10 @@ public void When_NullArrayOfInt()
MyArray = null
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullArrayOfInt", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullArrayOfInt", param, ret);

Assert.AreEqual("true", ret.Value);
Assert.AreEqual("true", ret.Value.Value);
}

[TestMethod]
Expand All @@ -117,9 +124,10 @@ public void When_ArrayOfStrings()
MyArray = new[] { "1", "2", "3", "42" }
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfStrings", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfStrings", param, ret);

Assert.AreEqual("1;2;3;42", ret.Value);
Assert.AreEqual("1;2;3;42", ret.Value.Value);
}

[TestMethod]
Expand All @@ -131,9 +139,10 @@ public void When_ArrayOfUnicodeStrings()
MyArray = new[] { "🎉🤣😊👆🎁" }
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfUnicodeStrings", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfUnicodeStrings", param, ret);

Assert.AreEqual(param.MyArray[0], ret.Value);
Assert.AreEqual(param.MyArray[0], ret.Value.Value);
}

[TestMethod]
Expand All @@ -145,9 +154,10 @@ public void When_NullArrayOfStrings()
MyArray = null
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullArrayOfStrings", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_NullArrayOfStrings", param, ret);

Assert.AreEqual("true", ret.Value);
Assert.AreEqual("true", ret.Value.Value);
}

[TestMethod]
Expand All @@ -159,9 +169,10 @@ public void When_ArrayOfNullStrings()
MyArray = new string[4]
};

var ret = (GenericReturn)TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfNullStrings", param, typeof(GenericReturn));
var ret = new GenericReturn_Wrapper();
TSInteropMarshaller.InvokeJS("TSBindingsUnitTests:When_ArrayOfNullStrings", param, ret);

Assert.AreEqual("true;true;true;true", ret.Value);
Assert.AreEqual("true;true;true;true", ret.Value.Value);
}
}

Expand Down Expand Up @@ -205,5 +216,11 @@ public struct GenericReturn
{
public string Value;
}

[StructLayout(LayoutKind.Sequential)]
public class GenericReturn_Wrapper
{
public GenericReturn Value;
}
}
#endif
75 changes: 62 additions & 13 deletions src/Uno.UI/UI/Xaml/WindowManagerInterop.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Uno.Foundation.Interop;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;

namespace Uno.UI.Xaml
{
Expand Down Expand Up @@ -38,7 +39,8 @@ internal static void Init(bool isHostedMode, bool isLoadEventsEnabled)
IsLoadEventsEnabled = isLoadEventsEnabled
};

TSInteropMarshaller.InvokeJS("UnoStatic:initNative", parms, typeof(bool));
var ret = TSInteropMarshaller.WrapperBoolean_Return.Instance;
TSInteropMarshaller.InvokeJS("UnoStatic:initNative", parms, ret);
}
}

Expand Down Expand Up @@ -83,7 +85,8 @@ internal static void CreateContent(IntPtr htmlId, string htmlTag, IntPtr handle,
IsFocusable = isFocusable
};

TSInteropMarshaller.InvokeJS("Uno:createContentNative", parms, typeof(bool));
var ret = TSInteropMarshaller.WrapperBoolean_Return.Instance;
TSInteropMarshaller.InvokeJS("Uno:createContentNative", parms, ret);
}
}

Expand Down Expand Up @@ -133,11 +136,13 @@ internal static int RegisterUIElement(string typeName, string[] classNames, bool
Classes = classNames,
};

var ret = (WindowManagerRegisterUIElementReturn)TSInteropMarshaller.InvokeJS("Uno:registerUIElementNative", parms, typeof(WindowManagerRegisterUIElementReturn));
return ret.RegistrationId;
var ret = new Wrapper_WindowManagerRegisterUIElementReturn();
TSInteropMarshaller.InvokeJS("Uno:registerUIElementNative", parms, ret);
return ret.Value.RegistrationId;
}
}


[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct WindowManagerRegisterUIElementParams
Expand All @@ -153,6 +158,12 @@ private struct WindowManagerRegisterUIElementParams
public string[] Classes;
}

[StructLayout(LayoutKind.Sequential)]
private class Wrapper_WindowManagerRegisterUIElementReturn
{
public WindowManagerRegisterUIElementReturn Value;
}

[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct WindowManagerRegisterUIElementReturn
Expand Down Expand Up @@ -189,7 +200,8 @@ internal static void SetElementTransform(IntPtr htmlId, Matrix3x2 matrix)
M32 = matrix.M32,
};

TSInteropMarshaller.InvokeJS("Uno:setElementTransformNative", parms, typeof(bool));
var ret = TSInteropMarshaller.WrapperBoolean_Return.Instance;
TSInteropMarshaller.InvokeJS("Uno:setElementTransformNative", parms, ret);
}
}

Expand Down Expand Up @@ -228,7 +240,8 @@ internal static void SetPointerEvents(IntPtr htmlId, bool enabled)
Enabled = enabled
};

TSInteropMarshaller.InvokeJS("Uno:setPointerEventsNative", parms, typeof(bool));
var ret = TSInteropMarshaller.WrapperBoolean_Return.Instance;
TSInteropMarshaller.InvokeJS("Uno:setPointerEventsNative", parms, ret);
}
}

Expand Down Expand Up @@ -269,9 +282,10 @@ internal static Size MeasureView(IntPtr htmlId, Size availableSize)
AvailableHeight = availableSize.Height
};

var ret = (WindowManagerMeasureViewReturn)TSInteropMarshaller.InvokeJS("Uno:measureViewNative", parms, typeof(WindowManagerMeasureViewReturn));
var ret = WindowManagerMeasureViewReturn_Wrapper.Instance;
TSInteropMarshaller.InvokeJS("Uno:measureViewNative", parms, ret);

return new Size(ret.DesiredWidth, ret.DesiredHeight);
return new Size(ret.Value.DesiredWidth, ret.Value.DesiredHeight);
}
}

Expand All @@ -285,6 +299,17 @@ private struct WindowManagerMeasureViewParams
public double AvailableHeight;
}

[StructLayout(LayoutKind.Sequential)]
private class WindowManagerMeasureViewReturn_Wrapper
{
public static WindowManagerMeasureViewReturn_Wrapper Instance { get; }
= new WindowManagerMeasureViewReturn_Wrapper();

private WindowManagerMeasureViewReturn_Wrapper() { }

public WindowManagerMeasureViewReturn Value;
}

[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
private struct WindowManagerMeasureViewReturn
Expand Down Expand Up @@ -1008,9 +1033,10 @@ internal static Rect GetBBox(IntPtr htmlId)
HtmlId = htmlId
};

var ret = (WindowManagerGetBBoxReturn)TSInteropMarshaller.InvokeJS("Uno:getBBoxNative", parms, typeof(WindowManagerGetBBoxReturn));
var ret = WindowManagerGetBBoxReturn_Wrapper.Instance;
TSInteropMarshaller.InvokeJS("Uno:getBBoxNative", parms, ret);

return new Rect(ret.X, ret.Y, ret.Width, ret.Height);
return new Rect(ret.Value.X, ret.Value.Y, ret.Value.Width, ret.Value.Height);
}
}

Expand All @@ -1021,6 +1047,17 @@ private struct WindowManagerGetBBoxParams
public IntPtr HtmlId;
}

[StructLayout(LayoutKind.Sequential)]
private class WindowManagerGetBBoxReturn_Wrapper
{
public static WindowManagerGetBBoxReturn_Wrapper Instance { get; }
= new WindowManagerGetBBoxReturn_Wrapper();

private WindowManagerGetBBoxReturn_Wrapper() { }

public WindowManagerGetBBoxReturn Value;

}

[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
Expand Down Expand Up @@ -1166,11 +1203,12 @@ internal static (Size clientSize, Size offsetSize) GetClientViewSize(IntPtr html
HtmlId = htmlId
};

var ret = (WindowManagerGetClientViewSizeReturn)TSInteropMarshaller.InvokeJS("Uno:getClientViewSizeNative", parms, typeof(WindowManagerGetClientViewSizeReturn));
var ret = WindowManagerGetClientViewSizeReturn_Wrapper.Instance;
TSInteropMarshaller.InvokeJS("Uno:getClientViewSizeNative", parms, ret);

return (
clientSize: new Size(ret.ClientWidth, ret.ClientHeight),
offsetSize: new Size(ret.OffsetWidth, ret.OffsetHeight)
clientSize: new Size(ret.Value.ClientWidth, ret.Value.ClientHeight),
offsetSize: new Size(ret.Value.OffsetWidth, ret.Value.OffsetHeight)
);
}
}
Expand All @@ -1182,6 +1220,17 @@ private struct WindowManagerGetClientViewSizeParams
public IntPtr HtmlId;
}

[StructLayout(LayoutKind.Sequential)]
private class WindowManagerGetClientViewSizeReturn_Wrapper
{
public static WindowManagerGetClientViewSizeReturn_Wrapper Instance { get; }
= new WindowManagerGetClientViewSizeReturn_Wrapper();

private WindowManagerGetClientViewSizeReturn_Wrapper() { }

public WindowManagerGetClientViewSizeReturn Value;

}

[TSInteropMessage]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
Expand Down
Loading

0 comments on commit 20ea231

Please sign in to comment.