Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
47a0b01
rebase
pavelsavara Sep 25, 2025
32680f9
more
pavelsavara Sep 25, 2025
b4d1f97
fix
pavelsavara Sep 25, 2025
1b932b5
more
pavelsavara Sep 25, 2025
1cf1e51
Update src/native/corehost/browserhost/loader/run.ts
pavelsavara Sep 25, 2025
828f9e9
feedback
pavelsavara Sep 25, 2025
8b0301c
more sharing by table/index
pavelsavara Sep 25, 2025
4af1ad6
fix
pavelsavara Sep 25, 2025
12619cf
fix
pavelsavara Sep 25, 2025
ac5aa58
comment
pavelsavara Sep 25, 2025
3fa7292
feedback: dotnet prefix
pavelsavara Sep 25, 2025
c456f3d
feedback about names in dotnetUpdateModuleInternals()
pavelsavara Sep 26, 2025
549a859
ecma feedback
pavelsavara Sep 26, 2025
7e2b052
feedback about rollup config flags
pavelsavara Sep 26, 2025
7258af3
todo feedback in memory
pavelsavara Sep 26, 2025
bd33d27
ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent
pavelsavara Sep 26, 2025
ddbfa3e
todo fetchWasm feedback
pavelsavara Sep 26, 2025
df9f8c2
missing config feedback
pavelsavara Sep 26, 2025
d197301
DotnetHostBuilder todo feedback
pavelsavara Sep 26, 2025
d82c891
cwraps todo
pavelsavara Sep 26, 2025
3779a39
isConfigReady feedback
pavelsavara Sep 26, 2025
5c7e603
Merge branch 'main' into browser_host_ts
pavelsavara Sep 26, 2025
84589d5
WASM-TODO
pavelsavara Sep 26, 2025
9d02e42
fix type names
pavelsavara Sep 26, 2025
8496bc2
Merge branch 'main' into browser_host_ts
pavelsavara Sep 26, 2025
46e640a
isConfigReady feedback
pavelsavara Sep 26, 2025
3944860
Merge branch 'main' into browser_host_ts
pavelsavara Sep 29, 2025
246530b
fix dotnet.boot.js
pavelsavara Sep 29, 2025
5bd6b41
ENVIRONMENT_IS_* feedback
pavelsavara Sep 29, 2025
faa1d42
fix
pavelsavara Sep 29, 2025
ba46624
_zero_region feedback
pavelsavara Sep 29, 2025
8f60c56
tabulateLoaderExports feedback
pavelsavara Sep 29, 2025
a59a4c5
DOTNET: feedback
pavelsavara Sep 29, 2025
9e058b4
CoreCLRInitialized feedback
pavelsavara Sep 29, 2025
0b0e5b6
crossLink feedback
pavelsavara Sep 29, 2025
53b7025
feedback: remove exports, keep IIFE
pavelsavara Sep 29, 2025
43bfcd7
exchange feedback
pavelsavara Sep 29, 2025
c1613ef
feedback: document the JS symbol exchange
pavelsavara Sep 29, 2025
773b59e
- added new emscripten JS module libSystem.Browser.Utils.js
pavelsavara Sep 29, 2025
702a096
fix
pavelsavara Sep 29, 2025
fe9fc87
Merge branch 'main' into browser_host_ts
pavelsavara Sep 29, 2025
f106a71
cleanup
pavelsavara Sep 29, 2025
42c0ba7
lint, minor fixes
pavelsavara Sep 29, 2025
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
8 changes: 4 additions & 4 deletions src/native/corehost/browserhost/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
)
endif ()

# TODO-WASM -sWASM_BIGINT=1
# TODO-WASM -emit-llvm
# TODO-WASM --source-map-base http://microsoft.com
# WASM-TODO -sWASM_BIGINT=1
# WASM-TODO -emit-llvm
# WASM-TODO --source-map-base http://microsoft.com
target_link_options(browserhost PRIVATE
-sINITIAL_MEMORY=134217728
-sMAXIMUM_MEMORY=2147483648
Expand All @@ -85,7 +85,7 @@ target_link_options(browserhost PRIVATE
-sEXPORT_ES6=1
-sEXIT_RUNTIME=0
-sEXPORTED_RUNTIME_METHODS=UTF8ToString,cwrap,ccall,HEAPU8,HEAPU32,HEAPU64,BROWSER_HOST
-sEXPORTED_FUNCTIONS=_posix_memalign,_free,stackAlloc,stackRestore,stackSave,_browserHostInitializeCoreCLR,_browserHostExecuteAssembly,___cpp_exception
-sEXPORTED_FUNCTIONS=_posix_memalign,_free,stackAlloc,stackRestore,stackSave,_BrowserHost_InitializeCoreCLR,_BrowserHost_ExecuteAssembly,___cpp_exception
-sEXPORT_NAME=createDotnetRuntime
-fwasm-exceptions
-msimd128
Expand Down
28 changes: 12 additions & 16 deletions src/native/corehost/browserhost/browserhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ extern "C"
const void* GlobalizationResolveDllImport(const char* name);
const void* CompressionResolveDllImport(const char* name);

bool browserHostExternalAssemblyProbe(const char* pathPtr, /*out*/ void **outDataStartPtr, /*out*/ int64_t* outSize);
void browserHostResolveMain(int exitCode);
void browserHostRejectMain(const char *reason);
bool BrowserHost_ExternalAssemblyProbe(const char* pathPtr, /*out*/ void **outDataStartPtr, /*out*/ int64_t* outSize);
void BrowserHost_ResolveMain(int exitCode);
void BrowserHost_RejectMain(const char *reason);
}

// The current CoreCLR instance details.
Expand All @@ -64,13 +64,6 @@ static void log_error_info(const char* line)
std::fprintf(stderr, "log error: %s\n", line);
}

static bool external_assembly_probe(const char* path, /*out*/ void **data_start, /*out*/ int64_t* size)
{
*size = 0;
*data_start = nullptr;
return browserHostExternalAssemblyProbe(path, data_start, size);;
}

static const void* pinvoke_override(const char* library_name, const char* entry_point_name)
{
if (strcmp(library_name, "libSystem.Native") == 0)
Expand Down Expand Up @@ -107,9 +100,11 @@ static std::vector<const char*> propertyKeys;
static std::vector<const char*> propertyValues;
static pal::char_t ptr_to_string_buffer[STRING_LENGTH("0xffffffffffffffff") + 1];

extern "C" int browserHostInitializeCoreCLR(void)
// WASM-TODO: pass TPA via argument, not env
// WASM-TODO: pass app_path via argument, not env
// WASM-TODO: pass search_paths via argument, not env
extern "C" int BrowserHost_InitializeCoreCLR(void)
{
//WASM-TODO: does getenv return UTF8 ?
pal::getenv(HOST_PROPERTY_APP_PATHS, &app_path);
pal::getenv(HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES, &search_paths);
pal::getenv(HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES, &tpa);
Expand All @@ -124,7 +119,7 @@ extern "C" int browserHostInitializeCoreCLR(void)

host_runtime_contract host_contract = { sizeof(host_runtime_contract), nullptr };
host_contract.pinvoke_override = &pinvoke_override;
host_contract.external_assembly_probe = &external_assembly_probe;
host_contract.external_assembly_probe = &BrowserHost_ExternalAssemblyProbe;

pal::snwprintf(ptr_to_string_buffer, ARRAY_SIZE(ptr_to_string_buffer), _X("0x%zx"), (size_t)(&host_contract));

Expand All @@ -144,7 +139,8 @@ extern "C" int browserHostInitializeCoreCLR(void)
}

// WASM-TODO: browser needs async entrypoint
extern "C" int browserHostExecuteAssembly(const char* assemblyPath)
// WASM-TODO: don't coreclr_shutdown_2 when browser
extern "C" int BrowserHost_ExecuteAssembly(const char* assemblyPath)
{
int exit_code;
int retval = coreclr_execute_assembly(CurrentClrInstance, CurrentAppDomainId, 0, nullptr, assemblyPath, (uint32_t*)&exit_code);
Expand All @@ -164,11 +160,11 @@ extern "C" int browserHostExecuteAssembly(const char* assemblyPath)
std::fprintf(stderr, "coreclr_shutdown_2 failed - Error: 0x%08x\n", retval);
exit_code = -1;
// WASM-TODO: this is too trivial
browserHostRejectMain("coreclr_shutdown_2 failed");
BrowserHost_RejectMain("coreclr_shutdown_2 failed");
}

// WASM-TODO: this is too trivial
// because nothing runs continuations yet and also coreclr_execute_assembly is sync looping
browserHostResolveMain(exit_code);
BrowserHost_ResolveMain(exit_code);
return retval;
}
4 changes: 4 additions & 0 deletions src/native/corehost/browserhost/cross-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

export * from "../../libs/Common/JavaScript/cross-module";
5 changes: 5 additions & 0 deletions src/native/corehost/browserhost/host/cross-linked.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import { } from "../../../libs/Common/JavaScript/cross-linked";

95 changes: 95 additions & 0 deletions src/native/corehost/browserhost/host/host.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { CharPtr, VoidPtr, VoidPtrPtr } from "./types";
import { } from "./cross-linked"; // ensure ambient symbols are declared

const loadedAssemblies : Map<string, { ptr: number, length: number }> = new Map();

export function registerDllBytes(bytes: Uint8Array, asset: { name: string }) {
const sp = Module.stackSave();
try {
const sizeOfPtr = 4;
const ptrPtr = Module.stackAlloc(sizeOfPtr);
if (Module._posix_memalign(ptrPtr as any, 16, bytes.length)) {
throw new Error("posix_memalign failed");
}

const ptr = Module.HEAPU32[ptrPtr as any >>> 2];
Module.HEAPU8.set(bytes, ptr);
loadedAssemblies.set(asset.name, { ptr, length: bytes.length });
} finally {
Module.stackRestore(sp);
}
}

// bool BrowserHost_ExternalAssemblyProbe(const char* pathPtr, /*out*/ void **outDataStartPtr, /*out*/ int64_t* outSize);
export function BrowserHost_ExternalAssemblyProbe(pathPtr:CharPtr, outDataStartPtr:VoidPtrPtr, outSize:VoidPtr) {
const path = Module.UTF8ToString(pathPtr);
const assembly = loadedAssemblies.get(path);
if (assembly) {
Module.HEAPU32[outDataStartPtr as any >>> 2] = assembly.ptr;
// int64_t target
Module.HEAPU32[outSize as any >>> 2] = assembly.length;
Module.HEAPU32[((outSize as any) + 4) >>> 2] = 0;
return true;
}
Module.HEAPU32[outDataStartPtr as any >>> 2] = 0;
Module.HEAPU32[outSize as any >>> 2] = 0;
Module.HEAPU32[((outSize as any) + 4) >>> 2] = 0;
return false;
}

export function BrowserHost_ResolveMain(exitCode:number) {
dotnetLoaderExports.resolveRunMainPromise(exitCode);
}

export function BrowserHost_RejectMain(reason:any) {
dotnetLoaderExports.rejectRunMainPromise(reason);
}

// WASM-TODO: take ideas from Mono
// - second call to exit should be silent
// - second call to exit not override the first exit code
// - improve reason extraction
// - install global handler for unhandled exceptions and promise rejections
// - raise ExceptionHandling.RaiseAppDomainUnhandledExceptionEvent()
export function exit(exit_code: number, reason: any): void {
const reasonStr = reason ? (reason.stack ? reason.stack || reason.message : reason.toString()) : "";
if (exit_code !== 0) {
dotnetLogger.error(`Exit with code ${exit_code} ${reason ? "and reason: " + reasonStr : ""}`);
}
if (dotnetJSEngine.IS_NODE) {
(globalThis as any).process.exit(exit_code);
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function runMain(mainAssemblyName?: string, args?: string[]): Promise<number> {
// int BrowserHost_ExecuteAssembly(char * assemblyPath)
const res = Module.ccall("BrowserHost_ExecuteAssembly", "number", ["string"], [mainAssemblyName]) as number;
if (res != 0) {
const reason = new Error("Failed to execute assembly");
exit(res, reason);
throw reason;
}

return dotnetLoaderExports.getRunMainPromise();
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function runMainAndExit(mainAssemblyName?: string, args?: string[]): Promise<number> {
try {
await runMain(mainAssemblyName, args);
} catch (error) {
exit(1, error);
throw error;
}
exit(0, null);
return 0;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function setEnvironmentVariable(name: string, value: string): void {
throw new Error("Not implemented");
}
47 changes: 47 additions & 0 deletions src/native/corehost/browserhost/host/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { InternalExchange, BrowserHostExports, RuntimeAPI, BrowserHostExportsTable } from "./types";
import { InternalExchangeIndex } from "./types";
import { } from "./cross-linked"; // ensure ambient symbols are declared

import { exit, runMain, runMainAndExit, setEnvironmentVariable, registerDllBytes } from "./host";
import {
setHeapB32, setHeapB8, setHeapU8, setHeapU16, setHeapU32, setHeapI8, setHeapI16, setHeapI32, setHeapI52, setHeapU52, setHeapI64Big, setHeapF32, setHeapF64,
getHeapB32, getHeapB8, getHeapU8, getHeapU16, getHeapU32, getHeapI8, getHeapI16, getHeapI32, getHeapI52, getHeapU52, getHeapI64Big, getHeapF32, getHeapF64,
localHeapViewI8, localHeapViewI16, localHeapViewI32, localHeapViewI64Big, localHeapViewU8, localHeapViewU16, localHeapViewU32, localHeapViewF32, localHeapViewF64,
isSharedArrayBuffer,
} from "./memory";

export function dotnetInitializeModule(internals: InternalExchange): void {
const runtimeApiLocal: Partial<RuntimeAPI> = {
runMain,
runMainAndExit,
setEnvironmentVariable,
exit,
setHeapB32, setHeapB8, setHeapU8, setHeapU16, setHeapU32, setHeapI8, setHeapI16, setHeapI32, setHeapI52, setHeapU52, setHeapI64Big, setHeapF32, setHeapF64,
getHeapB32, getHeapB8, getHeapU8, getHeapU16, getHeapU32, getHeapI8, getHeapI16, getHeapI32, getHeapI52, getHeapU52, getHeapI64Big, getHeapF32, getHeapF64,
localHeapViewI8, localHeapViewI16, localHeapViewI32, localHeapViewI64Big, localHeapViewU8, localHeapViewU16, localHeapViewU32, localHeapViewF32, localHeapViewF64,
};

const hostNativeExportsLocal: BrowserHostExports = {
registerDllBytes,
isSharedArrayBuffer
};
dotnetSetInternals(internals);
Object.assign(internals[InternalExchangeIndex.RuntimeAPI], runtimeApiLocal);
internals[InternalExchangeIndex.BrowserHostExportsTable] = tabulateBrowserHostExports(hostNativeExportsLocal);
const updates = internals[InternalExchangeIndex.InternalUpdatesCallbacks];
if (!updates.includes(dotnetUpdateModuleInternals)) updates.push(dotnetUpdateModuleInternals);
dotnetUpdateAllInternals();

function tabulateBrowserHostExports(map:BrowserHostExports):BrowserHostExportsTable {
// keep in sync with dotnetUpdateModuleInternals()
return [
map.registerDllBytes,
map.isSharedArrayBuffer,
];
}
}

export { BrowserHost_ExternalAssemblyProbe, BrowserHost_ResolveMain, BrowserHost_RejectMain } from "./host";
Loading
Loading