Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion src/coreclr/hosts/corerun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@
<PlatformManifestFileEntry Include="libnativeresourcestring.a" IsNative="true" />
<PlatformManifestFileEntry Include="libBrowserHost.js" IsNative="true" />
<PlatformManifestFileEntry Include="libBrowserHost.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Browser.Utils.js" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Browser.Utils.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Native.Browser.Utils.js" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Native.Browser.Utils.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Native.Browser.js" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Native.Browser.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="libSystem.Runtime.InteropServices.JavaScript.Native.js" IsNative="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
3 changes: 2 additions & 1 deletion src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1378,8 +1378,8 @@
<Compile Include="$(CommonPath)Interop\Browser\Interop.Locale.CoreCLR.cs" Condition="'$(TargetsBrowser)' == 'true' and '$(RuntimeFlavor)' == 'CoreCLR'">
<Link>Common\Interop\Browser\Interop.Locale.CoreCLR.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Browser\Interop.Locale.cs" Condition="'$(TargetsBrowser)' == 'true' and '$(RuntimeFlavor)' == 'Mono'">
<Link>Common\Interop\Browser\Interop.Locale.cs</Link>
<Compile Include="$(CommonPath)Interop\Browser\Interop.Locale.Mono.cs" Condition="'$(TargetsBrowser)' == 'true' and '$(RuntimeFlavor)' == 'Mono'">
<Link>Common\Interop\Browser\Interop.Locale.Mono.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Interop.Calendar.cs">
<Link>Common\Interop\Interop.Calendar.cs</Link>
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/externals.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
<RuntimeFiles Include="@(HostPolicyFile)" Condition="Exists('@(HostPolicyFile)')" />
<RuntimeFiles Include="@(_HostSymbols)" Condition="Exists('@(_HostSymbols)')" IsNative="true" />
<!-- CoreRun is not used for testing anymore, but we still use it for benchmarking and profiling -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\corerun*" Condition="'$(TargetsAndroid)' != 'true'" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\corerun*" Condition="'$(TargetsAndroid)' != 'true'" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\corerun*" Condition="'$(TargetsAndroid)' != 'true' and '$(TargetsBrowser)' != 'true'" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\corerun*" Condition="'$(TargetsAndroid)' != 'true' and '$(TargetsBrowser)' != 'true'" />
<!-- Include cDAC reader library
TODO: [cdac] Remove once cdacreader is added to shipping shared framework -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\*mscordaccore_universal*" />
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/browserhost/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/browserhost/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.footer.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`
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/browserhost/browserhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
15 changes: 9 additions & 6 deletions src/native/corehost/browserhost/libBrowserHost.footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [() => {
Expand Down
152 changes: 152 additions & 0 deletions src/native/corehost/browserhost/loader/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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 { ENVIRONMENT_IS_NODE } from "./per-module";
import { getIcuResourceName } from "./icu";
import { getLoaderConfig } from "./config";
import { BrowserHost_InitializeCoreCLR } from "./run";
import { createPromiseCompletionSource } from "./promise-completion-source";
import { locateFile } from "./bootstrap";

const nativeModulePromiseController = createPromiseCompletionSource<EmscriptenModuleInternal>(() => {
dotnetUpdateInternals(dotnetGetInternals());
});
let wasmBinaryPromise: Promise<Response> = undefined as any;

// 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<any> {
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<EmscriptenModuleInternal>(dotnetGetInternals());
nativeModulePromiseController.propagateFrom(modulePromise);

const runtimeModule = await runtimeModulePromise;
const runtimeModuleReady = runtimeModule.dotnetInitializeModule<void>(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<JsModuleExports> {
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<Response> {
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<void> {
const res = await WebAssembly.instantiateStreaming(wasmBinaryPromise, imports);
successCallback(res.instance, res.module);
}

async function fetchIcu(asset: IcuAsset): Promise<void> {
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<void> {
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<void> {
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<Uint8Array> {
dotnetAssert.check(asset && asset.resolvedUrl, "Bad asset.resolvedUrl");
const response = await fetchLike(asset.resolvedUrl);
const buffer = await response.arrayBuffer();
return new Uint8Array(buffer);
}

async function fetchLike(resolvedUrl: string): Promise<Response> {
dotnetAssert.check(resolvedUrl, "Bad resolvedUrl");
if (ENVIRONMENT_IS_NODE) {
const { promises: fs } = await import(/*! webpackIgnore: true */"fs");
const { fileURLToPath } = await import(/*! webpackIgnore: true */"url");
const isFileUrl = resolvedUrl.startsWith("file://");
if (isFileUrl) {
resolvedUrl = fileURLToPath(resolvedUrl);
}
const arrayBuffer = await fs.readFile(resolvedUrl) as any;
return <Response><any>{
ok: true,
headers: {
length: 0,
get: () => null
},
url: resolvedUrl,
arrayBuffer: () => arrayBuffer,
json: () => JSON.parse(arrayBuffer),
text: () => {
throw new Error("NotImplementedException");
}
};
} else {
const response = await fetch(resolvedUrl);
if (!response.ok) {
throw new Error(`Failed to load ${resolvedUrl} with ${response.status} ${response.statusText}`);
}
return response;
}
}
Loading
Loading