Skip to content

Commit

Permalink
perf: [Wasm] Remove pass-through try/catch block in InvokeJSUnmarshalled
Browse files Browse the repository at this point in the history
try/catch blocks are very expensive in emscripten 1.39.9, as those need to go through javascript to handle exceptions.
  • Loading branch information
jeromelaban committed Mar 31, 2020
1 parent d48e297 commit 3175803
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 22 deletions.
25 changes: 11 additions & 14 deletions src/Uno.Foundation/Interop/TSInteropMarshaller.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,24 @@ public static void InvokeJS<TParam>(
{
_logger.Value.LogDebug($"InvokeJS for {memberName}/{typeof(TParam)}");
}

var pParms = Marshal.AllocHGlobal(MarshalSizeOf<TParam>.Size);

try
{
Marshal.StructureToPtr(paramStruct, pParms, false);
Marshal.StructureToPtr(paramStruct, pParms, false);

var ret = WebAssemblyRuntime.InvokeJSUnmarshalled(methodName, pParms);
}
catch(Exception e)
WebAssemblyRuntime.InvokeJSUnmarshalled(methodName, pParms, out var exception);

Marshal.DestroyStructure(pParms, typeof(TParam));
Marshal.FreeHGlobal(pParms);

if (exception != null)
{
if (_logger.Value.IsEnabled(LogLevel.Error))
{
_logger.Value.LogError($"Failed InvokeJS for {memberName}/{typeof(TParam)}: {e}");
_logger.Value.LogError($"Failed InvokeJS for {memberName}/{typeof(TParam)}: {exception}");
}
throw;
}
finally
{
Marshal.DestroyStructure(pParms, typeof(TParam));
Marshal.FreeHGlobal(pParms);

throw exception;
}
}

Expand Down
50 changes: 42 additions & 8 deletions src/Uno.Foundation/Runtime.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal static class InternalCalls
// Matches this signature:
// https://github.com/mono/mono/blob/f24d652d567c4611f9b4e3095be4e2a1a2ab23a4/sdks/wasm/driver.c#L21
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern IntPtr InvokeJSUnmarshalled(out string exception, string functionIdentifier, IntPtr arg0, IntPtr arg1, IntPtr arg2);
public static extern IntPtr InvokeJSUnmarshalled(out string exceptionMessage, string functionIdentifier, IntPtr arg0, IntPtr arg1, IntPtr arg2);
}
}
}
Expand Down Expand Up @@ -72,7 +72,7 @@ private static IntPtr GetMethodId(string methodName)
{
if (!MethodMap.TryGetValue(methodName, out var methodId))
{
MethodMap[methodName] = methodId = WebAssembly.JSInterop.InternalCalls.InvokeJSUnmarshalled(out var e, methodName, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
MethodMap[methodName] = methodId = WebAssembly.JSInterop.InternalCalls.InvokeJSUnmarshalled(out _, methodName, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}

return methodId;
Expand All @@ -89,22 +89,56 @@ public static bool InvokeJSUnmarshalled(string functionIdentifier, IntPtr arg0)
{
using (WritePropertyEventTrace(TraceProvider.UnmarshalledInvokedStart, TraceProvider.UnmarshalledInvokedEnd, functionIdentifier))
{
return InnerInvokeJSUnmarshalled(functionIdentifier, arg0);
var ret = InnerInvokeJSUnmarshalled(functionIdentifier, arg0, out var exception);

if(exception != null)
{
throw exception;
}

return ret;
}
}
else
{
var ret = InnerInvokeJSUnmarshalled(functionIdentifier, arg0, out var exception);

if (exception != null)
{
throw exception;
}

return ret;
}
}

/// <summary>
/// Invoke a Javascript method using unmarshaled conversion.
/// </summary>
/// <param name="functionIdentifier">A function identifier name</param>
internal static bool InvokeJSUnmarshalled(string functionIdentifier, IntPtr arg0, out Exception exception)
{
if (_trace.IsEnabled)
{
using (WritePropertyEventTrace(TraceProvider.UnmarshalledInvokedStart, TraceProvider.UnmarshalledInvokedEnd, functionIdentifier))
{
return InnerInvokeJSUnmarshalled(functionIdentifier, arg0, out exception);
}
}
else
{
return InnerInvokeJSUnmarshalled(functionIdentifier, arg0);
return InnerInvokeJSUnmarshalled(functionIdentifier, arg0, out exception);
}
}

private static bool InnerInvokeJSUnmarshalled(string functionIdentifier, IntPtr arg0)
private static bool InnerInvokeJSUnmarshalled(string functionIdentifier, IntPtr arg0, out Exception exception)
{
exception = null;
var methodId = GetMethodId(functionIdentifier);

var res = WebAssembly.JSInterop.InternalCalls.InvokeJSUnmarshalled(out var exception, null, methodId, arg0, IntPtr.Zero);
var res = WebAssembly.JSInterop.InternalCalls.InvokeJSUnmarshalled(out var exceptionMessage, null, methodId, arg0, IntPtr.Zero);

if (exception != null)
if (!string.IsNullOrEmpty(exceptionMessage))
{
if (_trace.IsEnabled)
{
Expand All @@ -114,7 +148,7 @@ private static bool InnerInvokeJSUnmarshalled(string functionIdentifier, IntPtr
);
}

throw new Exception(exception);
exception = new Exception(exceptionMessage);
}

return res != IntPtr.Zero;
Expand Down

0 comments on commit 3175803

Please sign in to comment.