Skip to content

Commit

Permalink
[browser] legacy JS interop optional via WasmEnableLegacyJsInterop - …
Browse files Browse the repository at this point in the history
…managed (#82826)

* WasmEnableLegacyJsInterop and ILLink.Descriptors.LegacyJsInterop.xml
* revert back to USE_PTHREADS symbol
* feedback
  • Loading branch information
pavelsavara committed Mar 8, 2023
1 parent ceb2344 commit 6c836e8
Show file tree
Hide file tree
Showing 21 changed files with 99 additions and 37 deletions.
6 changes: 6 additions & 0 deletions eng/testing/tests.browser.targets
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

<GetNuGetsToBuildForWorkloadTestingDependsOn>_GetRuntimePackNuGetsToBuild;_GetNugetsForAOT;$(GetNuGetsToBuildForWorkloadTestingDependsOn)</GetNuGetsToBuildForWorkloadTestingDependsOn>
<_BundleAOTTestWasmAppForHelixDependsOn>$(_BundleAOTTestWasmAppForHelixDependsOn);PrepareForWasmBuildApp;_PrepareForAOTOnHelix</_BundleAOTTestWasmAppForHelixDependsOn>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
</PropertyGroup>

<!-- We expect WASM users to indicate they would like to have bigger download size by adding WasmIncludeFullIcuData, -->
Expand Down Expand Up @@ -126,6 +127,11 @@
<PropertyGroup Condition="'$(BuildAOTTestsOnHelix)' == 'true'">
<!-- wasm targets are not imported at all, in this case, because we run the wasm build on helix -->
</PropertyGroup>
<ItemGroup Condition="'$(BuildAOTTestsOn)' == 'helix'">
<TrimmerRootDescriptor
Condition="'$(WasmEnableLegacyJsInterop)' == 'true'"
Include="$(MonoProjectRoot)\wasm\build\ILLink.Descriptors.LegacyJsInterop.xml" />
</ItemGroup>

<PropertyGroup Condition="'$(IsWasmProject)' == 'true' and '$(BuildAOTTestsOnHelix)' != 'true'">
<WasmBuildOnlyAfterPublish>true</WasmBuildOnlyAfterPublish>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
<PlatformManifestFileEntry Include="emcc-props.json" IsNative="true" />
<PlatformManifestFileEntry Include="ILLink.Substitutions.WasmIntrinsics.xml" IsNative="true" />
<PlatformManifestFileEntry Include="ILLink.Substitutions.NoWasmIntrinsics.xml" IsNative="true" />
<PlatformManifestFileEntry Include="ILLink.Descriptors.LegacyJsInterop.xml" IsNative="true" />
<!-- wasi specific -->
<PlatformManifestFileEntry Include="main.c" IsNative="true" />
<PlatformManifestFileEntry Include="driver.h" IsNative="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<FeatureWasmThreads Condition="'$(TargetOS)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
<DefineConstants Condition="'$(FeatureWasmThreads)' == 'true'" >$(DefineConstants);FEATURE_WASM_THREADS</DefineConstants>
<EnableAOTAnalyzer>false</EnableAOTAnalyzer>
</PropertyGroup>

<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
<PropertyGroup>
<TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetPlatformIdentifier)' != 'browser'">SR.SystemRuntimeInteropServicesJavaScript_PlatformNotSupported</GeneratePlatformNotSupportedAssemblyMessage>
<FeatureWasmThreads Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
<WasmEnableLegacyJsInterop Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<DefineConstants Condition="'$(FeatureWasmThreads)' == 'true'" >$(DefineConstants);FEATURE_WASM_THREADS</DefineConstants>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'true'" >$(DefineConstants);ENABLE_LEGACY_JS_INTEROP</DefineConstants>
<ILLinkDescriptorsLibraryBuildXml
Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' == 'true'"
>$(MonoProjectRoot)wasm\build\ILLink.Descriptors.LegacyJsInterop.xml</ILLinkDescriptorsLibraryBuildXml>
</PropertyGroup>

<ItemGroup>
Expand All @@ -22,15 +27,6 @@
<Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptImports.Generated.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptExports.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptImports.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Interop\LegacyExports.cs" />

<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Runtime.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Array.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\ArrayBuffer.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\DataView.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Function.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Uint8Array.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\LegacyHostImplementation.cs" />

<Compile Include="System\Runtime\InteropServices\JavaScript\JSHost.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\JSMarshalerType.cs" />
Expand Down Expand Up @@ -69,6 +65,18 @@
<Compile Include="System\Runtime\InteropServices\JavaScript\JSSynchronizationContext.cs" />
</ItemGroup>

<!-- only include legacy interop when WasmEnableLegacyJsInterop is enabled -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' == 'true'">
<Compile Include="System\Runtime\InteropServices\JavaScript\Interop\LegacyExports.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Runtime.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Array.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\ArrayBuffer.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\DataView.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Function.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Uint8Array.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\LegacyHostImplementation.cs" />
</ItemGroup>

<ItemGroup>
<Reference Include="System.Collections" />
<Reference Include="System.Memory" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static void MarshalPromise(Span<JSMarshalerArgument> arguments)
}
}

#if ENABLE_LEGACY_JS_INTEROP
#region legacy

public static object GetGlobalObject(string? str = null)
Expand All @@ -30,7 +31,7 @@ public static object GetGlobalObject(string? str = null)
if (exception != 0)
throw new JSException(SR.Format(SR.ErrorResolvingFromGlobalThis, str));

JSHostImplementation.ReleaseInFlight(jsObj);
LegacyHostImplementation.ReleaseInFlight(jsObj);
return jsObj;
}

Expand All @@ -44,5 +45,6 @@ public static IntPtr CreateCSOwnedObject(string typeName, object[] parms)
}

#endregion
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

namespace System.Runtime.InteropServices.JavaScript
{
// this maps to src\mono\wasm\runtime\legacy\corebindings.ts
// the public methods are protected from trimming by DynamicDependency on JSFunctionBinding.BindJSFunction
// the public methods are protected from trimming by ILLink.Descriptors.LegacyJsInterop.xml
internal static unsafe partial class LegacyExports
{
public static void GetCSOwnedObjectByJSHandleRef(nint jsHandle, int shouldAddInflight, out JSObject? result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ public static void InvokeJS(JSFunctionBinding signature, Span<JSMarshalerArgumen
/// <exception cref="PlatformNotSupportedException">The method is executed on an architecture other than WebAssembly.</exception>
// JavaScriptExports need to be protected from trimming because they are used from C/JS code which IL linker can't see
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JavaScriptExports", "System.Runtime.InteropServices.JavaScript")]
// TODO make this DynamicDependency conditional
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.LegacyExports", "System.Runtime.InteropServices.JavaScript")]
public static JSFunctionBinding BindJSFunction(string functionName, string moduleName, ReadOnlySpan<JSMarshalerType> signatures)
{
if (RuntimeInformation.OSArchitecture != Architecture.Wasm)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ public static void ReleaseCSOwnedObject(nint jsHandle)
throw new InvalidOperationException();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReleaseInFlight(object obj)
{
JSObject? jsObj = obj as JSObject;
jsObj?.ReleaseInFlight();
}

// A JSOwnedObject is a managed object with its lifetime controlled by javascript.
// The managed side maintains a strong reference to the object, while the JS side
// maintains a weak reference and notifies the managed side if the JS wrapper object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ public partial class JSObject
{
internal nint JSHandle;

#if ENABLE_LEGACY_JS_INTEROP
internal GCHandle? InFlight;
internal int InFlightCounter;
#endif
private bool _isDisposed;

internal JSObject(IntPtr jsHandle)
{
JSHandle = jsHandle;
InFlight = null;
InFlightCounter = 0;
}

#if ENABLE_LEGACY_JS_INTEROP
internal void AddInFlight()
{
ObjectDisposedException.ThrowIf(IsDisposed, this);
Expand Down Expand Up @@ -53,6 +54,7 @@ internal void ReleaseInFlight()
}
}
}
#endif

/// <inheritdoc />
public override bool Equals([NotNullWhen(true)] object? obj) => obj is JSObject other && JSHandle == other.JSHandle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public object this[int i]

if (exception != 0)
throw new JSException((string)indexValue);
JSHostImplementation.ReleaseInFlight(indexValue);
LegacyHostImplementation.ReleaseInFlight(indexValue);
return indexValue;
}
set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ namespace System.Runtime.InteropServices.JavaScript
[SupportedOSPlatform("browser")]
internal static class LegacyHostImplementation
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReleaseInFlight(object obj)
{
JSObject? jsObj = obj as JSObject;
jsObj?.ReleaseInFlight();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void RegisterCSOwnedObject(JSObject proxy)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static object Invoke(this JSObject self, string method, params object?[]
Interop.Runtime.InvokeJSWithArgsRef(self.JSHandle, method, args, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
JSHostImplementation.ReleaseInFlight(res);
LegacyHostImplementation.ReleaseInFlight(res);
return res;
}

Expand Down Expand Up @@ -74,7 +74,7 @@ public static object GetObjectProperty(this JSObject self, string name)
Interop.Runtime.GetObjectPropertyRef(self.JSHandle, name, out int exception, out object propertyValue);
if (exception != 0)
throw new JSException((string)propertyValue);
JSHostImplementation.ReleaseInFlight(propertyValue);
LegacyHostImplementation.ReleaseInFlight(propertyValue);
return propertyValue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
<TestRuntime>true</TestRuntime>
<WasmXHarnessArgs>$(WasmXHarnessArgs) --engine-arg=--expose-gc --web-server-use-cop</WasmXHarnessArgs>
<NoWarn>0612</NoWarn>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'true'">$(DefineConstants);ENABLE_LEGACY_JS_INTEROP</DefineConstants>
</PropertyGroup>
<ItemGroup>

<ItemGroup Condition="'$(WasmEnableLegacyJsInterop)' == 'true'">
<Compile Include="System\Runtime\InteropServices\JavaScript\JavaScriptTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\DataViewTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\MemoryTests.cs" />
Expand All @@ -16,9 +19,12 @@
<Compile Include="System\Runtime\InteropServices\JavaScript\DelegateTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\HelperMarshal.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Http\HttpRequestMessageTest.cs" />
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.UnitTests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
</ItemGroup>

<ItemGroup>
<Compile Include="System\Runtime\InteropServices\JavaScript\ParallelTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\TimerTests.cs" />
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.UnitTests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<TargetFrameworks>$(NetCoreAppCurrent)-browser</TargetFrameworks>
<TestRuntime>true</TestRuntime>
<WasmXHarnessArgs>$(WasmXHarnessArgs) --engine-arg=--expose-gc --web-server-use-cop</WasmXHarnessArgs>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'true'">$(DefineConstants);ENABLE_LEGACY_JS_INTEROP</DefineConstants>
<!-- Use following lines to write the generated files to disk. -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ public unsafe void GlobalThis()
[Fact]
public unsafe void DotnetInstance()
{
#if ENABLE_LEGACY_JS_INTEROP
Assert.True(JSHost.DotnetInstance.HasProperty("MONO"));
Assert.Equal("object", JSHost.DotnetInstance.GetTypeOfProperty("MONO"));
#endif

JSHost.DotnetInstance.SetProperty("testBool", true);
Assert.Equal("boolean", JSHost.DotnetInstance.GetTypeOfProperty("testBool"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageFile Include="Sdk\AutoImport.props" TargetPath="Sdk" />
<PackageFile Include="Sdk\Sdk.props" TargetPath="Sdk" />
<PackageFile Include="$(RepoRoot)\src\mono\wasm\build\ILLink.Substitutions.*.xml" TargetPath="Sdk" />
<PackageFile Include="$(RepoRoot)\src\mono\wasm\build\ILLink.Descriptors.*.xml" TargetPath="Sdk" />
<PackageFile Include="$(RepoRoot)\src\mono\wasm\build\WasmApp.props" TargetPath="Sdk" />
<PackageFile Include="$(RepoRoot)\src\mono\wasm\build\WasmApp.targets" TargetPath="Sdk" />
<PackageFile Include="$(RepoRoot)\src\mono\wasm\build\WasmApp.Native.*" TargetPath="Sdk" />
Expand Down
24 changes: 24 additions & 0 deletions src/mono/wasm/build/ILLink.Descriptors.LegacyJsInterop.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<linker>
<!-- LegacyExports need to be protected from trimming because methods are used from C/JS code which IL linker can't see -->
<assembly fullname="System.Runtime.InteropServices.JavaScript">
<type fullname="System.Runtime.InteropServices.JavaScript.LegacyExports">
<method name="GetCSOwnedObjectByJSHandleRef" />
<method name="GetCSOwnedObjectJSHandleRef" />
<method name="TryGetCSOwnedObjectJSHandleRef" />
<method name="CreateCSOwnedProxyRef" />
<method name="GetJSOwnedObjectByGCHandleRef" />
<method name="GetJSOwnedObjectGCHandleRef" />
<method name="CreateTaskSource" />
<method name="SetTaskSourceResultRef" />
<method name="SetTaskSourceFailure" />
<method name="GetTaskSourceTaskRef" />
<method name="SetupJSContinuationRef" />
<method name="ObjectToStringRef" />
<method name="GetDateValueRef" />
<method name="CreateDateTimeRef" />
<method name="CreateUriRef" />
<method name="IsSimpleArrayRef" />
<method name="GetCallSignatureRef" />
</type>
</assembly>
</linker>
1 change: 0 additions & 1 deletion src/mono/wasm/build/WasmApp.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,6 @@
<EmscriptenEnvVars Include="PYTHONHOME=" Condition="'$(OS)' == 'Windows_NT'" />
<EmscriptenEnvVars Include="EM_CACHE=$(WasmCachePath)" Condition="'$(WasmCachePath)' != ''" />
<EmscriptenEnvVars Include="WasmEnableLegacyJsInterop=$(WasmEnableLegacyJsInterop)"/>
<EmscriptenEnvVars Include="MonoWasmThreads=$(MonoWasmThreads)"/>
</ItemGroup>

<ItemGroup Condition="'$(WasmAllowUndefinedSymbols)' == 'true'">
Expand Down
4 changes: 4 additions & 0 deletions src/mono/wasm/build/WasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@

<SupportedPlatform Condition="'$(IsBrowserWasmProject)' == 'true'" Remove="@(SupportedPlatform)" />
<SupportedPlatform Condition="'$(IsBrowserWasmProject)' == 'true'" Include="browser" />

<TrimmerRootDescriptor
Condition="'$(WasmEnableLegacyJsInterop)' == 'true'"
Include="$(MSBuildThisFileDirectory)ILLink.Descriptors.LegacyJsInterop.xml" />
</ItemGroup>

<PropertyGroup Label="Identify app bundle directory to run from">
Expand Down
14 changes: 11 additions & 3 deletions src/mono/wasm/runtime/es6/dotnet.es6.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@

"use strict";

const monoWasmThreads = process.env.MonoWasmThreads == "true";
const WasmEnableLegacyJsInterop = process.env.WasmEnableLegacyJsInterop === "true";
const isPThread = monoWasmThreads ? "ENVIRONMENT_IS_PTHREAD" : "false";
// USE_PTHREADS is emscripten's define symbol, which is passed to acorn optimizer, so we could use it here
#if USE_PTHREADS
const monoWasmThreads = true;
const isPThread = `ENVIRONMENT_IS_PTHREAD`;
#else
const monoWasmThreads = false;
const isPThread = "false";
#endif

// because we can't pass custom define symbols to acorn optimizer, we use environment variables to pass other build options
const WasmEnableLegacyJsInterop = process.env.WasmEnableLegacyJsInterop !== "false";

const DotnetSupportLib = {
$DOTNET: {},
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/runtime/net6-legacy/corebindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export function init_legacy_exports(): void {
legacyHelpers.runtime_legacy_exports_classname = "LegacyExports";
legacyHelpers.runtime_legacy_exports_class = cwraps.mono_wasm_assembly_find_class(runtimeHelpers.runtime_interop_module, runtimeHelpers.runtime_interop_namespace, legacyHelpers.runtime_legacy_exports_classname);
if (!legacyHelpers.runtime_legacy_exports_class)
throw "Can't find " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_interop_exports_classname + " class";
throw "Can't find " + runtimeHelpers.runtime_interop_namespace + "." + legacyHelpers.runtime_legacy_exports_classname + " class";

for (const sig of fn_signatures) {
const wf: any = legacyManagedExports;
Expand Down
Loading

0 comments on commit 6c836e8

Please sign in to comment.