diff --git a/src/coreclr/hosts/corerun/CMakeLists.txt b/src/coreclr/hosts/corerun/CMakeLists.txt index 509cdf95b09af3..b3613dcf767a05 100644 --- a/src/coreclr/hosts/corerun/CMakeLists.txt +++ b/src/coreclr/hosts/corerun/CMakeLists.txt @@ -61,7 +61,7 @@ else() set(JS_SYSTEM_NATIVE_BROWSER "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.js") set(JS_SYSTEM_BROWSER_UTILS - "${STATIC_LIB_DESTINATION}/libSystem.Browser.Utils.js") + "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.Utils.js") set(JS_CORE_RUN "${CMAKE_CURRENT_SOURCE_DIR}/wasm/libCorerun.extpost.js") set_target_properties(corerun PROPERTIES diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 30cb047bc02ba2..4b649df6a6b8b7 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -271,8 +271,8 @@ - - + + diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.CoreCLR.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.CoreCLR.cs index df35ebf640f4dd..290dc72fcd28dd 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Locale.CoreCLR.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.CoreCLR.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static unsafe partial class JsGlobalization { - [LibraryImport(Libraries.JavaScriptNative, EntryPoint = "SystemJS_GetLocaleInfo")] + [LibraryImport(Libraries.SystemBrowserNative, EntryPoint = "SystemJS_GetLocaleInfo")] public static unsafe partial nint GetLocaleInfo(char* locale, int localeLength, char* culture, int cultureLength, char* buffer, int bufferLength, out int resultLength); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.Mono.cs similarity index 100% rename from src/libraries/Common/src/Interop/Browser/Interop.Locale.cs rename to src/libraries/Common/src/Interop/Browser/Interop.Locale.Mono.cs diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs index 1ea74c7c6aaff5..493c0113259762 100644 --- a/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs @@ -13,8 +13,9 @@ internal static partial class Libraries internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl"; internal const string CompressionNative = "libSystem.IO.Compression.Native"; internal const string GlobalizationNative = "libSystem.Globalization.Native"; + internal const string JavaScriptNative = "libSystem.Runtime.InteropServices.JavaScript.Native"; internal const string IOPortsNative = "libSystem.IO.Ports.Native"; internal const string HostPolicy = "libhostpolicy"; - internal const string JavaScriptNative = "libSystem.JavaScript.Native"; + internal const string SystemBrowserNative = "libSystem.Native.Browser"; } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index f8cf9733e24181..80981a2f3acaef 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1378,8 +1378,8 @@ Common\Interop\Browser\Interop.Locale.CoreCLR.cs - - Common\Interop\Browser\Interop.Locale.cs + + Common\Interop\Browser\Interop.Locale.Mono.cs Common\Interop\Interop.Calendar.cs diff --git a/src/libraries/externals.csproj b/src/libraries/externals.csproj index d689529b137efa..b83b9ac3e0810a 100644 --- a/src/libraries/externals.csproj +++ b/src/libraries/externals.csproj @@ -86,8 +86,8 @@ - - + + diff --git a/src/native/corehost/browserhost/CMakeLists.txt b/src/native/corehost/browserhost/CMakeLists.txt index 7c4bdfd3b3eb77..6173bee1ef0bd2 100644 --- a/src/native/corehost/browserhost/CMakeLists.txt +++ b/src/native/corehost/browserhost/CMakeLists.txt @@ -79,7 +79,7 @@ LIST(APPEND NATIVE_LIBS set(JS_SYSTEM_NATIVE_BROWSER "${SHARED_LIB_DESTINATION}/libSystem.Native.Browser.js") set(JS_SYSTEM_BROWSER_UTILS - "${SHARED_LIB_DESTINATION}/libSystem.Browser.Utils.js") + "${SHARED_LIB_DESTINATION}/libSystem.Native.Browser.Utils.js") set(JS_SYSTEM_RUNTIME_INTEROPSERVICES_JAVASCRIPT_NATIVE "${SHARED_LIB_DESTINATION}/libSystem.Runtime.InteropServices.JavaScript.Native.js") set(JS_BROWSER_HOST diff --git a/src/native/corehost/browserhost/ReadMe.md b/src/native/corehost/browserhost/ReadMe.md index c84b888122e964..042b5d9ee763a5 100644 --- a/src/native/corehost/browserhost/ReadMe.md +++ b/src/native/corehost/browserhost/ReadMe.md @@ -17,7 +17,7 @@ Implements native part of the CoreCLR host and exposes it as an internal JavaScr It is **Emscripten application** statically linked from libraries. - `libSystem.Native.Browser.js` linked -> `dotnet.native.js` -- `libSystem.Browser.Utils.js` linked -> `dotnet.native.js` +- `libSystem.Native.Browser.Utils.js` linked -> `dotnet.native.js` - `libSystem.Runtime.InteropServices.JavaScript.Native.js` linked -> `dotnet.native.js` - `libSystem.Native.Browser.a` linked -> `dotnet.native.wasm` - `libSystem.Runtime.InteropServices.JavaScript.Native.a` linked -> `dotnet.native.wasm` diff --git a/src/native/corehost/browserhost/browserhost.cpp b/src/native/corehost/browserhost/browserhost.cpp index 1350d13ad59b7d..14d26f295d1df6 100644 --- a/src/native/corehost/browserhost/browserhost.cpp +++ b/src/native/corehost/browserhost/browserhost.cpp @@ -68,7 +68,7 @@ static const void* pinvoke_override(const char* library_name, const char* entry_ { return SystemResolveDllImport(entry_point_name); } - if (strcmp(library_name, "libSystem.JavaScript.Native") == 0) + if (strcmp(library_name, "libSystem.Native.Browser") == 0) { return SystemJSResolveDllImport(entry_point_name); } diff --git a/src/native/corehost/browserhost/libBrowserHost.footer.js b/src/native/corehost/browserhost/libBrowserHost.footer.js index 8d89fdd829395f..dfedd5ce7875b4 100644 --- a/src/native/corehost/browserhost/libBrowserHost.footer.js +++ b/src/native/corehost/browserhost/libBrowserHost.footer.js @@ -45,12 +45,15 @@ !config.environmentVariables) { throw new Error("Invalid runtime config, cannot initialize the runtime."); } - const assemblyPaths = config.resources.assembly.map(a => a.virtualPath); - const coreAssemblyPaths = config.resources.coreAssembly.map(a => a.virtualPath); - ENV[HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES] = config.environmentVariables[HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES] = [...coreAssemblyPaths, ...assemblyPaths].join(":"); - ENV[HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES] = config.environmentVariables[HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES] = config.virtualWorkingDirectory; - ENV[HOST_PROPERTY_APP_PATHS] = config.environmentVariables[HOST_PROPERTY_APP_PATHS] = config.virtualWorkingDirectory; - ENV[HOST_PROPERTY_ENTRY_ASSEMBLY_NAME] = config.environmentVariables[HOST_PROPERTY_ENTRY_ASSEMBLY_NAME] = config.mainAssemblyName; + const assemblyPaths = config.resources.assembly.map(a => "/" + a.virtualPath); + const coreAssemblyPaths = config.resources.coreAssembly.map(a => "/" + a.virtualPath); + config.environmentVariables[HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES] = [...coreAssemblyPaths, ...assemblyPaths].join(":"); + config.environmentVariables[HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES] = config.virtualWorkingDirectory; + config.environmentVariables[HOST_PROPERTY_APP_PATHS] = config.virtualWorkingDirectory; + config.environmentVariables[HOST_PROPERTY_ENTRY_ASSEMBLY_NAME] = config.mainAssemblyName; + for (const key in config.environmentVariables) { + ENV[key] = config.environmentVariables[key]; + } if (ENVIRONMENT_IS_NODE) { Module.preInit = [() => { diff --git a/src/native/corehost/browserhost/loader/assets.ts b/src/native/corehost/browserhost/loader/assets.ts new file mode 100644 index 00000000000000..c214e61b8f4a5b --- /dev/null +++ b/src/native/corehost/browserhost/loader/assets.ts @@ -0,0 +1,129 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { LoadBootResourceCallback, JsModuleExports, JsAsset, AssemblyAsset, PdbAsset, WasmAsset, IcuAsset, EmscriptenModuleInternal, InstantiateWasmSuccessCallback } from "./types"; + +import { dotnetAssert, dotnetGetInternals, dotnetBrowserHostExports, dotnetUpdateInternals } from "./cross-module"; +import { getIcuResourceName } from "./icu"; +import { getLoaderConfig } from "./config"; +import { BrowserHost_InitializeCoreCLR } from "./run"; +import { createPromiseCompletionSource } from "./promise-completion-source"; +import { locateFile } from "./bootstrap"; +import { fetchLike } from "./polyfills"; + +const nativeModulePromiseController = createPromiseCompletionSource(() => { + dotnetUpdateInternals(dotnetGetInternals()); +}); +let wasmBinaryPromise: any = undefined; + +// WASM-TODO: retry logic +// WASM-TODO: throttling logic +// WASM-TODO: invokeLibraryInitializers +// WASM-TODO: webCIL +// WASM-TODO: downloadOnly - blazor render mode auto pre-download. Really no start. +// WASM-TODO: no-cache, force-cache, integrity +// WASM-TODO: LoadBootResourceCallback +// WASM-TODO: fail fast for missing WASM features - SIMD, EH, BigInt detection + +export async function createRuntime(downloadOnly: boolean, loadBootResource?: LoadBootResourceCallback): Promise { + if (loadBootResource) throw new Error("TODO: loadBootResource is not implemented yet"); + const config = getLoaderConfig(); + if (!config.resources || !config.resources.coreAssembly || !config.resources.coreAssembly.length) throw new Error("Invalid config, resources is not set"); + + const nativeModulePromise = loadJSModule(config.resources.jsModuleNative[0]); + const runtimeModulePromise = loadJSModule(config.resources.jsModuleRuntime[0]); + const wasmNativePromise = fetchWasm(config.resources.wasmNative[0]); + + const coreAssembliesPromise = Promise.all(config.resources.coreAssembly.map(fetchDll)); + const coreVfsPromise = Promise.all((config.resources.coreVfs || []).map(fetchVfs)); + const assembliesPromise = Promise.all(config.resources.assembly.map(fetchDll)); + const vfsPromise = Promise.all((config.resources.vfs || []).map(fetchVfs)); + const icuResourceName = getIcuResourceName(config); + const icuDataPromise = icuResourceName ? Promise.all((config.resources.icu || []).filter(asset => asset.name === icuResourceName).map(fetchIcu)) : Promise.resolve([]); + + const nativeModule = await nativeModulePromise; + const modulePromise = nativeModule.dotnetInitializeModule(dotnetGetInternals()); + nativeModulePromiseController.propagateFrom(modulePromise); + + const runtimeModule = await runtimeModulePromise; + const runtimeModuleReady = runtimeModule.dotnetInitializeModule(dotnetGetInternals()); + + await nativeModulePromiseController.promise; + await coreAssembliesPromise; + await coreVfsPromise; + await vfsPromise; + await icuDataPromise; + await wasmNativePromise; // this is just to propagate errors + if (!downloadOnly) { + BrowserHost_InitializeCoreCLR(); + } + + await assembliesPromise; + await runtimeModuleReady; +} + +async function loadJSModule(asset: JsAsset): Promise { + if (asset.name && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(asset.name); + } + if (!asset.resolvedUrl) throw new Error("Invalid config, resources is not set"); + return await import(/* webpackIgnore: true */ asset.resolvedUrl); +} + +function fetchWasm(asset: WasmAsset): Promise { + if (asset.name && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(asset.name); + } + if (!asset.resolvedUrl) throw new Error("Invalid config, resources is not set"); + wasmBinaryPromise = fetchLike(asset.resolvedUrl); + return wasmBinaryPromise; +} + +export async function instantiateWasm(imports: WebAssembly.Imports, successCallback: InstantiateWasmSuccessCallback): Promise { + if (wasmBinaryPromise instanceof globalThis.Response === false || !WebAssembly.instantiateStreaming) { + const res = await wasmBinaryPromise; + const data = await res.arrayBuffer(); + const module = await WebAssembly.compile(data); + const instance = await WebAssembly.instantiate(module, imports); + successCallback(instance, module); + } else { + const res = await WebAssembly.instantiateStreaming(wasmBinaryPromise, imports); + successCallback(res.instance, res.module); + } +} + +async function fetchIcu(asset: IcuAsset): Promise { + if (asset.name && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(asset.name); + } + const bytes = await fetchBytes(asset); + await nativeModulePromiseController.promise; + dotnetBrowserHostExports.loadIcuData(bytes); +} + +async function fetchDll(asset: AssemblyAsset): Promise { + if (asset.name && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(asset.name); + } + const bytes = await fetchBytes(asset); + await nativeModulePromiseController.promise; + + dotnetBrowserHostExports.registerDllBytes(bytes, asset); +} + +async function fetchVfs(asset: AssemblyAsset): Promise { + if (asset.name && !asset.resolvedUrl) { + asset.resolvedUrl = locateFile(asset.name); + } + const bytes = await fetchBytes(asset); + await nativeModulePromiseController.promise; + + dotnetBrowserHostExports.installVfsFile(bytes, asset); +} + +async function fetchBytes(asset: WasmAsset | AssemblyAsset | PdbAsset | IcuAsset): Promise { + dotnetAssert.check(asset && asset.resolvedUrl, "Bad asset.resolvedUrl"); + const response = await fetchLike(asset.resolvedUrl); + const buffer = await response.arrayBuffer(); + return new Uint8Array(buffer); +} diff --git a/src/native/corehost/browserhost/loader/bootstrap.ts b/src/native/corehost/browserhost/loader/bootstrap.ts index 4083099ad56d75..b2f7843759065e 100644 --- a/src/native/corehost/browserhost/loader/bootstrap.ts +++ b/src/native/corehost/browserhost/loader/bootstrap.ts @@ -1,13 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { LoadBootResourceCallback, JsModuleExports, JsAsset, AssemblyAsset, PdbAsset, WasmAsset, IcuAsset, EmscriptenModuleInternal, LoaderConfig, DotnetHostBuilder } from "./types"; -import { dotnetAssert, dotnetGetInternals, dotnetBrowserHostExports, dotnetUpdateInternals } from "./cross-module"; +import { type LoaderConfig, type DotnetHostBuilder, GlobalizationMode } from "./types"; import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL } from "./per-module"; -import { getIcuResourceName } from "./icu"; -import { getLoaderConfig } from "./config"; -import { BrowserHost_InitializeCoreCLR } from "./run"; -import { createPromiseCompletionSource } from "./promise-completion-source"; import { nodeFs } from "./polyfills"; const scriptUrlQuery = /*! webpackIgnore: true */import.meta.url; @@ -16,110 +11,7 @@ const modulesUniqueQuery = queryIndex > 0 ? scriptUrlQuery.substring(queryIndex) const scriptUrl = normalizeFileUrl(scriptUrlQuery); const scriptDirectory = normalizeDirectoryUrl(scriptUrl); -const nativeModulePromiseController = createPromiseCompletionSource(() => { - dotnetUpdateInternals(dotnetGetInternals()); -}); - -// WASM-TODO: retry logic -// WASM-TODO: throttling logic -// WASM-TODO: invokeLibraryInitializers -// WASM-TODO: webCIL -// WASM-TODO: downloadOnly - blazor render mode auto pre-download. Really no start. - -export async function createRuntime(downloadOnly: boolean, loadBootResource?: LoadBootResourceCallback): Promise { - const config = getLoaderConfig(); - if (!config.resources || !config.resources.coreAssembly || !config.resources.coreAssembly.length) throw new Error("Invalid config, resources is not set"); - - const nativeModulePromise = loadJSModule(config.resources.jsModuleNative[0], loadBootResource); - const runtimeModulePromise = loadJSModule(config.resources.jsModuleRuntime[0], loadBootResource); - const coreAssembliesPromise = Promise.all(config.resources.coreAssembly.map(fetchDll)); - const coreVfsPromise = Promise.all((config.resources.coreVfs || []).map(fetchVfs)); - const assembliesPromise = Promise.all(config.resources.assembly.map(fetchDll)); - const vfsPromise = Promise.all((config.resources.vfs || []).map(fetchVfs)); - const icuResourceName = getIcuResourceName(config); - const icuDataPromise = icuResourceName ? Promise.all((config.resources.icu || []).filter(asset => asset.name === icuResourceName).map(fetchIcu)) : Promise.resolve([]); - // WASM-TODO fetchWasm(config.resources.wasmNative[0]);// start loading early, no await - - const nativeModule = await nativeModulePromise; - const modulePromise = nativeModule.dotnetInitializeModule(dotnetGetInternals()); - nativeModulePromiseController.propagateFrom(modulePromise); - - const runtimeModule = await runtimeModulePromise; - const runtimeModuleReady = runtimeModule.dotnetInitializeModule(dotnetGetInternals()); - - await nativeModulePromiseController.promise; - await coreAssembliesPromise; - await coreVfsPromise; - await vfsPromise; - await icuDataPromise; - if (!downloadOnly) { - BrowserHost_InitializeCoreCLR(); - } - - await assembliesPromise; - await runtimeModuleReady; -} - -async function loadJSModule(asset: JsAsset, loadBootResource?: LoadBootResourceCallback): Promise { - if (loadBootResource) throw new Error("TODO: loadBootResource is not implemented yet"); - if (asset.name && !asset.resolvedUrl) { - asset.resolvedUrl = locateFile(asset.name); - } - if (!asset.resolvedUrl) throw new Error("Invalid config, resources is not set"); - return await import(/* webpackIgnore: true */ asset.resolvedUrl); -} - -async function fetchIcu(asset: IcuAsset): Promise { - if (asset.name && !asset.resolvedUrl) { - asset.resolvedUrl = locateFile(asset.name); - } - const bytes = await fetchBytes(asset); - await nativeModulePromiseController.promise; - dotnetBrowserHostExports.loadIcuData(bytes); -} - -async function fetchDll(asset: AssemblyAsset): Promise { - if (asset.name && !asset.resolvedUrl) { - asset.resolvedUrl = locateFile(asset.name); - } - const bytes = await fetchBytes(asset); - await nativeModulePromiseController.promise; - - dotnetBrowserHostExports.registerDllBytes(bytes, asset); -} - -async function fetchVfs(asset: AssemblyAsset): Promise { - if (asset.name && !asset.resolvedUrl) { - asset.resolvedUrl = locateFile(asset.name); - } - const bytes = await fetchBytes(asset); - await nativeModulePromiseController.promise; - - dotnetBrowserHostExports.installVfsFile(bytes, asset); -} - -async function fetchBytes(asset: WasmAsset | AssemblyAsset | PdbAsset | IcuAsset): Promise { - dotnetAssert.check(asset && asset.resolvedUrl, "Bad asset.resolvedUrl"); - if (ENVIRONMENT_IS_NODE) { - const { promises: fs } = await import("fs"); - const { fileURLToPath } = await import(/*! webpackIgnore: true */"url"); - const isFileUrl = asset.resolvedUrl!.startsWith("file://"); - if (isFileUrl) { - asset.resolvedUrl = fileURLToPath(asset.resolvedUrl!); - } - const buffer = await fs.readFile(asset.resolvedUrl!); - return new Uint8Array(buffer); - } else { - const response = await fetch(asset.resolvedUrl!); - if (!response.ok) { - throw new Error(`Failed to load ${asset.resolvedUrl} with ${response.status} ${response.statusText}`); - } - const buffer = await response.arrayBuffer(); - return new Uint8Array(buffer); - } -} - -function locateFile(path: string) { +export function locateFile(path: string) { if ("URL" in globalThis) { return new URL(path, scriptDirectory).toString(); } @@ -192,17 +84,34 @@ export async function findResources(dotnet: DotnetHostBuilder): Promise { const json = await fs.promises.readFile(runtimeConfigName, { encoding: "utf8" }); runtimeConfig = JSON.parse(json); } + const icus = files + .filter(file => file.startsWith("icudt") && file.endsWith(".dat")) + .map(filename => { + // filename without path + const name = filename.substring(filename.lastIndexOf("/") + 1); + return { virtualPath: name, name }; + }); + + const environmentVariables: { [key: string]: string } = {}; + let globalizationMode = GlobalizationMode.All; + if (!icus.length) { + globalizationMode = GlobalizationMode.Invariant; + environmentVariables["DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"] = "1"; + } const config: LoaderConfig = { mainAssemblyName, runtimeConfig, + globalizationMode, virtualWorkingDirectory: mountedDir, + environmentVariables, resources: { jsModuleNative: [{ name: "dotnet.native.js" }], jsModuleRuntime: [{ name: "dotnet.runtime.js" }], wasmNative: [{ name: "dotnet.native.wasm", }], coreAssembly: [{ virtualPath: mountedDir + "/System.Private.CoreLib.dll", name: "System.Private.CoreLib.dll" },], assembly: assemblies, + icu: icus, } }; dotnet.withConfig(config); diff --git a/src/native/corehost/browserhost/loader/dotnet.d.ts b/src/native/corehost/browserhost/loader/dotnet.d.ts index bb4e95306d7729..17df552d1ac178 100644 --- a/src/native/corehost/browserhost/loader/dotnet.d.ts +++ b/src/native/corehost/browserhost/loader/dotnet.d.ts @@ -773,10 +773,6 @@ declare global { function getDotnetRuntime(runtimeId: number): RuntimeAPI | undefined; } -declare global { - function getDotnetRuntime(runtimeId: number): RuntimeAPI | undefined; - const dotnetSidecar: boolean | undefined; -} declare const createDotnetRuntime: CreateDotnetRuntimeType; export { GlobalizationMode, createDotnetRuntime as default, dotnet, exit }; diff --git a/src/native/corehost/browserhost/loader/dotnet.ts b/src/native/corehost/browserhost/loader/dotnet.ts index f9fc7fe6d1138c..6a1b68cf62618e 100644 --- a/src/native/corehost/browserhost/loader/dotnet.ts +++ b/src/native/corehost/browserhost/loader/dotnet.ts @@ -23,5 +23,7 @@ await initPolyfillsAsync(); export const dotnet: DotnetHostBuilder | undefined = new HostBuilder() as DotnetHostBuilder; export { exit }; +dotnet.withConfig(/*! dotnetBootConfig */{}); + // Auto-start when in Node.js or Shell environment selfHostNodeJS(dotnet!).catch(); diff --git a/src/native/corehost/browserhost/loader/host-builder.ts b/src/native/corehost/browserhost/loader/host-builder.ts index 4114eaa1aeec65..465f60ae7fbd7d 100644 --- a/src/native/corehost/browserhost/loader/host-builder.ts +++ b/src/native/corehost/browserhost/loader/host-builder.ts @@ -5,7 +5,7 @@ import type { DotnetHostBuilder, LoaderConfig, RuntimeAPI, LoadBootResourceCallb import { Module, dotnetApi } from "./cross-module"; import { getLoaderConfig, mergeLoaderConfig, validateLoaderConfig } from "./config"; -import { createRuntime } from "./bootstrap"; +import { createRuntime } from "./assets"; import { exit } from "./exit"; let applicationArguments: string[] | undefined = []; diff --git a/src/native/corehost/browserhost/loader/icu.ts b/src/native/corehost/browserhost/loader/icu.ts index 1e0d9359d4a518..6aef6afa31e86d 100644 --- a/src/native/corehost/browserhost/loader/icu.ts +++ b/src/native/corehost/browserhost/loader/icu.ts @@ -33,6 +33,7 @@ export function getIcuResourceName(config: LoaderConfig): string | null { } config.globalizationMode = GlobalizationMode.Invariant; + config.environmentVariables!["DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"] = "1"; return null; } diff --git a/src/native/corehost/browserhost/loader/index.ts b/src/native/corehost/browserhost/loader/index.ts index 63eb64cdd35c5a..241edb02e9b234 100644 --- a/src/native/corehost/browserhost/loader/index.ts +++ b/src/native/corehost/browserhost/loader/index.ts @@ -3,7 +3,8 @@ import type { LoggerType, AssertType, RuntimeAPI, LoaderExports, - NativeBrowserExportsTable, LoaderExportsTable, RuntimeExportsTable, InternalExchange, BrowserHostExportsTable, InteropJavaScriptExportsTable, BrowserUtilsExportsTable + NativeBrowserExportsTable, LoaderExportsTable, RuntimeExportsTable, InternalExchange, BrowserHostExportsTable, InteropJavaScriptExportsTable, BrowserUtilsExportsTable, + EmscriptenModuleInternal } from "./types"; import { InternalExchangeIndex } from "../types"; @@ -19,6 +20,7 @@ import { check, error, info, warn, debug } from "./logging"; import { dotnetAssert, dotnetLoaderExports, dotnetLogger, dotnetUpdateInternals, dotnetUpdateInternalsSubscriber } from "./cross-module"; import { rejectRunMainPromise, resolveRunMainPromise, getRunMainPromise } from "./run"; import { createPromiseCompletionSource, getPromiseCompletionSource, isControllablePromise } from "./promise-completion-source"; +import { instantiateWasm } from "./assets"; export function dotnetInitializeModule(): RuntimeAPI { @@ -71,6 +73,12 @@ export function dotnetInitializeModule(): RuntimeAPI { }; Object.assign(dotnetAssert, assert); + // emscripten extension point + const localModule: Partial = { + instantiateWasm, + }; + Object.assign(dotnetApi.Module!, localModule); + internals[InternalExchangeIndex.LoaderExportsTable] = loaderExportsToTable(dotnetLogger, dotnetAssert, dotnetLoaderExports); dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber); return dotnetApi as RuntimeAPI; diff --git a/src/native/libs/Common/JavaScript/CMakeLists.txt b/src/native/libs/Common/JavaScript/CMakeLists.txt index a4a5842dbd7d5e..b01a16cef84b98 100644 --- a/src/native/libs/Common/JavaScript/CMakeLists.txt +++ b/src/native/libs/Common/JavaScript/CMakeLists.txt @@ -12,14 +12,17 @@ set(ROLLUP_TS_SOURCES "${CLR_SRC_NATIVE_DIR}/rollup.config.defines.js" "${CLR_SRC_NATIVE_DIR}/rollup.config.plugins.js" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/libBrowserHost.footer.js" - "${CLR_SRC_NATIVE_DIR}/libs/System.Native.Browser/libSystem.Browser.Utils.footer.js" + "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/sample/dotnet.boot.js" + "${CLR_SRC_NATIVE_DIR}/libs/System.Native.Browser/libSystem.Native.Browser.Utils.footer.js" "${CLR_SRC_NATIVE_DIR}/libs/System.Native.Browser/libSystem.Native.Browser.extpost.js" "${CLR_SRC_NATIVE_DIR}/libs/System.Native.Browser/libSystem.Native.Browser.footer.js" "${CLR_SRC_NATIVE_DIR}/libs/System.Runtime.InteropServices.JavaScript.Native/libSystem.Runtime.InteropServices.JavaScript.Native.footer.js" + "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/host/cross-linked.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/host/host.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/host/index.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/host/types.ts" + "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/assets.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/bootstrap.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/config.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/cross-module.ts" @@ -27,6 +30,7 @@ set(ROLLUP_TS_SOURCES "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/dotnet.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/exit.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/host-builder.ts" + "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/icu.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/index.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/lib-initializers.ts" "${CLR_SRC_NATIVE_DIR}/corehost/browserhost/loader/logging.ts" @@ -87,8 +91,8 @@ set(ROLLUP_OUTPUTS "${STATIC_LIB_DESTINATION}/libBrowserHost.js.map" "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.js" "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.js.map" - "${STATIC_LIB_DESTINATION}/libSystem.Browser.Utils.js" - "${STATIC_LIB_DESTINATION}/libSystem.Browser.Utils.js.map" + "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.Utils.js" + "${STATIC_LIB_DESTINATION}/libSystem.Native.Browser.Utils.js.map" "${STATIC_LIB_DESTINATION}/dotnet.runtime.js" "${STATIC_LIB_DESTINATION}/dotnet.runtime.js.map" "${STATIC_LIB_DESTINATION}/dotnet.diagnostics.js" diff --git a/src/native/libs/Common/JavaScript/cross-linked/index.ts b/src/native/libs/Common/JavaScript/cross-linked/index.ts index 59daab0da57af1..2700568e6bada0 100644 --- a/src/native/libs/Common/JavaScript/cross-linked/index.ts +++ b/src/native/libs/Common/JavaScript/cross-linked/index.ts @@ -4,7 +4,7 @@ import type { AssertType, EmscriptenModuleInternal, LoggerType, LoaderExports, InternalExchange, InternalExchangeSubscriber, RuntimeAPI, BrowserUtilsExports, NativePointer, CharPtr, VoidPtr, RuntimeExports } from "../types"; // we want to use the cross-module symbols defined in closure of dotnet.native.js -// which are installed there by libSystem.Browser.Utils.footer.js +// which are installed there by libSystem.Native.Browser.Utils.footer.js // see also `reserved` in `rollup.config.defines.js` declare global { export const dotnetApi: RuntimeAPI; diff --git a/src/native/libs/Common/JavaScript/cross-module/index.ts b/src/native/libs/Common/JavaScript/cross-module/index.ts index 2ad7099edae221..d0821b10cc09cd 100644 --- a/src/native/libs/Common/JavaScript/cross-module/index.ts +++ b/src/native/libs/Common/JavaScript/cross-module/index.ts @@ -156,6 +156,7 @@ export function dotnetUpdateInternalsSubscriber() { stringToUTF16Ptr: table[2], stringToUTF8Ptr: table[3], zeroRegion: table[4], + isSharedArrayBuffer: table[5], }; Object.assign(interop, interopLocal); } diff --git a/src/native/libs/Common/JavaScript/per-module/index.ts b/src/native/libs/Common/JavaScript/per-module/index.ts index 532437903bcd19..8858f9084f1885 100644 --- a/src/native/libs/Common/JavaScript/per-module/index.ts +++ b/src/native/libs/Common/JavaScript/per-module/index.ts @@ -3,7 +3,7 @@ export const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; export const ENVIRONMENT_IS_WEB_WORKER = typeof importScripts == "function"; -export const ENVIRONMENT_IS_SIDECAR = ENVIRONMENT_IS_WEB_WORKER && typeof dotnetSidecar !== "undefined"; // sidecar is emscripten main running in a web worker +export const ENVIRONMENT_IS_SIDECAR = ENVIRONMENT_IS_WEB_WORKER && typeof (globalThis as any).dotnetSidecar !== "undefined"; // sidecar is emscripten main running in a web worker export const ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_SIDECAR; // we redefine what ENVIRONMENT_IS_WORKER, we replace it in emscripten internals, so that sidecar works export const ENVIRONMENT_IS_WEB = typeof window == "object" || (ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_NODE); export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE; diff --git a/src/native/libs/Common/JavaScript/types/exchange.ts b/src/native/libs/Common/JavaScript/types/exchange.ts index 5222954bc0595a..fcb988b447ee97 100644 --- a/src/native/libs/Common/JavaScript/types/exchange.ts +++ b/src/native/libs/Common/JavaScript/types/exchange.ts @@ -5,7 +5,7 @@ import type { installVfsFile, registerDllBytes, loadIcuData } from "../../../../ import type { check, error, info, warn, debug } from "../../../../corehost/browserhost/loader/logging"; import type { createPromiseCompletionSource, getPromiseCompletionSource, isControllablePromise } from "../../../../corehost/browserhost/loader/promise-completion-source"; import type { resolveRunMainPromise, rejectRunMainPromise, getRunMainPromise } from "../../../../corehost/browserhost/loader/run"; -import type { zeroRegion } from "../../../System.Native.Browser/utils/memory"; +import type { isSharedArrayBuffer, zeroRegion } from "../../../System.Native.Browser/utils/memory"; import type { stringToUTF16, stringToUTF16Ptr, stringToUTF8Ptr, utf16ToString } from "../../../System.Native.Browser/utils/strings"; export type RuntimeExports = { @@ -78,6 +78,7 @@ export type BrowserUtilsExports = { stringToUTF16Ptr: typeof stringToUTF16Ptr, stringToUTF8Ptr: typeof stringToUTF8Ptr, zeroRegion: typeof zeroRegion, + isSharedArrayBuffer: typeof isSharedArrayBuffer } export type BrowserUtilsExportsTable = [ @@ -86,4 +87,5 @@ export type BrowserUtilsExportsTable = [ typeof stringToUTF16Ptr, typeof stringToUTF8Ptr, typeof zeroRegion, + typeof isSharedArrayBuffer, ] diff --git a/src/native/libs/Common/JavaScript/types/export-api.ts b/src/native/libs/Common/JavaScript/types/export-api.ts index 90d65cc84dd041..59281204a5fe10 100644 --- a/src/native/libs/Common/JavaScript/types/export-api.ts +++ b/src/native/libs/Common/JavaScript/types/export-api.ts @@ -4,12 +4,6 @@ import type { CreateDotnetRuntimeType, DotnetHostBuilder, DotnetModuleConfig, ModuleAPI, LoaderConfig, IMemoryView, AssetEntry, GlobalizationMode, AssetBehaviors, RuntimeAPI, dotnet, exit } from "./public-api"; import type { EmscriptenModule } from "./emscripten"; -// Here, declare things that go in the global namespace, or augment existing declarations in the global namespace -declare global { - function getDotnetRuntime(runtimeId: number): RuntimeAPI | undefined; - const dotnetSidecar: boolean | undefined; -} - declare const createDotnetRuntime: CreateDotnetRuntimeType; export default createDotnetRuntime; diff --git a/src/native/libs/System.Native.Browser/ReadMe.md b/src/native/libs/System.Native.Browser/ReadMe.md index 19b1cc2f2e823d..4005d0792d07f5 100644 --- a/src/native/libs/System.Native.Browser/ReadMe.md +++ b/src/native/libs/System.Native.Browser/ReadMe.md @@ -8,9 +8,9 @@ And a native library compiled by CMake into `libSystem.Native.Browser.a` as part ## Emscripten library - `native/index` compiled -> `libSystem.Native.Browser.js` linked ->`dotnet.native.js` - `libSystem.Native.Browser.footer.js` compiled -> `libSystem.Native.Browser.js` linked ->`dotnet.native.js` -- `libSystem.Browser.Utils.footer.js` compiled -> `libSystem.Browser.Utils.js` linked ->`dotnet.native.js` +- `libSystem.Native.Browser.Utils.footer.js` compiled -> `libSystem.Native.Browser.Utils.js` linked ->`dotnet.native.js` - `libSystem.Native.Browser.extpost.js` linked ->`dotnet.native.js` -- `ententrypoints.c` compiled -> `libSystem.Native.Browser.a` linked -> `dotnet.native.wasm` +- `entrypoints.c` compiled -> `libSystem.Native.Browser.a` linked -> `dotnet.native.wasm` ## Build TypeScript is compiled by `src/native/rollup.config.js` diff --git a/src/native/libs/System.Native.Browser/libSystem.Browser.Utils.footer.js b/src/native/libs/System.Native.Browser/libSystem.Native.Browser.Utils.footer.js similarity index 100% rename from src/native/libs/System.Native.Browser/libSystem.Browser.Utils.footer.js rename to src/native/libs/System.Native.Browser/libSystem.Native.Browser.Utils.footer.js diff --git a/src/native/libs/System.Native.Browser/native/crypto.ts b/src/native/libs/System.Native.Browser/native/crypto.ts index db2d03832513d2..2143d94ad20b47 100644 --- a/src/native/libs/System.Native.Browser/native/crypto.ts +++ b/src/native/libs/System.Native.Browser/native/crypto.ts @@ -22,7 +22,7 @@ export function SystemJS_RandomBytes(bufferPtr: number, bufferLength: number): n const targetView = memoryView.subarray(bufferPtr, bufferPtr + bufferLength); // When threading is enabled, Chrome doesn't want SharedArrayBuffer to be passed to crypto APIs - const needsCopy = false;//TODOHelpers.isSharedArrayBuffer(memoryView.buffer); + const needsCopy = dotnetBrowserUtilsExports.isSharedArrayBuffer(memoryView.buffer); const targetBuffer = needsCopy ? new Uint8Array(bufferLength) : targetView; diff --git a/src/native/libs/System.Native.Browser/native/globalization-locale.ts b/src/native/libs/System.Native.Browser/native/globalization-locale.ts index 76d770ff51a795..0687aa5b44c7c0 100644 --- a/src/native/libs/System.Native.Browser/native/globalization-locale.ts +++ b/src/native/libs/System.Native.Browser/native/globalization-locale.ts @@ -13,7 +13,7 @@ export function SystemJS_GetLocaleInfo(culture: number, cultureLength: number, l if (!localeName && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code dotnetBrowserUtilsExports.stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); - dotnetApi.setHeapI32( dstLength, localeNameOriginal.length); + dotnetApi.setHeapI32(dstLength, localeNameOriginal.length); return VoidPtrNull; } const cultureNameOriginal = dotnetBrowserUtilsExports.utf16ToString(culture, (culture + 2 * cultureLength)); @@ -79,8 +79,8 @@ export function SystemJS_GetLocaleInfo(culture: number, cultureLength: number, l try { locale = locale.toLocaleLowerCase().replace("_", "-"); if (locale.startsWith("zh-")) { - // browser does not recognize "zh-chs" and "zh-cht" as equivalents of "zh-Hans" "zh-Hant", we are helping, otherwise - // it would throw on getCanonicalLocales with "RangeError: Incorrect locale information provided" + // browser does not recognize "zh-chs" and "zh-cht" as equivalents of "zh-Hans" "zh-Hant", we are helping, otherwise + // it would throw on getCanonicalLocales with "RangeError: Incorrect locale information provided" locale = locale.replace("-chs", "-Hans").replace("-cht", "-Hant"); } const canonicalLocales = (Intl as any).getCanonicalLocales(locale); diff --git a/src/native/libs/System.Native.Browser/utils/index.ts b/src/native/libs/System.Native.Browser/utils/index.ts index 8328cb2b486a57..7e4cfa6577c8f4 100644 --- a/src/native/libs/System.Native.Browser/utils/index.ts +++ b/src/native/libs/System.Native.Browser/utils/index.ts @@ -10,6 +10,7 @@ import { getHeapB32, getHeapB8, getHeapU8, getHeapU16, getHeapU32, getHeapI8, getHeapI16, getHeapI32, getHeapI52, getHeapU52, getHeapI64Big, getHeapF32, getHeapF64, localHeapViewI8, localHeapViewI16, localHeapViewI32, localHeapViewI64Big, localHeapViewU8, localHeapViewU16, localHeapViewU32, localHeapViewF32, localHeapViewF64, zeroRegion, + isSharedArrayBuffer, } from "./memory"; import { stringToUTF16, stringToUTF16Ptr, stringToUTF8Ptr, utf16ToString } from "./strings"; import { exit, setEnvironmentVariable } from "./host"; @@ -41,6 +42,7 @@ export function dotnetInitializeModule(internals: InternalExchange): void { stringToUTF16Ptr, stringToUTF8Ptr, zeroRegion, + isSharedArrayBuffer, }); dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber); function browserUtilsExportsToTable(map: BrowserUtilsExports): BrowserUtilsExportsTable { @@ -51,6 +53,7 @@ export function dotnetInitializeModule(internals: InternalExchange): void { map.stringToUTF16Ptr, map.stringToUTF8Ptr, map.zeroRegion, + map.isSharedArrayBuffer, ]; } } diff --git a/src/native/libs/System.Native.Browser/utils/memory.ts b/src/native/libs/System.Native.Browser/utils/memory.ts index bb6484c04be3e3..9b9fb60dd0c617 100644 --- a/src/native/libs/System.Native.Browser/utils/memory.ts +++ b/src/native/libs/System.Native.Browser/utils/memory.ts @@ -139,12 +139,12 @@ export function getHeapU16_local(localView: Uint16Array, offset: MemOffset): num } export function getHeapU32(offset: MemOffset): number { - return Module.HEAPU32[offset >>> 2]; + return Module.HEAPU32[offset >>> 2] >>> 0; } // does not check for growable heap export function getHeapU32_local(localView: Uint32Array, offset: MemOffset): number { - return localView[offset >>> 2]; + return localView[offset >>> 2] >>> 0; } export function getHeapI8(offset: MemOffset): number { diff --git a/src/native/rollup.config.js b/src/native/rollup.config.js index c3ac696471176b..a0504349a19c18 100644 --- a/src/native/rollup.config.js +++ b/src/native/rollup.config.js @@ -74,8 +74,8 @@ const libBrowserUtils = configure({ output: [{ name: "libBrowserUtils", format: "iife", - file: staticLibDestination + "/libSystem.Browser.Utils.js", - footer: await fs.readFile("./libs/System.Native.Browser/libSystem.Browser.Utils.footer.js"), + file: staticLibDestination + "/libSystem.Native.Browser.Utils.js", + footer: await fs.readFile("./libs/System.Native.Browser/libSystem.Native.Browser.Utils.footer.js"), }], terser: { compress: {