From a08903f6847a409093bb90dfa39d7bd020ab98d5 Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 31 Mar 2025 19:06:53 +0000 Subject: [PATCH 1/6] chore: nuking debug-only logger --- yarn-project/foundation/src/log/debug.ts | 32 ------------ .../foundation/src/log/log_history.test.ts | 49 ++++++++++--------- .../foundation/src/wasm/empty_wasi_sdk.ts | 34 ++++++------- .../foundation/src/wasm/wasm_module.ts | 32 +++++++----- .../src/worker/browser/start_web_module.ts | 5 +- .../src/worker/node/start_node_module.ts | 5 +- .../foundation/src/worker/worker_logger.ts | 30 ++++++++++++ .../capsule_data_provider.ts | 8 +-- 8 files changed, 101 insertions(+), 94 deletions(-) create mode 100644 yarn-project/foundation/src/worker/worker_logger.ts diff --git a/yarn-project/foundation/src/log/debug.ts b/yarn-project/foundation/src/log/debug.ts index d4c3dfad497c..daa4d0ab7826 100644 --- a/yarn-project/foundation/src/log/debug.ts +++ b/yarn-project/foundation/src/log/debug.ts @@ -1,40 +1,8 @@ import debug from 'debug'; -import type { LogFn } from './log_fn.js'; - let preLogHook: ((...args: any[]) => void) | undefined; let postLogHook: ((...args: any[]) => void) | undefined; -/** - * Process and handle the logging of messages through custom hooks and the given logger. - * This function checks if the logger's namespace is enabled, executes any preLogHook functions, logs the message using the provided logger, and then executes any postLogHook functions. - * - * @param logger - The debug logger instance to be used for logging. - * @param args - The arguments to be passed to the logger and any hook functions. - */ -function theFunctionThroughWhichAllLogsPass(logger: any, ...args: any[]) { - if (!debug.enabled(logger.namespace)) { - return; - } - if (preLogHook) { - preLogHook(logger.namespace, ...args); - } - logger(...args); - if (postLogHook) { - postLogHook(logger.namespace, ...args); - } -} - -/** - * Return a logger, meant to be silent by default and verbose during debugging. - * @param name - The module name of the logger. - * @returns A callable log function. - */ -export function createDebugOnlyLogger(name: string): LogFn { - const logger = debug(name); - return (...args: any[]) => theFunctionThroughWhichAllLogsPass(logger, ...args); -} - /** * Set a function to be called before each log message is handled by the debug logger. * The hook function will receive the logger namespace and any arguments passed to the logger. diff --git a/yarn-project/foundation/src/log/log_history.test.ts b/yarn-project/foundation/src/log/log_history.test.ts index d0aff6a4b747..9845c88e3ad1 100644 --- a/yarn-project/foundation/src/log/log_history.test.ts +++ b/yarn-project/foundation/src/log/log_history.test.ts @@ -1,19 +1,20 @@ import { jest } from '@jest/globals'; -import { createDebugOnlyLogger, enableLogs } from './debug.js'; +import { enableLogs } from './debug.js'; +import { type Logger, createLogger } from './index.js'; import { LogHistory } from './log_history.js'; jest.useFakeTimers({ doNotFake: ['performance'] }); // We skip log history tests since this class is not used and it pollutes the logs in CI. describe.skip('log history', () => { - let debug: (msg: string) => void; + let logger: Logger; let logHistory: LogHistory; const timestamp = new Date().toISOString(); const name = 'test:a'; beforeEach(() => { - debug = createDebugOnlyLogger(name); + logger = createLogger(name); enableLogs(name); logHistory = new LogHistory(); }); @@ -21,9 +22,9 @@ describe.skip('log history', () => { it('keeps debug logs', () => { logHistory.enable(); expect(logHistory.getLogs()).toEqual([]); - debug('0'); - debug('1'); - debug('2'); + logger.debug('0'); + logger.debug('1'); + logger.debug('2'); expect(logHistory.getLogs()).toEqual([ [timestamp, name, '0'], [timestamp, name, '1'], @@ -32,19 +33,19 @@ describe.skip('log history', () => { }); it('does not keep logs if not enabled', () => { - debug('0'); - debug('1'); + logger.debug('0'); + logger.debug('1'); expect(logHistory.getLogs()).toEqual([]); }); it('returns last n logs', () => { logHistory.enable(); expect(logHistory.getLogs()).toEqual([]); - debug('0'); - debug('1'); - debug('2'); - debug('3'); - debug('4'); + logger.debug('0'); + logger.debug('1'); + logger.debug('2'); + logger.debug('3'); + logger.debug('4'); expect(logHistory.getLogs(2)).toEqual([ [timestamp, name, '3'], [timestamp, name, '4'], @@ -54,14 +55,14 @@ describe.skip('log history', () => { it('only keeps logs with enabled namespace', () => { logHistory.enable(); const name2 = 'test:b'; - const debug2 = createDebugOnlyLogger(name2); - debug('0'); - debug2('zero'); + const logger2 = createLogger(name2); + logger.debug('0'); + logger2.debug('zero'); expect(logHistory.getLogs()).toEqual([[timestamp, name, '0']]); enableLogs(`${name},${name2}`); - debug('1'); - debug2('one'); + logger.debug('1'); + logger2.debug('one'); expect(logHistory.getLogs()).toEqual([ [timestamp, name, '0'], [timestamp, name, '1'], @@ -71,18 +72,18 @@ describe.skip('log history', () => { it('clears all logs', () => { logHistory.enable(); - debug('0'); - debug('1'); - debug('2'); + logger.debug('0'); + logger.debug('1'); + logger.debug('2'); logHistory.clear(); expect(logHistory.getLogs()).toEqual([]); }); it('clears first n logs', () => { logHistory.enable(); - debug('0'); - debug('1'); - debug('2'); + logger.debug('0'); + logger.debug('1'); + logger.debug('2'); logHistory.clear(2); expect(logHistory.getLogs()).toEqual([[timestamp, name, '2']]); }); diff --git a/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts b/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts index 209c1bac6e6c..968ee6240758 100644 --- a/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts +++ b/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts @@ -1,4 +1,4 @@ -import { createDebugOnlyLogger } from '../log/index.js'; +import { createLogger } from '../log/index.js'; /** * Dummy implementation of a necessary part of the wasi api: @@ -7,7 +7,7 @@ import { createDebugOnlyLogger } from '../log/index.js'; * TODO find a way to update off of wasi 12. */ /* eslint-disable camelcase */ -export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_sdk')) => ({ +export const getEmptyWasiSdk = (logger = createLogger('wasm:empty_wasi_sdk')) => ({ /** * Retrieves the current time from the system clock. * This function is a dummy implementation of the WASI API's `clock_time_get` method, @@ -17,7 +17,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * is solely to satisfy the environment expectations and provide debugging information. */ clock_time_get() { - debug('clock_time_get'); + logger.debug('clock_time_get'); }, /** * Dummy implementation of WASI's environ_get function. @@ -28,7 +28,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @see https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#environ_get */ environ_get() { - debug('environ_get'); + logger.debug('environ_get'); }, /** * Retrieves the environment variable sizes from the WebAssembly environment. @@ -36,7 +36,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * It does not have any actual functionality, but serves as a placeholder in the environment. */ environ_sizes_get() { - debug('environ_sizes_get'); + logger.debug('environ_sizes_get'); }, /** * Closes a file descriptor, releasing any resources associated with it. @@ -47,7 +47,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @see https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md */ fd_close() { - debug('fd_close'); + logger.debug('fd_close'); }, /** * A dummy implementation of the 'fd_read' function from the WASI API. @@ -56,7 +56,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * but here it simply logs the invocation for debugging purposes. */ fd_read() { - debug('fd_read'); + logger.debug('fd_read'); }, /** * Handles the file descriptor write operation. @@ -66,7 +66,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * It is used to write data from WebAssembly memory to a file descriptor. */ fd_write() { - debug('fd_write'); + logger.debug('fd_write'); }, /** * Perform a file seek operation on the given file descriptor to change its current position. @@ -79,7 +79,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns The new position in the file after the seek operation has been performed. */ fd_seek() { - debug('fd_seek'); + logger.debug('fd_seek'); }, /** * This function is a dummy implementation of the 'fd_fdstat_get' function in the WebAssembly System Interface (WASI) API. @@ -87,7 +87,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * The 'fd_fdstat_get' function is typically responsible for obtaining file descriptor status information. */ fd_fdstat_get() { - debug('fd_fdstat_get'); + logger.debug('fd_fdstat_get'); }, /** * Sets the file descriptor flags for a given file descriptor. @@ -96,7 +96,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * This is provided since the environment expects this function to be present. */ fd_fdstat_set_flags() { - debug('fd_fdstat_set_flags'); + logger.debug('fd_fdstat_set_flags'); }, /** * Handles the `fd_prestat_get` function call for the dummy WebAssembly System Interface (WASI) implementation. @@ -106,7 +106,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns A constant integer value indicating successful completion of the function call. */ fd_prestat_get() { - debug('fd_prestat_get'); + logger.debug('fd_prestat_get'); return 8; }, /** @@ -117,7 +117,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns A constant number representing a dummy return value for the function call. */ fd_prestat_dir_name() { - debug('fd_prestat_dir_name'); + logger.debug('fd_prestat_dir_name'); return 28; }, /** @@ -127,7 +127,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * actual file opening operation. It is mainly used for debugging purposes. */ path_open() { - debug('path_open'); + logger.debug('path_open'); }, /** * Retrieve file system information of the specified path. @@ -137,7 +137,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns An object containing file statistics like size, permissions, etc. */ path_filestat_get() { - debug('path_filestat_get'); + logger.debug('path_filestat_get'); }, /** * Terminate the process normally, performing the regular cleanup for terminating programs. @@ -149,7 +149,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns The exit status code. */ proc_exit() { - debug('proc_exit'); + logger.debug('proc_exit'); return 52; }, /** @@ -160,7 +160,7 @@ export const getEmptyWasiSdk = (debug = createDebugOnlyLogger('wasm:empty_wasi_s * @returns A random number. In this implementation, always returns 1. */ random_get() { - debug('random_get'); + logger.debug('random_get'); return 1; }, }); diff --git a/yarn-project/foundation/src/wasm/wasm_module.ts b/yarn-project/foundation/src/wasm/wasm_module.ts index b98a72e4455d..69995752a2f2 100644 --- a/yarn-project/foundation/src/wasm/wasm_module.ts +++ b/yarn-project/foundation/src/wasm/wasm_module.ts @@ -1,7 +1,7 @@ import { Buffer } from 'buffer'; import { randomBytes } from '../crypto/index.js'; -import { type LogFn, createDebugOnlyLogger } from '../log/index.js'; +import { type Logger, createLogger } from '../log/index.js'; import { FifoMemoryQueue } from '../queue/index.js'; import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; @@ -48,7 +48,7 @@ export class WasmModule implements IWasmModule { private heap!: Uint8Array; private instance?: WebAssembly.Instance; private mutexQ = new FifoMemoryQueue(); - private debug: LogFn; + private logger: Logger; /** * Create a wasm module. Should be followed by await init();. @@ -61,7 +61,7 @@ export class WasmModule implements IWasmModule { private importFn: (module: WasmModule) => any, loggerName = 'wasm', ) { - this.debug = createDebugOnlyLogger(loggerName); + this.logger = createLogger(loggerName); this.mutexQ.put(true); } @@ -80,7 +80,7 @@ export class WasmModule implements IWasmModule { * @param maximum - 8192 maximum by default. 512mb. */ public async init(initial = 31, maximum = 8192, initMethod: string | null = '_initialize') { - this.debug( + this.logger.debug( `initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${ (maximum * 2 ** 16) / (1024 * 1024) }mb`, @@ -98,7 +98,7 @@ export class WasmModule implements IWasmModule { /* eslint-disable camelcase */ const importObj = { wasi_snapshot_preview1: { - ...getEmptyWasiSdk(this.debug), + ...getEmptyWasiSdk(this.logger), random_get: (arr: number, length: number) => { arr = arr >>> 0; const heap = this.getMemory(); @@ -140,19 +140,25 @@ export class WasmModule implements IWasmModule { * @returns Logging function. */ public getLogger() { - return this.debug; + return this.logger; } /** * Add a logger. - * @param logger - Function to call when logging. + * @param logger - Logger to call when logging. */ - public addLogger(logger: LogFn) { - const oldDebug = this.debug; - this.debug = (msg: string) => { - logger(msg); - oldDebug(msg); - }; + public addLogger(logger: Logger) { + const oldLogger = this.logger; + this.logger = createLogger(oldLogger.module); + // Copy all log levels from both loggers + Object.keys(oldLogger).forEach(level => { + if (typeof oldLogger[level as keyof Logger] === 'function') { + (this.logger as any)[level] = (msg: string, ...args: any[]) => { + (oldLogger as any)[level](msg, ...args); + (logger as any)[level](msg, ...args); + }; + } + }); } /** diff --git a/yarn-project/foundation/src/worker/browser/start_web_module.ts b/yarn-project/foundation/src/worker/browser/start_web_module.ts index 21dcbc9d93d4..9cb0886d3726 100644 --- a/yarn-project/foundation/src/worker/browser/start_web_module.ts +++ b/yarn-project/foundation/src/worker/browser/start_web_module.ts @@ -1,5 +1,6 @@ import { type DispatchMsg, TransportServer, WorkerListener } from '../../transport/index.js'; import type { WasmModule } from '../../wasm/index.js'; +import { WorkerLogger } from '../worker_logger.js'; /** * Start the transport server corresponding to this module. @@ -18,7 +19,7 @@ export function startWebModule(module: WasmModule) { }; const transportListener = new WorkerListener(self); const transportServer = new TransportServer(transportListener, dispatch); - // eslint-disable-next-line @typescript-eslint/no-misused-promises - module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + const logger = new WorkerLogger(transportServer); + module.addLogger(logger); transportServer.start(); } diff --git a/yarn-project/foundation/src/worker/node/start_node_module.ts b/yarn-project/foundation/src/worker/node/start_node_module.ts index 74fa22e84c23..a3cf11031263 100644 --- a/yarn-project/foundation/src/worker/node/start_node_module.ts +++ b/yarn-project/foundation/src/worker/node/start_node_module.ts @@ -2,6 +2,7 @@ import { parentPort } from 'worker_threads'; import { type DispatchMsg, NodeListener, TransportServer } from '../../transport/index.js'; import type { WasmModule } from '../../wasm/wasm_module.js'; +import { WorkerLogger } from '../worker_logger.js'; if (!parentPort) { throw new Error('InvalidWorker'); @@ -24,7 +25,7 @@ export function startNodeModule(module: WasmModule) { }; const transportListener = new NodeListener(); const transportServer = new TransportServer(transportListener, dispatch); - // eslint-disable-next-line @typescript-eslint/no-misused-promises - module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + const logger = new WorkerLogger(transportServer); + module.addLogger(logger); transportServer.start(); } diff --git a/yarn-project/foundation/src/worker/worker_logger.ts b/yarn-project/foundation/src/worker/worker_logger.ts new file mode 100644 index 000000000000..e8f457e9a6b8 --- /dev/null +++ b/yarn-project/foundation/src/worker/worker_logger.ts @@ -0,0 +1,30 @@ +import { type DispatchMsg, TransportServer } from '../transport/index.js'; + +/** + * A logger implementation that forwards log messages via a transport server. + * The logger maintains a fixed trace level and always enables logging. + */ + +export class WorkerLogger { + constructor(private transportServer: TransportServer) {} + + silent = () => {}; + fatal = (msg: string, err?: unknown, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'fatal', msg, err, data] }); + error = (msg: string, err?: unknown, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'error', msg, err, data] }); + warn = (msg: string, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'warn', msg, data] }); + info = (msg: string, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'info', msg, data] }); + verbose = (msg: string, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'verbose', msg, data] }); + debug = (msg: string, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'debug', msg, data] }); + trace = (msg: string, data?: unknown) => + this.transportServer.broadcast({ fn: 'emit', args: ['log', 'trace', msg, data] }); + + readonly level = 'trace' as const; + readonly isLevelEnabled = () => true; + readonly module = 'web-worker'; +} diff --git a/yarn-project/pxe/src/storage/capsule_data_provider/capsule_data_provider.ts b/yarn-project/pxe/src/storage/capsule_data_provider/capsule_data_provider.ts index bb24ff5aa1cf..7be8c4280e40 100644 --- a/yarn-project/pxe/src/storage/capsule_data_provider/capsule_data_provider.ts +++ b/yarn-project/pxe/src/storage/capsule_data_provider/capsule_data_provider.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; import { toArray } from '@aztec/foundation/iterable'; -import { type LogFn, createDebugOnlyLogger } from '@aztec/foundation/log'; +import { type Logger, createLogger } from '@aztec/foundation/log'; import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; @@ -12,14 +12,14 @@ export class CapsuleDataProvider implements DataProvider { // Arbitrary data stored by contracts. Key is computed as `${contractAddress}:${key}` #capsules: AztecAsyncMap; - debug: LogFn; + logger: Logger; constructor(store: AztecAsyncKVStore) { this.#store = store; this.#capsules = this.#store.openMap('capsules'); - this.debug = createDebugOnlyLogger('pxe:capsule-data-provider'); + this.logger = createLogger('pxe:capsule-data-provider'); } async storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise { @@ -29,7 +29,7 @@ export class CapsuleDataProvider implements DataProvider { async loadCapsule(contractAddress: AztecAddress, slot: Fr): Promise { const dataBuffer = await this.#capsules.getAsync(dbSlotToKey(contractAddress, slot)); if (!dataBuffer) { - this.debug(`Data not found for contract ${contractAddress.toString()} and slot ${slot.toString()}`); + this.logger.debug(`Data not found for contract ${contractAddress.toString()} and slot ${slot.toString()}`); return null; } const capsule: Fr[] = []; From 8223f620524c120aaa2cf913caef06a8b7156855 Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 31 Mar 2025 19:22:16 +0000 Subject: [PATCH 2/6] nuking more stuff I don't understand --- yarn-project/foundation/src/log/debug.ts | 72 --------------- yarn-project/foundation/src/log/index.ts | 3 +- .../foundation/src/log/log_history.test.ts | 90 ------------------- .../foundation/src/log/log_history.ts | 44 --------- yarn-project/foundation/src/log/utils.ts | 21 +++++ 5 files changed, 22 insertions(+), 208 deletions(-) delete mode 100644 yarn-project/foundation/src/log/debug.ts delete mode 100644 yarn-project/foundation/src/log/log_history.test.ts delete mode 100644 yarn-project/foundation/src/log/log_history.ts create mode 100644 yarn-project/foundation/src/log/utils.ts diff --git a/yarn-project/foundation/src/log/debug.ts b/yarn-project/foundation/src/log/debug.ts deleted file mode 100644 index daa4d0ab7826..000000000000 --- a/yarn-project/foundation/src/log/debug.ts +++ /dev/null @@ -1,72 +0,0 @@ -import debug from 'debug'; - -let preLogHook: ((...args: any[]) => void) | undefined; -let postLogHook: ((...args: any[]) => void) | undefined; - -/** - * Set a function to be called before each log message is handled by the debug logger. - * The hook function will receive the logger namespace and any arguments passed to the logger. - * This can be useful for adding additional context, filtering logs, or performing side-effects - * based on logged messages. - * - * @param fn - The function to be called before each log message. - */ -export function setPreDebugLogHook(fn: (...args: any[]) => void) { - preLogHook = fn; -} - -/** - * Set a callback function to be executed after each log is written by the debug logger. - * This allows additional behavior or side effects to occur after a log has been written, - * such as sending logs to external services, formatting output, or triggering events. - * - * @param fn - The callback function to be executed after each log. It receives the same arguments as the original log function call. - */ -export function setPostDebugLogHook(fn: (...args: any[]) => void) { - postLogHook = fn; -} - -/** - * Enable logs for the specified namespace(s) or wildcard pattern(s). - * This function activates the logging functionality for the given - * namespace(s) or pattern(s), allowing developers to selectively display - * debug logs that match the provided string(s). - * - * @param str - The namespace(s) or wildcard pattern(s) for which logs should be enabled. - */ -export function enableLogs(str: string) { - debug.enable(str); -} - -/** - * Check if the logging is enabled for a given namespace. - * The input 'str' represents the namespace for which the log status is being checked. - * Returns true if the logging is enabled, otherwise false. - * - * @param str - The namespace string used to determine if logging is enabled. - * @returns A boolean indicating whether logging is enabled for the given namespace. - */ -export function isLogEnabled(str: string) { - return debug.enabled(str); -} - -/** - * Format a debug string filling in `'{0}'` entries with their - * corresponding values from the args array, amd `'{}'` with the whole array. - * - * @param formatStr - str of form `'this is a string with some entries like {0} and {1}'` - * @param args - array of fields to fill in the string format entries with - * @returns formatted string - */ -interface Printable { - toString(): string; -} -export function applyStringFormatting(formatStr: string, args: Printable[]): string { - return formatStr - .replace(/{(\d+)}/g, (match, index) => { - return typeof args[index] === 'undefined' ? match : args[index].toString(); - }) - .replace(/{}/g, (_match, _index) => { - return args.toString(); - }); -} diff --git a/yarn-project/foundation/src/log/index.ts b/yarn-project/foundation/src/log/index.ts index dcc425e972c2..e3d087bcc925 100644 --- a/yarn-project/foundation/src/log/index.ts +++ b/yarn-project/foundation/src/log/index.ts @@ -1,6 +1,5 @@ export * from './console.js'; -export * from './debug.js'; export * from './pino-logger.js'; -export * from './log_history.js'; export * from './log_fn.js'; export * from './libp2p_logger.js'; +export * from './utils.js'; diff --git a/yarn-project/foundation/src/log/log_history.test.ts b/yarn-project/foundation/src/log/log_history.test.ts deleted file mode 100644 index 9845c88e3ad1..000000000000 --- a/yarn-project/foundation/src/log/log_history.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { jest } from '@jest/globals'; - -import { enableLogs } from './debug.js'; -import { type Logger, createLogger } from './index.js'; -import { LogHistory } from './log_history.js'; - -jest.useFakeTimers({ doNotFake: ['performance'] }); - -// We skip log history tests since this class is not used and it pollutes the logs in CI. -describe.skip('log history', () => { - let logger: Logger; - let logHistory: LogHistory; - const timestamp = new Date().toISOString(); - const name = 'test:a'; - - beforeEach(() => { - logger = createLogger(name); - enableLogs(name); - logHistory = new LogHistory(); - }); - - it('keeps debug logs', () => { - logHistory.enable(); - expect(logHistory.getLogs()).toEqual([]); - logger.debug('0'); - logger.debug('1'); - logger.debug('2'); - expect(logHistory.getLogs()).toEqual([ - [timestamp, name, '0'], - [timestamp, name, '1'], - [timestamp, name, '2'], - ]); - }); - - it('does not keep logs if not enabled', () => { - logger.debug('0'); - logger.debug('1'); - expect(logHistory.getLogs()).toEqual([]); - }); - - it('returns last n logs', () => { - logHistory.enable(); - expect(logHistory.getLogs()).toEqual([]); - logger.debug('0'); - logger.debug('1'); - logger.debug('2'); - logger.debug('3'); - logger.debug('4'); - expect(logHistory.getLogs(2)).toEqual([ - [timestamp, name, '3'], - [timestamp, name, '4'], - ]); - }); - - it('only keeps logs with enabled namespace', () => { - logHistory.enable(); - const name2 = 'test:b'; - const logger2 = createLogger(name2); - logger.debug('0'); - logger2.debug('zero'); - expect(logHistory.getLogs()).toEqual([[timestamp, name, '0']]); - - enableLogs(`${name},${name2}`); - logger.debug('1'); - logger2.debug('one'); - expect(logHistory.getLogs()).toEqual([ - [timestamp, name, '0'], - [timestamp, name, '1'], - [timestamp, name2, 'one'], - ]); - }); - - it('clears all logs', () => { - logHistory.enable(); - logger.debug('0'); - logger.debug('1'); - logger.debug('2'); - logHistory.clear(); - expect(logHistory.getLogs()).toEqual([]); - }); - - it('clears first n logs', () => { - logHistory.enable(); - logger.debug('0'); - logger.debug('1'); - logger.debug('2'); - logHistory.clear(2); - expect(logHistory.getLogs()).toEqual([[timestamp, name, '2']]); - }); -}); diff --git a/yarn-project/foundation/src/log/log_history.ts b/yarn-project/foundation/src/log/log_history.ts deleted file mode 100644 index abf5987e723f..000000000000 --- a/yarn-project/foundation/src/log/log_history.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { setPreDebugLogHook } from './debug.js'; - -/** - * LogHistory is a utility class that provides the ability to store and manage debug logs. - * It can be enabled to record logs along with their timestamps, retrieve a specified number - * of recent logs, or clear stored logs based on a given count. This can be useful for debugging - * purposes, monitoring application activities, and maintaining log history. - */ -export class LogHistory { - private logs: any[][] = []; - - /** - * Enables the logging of debug messages with timestamps. - * Hooks into the pre-debug log and stores each log entry along with its timestamp in the logs array. - */ - public enable() { - setPreDebugLogHook((...args: any[]) => { - this.logs.push([new Date().toISOString(), ...args]); - }); - } - - /** - * Retrieves a specified number of logs from the end of the log history or all logs if no argument is provided. - * The logs are ordered chronologically, with the oldest logs at the beginning of the array. - * - * @param last - Optional number representing the amount of recent logs to return. Defaults to 0, which returns all logs. - * @returns An array of log arrays, each containing a timestamp and log arguments. - */ - public getLogs(last = 0) { - return last ? this.logs.slice(-last) : this.logs; - } - - /** - * Clear a specified number of logs from the beginning of the logs array. - * If no count is provided, it will clear all logs. - * - * @param count - The number of logs to be removed (default: total logs length). - */ - public clear(count = this.logs.length) { - this.logs = this.logs.slice(count); - } -} - -export const logHistory = new LogHistory(); diff --git a/yarn-project/foundation/src/log/utils.ts b/yarn-project/foundation/src/log/utils.ts new file mode 100644 index 000000000000..43dd4ad0a854 --- /dev/null +++ b/yarn-project/foundation/src/log/utils.ts @@ -0,0 +1,21 @@ +interface Printable { + toString(): string; +} + +/** + * Format a debug string filling in `'{0}'` entries with their + * corresponding values from the args array, amd `'{}'` with the whole array. + * + * @param formatStr - str of form `'this is a string with some entries like {0} and {1}'` + * @param args - array of fields to fill in the string format entries with + * @returns formatted string + */ +export function applyStringFormatting(formatStr: string, args: Printable[]): string { + return formatStr + .replace(/{(\d+)}/g, (match, index) => { + return typeof args[index] === 'undefined' ? match : args[index].toString(); + }) + .replace(/{}/g, (_match, _index) => { + return args.toString(); + }); +} From 602cd8abb4f25d0bbd7b61dbd0791c0936ba486a Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 31 Mar 2025 19:34:34 +0000 Subject: [PATCH 3/6] WIP --- yarn-project/foundation/src/log/index.ts | 6 +++--- .../foundation/src/log/{utils.ts => noir_debug_log_util.ts} | 0 yarn-project/foundation/src/worker/worker_logger.ts | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) rename yarn-project/foundation/src/log/{utils.ts => noir_debug_log_util.ts} (100%) diff --git a/yarn-project/foundation/src/log/index.ts b/yarn-project/foundation/src/log/index.ts index e3d087bcc925..ec0a0152fe0f 100644 --- a/yarn-project/foundation/src/log/index.ts +++ b/yarn-project/foundation/src/log/index.ts @@ -1,5 +1,5 @@ export * from './console.js'; -export * from './pino-logger.js'; -export * from './log_fn.js'; export * from './libp2p_logger.js'; -export * from './utils.js'; +export * from './log_fn.js'; +export * from './noir_debug_log_util.js'; +export * from './pino-logger.js'; diff --git a/yarn-project/foundation/src/log/utils.ts b/yarn-project/foundation/src/log/noir_debug_log_util.ts similarity index 100% rename from yarn-project/foundation/src/log/utils.ts rename to yarn-project/foundation/src/log/noir_debug_log_util.ts diff --git a/yarn-project/foundation/src/worker/worker_logger.ts b/yarn-project/foundation/src/worker/worker_logger.ts index e8f457e9a6b8..57e84d99f673 100644 --- a/yarn-project/foundation/src/worker/worker_logger.ts +++ b/yarn-project/foundation/src/worker/worker_logger.ts @@ -4,7 +4,6 @@ import { type DispatchMsg, TransportServer } from '../transport/index.js'; * A logger implementation that forwards log messages via a transport server. * The logger maintains a fixed trace level and always enables logging. */ - export class WorkerLogger { constructor(private transportServer: TransportServer) {} From b6fdf46f17e53669e0b189aa34a2a4e25ce7d902 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 1 Apr 2025 14:42:45 +0000 Subject: [PATCH 4/6] nuking foundation/src/worker --- yarn-project/foundation/package.json | 1 - yarn-project/foundation/src/index.ts | 1 - .../foundation/src/worker/browser/index.ts | 2 - .../src/worker/browser/start_web_module.ts | 25 ------- .../src/worker/browser/web_data_store.ts | 38 ---------- .../src/worker/browser/web_worker.ts | 25 ------- .../foundation/src/worker/data_store.ts | 19 ----- yarn-project/foundation/src/worker/index.ts | 2 - .../foundation/src/worker/node/index.ts | 2 - .../src/worker/node/node_data_store.ts | 27 ------- .../foundation/src/worker/node/node_worker.ts | 23 ------ .../src/worker/node/start_node_module.ts | 31 -------- .../foundation/src/worker/wasm_worker.ts | 7 -- .../foundation/src/worker/worker_logger.ts | 29 -------- .../foundation/src/worker/worker_pool.ts | 73 ------------------- 15 files changed, 305 deletions(-) delete mode 100644 yarn-project/foundation/src/worker/browser/index.ts delete mode 100644 yarn-project/foundation/src/worker/browser/start_web_module.ts delete mode 100644 yarn-project/foundation/src/worker/browser/web_data_store.ts delete mode 100644 yarn-project/foundation/src/worker/browser/web_worker.ts delete mode 100644 yarn-project/foundation/src/worker/data_store.ts delete mode 100644 yarn-project/foundation/src/worker/index.ts delete mode 100644 yarn-project/foundation/src/worker/node/index.ts delete mode 100644 yarn-project/foundation/src/worker/node/node_data_store.ts delete mode 100644 yarn-project/foundation/src/worker/node/node_worker.ts delete mode 100644 yarn-project/foundation/src/worker/node/start_node_module.ts delete mode 100644 yarn-project/foundation/src/worker/wasm_worker.ts delete mode 100644 yarn-project/foundation/src/worker/worker_logger.ts delete mode 100644 yarn-project/foundation/src/worker/worker_pool.ts diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index c053b9392f7f..3035f417a638 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -40,7 +40,6 @@ "./transport": "./dest/transport/index.js", "./trees": "./dest/trees/index.js", "./wasm": "./dest/wasm/index.js", - "./worker": "./dest/worker/index.js", "./bigint-buffer": "./dest/bigint-buffer/index.js", "./types": "./dest/types/index.js", "./schemas": "./dest/schemas/index.js", diff --git a/yarn-project/foundation/src/index.ts b/yarn-project/foundation/src/index.ts index ae226835a7de..2c6012ef17ef 100644 --- a/yarn-project/foundation/src/index.ts +++ b/yarn-project/foundation/src/index.ts @@ -24,7 +24,6 @@ export * as trees from './trees/index.js'; export * as types from './types/index.js'; export * as url from './url/index.js'; export * as wasm from './wasm/index.js'; -export * as worker from './worker/index.js'; export * as testing from './testing/index.js'; export * as config from './config/index.js'; export * as buffer from './buffer/index.js'; diff --git a/yarn-project/foundation/src/worker/browser/index.ts b/yarn-project/foundation/src/worker/browser/index.ts deleted file mode 100644 index ae6a02c0771b..000000000000 --- a/yarn-project/foundation/src/worker/browser/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './web_worker.js'; -export * from './web_data_store.js'; diff --git a/yarn-project/foundation/src/worker/browser/start_web_module.ts b/yarn-project/foundation/src/worker/browser/start_web_module.ts deleted file mode 100644 index 9cb0886d3726..000000000000 --- a/yarn-project/foundation/src/worker/browser/start_web_module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { type DispatchMsg, TransportServer, WorkerListener } from '../../transport/index.js'; -import type { WasmModule } from '../../wasm/index.js'; -import { WorkerLogger } from '../worker_logger.js'; - -/** - * Start the transport server corresponding to this module. - * @param module - The WasmModule to host. - */ -export function startWebModule(module: WasmModule) { - const dispatch = async ({ fn, args }: DispatchMsg) => { - if (fn === '__destroyWorker__') { - transportServer.stop(); - return; - } - if (!(module as any)[fn]) { - throw new Error(`dispatch error, function not found: ${fn}`); - } - return await (module as any)[fn](...args); - }; - const transportListener = new WorkerListener(self); - const transportServer = new TransportServer(transportListener, dispatch); - const logger = new WorkerLogger(transportServer); - module.addLogger(logger); - transportServer.start(); -} diff --git a/yarn-project/foundation/src/worker/browser/web_data_store.ts b/yarn-project/foundation/src/worker/browser/web_data_store.ts deleted file mode 100644 index 4ac6fc822c83..000000000000 --- a/yarn-project/foundation/src/worker/browser/web_data_store.ts +++ /dev/null @@ -1,38 +0,0 @@ -import levelup, { type LevelUp } from 'levelup'; -import memdown from 'memdown'; - -import type { DataStore } from '../data_store.js'; - -/** - * Cache for data used by wasm module. - * Stores in a LevelUp database. - */ -export class WebDataStore implements DataStore { - private db: LevelUp; - - constructor() { - // TODO: The whole point of this is to reduce memory load in the browser. - // Replace with leveljs so the data is stored in indexeddb and not in memory. - // Hack: Cast as any to work around package "broken" with node16 resolution - // See https://github.com/microsoft/TypeScript/issues/49160 - this.db = levelup((memdown as any)()); - } - - /** - * Lookup a key. - * @param key - Key to lookup. - * @returns The buffer. - */ - async get(key: string): Promise { - return await this.db.get(key).catch(() => {}); - } - - /** - * Alter a key. - * @param key - Key to alter. - * @param value - Buffer to store. - */ - async set(key: string, value: Buffer): Promise { - await this.db.put(key, value); - } -} diff --git a/yarn-project/foundation/src/worker/browser/web_worker.ts b/yarn-project/foundation/src/worker/browser/web_worker.ts deleted file mode 100644 index c166166ca346..000000000000 --- a/yarn-project/foundation/src/worker/browser/web_worker.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { type DispatchMsg, TransportClient, WorkerConnector, createDispatchProxy } from '../../transport/index.js'; -import { WasmModule } from '../../wasm/index.js'; -import type { WasmWorker } from '../wasm_worker.js'; - -/** - * Instantiate a web worker. - * @param url - The URL. - * @param initialMem - Initial memory pages. - * @param maxMem - Maximum memory pages. - * @returns The worker. - */ -export async function createWebWorker(url: string, initialMem?: number, maxMem?: number): Promise { - const worker = new Worker(url); - const transportConnect = new WorkerConnector(worker); - const transportClient = new TransportClient(transportConnect); - await transportClient.open(); - const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; - // eslint-disable-next-line @typescript-eslint/no-misused-promises - remoteModule.destroyWorker = async () => { - await transportClient.request({ fn: '__destroyWorker__', args: [] }); - transportClient.close(); - }; - await remoteModule.init(initialMem, maxMem); - return remoteModule; -} diff --git a/yarn-project/foundation/src/worker/data_store.ts b/yarn-project/foundation/src/worker/data_store.ts deleted file mode 100644 index afa4b4d47584..000000000000 --- a/yarn-project/foundation/src/worker/data_store.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Simple read/write interface for wasm modules. - */ -export interface DataStore { - /** - * Get a value from our DB. - * @param key - The key to look up. - * @returns The value. - */ - get(key: string): Promise; - - /** - * Set a value in our DB. - * @param key - The key to update. - * @param value - The value to set. - * @returns Nothing. - */ - set(key: string, value: Buffer): Promise; -} diff --git a/yarn-project/foundation/src/worker/index.ts b/yarn-project/foundation/src/worker/index.ts deleted file mode 100644 index 40ba3dfad773..000000000000 --- a/yarn-project/foundation/src/worker/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { WorkerPool } from './worker_pool.js'; -export type { WasmWorker } from './wasm_worker.js'; diff --git a/yarn-project/foundation/src/worker/node/index.ts b/yarn-project/foundation/src/worker/node/index.ts deleted file mode 100644 index 6ac2cfb6ba37..000000000000 --- a/yarn-project/foundation/src/worker/node/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './node_worker.js'; -export * from './node_data_store.js'; diff --git a/yarn-project/foundation/src/worker/node/node_data_store.ts b/yarn-project/foundation/src/worker/node/node_data_store.ts deleted file mode 100644 index 8a5137e0693a..000000000000 --- a/yarn-project/foundation/src/worker/node/node_data_store.ts +++ /dev/null @@ -1,27 +0,0 @@ -import leveldown from 'leveldown'; -import levelup, { type LevelUp } from 'levelup'; -import memdown from 'memdown'; - -import type { DataStore } from '../data_store.js'; - -/** - * Cache for data used by wasm module. - */ -export class NodeDataStore implements DataStore { - private db: LevelUp; - - // eslint-disable-next-line - constructor(path?: string) { - // Hack: Cast as any to work around packages "broken" with node16 resolution - // See https://github.com/microsoft/TypeScript/issues/49160 - this.db = levelup(path ? (leveldown as any)(path) : (memdown as any)()); - } - - async get(key: string): Promise { - return await this.db.get(key).catch(() => {}); - } - - async set(key: string, value: Buffer): Promise { - await this.db.put(key, value); - } -} diff --git a/yarn-project/foundation/src/worker/node/node_worker.ts b/yarn-project/foundation/src/worker/node/node_worker.ts deleted file mode 100644 index 0e4435714008..000000000000 --- a/yarn-project/foundation/src/worker/node/node_worker.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Worker } from 'worker_threads'; - -import { type DispatchMsg, NodeConnector, TransportClient, createDispatchProxy } from '../../transport/index.js'; -import { WasmModule } from '../../wasm/wasm_module.js'; -import type { WasmWorker } from '../wasm_worker.js'; - -/** - * Creates a node worker. - */ -export async function createNodeWorker(filepath: string, initialMem?: number, maxMem?: number): Promise { - const worker = new Worker(filepath); - const transportConnect = new NodeConnector(worker); - const transportClient = new TransportClient(transportConnect); - await transportClient.open(); - const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; - // eslint-disable-next-line @typescript-eslint/no-misused-promises - remoteModule.destroyWorker = async () => { - await transportClient.request({ fn: '__destroyWorker__', args: [] }); - transportClient.close(); - }; - await remoteModule.init(initialMem, maxMem); - return remoteModule; -} diff --git a/yarn-project/foundation/src/worker/node/start_node_module.ts b/yarn-project/foundation/src/worker/node/start_node_module.ts deleted file mode 100644 index a3cf11031263..000000000000 --- a/yarn-project/foundation/src/worker/node/start_node_module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { parentPort } from 'worker_threads'; - -import { type DispatchMsg, NodeListener, TransportServer } from '../../transport/index.js'; -import type { WasmModule } from '../../wasm/wasm_module.js'; -import { WorkerLogger } from '../worker_logger.js'; - -if (!parentPort) { - throw new Error('InvalidWorker'); -} - -/** - * Start the transport server corresponding to this module. - * @param module - The WasmModule to host. - */ -export function startNodeModule(module: WasmModule) { - const dispatch = async ({ fn, args }: DispatchMsg) => { - if (fn === '__destroyWorker__') { - transportServer.stop(); - return; - } - if (!(module as any)[fn]) { - throw new Error(`dispatch error, function not found: ${fn}`); - } - return await (module as any)[fn](...args); - }; - const transportListener = new NodeListener(); - const transportServer = new TransportServer(transportListener, dispatch); - const logger = new WorkerLogger(transportServer); - module.addLogger(logger); - transportServer.start(); -} diff --git a/yarn-project/foundation/src/worker/wasm_worker.ts b/yarn-project/foundation/src/worker/wasm_worker.ts deleted file mode 100644 index 06202e0d07c6..000000000000 --- a/yarn-project/foundation/src/worker/wasm_worker.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Proxify } from '../transport/index.js'; -import type { WasmModule } from '../wasm/wasm_module.js'; - -/** - * Represents either a WASM web worker, or node.js worker. - */ -export type WasmWorker = Proxify & { destroyWorker(): void }; diff --git a/yarn-project/foundation/src/worker/worker_logger.ts b/yarn-project/foundation/src/worker/worker_logger.ts deleted file mode 100644 index 57e84d99f673..000000000000 --- a/yarn-project/foundation/src/worker/worker_logger.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { type DispatchMsg, TransportServer } from '../transport/index.js'; - -/** - * A logger implementation that forwards log messages via a transport server. - * The logger maintains a fixed trace level and always enables logging. - */ -export class WorkerLogger { - constructor(private transportServer: TransportServer) {} - - silent = () => {}; - fatal = (msg: string, err?: unknown, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'fatal', msg, err, data] }); - error = (msg: string, err?: unknown, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'error', msg, err, data] }); - warn = (msg: string, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'warn', msg, data] }); - info = (msg: string, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'info', msg, data] }); - verbose = (msg: string, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'verbose', msg, data] }); - debug = (msg: string, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'debug', msg, data] }); - trace = (msg: string, data?: unknown) => - this.transportServer.broadcast({ fn: 'emit', args: ['log', 'trace', msg, data] }); - - readonly level = 'trace' as const; - readonly isLevelEnabled = () => true; - readonly module = 'web-worker'; -} diff --git a/yarn-project/foundation/src/worker/worker_pool.ts b/yarn-project/foundation/src/worker/worker_pool.ts deleted file mode 100644 index 353989c9a4ff..000000000000 --- a/yarn-project/foundation/src/worker/worker_pool.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { createLogger } from '../log/index.js'; -import type { WasmWorker } from './wasm_worker.js'; - -const log = createLogger('foundation:worker_pool'); - -/** - * Type of a worker factory. - * Used to customize WorkerPool worker construction. - */ -export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; -/** - * Allocates a pool of WasmWorker's. - * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key - * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). - */ -export class WorkerPool { - // TODO(AD): Revisit what this means in aztec 3 context - // -- - // Introduction of low mem prover work (polynomial cache) may actually increase mem usage when the backing store isn't - // enabled. We were seeing intermittent failings related to memory in production for some users when limiting to - // 6660 (416MB). It would be nice to understand why this is (the non determinism and/or the increased mem usage). - // For now, increasing mem usage to 512MB. This maybe preferable to backing out the low mem work, but - // ironically may break the chance of us using it in mobile. - // We *could* enable the low memory backing store, but this needs a little bit of work to actually - // read/write from indexeddb, performance testing, and actual further memory load testing. - // At this point it's hard to know what our memory savings would be relative to just fully reverting the LMP. - // public static MAX_PAGES = 6660; - /** - * The maximum number of memory pages to be used by the webassembly. - */ - public static MAX_PAGES = 8192; - /** - * The workers in the pool. - */ - private workers: WasmWorker[] = []; - - /** - * Create an instance and initialize the workers. - * @param createWorker - Worker factory. - * @param poolSize - Pool size. - * @returns An initialized WorkerPool. - */ - static async new(createWorker: CreateWorker, poolSize: number) { - const pool = new WorkerPool(); - await pool.init(createWorker, poolSize); - return pool; - } - - /** - * Initialize the workers. - * @param createWorker - Worker factory(). - * @param poolSize - Pool size. - * @param maxMem - Max memory pages. - */ - public async init(createWorker: CreateWorker, poolSize: number, maxMem = WorkerPool.MAX_PAGES) { - log.debug(`creating ${poolSize} workers...`); - const start = new Date().getTime(); - this.workers = await Promise.all( - Array(poolSize) - .fill(0) - .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem)), - ); - - log.debug(`created workers: ${new Date().getTime() - start}ms`); - } - - /** - * Tell all workers in the pool to stop processing. - */ - public async destroy() { - await Promise.all(this.workers.map(w => w.destroyWorker())); - } -} From 6e63f8339f5aa3269970b4cc21dcf7b53bf1f501 Mon Sep 17 00:00:00 2001 From: benesjan Date: Wed, 2 Apr 2025 17:04:05 +0000 Subject: [PATCH 5/6] nuking transport/browser --- .../foundation/src/transport/browser/index.ts | 4 -- .../transport/browser/message_port_socket.ts | 48 ----------------- .../browser/shared_worker_connector.ts | 21 -------- .../browser/shared_worker_listener.ts | 53 ------------------ .../src/transport/browser/worker_connector.ts | 30 ----------- .../src/transport/browser/worker_listener.ts | 54 ------------------- .../foundation/src/transport/index.ts | 1 - 7 files changed, 211 deletions(-) delete mode 100644 yarn-project/foundation/src/transport/browser/index.ts delete mode 100644 yarn-project/foundation/src/transport/browser/message_port_socket.ts delete mode 100644 yarn-project/foundation/src/transport/browser/shared_worker_connector.ts delete mode 100644 yarn-project/foundation/src/transport/browser/shared_worker_listener.ts delete mode 100644 yarn-project/foundation/src/transport/browser/worker_connector.ts delete mode 100644 yarn-project/foundation/src/transport/browser/worker_listener.ts diff --git a/yarn-project/foundation/src/transport/browser/index.ts b/yarn-project/foundation/src/transport/browser/index.ts deleted file mode 100644 index 24094f4965fa..000000000000 --- a/yarn-project/foundation/src/transport/browser/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './worker_connector.js'; -export * from './worker_listener.js'; -export * from './shared_worker_connector.js'; -export * from './shared_worker_listener.js'; diff --git a/yarn-project/foundation/src/transport/browser/message_port_socket.ts b/yarn-project/foundation/src/transport/browser/message_port_socket.ts deleted file mode 100644 index 64d46c530ece..000000000000 --- a/yarn-project/foundation/src/transport/browser/message_port_socket.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { Socket } from '../interface/socket.js'; - -/** - * An implementation of a TransportSocket using MessagePorts. - */ -export class MessagePortSocket implements Socket { - constructor(private port: MessagePort) {} - - /** - * Send a message to the connected MessagePort, optionally transferring ownership of certain objects. - * The 'msg' parameter can be any structured data type and will be sent to the other end of the MessagePort. - * The optional 'transfer' parameter is an array of Transferable objects whose ownership will be transferred, - * making them inaccessible on the sending side. This can improve performance for large data transfers. - * - * @param msg - The message to be sent through the MessagePort. - * @param transfer - An optional array of Transferable objects to transfer ownership. - * @returns A Promise that resolves when the message has been sent. - */ - send(msg: any, transfer: Transferable[] = []): Promise { - this.port.postMessage(msg, transfer); - return Promise.resolve(); - } - - /** - * Register a callback function to handle incoming messages from the MessagePort. - * The provided callback will be invoked with the message data whenever a new message arrives. - * Note that only one callback can be registered at a time. Subsequent calls to this method - * will overwrite the previously registered callback. - * - * @param cb - The callback function to handle incoming messages. - */ - registerHandler(cb: (msg: any) => any): void { - this.port.onmessage = event => cb(event.data); - } - - /** - * Close the MessagePort, unregister the message handler, and send an undefined message. - * The 'close' function is useful for gracefully shutting down a connection between two - * endpoints by sending an undefined message as an indication of disconnection before - * closing the port. After calling this method, the MessagePortSocket instance should not - * be used again. - */ - close() { - void this.send(undefined); - this.port.onmessage = null; - this.port.close(); - } -} diff --git a/yarn-project/foundation/src/transport/browser/shared_worker_connector.ts b/yarn-project/foundation/src/transport/browser/shared_worker_connector.ts deleted file mode 100644 index 54f2fe089b1c..000000000000 --- a/yarn-project/foundation/src/transport/browser/shared_worker_connector.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Connector } from '../interface/connector.js'; -import { MessagePortSocket } from './message_port_socket.js'; - -/** - * SharedWorkerConnector is an implementation of the Connector interface, specifically for SharedWorkers. - * It enables the creation of MessagePortSockets that communicate with a shared worker and allow - * multiple scripts to communicate with the worker using the same connection. - */ -export class SharedWorkerConnector implements Connector { - constructor(private worker: SharedWorker) {} - - /** - * Creates a new MessagePortSocket instance using the SharedWorker's port. - * This method allows for easy creation of sockets to communicate with the SharedWorker. - * - * @returns A Promise that resolves to a new MessagePortSocket instance. - */ - createSocket() { - return Promise.resolve(new MessagePortSocket(this.worker.port)); - } -} diff --git a/yarn-project/foundation/src/transport/browser/shared_worker_listener.ts b/yarn-project/foundation/src/transport/browser/shared_worker_listener.ts deleted file mode 100644 index d1ec4b89850a..000000000000 --- a/yarn-project/foundation/src/transport/browser/shared_worker_listener.ts +++ /dev/null @@ -1,53 +0,0 @@ -import EventEmitter from 'events'; - -import type { Listener } from '../interface/listener.js'; -import { MessagePortSocket } from './message_port_socket.js'; - -/** - * Represents the global scope of a Shared Worker. - * Provides functionality to handle incoming connections and manage communication with other scripts - * running in a shared context, enabling concurrent access and efficient resource sharing among those scripts. - */ -declare interface SharedWorkerGlobalScope { - /** - * Event handler for new connections to the Shared Worker. - */ - onconnect: (...args: any) => any; -} - -/** - * SharedWorkerListener is an extension of the EventEmitter class that implements the Listener interface. - * It provides functionality to handle incoming messages from a shared worker and emit events for new sockets - * created in response to these incoming connections. This class is meant to be used in the context of managing - * MessagePort connections within the SharedWorkerGlobalScope. - */ -export class SharedWorkerListener extends EventEmitter implements Listener { - constructor(private worker: SharedWorkerGlobalScope) { - super(); - } - - /** - * Initializes the shared worker listener by assigning the 'handleMessageEvent' method as the event handler - * for the 'onconnect' event of the SharedWorkerGlobalScope. The 'handleMessageEvent' function will be called - * whenever a new connection is established with the shared worker. - */ - open() { - this.worker.onconnect = this.handleMessageEvent; - } - - /** - * Closes the SharedWorkerListener by detaching the 'onconnect' event handler. - * This stops the listener from emitting new sockets on incoming connections. - */ - close() { - this.worker.onconnect = () => {}; - } - - private handleMessageEvent = (event: MessageEvent) => { - const [port] = event.ports; - if (!port) { - return; - } - this.emit('new_socket', new MessagePortSocket(port)); - }; -} diff --git a/yarn-project/foundation/src/transport/browser/worker_connector.ts b/yarn-project/foundation/src/transport/browser/worker_connector.ts deleted file mode 100644 index c1908d4af850..000000000000 --- a/yarn-project/foundation/src/transport/browser/worker_connector.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Connector } from '../interface/connector.js'; -import { MessagePortSocket } from './message_port_socket.js'; - -/** - * WorkerConnector is a class implementing the Connector interface for creating communication sockets - * with Web Workers. It allows to establish a connection with the worker and create MessagePortSockets - * using MessageChannels, enabling seamless communication between the main thread and worker threads. - * - * @example - * const worker = new Worker('./myWorker.js'); - * const connector = new WorkerConnector(worker); - * const socket = await connector.createSocket(); - * socket.send('Hello, worker!'); - */ -export class WorkerConnector implements Connector { - constructor(private worker: Worker) {} - - /** - * Creates a new MessagePortSocket instance by establishing a connection between the Worker and the main thread. - * A MessageChannel is created, and one of its ports is sent to the Worker using postMessage. - * The other port is used to create a new MessagePortSocket which is then returned as a Promise. - * - * @returns A Promise that resolves to a new MessagePortSocket instance. - */ - createSocket() { - const channel = new MessageChannel(); - this.worker.postMessage('', [channel.port2]); - return Promise.resolve(new MessagePortSocket(channel.port1)); - } -} diff --git a/yarn-project/foundation/src/transport/browser/worker_listener.ts b/yarn-project/foundation/src/transport/browser/worker_listener.ts deleted file mode 100644 index 6ca2f46498c7..000000000000 --- a/yarn-project/foundation/src/transport/browser/worker_listener.ts +++ /dev/null @@ -1,54 +0,0 @@ -import EventEmitter from 'events'; - -import type { Listener } from '../interface/listener.js'; -import { MessagePortSocket } from './message_port_socket.js'; - -/** - * Represents a DedicatedWorkerGlobalScope, which is the global execution context for a dedicated worker. - * Provides properties and methods to manage the worker's lifecycle and communication with other threads or workers. - */ -declare interface DedicatedWorkerGlobalScope { - /** - * Handler for incoming messages from other threads or workers. - */ - onmessage: any; -} - -/** - * WorkerListener is a class that extends EventEmitter and implements the Listener interface. - * It listens for incoming connections on a dedicated worker global scope, and emits a 'new_socket' event - * with a MessagePortSocket instance for each new connection. This allows applications to communicate - * with other workers or main thread through the MessagePortSocket abstraction. - * - * The open() method starts listening for incoming connections, while the close() method stops it. - */ -export class WorkerListener extends EventEmitter implements Listener { - constructor(private worker: DedicatedWorkerGlobalScope) { - super(); - } - - /** - * Initializes the WorkerListener by setting the 'onmessage' event handler of the worker. - * The 'onmessage' event will be triggered when the worker receives a message, and it will then - * call the handleMessageEvent method to handle incoming connections. - */ - open() { - this.worker.onmessage = this.handleMessageEvent; - } - - /** - * Close the worker listener by removing the 'onmessage' event handler. - * This method effectively stops the WorkerListener from reacting to new incoming messages. - */ - close() { - this.worker.onmessage = () => {}; - } - - private handleMessageEvent = (event: MessageEvent) => { - const [port] = event.ports; - if (!port) { - return; - } - this.emit('new_socket', new MessagePortSocket(port)); - }; -} diff --git a/yarn-project/foundation/src/transport/index.ts b/yarn-project/foundation/src/transport/index.ts index 1ea1f8c30cf3..0640157d9eb6 100644 --- a/yarn-project/foundation/src/transport/index.ts +++ b/yarn-project/foundation/src/transport/index.ts @@ -7,5 +7,4 @@ export * from './interface/socket.js'; export * from './interface/transferable.js'; export * from './transport_client.js'; export * from './transport_server.js'; -export * from './browser/index.js'; export * from './node/index.js'; From adf51d565d28614cea7096869b096a9ec47616ca Mon Sep 17 00:00:00 2001 From: benesjan Date: Wed, 2 Apr 2025 19:20:44 +0000 Subject: [PATCH 6/6] nuking wasm dir --- yarn-project/foundation/package.json | 1 - yarn-project/foundation/src/index.ts | 1 - yarn-project/foundation/src/wasm/README.md | 6 - .../foundation/src/wasm/empty_wasi_sdk.ts | 166 ----------- .../foundation/src/wasm/fixtures/gcd.wasm | Bin 76 -> 0 bytes .../foundation/src/wasm/fixtures/gcd.wat | 27 -- yarn-project/foundation/src/wasm/index.ts | 1 - .../foundation/src/wasm/wasm_module.ts | 266 ------------------ 8 files changed, 468 deletions(-) delete mode 100644 yarn-project/foundation/src/wasm/README.md delete mode 100644 yarn-project/foundation/src/wasm/empty_wasi_sdk.ts delete mode 100644 yarn-project/foundation/src/wasm/fixtures/gcd.wasm delete mode 100644 yarn-project/foundation/src/wasm/fixtures/gcd.wat delete mode 100644 yarn-project/foundation/src/wasm/index.ts delete mode 100644 yarn-project/foundation/src/wasm/wasm_module.ts diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index 3035f417a638..8db21b3169ee 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -39,7 +39,6 @@ "./timer": "./dest/timer/index.js", "./transport": "./dest/transport/index.js", "./trees": "./dest/trees/index.js", - "./wasm": "./dest/wasm/index.js", "./bigint-buffer": "./dest/bigint-buffer/index.js", "./types": "./dest/types/index.js", "./schemas": "./dest/schemas/index.js", diff --git a/yarn-project/foundation/src/index.ts b/yarn-project/foundation/src/index.ts index 2c6012ef17ef..f5f39dd6e830 100644 --- a/yarn-project/foundation/src/index.ts +++ b/yarn-project/foundation/src/index.ts @@ -23,7 +23,6 @@ export * as transport from './transport/index.js'; export * as trees from './trees/index.js'; export * as types from './types/index.js'; export * as url from './url/index.js'; -export * as wasm from './wasm/index.js'; export * as testing from './testing/index.js'; export * as config from './config/index.js'; export * as buffer from './buffer/index.js'; diff --git a/yarn-project/foundation/src/wasm/README.md b/yarn-project/foundation/src/wasm/README.md deleted file mode 100644 index b15e77562881..000000000000 --- a/yarn-project/foundation/src/wasm/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# wasm - -Functionality to: - -1. Call WebAssembly functions -2. Create asynchronous workers that host webassembly. diff --git a/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts b/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts deleted file mode 100644 index 968ee6240758..000000000000 --- a/yarn-project/foundation/src/wasm/empty_wasi_sdk.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { createLogger } from '../log/index.js'; - -/** - * Dummy implementation of a necessary part of the wasi api: - * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md - * We don't use these functions, but the environment expects them. - * TODO find a way to update off of wasi 12. - */ -/* eslint-disable camelcase */ -export const getEmptyWasiSdk = (logger = createLogger('wasm:empty_wasi_sdk')) => ({ - /** - * Retrieves the current time from the system clock. - * This function is a dummy implementation of the WASI API's `clock_time_get` method, - * which is expected by the environment but not used in this context. - * - * No input parameters or return values are required, as the purpose of this function - * is solely to satisfy the environment expectations and provide debugging information. - */ - clock_time_get() { - logger.debug('clock_time_get'); - }, - /** - * Dummy implementation of WASI's environ_get function. - * This function is used to obtain a snapshot of the current environment variables. - * In this dummy implementation, no actual actions are performed, but the debug logger logs 'environ_get' when called. - * Environment variables are not used in this context, so the real implementation is not required. - * - * @see https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#environ_get - */ - environ_get() { - logger.debug('environ_get'); - }, - /** - * Retrieves the environment variable sizes from the WebAssembly environment. - * This function is part of the WASI API and provides a dummy implementation to fulfill the expected APIs. - * It does not have any actual functionality, but serves as a placeholder in the environment. - */ - environ_sizes_get() { - logger.debug('environ_sizes_get'); - }, - /** - * Closes a file descriptor, releasing any resources associated with it. - * This function does not perform any actual closing operation, but exists to - * satisfy the requirements of the WebAssembly System Interface (WASI) API, - * which expects certain functions to be present for compatibility purposes. - * - * @see https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md - */ - fd_close() { - logger.debug('fd_close'); - }, - /** - * A dummy implementation of the 'fd_read' function from the WASI API. - * This function is required by the environment, but not used in this context. - * It would normally read data from a file descriptor into an array buffer, - * but here it simply logs the invocation for debugging purposes. - */ - fd_read() { - logger.debug('fd_read'); - }, - /** - * Handles the file descriptor write operation. - * This dummy implementation of the WASI 'fd_write' function is part of the wasi API: - * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md - * The environment expects this function, but it is not used in the current implementation. - * It is used to write data from WebAssembly memory to a file descriptor. - */ - fd_write() { - logger.debug('fd_write'); - }, - /** - * Perform a file seek operation on the given file descriptor to change its current position. - * The new position is calculated using the provided offset and whence values. - * Throws an error if the file descriptor is invalid or the operation cannot be performed. - * - * @param fd - The file descriptor of the file to perform the seek operation on. - * @param offset - The relative offset to apply, based on the whence value. - * @param whence - The reference point from which the offset should be calculated. One of SEEK_SET (start), SEEK_CUR (current), or SEEK_END (end). - * @returns The new position in the file after the seek operation has been performed. - */ - fd_seek() { - logger.debug('fd_seek'); - }, - /** - * This function is a dummy implementation of the 'fd_fdstat_get' function in the WebAssembly System Interface (WASI) API. - * Although not actually used in this context, it is present due to the environment's expectation of its existence. - * The 'fd_fdstat_get' function is typically responsible for obtaining file descriptor status information. - */ - fd_fdstat_get() { - logger.debug('fd_fdstat_get'); - }, - /** - * Sets the file descriptor flags for a given file descriptor. - * This function is a dummy implementation of the WASI API function 'fd_fdstat_set_flags'. - * It currently does not perform any operation but logs the function call with a debug instance. - * This is provided since the environment expects this function to be present. - */ - fd_fdstat_set_flags() { - logger.debug('fd_fdstat_set_flags'); - }, - /** - * Handles the `fd_prestat_get` function call for the dummy WebAssembly System Interface (WASI) implementation. - * This function is expected by the WASI environment, although it is not used in this implementation. - * The `fd_prestat_get` function retrieves pre-opened file descriptor properties. - * - * @returns A constant integer value indicating successful completion of the function call. - */ - fd_prestat_get() { - logger.debug('fd_prestat_get'); - return 8; - }, - /** - * Provides a dummy implementation for the `fd_prestat_dir_name` function, which is expected to be called by the WASI environment. - * This function is intended to retrieve the pre-opened directory's path associated with the given file descriptor. However, since it's a dummy implementation, - * it doesn't perform any actual operation and only logs the function call with the provided debug logger. - * - * @returns A constant number representing a dummy return value for the function call. - */ - fd_prestat_dir_name() { - logger.debug('fd_prestat_dir_name'); - return 28; - }, - /** - * Handles the opening of a file path within the WASI environment. - * This function is a dummy implementation required for compatibility with - * the WebAssembly System Interface (WASI) API, but it does not perform any - * actual file opening operation. It is mainly used for debugging purposes. - */ - path_open() { - logger.debug('path_open'); - }, - /** - * Retrieve file system information of the specified path. - * This function retrieves statistics, such as size and permissions, associated with the file or directory - * identified by the given path. In case of an error or non-existing path, appropriate debug logs will be generated. - * - * @returns An object containing file statistics like size, permissions, etc. - */ - path_filestat_get() { - logger.debug('path_filestat_get'); - }, - /** - * Terminate the process normally, performing the regular cleanup for terminating programs. - * The input 'status' represents the exit code and is used to indicate success or failure - * of the program execution. A zero value typically indicates successful execution, - * while non-zero values are treated as errors by the operating system. - * - * @param status - The exit code representing the success or failure of the program execution. - * @returns The exit status code. - */ - proc_exit() { - logger.debug('proc_exit'); - return 52; - }, - /** - * Generates a random number and returns it. - * This dummy implementation of 'random_get' method in the wasi API is expected by the environment. - * In this case, the function always returns 1 to maintain consistency with the environment's expectations. - * - * @returns A random number. In this implementation, always returns 1. - */ - random_get() { - logger.debug('random_get'); - return 1; - }, -}); diff --git a/yarn-project/foundation/src/wasm/fixtures/gcd.wasm b/yarn-project/foundation/src/wasm/fixtures/gcd.wasm deleted file mode 100644 index 19a859c306c3acf6de25eef3ea26711d05e783bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76 zcmWN@!3lsc5Cp*8&Evo`JzRW>MWmF7f-ga^fNNdnHQ3*q0B9V_WEK%-EZ1=Y)5eud Xb@f0+uxX~39t(); - private logger: Logger; - - /** - * Create a wasm module. Should be followed by await init();. - * @param module - The module as a WebAssembly.Module or a Buffer. - * @param importFn - Imports expected by the WASM. - * @param loggerName - Optional, for debug logging. - */ - constructor( - private module: WebAssembly.Module | Buffer, - private importFn: (module: WasmModule) => any, - loggerName = 'wasm', - ) { - this.logger = createLogger(loggerName); - this.mutexQ.put(true); - } - - /** - * Return the wasm source. - * @returns The source. - */ - public getModule(): WebAssembly.Module | Buffer { - return this.module; - } - /** - * Initialize this wasm module. - * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. - * @param initial - 30 pages by default. 30*2**16 \> 1mb stack size plus other overheads. - * @param initMethod - Defaults to calling '_initialize'. - * @param maximum - 8192 maximum by default. 512mb. - */ - public async init(initial = 31, maximum = 8192, initMethod: string | null = '_initialize') { - this.logger.debug( - `initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${ - (maximum * 2 ** 16) / (1024 * 1024) - }mb`, - ); - this.memory = new WebAssembly.Memory({ initial, maximum }); - // Create a view over the memory buffer. - // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, - // thus displaying double. It's only worse if we create views on demand. I haven't established yet if - // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be - // that the OS is actually getting an incorrect reading in the same way the memory profiler does... - // The view will have to be recreated if the memory is grown. See getMemory(). - this.heap = new Uint8Array(this.memory.buffer); - - // We support the wasi 12 SDK, but only implement random_get - /* eslint-disable camelcase */ - const importObj = { - wasi_snapshot_preview1: { - ...getEmptyWasiSdk(this.logger), - random_get: (arr: number, length: number) => { - arr = arr >>> 0; - const heap = this.getMemory(); - const randomData = randomBytes(length); - for (let i = arr; i < arr + length; ++i) { - heap[i] = randomData[i - arr]; - } - }, - }, - env: this.importFn(this), - }; - - if (this.module instanceof WebAssembly.Module) { - this.instance = await WebAssembly.instantiate(this.module, importObj); - } else { - const { instance } = await WebAssembly.instantiate(this.module, importObj); - this.instance = instance; - } - - // Init all global/static data. - if (initMethod) { - this.call(initMethod); - } - } - - /** - * The methods or objects exported by the WASM module. - * @returns An indexable object. - */ - public exports(): any { - if (!this.instance) { - throw new Error('WasmModule: not initialized!'); - } - return this.instance.exports; - } - - /** - * Get the current logger. - * @returns Logging function. - */ - public getLogger() { - return this.logger; - } - - /** - * Add a logger. - * @param logger - Logger to call when logging. - */ - public addLogger(logger: Logger) { - const oldLogger = this.logger; - this.logger = createLogger(oldLogger.module); - // Copy all log levels from both loggers - Object.keys(oldLogger).forEach(level => { - if (typeof oldLogger[level as keyof Logger] === 'function') { - (this.logger as any)[level] = (msg: string, ...args: any[]) => { - (oldLogger as any)[level](msg, ...args); - (logger as any)[level](msg, ...args); - }; - } - }); - } - - /** - * Calls into the WebAssembly. - * @param name - The method name. - * @param args - The arguments to the method. - * @returns The numeric method result. - */ - public call(name: string, ...args: any): number { - if (!this.exports()[name]) { - throw new Error(`WASM function ${name} not found.`); - } - try { - // When returning values from the WASM, use >>> operator to convert - // signed representation to unsigned representation. - return this.exports()[name](...args) >>> 0; - } catch (err: any) { - const message = `WASM function ${name} aborted, error: ${err}\n${err.stack}`; - throw new Error(message); - } - } - /** - * Get the memory used by the WASM module. - * @returns A WebAssembly memory object. - */ - public getRawMemory(): WebAssembly.Memory { - return this.memory; - } - /** - * Get the memory used by the WASM module, as a byte array. - * @returns A Uint8Array view of the WASM module memory. - */ - public getMemory(): Uint8Array { - // If the memory is grown, our view over it will be lost. Recreate the view. - if (this.heap.length === 0) { - this.heap = new Uint8Array(this.memory.buffer); - } - return this.heap; - } - - /** - * The memory size in bytes. - * @returns Number of bytes. - */ - public memSize(): number { - return this.getMemory().length; - } - - /** - * Get a slice of memory between two addresses. - * @param start - The start address. - * @param end - The end address. - * @returns A Uint8Array view of memory. - */ - public getMemorySlice(start: number, end: number): Uint8Array { - return this.getMemory().slice(start, end); - } - - /** - * Write data into the heap. - * @param offset - The address to write data at. - * @param arr - The data to write. - */ - public writeMemory(offset: number, arr: Uint8Array) { - const mem = this.getMemory(); - for (let i = 0; i < arr.length; i++) { - mem[i + offset] = arr[i]; - } - } - - /** - * Read WASM memory as a JS string. - * @param addr - The memory address. - * @returns A JS string. - */ - public getMemoryAsString(addr: number) { - addr = addr >>> 0; - const m = this.getMemory(); - let i = addr; - while (m[i] !== 0) { - ++i; - } - return Buffer.from(m.slice(addr, i)).toString('ascii'); - } - - /** - * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. - * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via - * writeMemory before the result is read via sliceMemory. - * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. - */ - public async acquire() { - await this.mutexQ.get(); - } - - /** - * Release the mutex, letting another promise call acquire(). - */ - public release() { - if (this.mutexQ.length() !== 0) { - throw new Error('Release called but not acquired.'); - } - this.mutexQ.put(true); - } -}