Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm] Redesign of managed objects marshaling and lifecycle #56538

Merged
merged 29 commits into from
Aug 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
920083c
- explicitly single parameter for EventListener delegate
pavelsavara Jul 29, 2021
0bce952
fix calling the delegate
pavelsavara Jul 30, 2021
8e07894
marshal all delegates
pavelsavara Aug 3, 2021
eda3dac
wrapped thenable/promise as Task
pavelsavara Aug 3, 2021
debf85a
syntax
pavelsavara Aug 3, 2021
d4fa37d
cleanup
pavelsavara Aug 3, 2021
47c6c3b
hold thenable alive while in flight
pavelsavara Aug 3, 2021
4e407e6
fix build
pavelsavara Aug 4, 2021
1c71fd7
redesign continuations
pavelsavara Aug 4, 2021
31163bb
marshaling C# reference types
pavelsavara Aug 4, 2021
35f58be
cleanup
pavelsavara Aug 4, 2021
bf48561
fix scope?
pavelsavara Aug 4, 2021
f6947e0
fix reference
pavelsavara Aug 4, 2021
b6f6dda
more useful error for bad handles
pavelsavara Aug 5, 2021
61b39d8
rename handles, remove jsHandle "math"
pavelsavara Aug 5, 2021
e627e7f
revert debug stuff
pavelsavara Aug 5, 2021
bc75215
fix error propagation
pavelsavara Aug 5, 2021
651f2bb
explicit v8 gc() via --expose-gc for the unit test
pavelsavara Aug 5, 2021
dc96058
missing gc() on old v8
pavelsavara Aug 6, 2021
030840d
rename GCHandleFromJSOwnedObject
pavelsavara Aug 6, 2021
a950c11
make sure GCHandle is not re-used
pavelsavara Aug 6, 2021
bec5c67
rename AnyRefHandle -> GCHandleValue
pavelsavara Aug 6, 2021
e17d31f
Kate's feedback
pavelsavara Aug 6, 2021
cf3e805
fix helix ?
pavelsavara Aug 6, 2021
69057aa
refactor methods around mono_wasm_object_registry
pavelsavara Aug 6, 2021
7929284
improved error messages
pavelsavara Aug 6, 2021
66496f1
move delegate init
pavelsavara Aug 6, 2021
24a7b45
fix
pavelsavara Aug 6, 2021
fa61c06
cleanup
pavelsavara Aug 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,37 @@ internal static partial class Runtime
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object CompileFunction(string str, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object InvokeJSWithArgs(int jsObjHandle, string method, object?[] parms, out int exceptionalResult);
internal static extern object InvokeJSWithArgs(int jsHandle, string method, object?[] parms, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object GetObjectProperty(int jsObjHandle, string propertyName, out int exceptionalResult);
internal static extern object GetObjectProperty(int jsHandle, string propertyName, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object SetObjectProperty(int jsObjHandle, string propertyName, object value, bool createIfNotExists, bool hasOwnProperty, out int exceptionalResult);
internal static extern object SetObjectProperty(int jsHandle, string propertyName, object value, bool createIfNotExists, bool hasOwnProperty, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object GetByIndex(int jsObjHandle, int index, out int exceptionalResult);
internal static extern object GetByIndex(int jsHandle, int index, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object SetByIndex(int jsObjHandle, int index, object? value, out int exceptionalResult);
internal static extern object SetByIndex(int jsHandle, int index, object? value, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object GetGlobalObject(string? globalName, out int exceptionalResult);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object ReleaseHandle(int jsObjHandle, out int exceptionalResult);
internal static extern object ReleaseHandle(int jsHandle, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object ReleaseObject(int jsObjHandle, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object BindCoreObject(int jsObjHandle, int gcHandle, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object BindHostObject(int jsObjHandle, int gcHandle, out int exceptionalResult);
internal static extern object BindCoreObject(int jsHandle, int gcHandle, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object New(string className, object[] parms, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object TypedArrayToArray(int jsObjHandle, out int exceptionalResult);
internal static extern object TypedArrayToArray(int jsHandle, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object TypedArrayCopyTo(int jsObjHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult);
internal static extern object TypedArrayCopyTo(int jsHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object TypedArrayFrom(int arrayPtr, int begin, int end, int bytesPerElement, int type, out int exceptionalResult);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern object TypedArrayCopyFrom(int jsObjHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult);
internal static extern object TypedArrayCopyFrom(int jsHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern string? AddEventListener(int jsObjHandle, string name, int weakDelegateHandle, int optionsObjHandle);
internal static extern string? AddEventListener(int jsHandle, string name, int gcHandle, int optionsJsHandle);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern string? RemoveEventListener(int jsObjHandle, string name, int weakDelegateHandle, bool capture);
internal static extern string? RemoveEventListener(int jsHandle, string name, int gcHandle, bool capture);

// / <summary>
// / Execute the provided string in the JavaScript context
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;

Expand All @@ -16,17 +14,14 @@ public abstract class AnyRef : SafeHandleMinusOneIsInvalid
private GCHandle AnyRefHandle;
public int JSHandle => (int)handle;

internal AnyRef(int jsHandle, bool ownsHandle) : this((IntPtr)jsHandle, ownsHandle)
{ }

internal AnyRef(IntPtr jsHandle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(jsHandle);
AnyRefHandle = GCHandle.Alloc(this, ownsHandle ? GCHandleType.Weak : GCHandleType.Normal);
InFlight = null;
InFlightCounter = 0;
}
internal int Int32Handle => (int)(IntPtr)AnyRefHandle;
internal int GCHandleValue => (int)(IntPtr)AnyRefHandle;

internal void AddInFlight()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public abstract class CoreObject : JSObject
{
protected CoreObject(int jsHandle) : base(jsHandle, true)
{
object result = Interop.Runtime.BindCoreObject(jsHandle, Int32Handle, out int exception);
object result = Interop.Runtime.BindCoreObject(jsHandle, GCHandleValue, out int exception);
if (exception != 0)
throw new JSException(SR.Format(SR.CoreObjectErrorBinding, result));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public HostObject(string hostName, params object[] _params) : base(Interop.Runti

public abstract class HostObjectBase : JSObject, IHostObject
{
protected HostObjectBase(int jHandle) : base(jHandle, true)
protected HostObjectBase(int jsHandle) : base(jsHandle, true)
{
object result = Interop.Runtime.BindHostObject(jHandle, Int32Handle, out int exception);
object result = Interop.Runtime.BindCoreObject(jsHandle, GCHandleValue, out int exception);
if (exception != 0)
throw new JSException(SR.Format(SR.HostObjectErrorBinding, result));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,12 @@ public interface IJSObject
/// </summary>
public class JSObject : AnyRef, IJSObject, IDisposable
{
internal object? RawObject;

private WeakReference<Delegate>? WeakRawObject;

// to detect redundant calls
public bool IsDisposed { get; private set; }

public JSObject() : this(Interop.Runtime.New<object>(), true)
{
object result = Interop.Runtime.BindCoreObject(JSHandle, Int32Handle, out int exception);
object result = Interop.Runtime.BindCoreObject(JSHandle, GCHandleValue, out int exception);
if (exception != 0)
throw new JSException(SR.Format(SR.JSObjectErrorBinding, result));

Expand All @@ -39,16 +35,6 @@ internal JSObject(IntPtr jsHandle, bool ownsHandle) : base(jsHandle, ownsHandle)
internal JSObject(int jsHandle, bool ownsHandle) : base((IntPtr)jsHandle, ownsHandle)
{ }

internal JSObject(int jsHandle, object rawObj) : base(jsHandle, false)
{
RawObject = rawObj;
}

internal JSObject(int jsHandle, Delegate rawDelegate, bool ownsHandle = true) : base(jsHandle, ownsHandle)
{
WeakRawObject = new WeakReference<Delegate>(rawDelegate, trackResurrection: false);
}

/// <summary>
/// Invoke a named method of the object, or throws a JSException on error.
/// </summary>
Expand Down Expand Up @@ -84,7 +70,7 @@ public struct EventListenerOptions {
public object? Signal;
}

public int AddEventListener(string name, Delegate listener, EventListenerOptions? options = null)
public int AddEventListener(string name, Action<JSObject> listener, EventListenerOptions? options = null)
{
var optionsDict = options.HasValue
? new JSObject()
Expand All @@ -94,7 +80,7 @@ public int AddEventListener(string name, Delegate listener, EventListenerOptions
if (options?.Signal != null)
throw new NotImplementedException("EventListenerOptions.Signal");

var jsfunc = Runtime.GetJSOwnedObjectHandle(listener);
var jsfunc = Runtime.GetJSOwnedObjectGCHandle(listener);
// int exception;
if (options.HasValue) {
// TODO: Optimize this
Expand All @@ -117,17 +103,17 @@ public int AddEventListener(string name, Delegate listener, EventListenerOptions
}
}

public void RemoveEventListener(string name, Delegate? listener, EventListenerOptions? options = null)
public void RemoveEventListener(string name, Action<JSObject>? listener, EventListenerOptions? options = null)
{
if (listener == null)
return;
var jsfunc = Runtime.GetJSOwnedObjectHandle(listener);
var jsfunc = Runtime.GetJSOwnedObjectGCHandle(listener);
RemoveEventListener(name, jsfunc, options);
}

public void RemoveEventListener(string name, int listenerHandle, EventListenerOptions? options = null)
public void RemoveEventListener(string name, int listenerGCHandle, EventListenerOptions? options = null)
{
var ret = Interop.Runtime.RemoveEventListener(JSHandle, name, listenerHandle, options?.Capture ?? false);
var ret = Interop.Runtime.RemoveEventListener(JSHandle, name, listenerGCHandle, options?.Capture ?? false);
if (ret != null)
throw new JSException(ret);
}
Expand Down Expand Up @@ -178,7 +164,7 @@ public void SetObjectProperty(string name, object value, bool createIfNotExists
{
object setPropResult = Interop.Runtime.SetObjectProperty(JSHandle, name, value, createIfNotExists, hasOwnProperty, out int exception);
if (exception != 0)
throw new JSException($"Error setting {name} on (js-obj js '{JSHandle}' .NET '{Int32Handle} raw '{RawObject != null})");
throw new JSException($"Error setting {name} on (js-obj js '{JSHandle}' .NET '{GCHandleValue})");
}

/// <summary>
Expand All @@ -205,19 +191,11 @@ public int Length
/// <param name="prop">The String name or Symbol of the property to test.</param>
public bool PropertyIsEnumerable(string prop) => (bool)Invoke("propertyIsEnumerable", prop);

internal bool IsWeakWrapper => WeakRawObject?.TryGetTarget(out _) == true;

internal object? GetWrappedObject()
{
return RawObject ?? (WeakRawObject is WeakReference<Delegate> wr && wr.TryGetTarget(out Delegate? d) ? d : null);
}
internal void FreeHandle()
{
Runtime.ReleaseJSObject(this);
SetHandleAsInvalid();
IsDisposed = true;
RawObject = null;
WeakRawObject = null;
FreeGCHandle();
}

Expand Down Expand Up @@ -258,7 +236,7 @@ protected override bool ReleaseHandle()

public override string ToString()
{
return $"(js-obj js '{Int32Handle}' raw '{RawObject != null}' weak_raw '{WeakRawObject != null}')";
return $"(js-obj js '{GCHandleValue}')";
}
}
}
Loading