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

[browser] legacy JS interop optional via WasmEnableLegacyJsInterop - managed #82826

Merged
merged 7 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
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,19 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<FeatureWasmThreads Condition="'$(TargetOS)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
pavelsavara marked this conversation as resolved.
Show resolved Hide resolved
<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>
<WasmEnableLegacyJsInterop Condition="'$(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 +26,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 +64,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