Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser][MT][hybridglobalization] Run HybridGlobalization threading tests #102595

Closed
wants to merge 13 commits into from
15 changes: 15 additions & 0 deletions eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,21 @@ jobs:
# - WasmTestOnChrome
# - WasmTestOnNodeJS


- template: /eng/pipelines/common/templates/wasm-library-tests.yml
parameters:
platforms:
- browser_wasm
- browser_wasm_win
nameSuffix: _HybridGlobalization_MultiThreaded
extraBuildArgs: /p:WasmEnableThreads=true /p:HybridGlobalization=true
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
alwaysRun: true
scenarios:
- WasmTestOnChrome
- WasmTestOnFirefox

- ${{ if and(ne(parameters.isRollingBuild, true), ne(parameters.excludeNonLibTests, true), ne(parameters.debuggerTestsOnly, true)) }}:
# Builds only
- template: /eng/pipelines/common/templates/wasm-build-only.yml
Expand Down
2 changes: 1 addition & 1 deletion src/mono/browser/runtime/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export async function instantiate_segmentation_rules_asset (pendingAsset: AssetE
const json = await response.json();
globalizationHelpers.setSegmentationRulesFromJson(json);
} catch (error: any) {
mono_log_info(`Error loading static json asset ${pendingAsset.name}: ${JSON.stringify(error)}`);
mono_log_info(`Error loading static json asset ${pendingAsset.name}: ${error}`);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/mono/browser/runtime/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { export_internal } from "./exports-internal";
import { export_api } from "./export-api";
import { initializeReplacements } from "./polyfills";

import { mono_wasm_stringify_as_error_with_stack } from "./logging";
import { mono_log_info, mono_wasm_stringify_as_error_with_stack } from "./logging";
import { instantiate_asset, instantiate_symbols_asset, instantiate_segmentation_rules_asset } from "./assets";
import { jiterpreter_dump_stats } from "./jiterpreter";
import { forceDisposeProxies } from "./gc-handles";
Expand Down Expand Up @@ -57,6 +57,8 @@ function initializeExports (globalObjects: GlobalObjects): RuntimeAPI {
rh.localHeapViewU16 = localHeapViewU16;
rh.setU16_local = setU16_local;
rh.setI32 = setI32;
// tmp:
rh.mono_log_info = mono_log_info;
}

Object.assign(runtimeHelpers, rh);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { isSurrogate } from "./helpers";
import { runtimeHelpers } from "./module-exports";

type SegmentationRule = {
breaks: boolean
Expand All @@ -26,7 +27,7 @@ type SegmentationTypeRaw = {
rules: Record<string, SegmentationRuleRaw>
}

let segmentationRules: Record<string, SegmentationRule>;
let segmentationRules: Record<string, SegmentationRule> = null as any;

function replaceVariables (variables: Record<string, string>, input: string): string {
const findVarRegex = /\$[A-Za-z0-9_]+/gm;
Expand All @@ -46,17 +47,44 @@ function isSegmentationTypeRaw (obj: any): obj is SegmentationTypeRaw {
return obj.variables != null && obj.rules != null;
}

export function setSegmentationRulesFromJson (json: string) {
if (!isSegmentationTypeRaw(json))
export function setSegmentationRulesFromJson (rawRules: SegmentationTypeRaw) {
if (!isSegmentationTypeRaw(rawRules))
throw new Error("Provided grapheme segmentation rules are not valid");
segmentationRules = GraphemeSegmenter.prepareSegmentationRules(json);

segmentationRules = {};

for (const key of Object.keys(rawRules.rules)) {
const ruleValue = rawRules.rules[key];
const preparedRule: SegmentationRule = { breaks: ruleValue.breaks, };

if ("before" in ruleValue && ruleValue.before) {
preparedRule.before = generateRegexRule(ruleValue.before, rawRules.variables, false);
}
if ("after" in ruleValue && ruleValue.after) {
preparedRule.after = generateRegexRule(ruleValue.after, rawRules.variables, true);
}

segmentationRules[key] = preparedRule;
}
runtimeHelpers.mono_log_info(`Grapheme segmentation rules are set ID: ${runtimeHelpers.monoThreadInfo.pthreadId}; ${runtimeHelpers.monoThreadInfo.threadName};\nStack: ${(new Error()).stack}`);
}

export function getSegmentationRules (): Record<string, SegmentationRule> {
runtimeHelpers.mono_log_info(`getSegmentationRules=${segmentationRules}; ID: ${runtimeHelpers.monoThreadInfo.pthreadId}; ${runtimeHelpers.monoThreadInfo.threadName}`);
return segmentationRules;
}

// ToDo: refactor to drop the class
export class GraphemeSegmenter {
private readonly rules: Record<string, SegmentationRule>;
private readonly ruleSortedKeys: string[];

public constructor () {
if (!segmentationRules) {
const message = `Grapheme segmentation rules are not set ID: ${runtimeHelpers.monoThreadInfo.pthreadId}; ${runtimeHelpers.monoThreadInfo.threadName};\nStack: ${(new Error()).stack}`;
runtimeHelpers.mono_log_info(message);
throw new Error(message);
}
this.rules = segmentationRules;
this.ruleSortedKeys = Object.keys(this.rules).sort((a, b) => Number(a) - Number(b));
}
Expand Down Expand Up @@ -120,23 +148,4 @@ export class GraphemeSegmenter {
// GB999: Any ÷ Any
return true;
}

public static prepareSegmentationRules (segmentationRules: SegmentationTypeRaw): Record<string, SegmentationRule> {
const preparedRules: Record<string, SegmentationRule> = {};

for (const key of Object.keys(segmentationRules.rules)) {
const ruleValue = segmentationRules.rules[key];
const preparedRule: SegmentationRule = { breaks: ruleValue.breaks, };

if ("before" in ruleValue && ruleValue.before) {
preparedRule.before = generateRegexRule(ruleValue.before, segmentationRules.variables, false);
}
if ("after" in ruleValue && ruleValue.after) {
preparedRule.after = generateRegexRule(ruleValue.after, segmentationRules.variables, true);
}

preparedRules[key] = preparedRule;
}
return preparedRules;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { mono_wasm_get_calendar_info } from "./calendar";
import { mono_wasm_change_case } from "./change-case";
import { mono_wasm_compare_string, mono_wasm_starts_with, mono_wasm_ends_with, mono_wasm_index_of } from "./collations";
import { mono_wasm_get_culture_info } from "./culture-info";
import { setSegmentationRulesFromJson } from "./grapheme-segmenter";
import { getSegmentationRules, setSegmentationRulesFromJson } from "./grapheme-segmenter";
import { mono_wasm_get_first_day_of_week, mono_wasm_get_first_week_of_year } from "./locales";

export let globalizationHelpers: GlobalizationHelpers;
Expand All @@ -20,6 +20,7 @@ export function initHybrid (gh: GlobalizationHelpers, rh: RuntimeHelpers) {
gh.mono_wasm_get_first_day_of_week = mono_wasm_get_first_day_of_week;
gh.mono_wasm_get_first_week_of_year = mono_wasm_get_first_week_of_year;
gh.setSegmentationRulesFromJson = setSegmentationRulesFromJson;
gh.getSegmentationRules = getSegmentationRules;
globalizationHelpers = gh;
runtimeHelpers = rh;
}
Expand Down
9 changes: 4 additions & 5 deletions src/mono/browser/runtime/loader/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,15 @@ export async function mono_download_assets (): Promise<void> {
// this await will get past the onRuntimeInitialized because we are not blocking via addRunDependency
// and we are not awaiting it here
Promise.all(promises_of_asset_instantiation_core).then(() => {
if (!ENVIRONMENT_IS_WORKER) {
runtimeHelpers.coreAssetsInMemory.promise_control.resolve();
}
runtimeHelpers.coreAssetsInMemory.promise_control.resolve();
}).catch(err => {
loaderHelpers.err("Error in mono_download_assets: " + err);
mono_exit(1, err);
throw err;
});
Promise.all(promises_of_asset_instantiation_remaining).then(async () => {
await runtimeHelpers.coreAssetsInMemory.promise;
if (!ENVIRONMENT_IS_WORKER) {
await runtimeHelpers.coreAssetsInMemory.promise;
runtimeHelpers.allAssetsInMemory.promise_control.resolve();
}
}).catch(err => {
Expand Down Expand Up @@ -478,8 +476,9 @@ export function prepareAssetsWorker () {

for (const asset of config.assets) {
set_single_asset(asset);
// note that assets are pushed into core collection in the worker, as opposed to the main thread
if (loadIntoWorker[asset.behavior]) {
assetsToLoad.push(asset);
coreAssetsToLoad.push(asset);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/browser/runtime/loader/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export function normalizeConfig () {
toMerge.satelliteResources[asset.culture!] = resource;
break;
case "icu":
case "segmentation-rules":
toMerge.icu = resource;
break;
case "symbols":
Expand Down
2 changes: 2 additions & 0 deletions src/mono/browser/runtime/loader/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,5 +575,7 @@ async function createEmscriptenWorker (): Promise<EmscriptenModuleInternal> {
const es6Modules = await Promise.all(promises);
await initializeModules(es6Modules as any);

await runtimeHelpers.coreAssetsInMemory.promise;

return emscriptenModule;
}
6 changes: 4 additions & 2 deletions src/mono/browser/runtime/pthreads/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import WasmEnableThreads from "consts:wasmEnableThreads";

import { ENVIRONMENT_IS_PTHREAD, Module, loaderHelpers, mono_assert, runtimeHelpers } from "../globals";
import { ENVIRONMENT_IS_PTHREAD, Module, globalizationHelpers, loaderHelpers, mono_assert, runtimeHelpers } from "../globals";
import { PThreadSelf, monoThreadInfo, mono_wasm_pthread_ptr, postMessageToMain, update_thread_info } from "./shared";
import { PThreadLibrary, MonoThreadMessage, PThreadInfo, PThreadPtr, WorkerToMainMessageType } from "../types/internal";
import {
Expand All @@ -15,7 +15,7 @@ import {
WorkerThreadEventTarget
} from "./worker-events";
import { postRunWorker, preRunWorker } from "../startup";
import { mono_log_debug, mono_log_error } from "../logging";
import { mono_log_debug, mono_log_error, mono_log_info } from "../logging";
import { CharPtr } from "../types/emscripten";
import { utf8ToString } from "../strings";
import { forceThreadMemoryViewRefresh } from "../memory";
Expand Down Expand Up @@ -110,6 +110,8 @@ export function mono_wasm_pthread_on_pthread_created (): void {
info: monoThreadInfo,
port: mainPort,
}, [mainPort]);
const segmentationRules = globalizationHelpers.getSegmentationRules();
mono_log_info(`[mono_wasm_pthread_on_pthread_created] ID: ${pthread_id}; segmentationRules = ${segmentationRules}; ${runtimeHelpers.monoThreadInfo.threadName}\nStack: ${(new Error()).stack}`);
} catch (err) {
mono_log_error("mono_wasm_pthread_on_pthread_created () failed", err);
loaderHelpers.mono_exit(1, err);
Expand Down
8 changes: 7 additions & 1 deletion src/mono/browser/runtime/types/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ export type RuntimeHelpers = {
localHeapViewU16: () => Uint16Array,
setU16_local: (heap: Uint16Array, ptr: number, value: number) => void,
setI32: (offset: MemOffset, value: number) => void,

// tmp:
mono_log_info: (message: string) => void,
}
export type GlobalizationHelpers = {

Expand All @@ -262,7 +265,10 @@ export type GlobalizationHelpers = {
mono_wasm_get_culture_info: (culture: number, cultureLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr) => VoidPtr;
mono_wasm_get_first_day_of_week: (culture: number, cultureLength: number, resultPtr: Int32Ptr) => VoidPtr;
mono_wasm_get_first_week_of_year: (culture: number, cultureLength: number, resultPtr: Int32Ptr) => VoidPtr;
setSegmentationRulesFromJson: (json: string) => void;
setSegmentationRulesFromJson: (rawRules: any) => void;

// tmp:
getSegmentationRules: () => Record<string, any>;
}

export type AOTProfilerOptions = {
Expand Down
Loading