Skip to content

Commit c376589

Browse files
authored
[blazor][wasm] Remove legacy interop (#52732)
1 parent 3b56881 commit c376589

20 files changed

+51
-492
lines changed

src/Components/Web.JS/src/Boot.WebAssembly.Common.ts

Lines changed: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
/* eslint-disable array-element-newline */
5-
import { DotNet } from '@microsoft/dotnet-js-interop';
5+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
66
import { Blazor } from './GlobalExports';
77
import * as Environment from './Environment';
8-
import { BINDING, monoPlatform, dispatcher, getInitializer } from './Platform/Mono/MonoPlatform';
8+
import { monoPlatform, dispatcher, getInitializer } from './Platform/Mono/MonoPlatform';
99
import { renderBatch, getRendererer, attachRootComponentToElement, attachRootComponentToLogicalElement } from './Rendering/Renderer';
1010
import { SharedMemoryRenderBatch } from './Rendering/RenderBatch/SharedMemoryRenderBatch';
11-
import { PlatformApi, Pointer } from './Platform/Platform';
11+
import { Pointer } from './Platform/Platform';
1212
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
1313
import { addDispatchEventMiddleware } from './Rendering/WebRendererInteropMethods';
1414
import { WebAssemblyComponentDescriptor, discoverWebAssemblyPersistedState } from './Services/ComponentDescriptorDiscovery';
@@ -19,7 +19,6 @@ import { RootComponentManager } from './Services/RootComponentManager';
1919
import { WebRendererId } from './Rendering/WebRendererId';
2020

2121
let options: Partial<WebAssemblyStartOptions> | undefined;
22-
let initializersPromise: Promise<void>;
2322
let platformLoadPromise: Promise<void> | undefined;
2423
let loadedWebAssemblyPlatform = false;
2524
let started = false;
@@ -43,7 +42,7 @@ export function resolveInitialUpdate(value: string): void {
4342
}
4443

4544
let resolveInitializersPromise: (value: void) => void;
46-
initializersPromise = new Promise<void>(resolve => {
45+
const initializersPromise = new Promise<void>(resolve => {
4746
resolveInitializersPromise = resolve;
4847
});
4948

@@ -105,7 +104,6 @@ async function startCore(components: RootComponentManager<WebAssemblyComponentDe
105104
Blazor._internal.getApplyUpdateCapabilities = () => dispatcher.invokeDotNetStaticMethod('Microsoft.AspNetCore.Components.WebAssembly', 'GetApplyUpdateCapabilities');
106105

107106
// Configure JS interop
108-
Blazor._internal.invokeJSFromDotNet = invokeJSFromDotNet;
109107
Blazor._internal.invokeJSJson = invokeJSJson;
110108
Blazor._internal.endInvokeDotNetFromJS = endInvokeDotNetFromJS;
111109
Blazor._internal.receiveWebAssemblyDotNetDataStream = receiveWebAssemblyDotNetDataStream;
@@ -169,7 +167,7 @@ async function startCore(components: RootComponentManager<WebAssemblyComponentDe
169167
Blazor._internal.endUpdateRootComponents = (batchId: number) =>
170168
components.onAfterUpdateRootComponents?.(batchId);
171169

172-
Blazor._internal.attachRootComponentToElement = (selector, componentId, rendererId: any) => {
170+
Blazor._internal.attachRootComponentToElement = (selector, componentId, rendererId) => {
173171
const element = componentAttacher.resolveRegisteredElement(selector);
174172
if (!element) {
175173
attachRootComponentToElement(selector, componentId, rendererId);
@@ -178,17 +176,16 @@ async function startCore(components: RootComponentManager<WebAssemblyComponentDe
178176
}
179177
};
180178

181-
let api: PlatformApi;
182179
try {
183180
await platformLoadPromise;
184-
api = await platform.start();
181+
await platform.start();
185182
} catch (ex) {
186183
throw new Error(`Failed to start platform. Reason: ${ex}`);
187184
}
188185

189186
// Start up the application
190187
platform.callEntryPoint();
191-
// At this point .NET has been initialized (and has yielded), we can't await the promise becasue it will
188+
// At this point .NET has been initialized (and has yielded), we can't await the promise because it will
192189
// only end when the app finishes running
193190
const initializer = getInitializer();
194191
initializer.invokeAfterStartedCallbacks(Blazor);
@@ -229,45 +226,6 @@ export function hasLoadedWebAssemblyPlatform(): boolean {
229226
return loadedWebAssemblyPlatform;
230227
}
231228

232-
// obsolete, legacy, don't use for new code!
233-
function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any): any {
234-
const functionIdentifier = monoPlatform.readStringField(callInfo, 0)!;
235-
const resultType = monoPlatform.readInt32Field(callInfo, 4);
236-
const marshalledCallArgsJson = monoPlatform.readStringField(callInfo, 8);
237-
const targetInstanceId = monoPlatform.readUint64Field(callInfo, 20);
238-
239-
if (marshalledCallArgsJson !== null) {
240-
const marshalledCallAsyncHandle = monoPlatform.readUint64Field(callInfo, 12);
241-
242-
if (marshalledCallAsyncHandle !== 0) {
243-
dispatcher.beginInvokeJSFromDotNet(marshalledCallAsyncHandle, functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId);
244-
return 0;
245-
} else {
246-
const resultJson = dispatcher.invokeJSFromDotNet(functionIdentifier, marshalledCallArgsJson, resultType, targetInstanceId)!;
247-
return resultJson === null ? 0 : BINDING.js_string_to_mono_string(resultJson);
248-
}
249-
} else {
250-
const func = DotNet.findJSFunction(functionIdentifier, targetInstanceId);
251-
const result = func.call(null, arg0, arg1, arg2);
252-
253-
switch (resultType) {
254-
case DotNet.JSCallResultType.Default:
255-
return result;
256-
case DotNet.JSCallResultType.JSObjectReference:
257-
return DotNet.createJSObjectReference(result).__jsObjectId;
258-
case DotNet.JSCallResultType.JSStreamReference: {
259-
const streamReference = DotNet.createJSStreamReference(result);
260-
const resultJson = JSON.stringify(streamReference);
261-
return BINDING.js_string_to_mono_string(resultJson);
262-
}
263-
case DotNet.JSCallResultType.JSVoidResult:
264-
return null;
265-
default:
266-
throw new Error(`Invalid JS call result type '${resultType}'.`);
267-
}
268-
}
269-
}
270-
271229
export function updateWebAssemblyRootComponents(operations: string): void {
272230
if (!startPromise) {
273231
throw new Error('Blazor WebAssembly has not started.');
@@ -307,7 +265,7 @@ function endInvokeDotNetFromJS(callId: string, success: boolean, resultJsonOrErr
307265
dispatcher.endInvokeDotNetFromJS(callId, success, resultJsonOrErrorMessage);
308266
}
309267

310-
function receiveWebAssemblyDotNetDataStream(streamId: number, data: any, bytesRead: number, errorMessage: string): void {
268+
function receiveWebAssemblyDotNetDataStream(streamId: number, data: Uint8Array, bytesRead: number, errorMessage: string): void {
311269
receiveDotNetDataStream(dispatcher, streamId, data, bytesRead, errorMessage);
312270
}
313271

src/Components/Web.JS/src/Boot.WebAssembly.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
/* eslint-disable array-element-newline */
55
import { Blazor } from './GlobalExports';
6-
import { Module } from './Platform/Mono/MonoPlatform';
76
import { shouldAutoStart } from './BootCommon';
87
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
98
import { setWebAssemblyOptions, startWebAssembly } from './Boot.WebAssembly.Common';
109
import { WebAssemblyComponentDescriptor, discoverComponents } from './Services/ComponentDescriptorDiscovery';
1110
import { DotNet } from '@microsoft/dotnet-js-interop';
1211
import { InitialRootComponentsList } from './Services/InitialRootComponentsList';
1312
import { JSEventRegistry } from './Services/JSEventRegistry';
13+
import { printErr } from './Platform/Mono/MonoPlatform';
1414

1515
let started = false;
1616

@@ -32,13 +32,5 @@ Blazor.start = boot;
3232
window['DotNet'] = DotNet;
3333

3434
if (shouldAutoStart()) {
35-
boot().catch(error => {
36-
if (typeof Module !== 'undefined' && Module.err) {
37-
// Logs it, and causes the error UI to appear
38-
Module.err(error);
39-
} else {
40-
// The error must have happened so early we didn't yet set up the error UI, so just log to console
41-
console.error(error);
42-
}
43-
});
35+
boot().catch(printErr);
4436
}

src/Components/Web.JS/src/GlobalExports.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export interface IBlazor {
5252
forceCloseConnection?: () => Promise<void>;
5353
InputFile?: typeof InputFile;
5454
NavigationLock: typeof NavigationLock;
55-
invokeJSFromDotNet?: (callInfo: Pointer, arg0: any, arg1: any, arg2: any) => any;
5655
invokeJSJson?: (identifier: string, targetInstanceId: number, resultType: number, argsJson: string, asyncHandle: number) => string | null;
5756
endInvokeDotNetFromJS?: (callId: string, success: boolean, resultJsonOrErrorMessage: string) => void;
5857
receiveByteArray?: (id: number, data: Uint8Array) => void;

src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts

Lines changed: 15 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,22 @@ import { showErrorNotification } from '../../BootErrors';
1010
import { Platform, System_Array, Pointer, System_Object, System_String, HeapLock, PlatformApi } from '../Platform';
1111
import { WebAssemblyBootResourceType, WebAssemblyStartOptions } from '../WebAssemblyStartOptions';
1212
import { Blazor } from '../../GlobalExports';
13-
import { DotnetModuleConfig, EmscriptenModule, MonoConfig, ModuleAPI, RuntimeAPI, GlobalizationMode } from 'dotnet-runtime';
14-
import { BINDINGType, MONOType } from 'dotnet-runtime/dotnet-legacy';
13+
import { DotnetModuleConfig, MonoConfig, ModuleAPI, RuntimeAPI, GlobalizationMode } from 'dotnet-runtime';
1514
import { fetchAndInvokeInitializers } from '../../JSInitializers/JSInitializers.WebAssembly';
1615
import { JSInitializer } from '../../JSInitializers/JSInitializers';
17-
import { WebRendererId } from '../../Rendering/WebRendererId';
1816

1917
// initially undefined and only fully initialized after createEmscriptenModuleInstance()
20-
export let BINDING: BINDINGType = undefined as any;
21-
export let MONO: MONOType = undefined as any;
22-
export let Module: DotnetModuleConfig & EmscriptenModule = undefined as any;
2318
export let dispatcher: DotNet.ICallDispatcher = undefined as any;
2419
let MONO_INTERNAL: any = undefined as any;
2520
let runtime: RuntimeAPI = undefined as any;
2621
let jsInitializer: JSInitializer;
2722

28-
const uint64HighOrderShift = Math.pow(2, 32);
29-
const maxSafeNumberHighPart = Math.pow(2, 21) - 1; // The high-order int32 from Number.MAX_SAFE_INTEGER
30-
3123
let currentHeapLock: MonoHeapLock | null = null;
3224

33-
// Memory access helpers
34-
// The implementations are exactly equivalent to what the global getValue(addr, type) function does,
35-
// except without having to parse the 'type' parameter, and with less risk of mistakes at the call site
36-
function getValueI16(ptr: number) {
37-
return MONO.getI16(ptr);
38-
}
39-
function getValueI32(ptr: number) {
40-
return MONO.getI32(ptr);
41-
}
42-
function getValueFloat(ptr: number) {
43-
return MONO.getF32(ptr);
44-
}
45-
4625
export function getInitializer() {
4726
return jsInitializer;
4827
}
4928

50-
function getValueU64(ptr: number) {
51-
// There is no Module.HEAPU64, and Module.getValue(..., 'i64') doesn't work because the implementation
52-
// treats 'i64' as being the same as 'i32'. Also we must take care to read both halves as unsigned.
53-
const heapU32Index = ptr >> 2;
54-
const highPart = Module.HEAPU32[heapU32Index + 1];
55-
if (highPart > maxSafeNumberHighPart) {
56-
throw new Error(`Cannot read uint64 with high order part ${highPart}, because the result would exceed Number.MAX_SAFE_INTEGER.`);
57-
}
58-
59-
return (highPart * uint64HighOrderShift) + Module.HEAPU32[heapU32Index];
60-
}
61-
6229
export const monoPlatform: Platform = {
6330
load: function load(options: Partial<WebAssemblyStartOptions>, onConfigLoaded?: (loadedConfig: MonoConfig) => void) {
6431
return createRuntimeInstance(options, onConfigLoaded);
@@ -77,18 +44,6 @@ export const monoPlatform: Platform = {
7744
}
7845
},
7946

80-
toUint8Array: function toUint8Array(array: System_Array<any>): Uint8Array {
81-
const dataPtr = getArrayDataPointer(array);
82-
const length = getValueI32(dataPtr);
83-
const uint8Array = new Uint8Array(length);
84-
uint8Array.set(Module.HEAPU8.subarray(dataPtr + 4, dataPtr + 4 + length));
85-
return uint8Array;
86-
},
87-
88-
getArrayLength: function getArrayLength(array: System_Array<any>): number {
89-
return getValueI32(getArrayDataPointer(array));
90-
},
91-
9247
getArrayEntryPtr: function getArrayEntryPtr<TPtr extends Pointer>(array: System_Array<TPtr>, index: number, itemSize: number): TPtr {
9348
// First byte is array length, followed by entries
9449
const address = getArrayDataPointer(array) + 4 + index * itemSize;
@@ -97,46 +52,42 @@ export const monoPlatform: Platform = {
9752

9853
getObjectFieldsBaseAddress: function getObjectFieldsBaseAddress(referenceTypedObject: System_Object): Pointer {
9954
// The first two int32 values are internal Mono data
100-
return (referenceTypedObject as any as number + 8) as any as Pointer;
55+
return (referenceTypedObject as any + 8) as any as Pointer;
10156
},
10257

10358
readInt16Field: function readHeapInt16(baseAddress: Pointer, fieldOffset?: number): number {
104-
return getValueI16((baseAddress as any as number) + (fieldOffset || 0));
59+
return runtime.getHeapI16((baseAddress as any) + (fieldOffset || 0));
10560
},
10661

10762
readInt32Field: function readHeapInt32(baseAddress: Pointer, fieldOffset?: number): number {
108-
return getValueI32((baseAddress as unknown as number) + (fieldOffset || 0));
63+
return runtime.getHeapI32((baseAddress as any) + (fieldOffset || 0));
10964
},
11065

11166
readUint64Field: function readHeapUint64(baseAddress: Pointer, fieldOffset?: number): number {
112-
return getValueU64((baseAddress as unknown as number) + (fieldOffset || 0));
113-
},
114-
115-
readFloatField: function readHeapFloat(baseAddress: Pointer, fieldOffset?: number): number {
116-
return getValueFloat((baseAddress as unknown as number) + (fieldOffset || 0));
67+
return runtime.getHeapU52((baseAddress as any) + (fieldOffset || 0));
11768
},
11869

119-
readObjectField: function readHeapObject<T extends System_Object>(baseAddress: Pointer, fieldOffset?: number): T {
120-
return getValueI32((baseAddress as unknown as number) + (fieldOffset || 0)) as any as T;
70+
readObjectField: function readObjectField<T extends System_Object>(baseAddress: Pointer, fieldOffset?: number): T {
71+
return runtime.getHeapU32((baseAddress as any) + (fieldOffset || 0)) as any as T;
12172
},
12273

123-
readStringField: function readHeapObject(baseAddress: Pointer, fieldOffset?: number, readBoolValueAsString?: boolean): string | null {
124-
const fieldValue = getValueI32((baseAddress as unknown as number) + (fieldOffset || 0));
74+
readStringField: function readStringField(baseAddress: Pointer, fieldOffset?: number, readBoolValueAsString?: boolean): string | null {
75+
const fieldValue = runtime.getHeapU32((baseAddress as any) + (fieldOffset || 0));
12576
if (fieldValue === 0) {
12677
return null;
12778
}
12879

12980
if (readBoolValueAsString) {
13081
// Some fields are stored as a union of bool | string | null values, but need to read as a string.
13182
// If the stored value is a bool, the behavior we want is empty string ('') for true, or null for false.
132-
const unboxedValue = BINDING.unbox_mono_obj(fieldValue as any as System_Object);
83+
84+
const unboxedValue = MONO_INTERNAL.monoObjectAsBoolOrNullUnsafe(fieldValue as any as System_Object);
13385
if (typeof (unboxedValue) === 'boolean') {
13486
return unboxedValue ? '' : null;
13587
}
136-
return unboxedValue;
13788
}
13889

139-
return BINDING.conv_string(fieldValue as any as System_String);
90+
return MONO_INTERNAL.monoStringToStringUnsafe(fieldValue as any as System_String);
14091
},
14192

14293
readStructField: function readStructField<T extends Pointer>(baseAddress: Pointer, fieldOffset?: number): T {
@@ -206,13 +157,12 @@ function prepareRuntimeConfig(options: Partial<WebAssemblyStartOptions>, onConfi
206157
jsInitializer = await fetchAndInvokeInitializers(options, loadedConfig);
207158
};
208159

209-
const moduleConfig = (window['Module'] || {}) as typeof Module;
160+
const moduleConfig = (window['Module'] || {}) as any;
210161
const dotnetModuleConfig: DotnetModuleConfig = {
211162
...moduleConfig,
212163
onConfigLoaded: (onConfigLoaded as (config: MonoConfig) => void | Promise<void>),
213164
onDownloadResourceProgress: setProgress,
214165
config,
215-
disableDotnet6Compatibility: false,
216166
out: print,
217167
err: printErr,
218168
};
@@ -251,10 +201,7 @@ async function configureRuntimeInstance(): Promise<PlatformApi> {
251201
throw new Error('The runtime must be loaded it gets configured.');
252202
}
253203

254-
const { MONO: mono, BINDING: binding, Module: module, setModuleImports, INTERNAL: mono_internal, getConfig, invokeLibraryInitializers } = runtime;
255-
Module = module;
256-
BINDING = binding;
257-
MONO = mono;
204+
const { setModuleImports, INTERNAL: mono_internal, getConfig, invokeLibraryInitializers } = runtime;
258205
MONO_INTERNAL = mono_internal;
259206

260207
attachDebuggerHotkey(getConfig());
@@ -285,7 +232,7 @@ function setProgress(resourcesLoaded, totalResources) {
285232

286233
const suppressMessages = ['DEBUGGING ENABLED'];
287234
const print = line => (suppressMessages.indexOf(line) < 0 && console.log(line));
288-
const printErr = line => {
235+
export const printErr = line => {
289236
// If anything writes to stderr, treat it as a critical exception. The underlying runtime writes
290237
// to stderr if a truly critical problem occurs outside .NET code. Note that .NET unhandled
291238
// exceptions also reach this, but via a different code path - see dotNetCriticalError below.

src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/Components/Web.JS/src/Platform/Platform.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
/* eslint-disable @typescript-eslint/ban-types */
5+
/* eslint-disable @typescript-eslint/no-unused-vars */
46
import { MonoObject, MonoString, MonoArray } from 'dotnet-runtime/dotnet-legacy';
57
import { WebAssemblyStartOptions } from './WebAssemblyStartOptions';
68
import { MonoConfig } from 'dotnet-runtime';
@@ -11,16 +13,12 @@ export interface Platform {
1113

1214
callEntryPoint(): Promise<unknown>;
1315

14-
toUint8Array(array: System_Array<unknown>): Uint8Array;
15-
16-
getArrayLength(array: System_Array<unknown>): number;
1716
getArrayEntryPtr<TPtr extends Pointer>(array: System_Array<TPtr>, index: number, itemSize: number): TPtr;
1817

1918
getObjectFieldsBaseAddress(referenceTypedObject: System_Object): Pointer;
2019
readInt16Field(baseAddress: Pointer, fieldOffset?: number): number;
2120
readInt32Field(baseAddress: Pointer, fieldOffset?: number): number;
2221
readUint64Field(baseAddress: Pointer, fieldOffset?: number): number;
23-
readFloatField(baseAddress: Pointer, fieldOffset?: number): number;
2422
readObjectField<T extends System_Object>(baseAddress: Pointer, fieldOffset?: number): T;
2523
readStringField(baseAddress: Pointer, fieldOffset?: number, readBoolValueAsString?: boolean): string | null;
2624
readStructField<T extends Pointer>(baseAddress: Pointer, fieldOffset?: number): T;

0 commit comments

Comments
 (0)