Skip to content

Commit 4a2bf17

Browse files
committed
rebase
1 parent 721c445 commit 4a2bf17

File tree

11 files changed

+80
-18
lines changed

11 files changed

+80
-18
lines changed

src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ internal static unsafe partial class Runtime
2323
public static extern unsafe void BindCSFunction(in string fully_qualified_name, int signature_hash, void* signature, out int is_exception, out object result);
2424
[MethodImpl(MethodImplOptions.InternalCall)]
2525
public static extern void ResolveOrRejectPromise(void* data);
26+
27+
#if !ENABLE_JS_INTEROP_BY_VALUE
2628
[MethodImpl(MethodImplOptions.InternalCall)]
2729
public static extern IntPtr RegisterGCRoot(IntPtr start, int bytesSize, IntPtr name);
2830
[MethodImpl(MethodImplOptions.InternalCall)]
2931
public static extern void DeregisterGCRoot(IntPtr handle);
32+
#endif
3033

3134
#if FEATURE_WASM_THREADS
3235
[MethodImpl(MethodImplOptions.InternalCall)]

src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
<TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
1313
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetPlatformIdentifier)' != 'browser'">SR.SystemRuntimeInteropServicesJavaScript_PlatformNotSupported</GeneratePlatformNotSupportedAssemblyMessage>
1414
<FeatureWasmThreads Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
15+
<WasmEnableJsInteropByValue Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableJsInteropByValue)' == '' and '$(FeatureWasmThreads)' == 'true'">true</WasmEnableJsInteropByValue>
1516
<WasmEnableLegacyJsInterop Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
1617
<DefineConstants Condition="'$(FeatureWasmThreads)' == 'true'" >$(DefineConstants);FEATURE_WASM_THREADS</DefineConstants>
1718
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'false'" >$(DefineConstants);DISABLE_LEGACY_JS_INTEROP</DefineConstants>
19+
<DefineConstants Condition="'$(WasmEnableJsInteropByValue)' == 'true'" >$(DefineConstants);ENABLE_JS_INTEROP_BY_VALUE</DefineConstants>
1820
</PropertyGroup>
1921

2022
<ItemGroup>

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ public unsafe void ToManaged(out object?[]? value)
344344
arg.ToManaged(out val);
345345
value[i] = val;
346346
}
347+
#if !ENABLE_JS_INTEROP_BY_VALUE
347348
Interop.Runtime.DeregisterGCRoot(slot.IntPtrValue);
349+
#endif
348350
Marshal.FreeHGlobal(slot.IntPtrValue);
349351
}
350352

@@ -366,7 +368,9 @@ public unsafe void ToJS(object?[] value)
366368
slot.Type = MarshalerType.Array;
367369
JSMarshalerArgument* payload = (JSMarshalerArgument*)Marshal.AllocHGlobal(bytes);
368370
Unsafe.InitBlock(payload, 0, (uint)bytes);
371+
#if !ENABLE_JS_INTEROP_BY_VALUE
369372
Interop.Runtime.RegisterGCRoot((IntPtr)payload, bytes, IntPtr.Zero);
373+
#endif
370374
for (int i = 0; i < slot.Length; i++)
371375
{
372376
ref JSMarshalerArgument arg = ref payload[i];

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.String.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ public unsafe void ToManaged(out string? value)
2020
value = null;
2121
return;
2222
}
23-
23+
#if ENABLE_JS_INTEROP_BY_VALUE
24+
value = Marshal.PtrToStringUni(slot.IntPtrValue, slot.Length);
25+
Marshal.FreeHGlobal(slot.IntPtrValue);
26+
#else
2427
fixed (void* argAsRoot = &slot.IntPtrValue)
2528
{
2629
value = Unsafe.AsRef<string>(argAsRoot);
2730
}
31+
#endif
2832
}
2933

3034
/// <summary>
@@ -42,6 +46,10 @@ public unsafe void ToJS(string? value)
4246
else
4347
{
4448
slot.Type = MarshalerType.String;
49+
#if ENABLE_JS_INTEROP_BY_VALUE
50+
slot.IntPtrValue = Marshal.StringToHGlobalUni(value); // alloc, JS side will free
51+
slot.Length = value.Length;
52+
#else
4553
// here we treat JSMarshalerArgument.IntPtrValue as root, because it's allocated on stack
4654
// or we register the buffer with JSFunctionBinding._RegisterGCRoot
4755
// We assume that GC would keep updating on GC move
@@ -52,6 +60,7 @@ public unsafe void ToJS(string? value)
5260
var currentRoot = (IntPtr*)Unsafe.AsPointer(ref cpy);
5361
argAsRoot[0] = currentRoot[0];
5462
}
63+
#endif
5564
}
5665
}
5766

@@ -78,7 +87,9 @@ public unsafe void ToManaged(out string?[]? value)
7887
arg.ToManaged(out val);
7988
value[i] = val;
8089
}
90+
#if !ENABLE_JS_INTEROP_BY_VALUE
8191
Interop.Runtime.DeregisterGCRoot(slot.IntPtrValue);
92+
#endif
8293
Marshal.FreeHGlobal(slot.IntPtrValue);
8394
}
8495

@@ -100,7 +111,9 @@ public unsafe void ToJS(string?[] value)
100111
slot.Type = MarshalerType.Array;
101112
JSMarshalerArgument* payload = (JSMarshalerArgument*)Marshal.AllocHGlobal(bytes);
102113
Unsafe.InitBlock(payload, 0, (uint)bytes);
114+
#if !ENABLE_JS_INTEROP_BY_VALUE
103115
Interop.Runtime.RegisterGCRoot((IntPtr)payload, bytes, IntPtr.Zero);
116+
#endif
104117
for (int i = 0; i < slot.Length; i++)
105118
{
106119
ref JSMarshalerArgument arg = ref payload[i];

src/mono/wasm/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ project(mono-wasm-runtime C)
44

55
option(DISABLE_THREADS "defined if the build does NOT support multithreading" ON)
66
option(DISABLE_LEGACY_JS_INTEROP "defined if the build does not support legacy JavaScript interop" OFF)
7+
option(ENABLE_JS_INTEROP_BY_VALUE "defined when JS interop without pointers to managed objects" OFF)
78

89
set(CMAKE_EXECUTABLE_SUFFIX ".js")
910
add_executable(dotnet.native corebindings.c driver.c pinvoke.c)

src/mono/wasm/runtime/corebindings.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ void bindings_initialize_internals (void)
6666
mono_add_internal_call ("Interop/Runtime::InvokeImport", mono_wasm_invoke_import);
6767
mono_add_internal_call ("Interop/Runtime::BindCSFunction", mono_wasm_bind_cs_function);
6868
mono_add_internal_call ("Interop/Runtime::ResolveOrRejectPromise", mono_wasm_resolve_or_reject_promise);
69+
70+
#ifndef ENABLE_JS_INTEROP_BY_VALUE
6971
mono_add_internal_call ("Interop/Runtime::RegisterGCRoot", mono_wasm_register_root);
7072
mono_add_internal_call ("Interop/Runtime::DeregisterGCRoot", mono_wasm_deregister_root);
73+
#endif /* ENABLE_JS_INTEROP_BY_VALUE */
7174

7275
#ifndef DISABLE_THREADS
7376
mono_add_internal_call ("Interop/Runtime::InstallWebWorkerInterop", mono_wasm_install_js_worker_interop);

src/mono/wasm/runtime/marshal-to-cs.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import MonoWasmThreads from "consts:monoWasmThreads";
55
import BuildConfiguration from "consts:configuration";
6+
import WasmEnableJsInteropByValue from "consts:wasmEnableJsInteropByValue";
67

78
import { isThenable } from "./cancelable-promise";
89
import cwraps from "./cwraps";
@@ -18,7 +19,7 @@ import {
1819
} from "./marshal";
1920
import { get_marshaler_to_js_by_type } from "./marshal-to-js";
2021
import { _zero_region, localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory";
21-
import { stringToMonoStringRoot } from "./strings";
22+
import { stringToMonoStringRoot, stringToUTF16 } from "./strings";
2223
import { JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types/internal";
2324
import { TypedArray } from "./types/emscripten";
2425
import { addUnsettledPromise, settleUnsettledPromise } from "./pthreads/shared/eventloop";
@@ -229,12 +230,20 @@ function _marshal_string_to_cs(arg: JSMarshalerArgument, value: string) {
229230
}
230231

231232
function _marshal_string_to_cs_impl(arg: JSMarshalerArgument, value: string) {
232-
const root = get_string_root(arg);
233-
try {
234-
stringToMonoStringRoot(value, root);
235-
}
236-
finally {
237-
root.release();
233+
if (WasmEnableJsInteropByValue) {
234+
const bufferLen = value.length * 2;
235+
const buffer = Module._malloc(bufferLen);
236+
stringToUTF16(buffer as any, buffer as any + bufferLen, value);
237+
set_arg_intptr(arg, buffer);
238+
set_arg_length(arg, value.length);
239+
} else {
240+
const root = get_string_root(arg);
241+
try {
242+
stringToMonoStringRoot(value, root);
243+
}
244+
finally {
245+
root.release();
246+
}
238247
}
239248
}
240249

@@ -505,7 +514,9 @@ export function marshal_array_to_cs_impl(arg: JSMarshalerArgument, value: Array<
505514
if (element_type == MarshalerType.String) {
506515
mono_check(Array.isArray(value), "Value is not an Array");
507516
_zero_region(buffer_ptr, buffer_length);
508-
cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs");
517+
if (!WasmEnableJsInteropByValue) {
518+
cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs");
519+
}
509520
for (let index = 0; index < length; index++) {
510521
const element_arg = get_arg(<any>buffer_ptr, index);
511522
_marshal_string_to_cs(element_arg, value[index]);
@@ -514,7 +525,9 @@ export function marshal_array_to_cs_impl(arg: JSMarshalerArgument, value: Array<
514525
else if (element_type == MarshalerType.Object) {
515526
mono_check(Array.isArray(value), "Value is not an Array");
516527
_zero_region(buffer_ptr, buffer_length);
517-
cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs");
528+
if (!WasmEnableJsInteropByValue) {
529+
cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs");
530+
}
518531
for (let index = 0; index < length; index++) {
519532
const element_arg = get_arg(<any>buffer_ptr, index);
520533
_marshal_cs_object_to_cs(element_arg, value[index]);

src/mono/wasm/runtime/marshal-to-js.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import MonoWasmThreads from "consts:monoWasmThreads";
55
import BuildConfiguration from "consts:configuration";
6+
import WasmEnableJsInteropByValue from "consts:wasmEnableJsInteropByValue";
67

78
import cwraps from "./cwraps";
89
import { _lookup_js_owned_object, mono_wasm_get_jsobj_from_js_handle, mono_wasm_release_cs_owned_object, register_with_jsv_handle, setup_managed_proxy, teardown_managed_proxy } from "./gc-handles";
@@ -15,7 +16,7 @@ import {
1516
get_signature_res_type, get_arg_u16, array_element_size, get_string_root,
1617
ArraySegment, Span, MemoryViewType, get_signature_arg3_type, get_arg_i64_big, get_arg_intptr, get_arg_element_type, JavaScriptMarshalerArgSize, proxy_debug_symbol
1718
} from "./marshal";
18-
import { monoStringToString } from "./strings";
19+
import { monoStringToString, utf16ToString } from "./strings";
1920
import { GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType } from "./types/internal";
2021
import { TypedArray } from "./types/emscripten";
2122
import { get_marshaler_to_cs_by_type, jsinteropDoc, marshal_exception_to_cs } from "./marshal-to-cs";
@@ -310,12 +311,21 @@ export function marshal_string_to_js(arg: JSMarshalerArgument): string | null {
310311
if (type == MarshalerType.None) {
311312
return null;
312313
}
313-
const root = get_string_root(arg);
314-
try {
315-
const value = monoStringToString(root);
314+
if (WasmEnableJsInteropByValue) {
315+
const buffer = get_arg_intptr(arg);
316+
const len = get_arg_length(arg) * 2;
317+
const value = utf16ToString(<any>buffer, <any>buffer + len);
318+
Module._free(buffer as any);
316319
return value;
317-
} finally {
318-
root.release();
320+
}
321+
else {
322+
const root = get_string_root(arg);
323+
try {
324+
const value = monoStringToString(root);
325+
return value;
326+
} finally {
327+
root.release();
328+
}
319329
}
320330
}
321331

@@ -421,15 +431,19 @@ function _marshal_array_to_js_impl(arg: JSMarshalerArgument, element_type: Marsh
421431
const element_arg = get_arg(<any>buffer_ptr, index);
422432
result[index] = marshal_string_to_js(element_arg);
423433
}
424-
cwraps.mono_wasm_deregister_root(<any>buffer_ptr);
434+
if (!WasmEnableJsInteropByValue) {
435+
cwraps.mono_wasm_deregister_root(<any>buffer_ptr);
436+
}
425437
}
426438
else if (element_type == MarshalerType.Object) {
427439
result = new Array(length);
428440
for (let index = 0; index < length; index++) {
429441
const element_arg = get_arg(<any>buffer_ptr, index);
430442
result[index] = _marshal_cs_object_to_js(element_arg);
431443
}
432-
cwraps.mono_wasm_deregister_root(<any>buffer_ptr);
444+
if (!WasmEnableJsInteropByValue) {
445+
cwraps.mono_wasm_deregister_root(<any>buffer_ptr);
446+
}
433447
}
434448
else if (element_type == MarshalerType.JSObject) {
435449
result = new Array(length);

src/mono/wasm/runtime/rollup.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const monoWasmThreads = process.env.MonoWasmThreads === "true" ? true : false;
2323
const wasmEnableSIMD = process.env.WASM_ENABLE_SIMD === "1" ? true : false;
2424
const wasmEnableExceptionHandling = process.env.WASM_ENABLE_EH === "1" ? true : false;
2525
const wasmEnableLegacyJsInterop = process.env.DISABLE_LEGACY_JS_INTEROP !== "1" ? true : false;
26+
const wasmEnableJsInteropByValue = process.env.ENABLE_JS_INTEROP_BY_VALUE !== "1" ? true : false;
2627
const monoDiagnosticsMock = process.env.MonoDiagnosticsMock === "true" ? true : false;
2728
// because of stack walk at src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
2829
// and unit test at src\libraries\System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.Legacy.UnitTests\timers.mjs
@@ -103,6 +104,7 @@ const envConstants = {
103104
monoDiagnosticsMock,
104105
gitHash,
105106
wasmEnableLegacyJsInterop,
107+
wasmEnableJsInteropByValue,
106108
isContinuousIntegrationBuild,
107109
};
108110

src/mono/wasm/runtime/wasm-config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@
1010
/* Support for legacy JS interop is disabled */
1111
#cmakedefine DISABLE_LEGACY_JS_INTEROP
1212

13+
/* Support for JS interop without pointers to managed objects */
14+
#cmakedefine ENABLE_JS_INTEROP_BY_VALUE
15+
1316
#endif/*__MONO_WASM_CONFIG_H__*/

0 commit comments

Comments
 (0)