Skip to content

Commit

Permalink
refactor: use @emnapi/wasi-threads as dep
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi committed May 8, 2024
1 parent f8b6aae commit 01b5fdd
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 388 deletions.
2 changes: 1 addition & 1 deletion packages/core/script/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const dist = path.join(__dirname, '../dist')
function build () {
compile(path.join(__dirname, '../tsconfig.json'), {
optionsToExtend: {
target: require('typescript').ScriptTarget.ES2019,
target: ts.ScriptTarget.ES2019,
emitDeclarationOnly: true,
declaration: true,
declarationDir: path.join(__dirname, '../lib/typings')
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/emnapi/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Context } from '@emnapi/runtime'
import type { ThreadManager } from '@emnapi/wasi-threads'

/** @public */
export declare interface PointerInfo {
Expand Down Expand Up @@ -34,6 +35,7 @@ export declare interface NapiModule {
len?: number
): T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}

init (options: InitOptions): any
Expand All @@ -42,6 +44,10 @@ export declare interface NapiModule {
initWorker (arg: number): void
executeAsyncWork (work: number): void
postMessage?: (msg: any) => any

waitThreadStart: boolean
/** @internal */
PThread: ThreadManager
}

/** @public */
Expand Down
20 changes: 13 additions & 7 deletions packages/core/src/load.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { WASIThreads } from '@emnapi/wasi-threads'
import { type InputType, load, loadSync } from './util'
import { createNapiModule } from './emnapi/index'
import type { CreateOptions, NapiModule } from './emnapi/index'
Expand Down Expand Up @@ -67,16 +68,18 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
}

const wasi = options!.wasi
const wasiThreads = new WASIThreads(
napiModule.childThread
? { postMessage: napiModule.postMessage! }
: {
threadManager: napiModule.PThread,
waitThreadStart: napiModule.waitThreadStart
}
)
let importObject: WebAssembly.Imports = {
env: napiModule.imports.env,
napi: napiModule.imports.napi,
emnapi: napiModule.imports.emnapi,
wasi: {
// eslint-disable-next-line camelcase
'thread-spawn': function __imported_wasi_thread_spawn (startArg: number, errorOrTid: number) {
return napiModule.spawnThread(startArg, errorOrTid)
}
}
emnapi: napiModule.imports.emnapi
}

if (wasi) {
Expand All @@ -88,6 +91,8 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
)
}

Object.assign(importObject, wasiThreads.getImportObject())

const overwriteImports = options!.overwriteImports
if (typeof overwriteImports === 'function') {
const newImportObject = overwriteImports(importObject)
Expand Down Expand Up @@ -177,6 +182,7 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
}
wasi.initialize(instance)
}
wasiThreads.setup(instance, module, memory)

if (beforeInit) {
beforeInit({
Expand Down
133 changes: 15 additions & 118 deletions packages/core/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,144 +1,41 @@
import {
MessageHandler as WASIThreadsMessageHandler,
type HandleOptions,
type OnLoadData
} from '@emnapi/wasi-threads'
import type { NapiModule } from './emnapi/index'
import type { InstantiatedSource } from './load'

/** @public */
export interface OnLoadData {
wasmModule: WebAssembly.Module
wasmMemory: WebAssembly.Memory
}
export type { HandleOptions, OnLoadData }

/** @public */
export interface HandleOptions {
onLoad (data: OnLoadData): InstantiatedSource | Promise<InstantiatedSource>
}

/** @public */
export class MessageHandler {
onLoad: (data: OnLoadData) => InstantiatedSource | Promise<InstantiatedSource>
instance: WebAssembly.Instance | undefined
// module: WebAssembly.Module | undefined
export class MessageHandler extends WASIThreadsMessageHandler {
napiModule: NapiModule | undefined
messagesBeforeLoad: any[]

constructor (options: HandleOptions) {
const onLoad = options.onLoad
if (typeof onLoad !== 'function') {
throw new TypeError('options.onLoad is not a function')
}
this.onLoad = onLoad
this.instance = undefined
// this.module = undefined
super(options)
this.napiModule = undefined
this.messagesBeforeLoad = []
}

handle (e: any): void {
public override handle (e: any): void {
super.handle(e)
if (e?.data?.__emnapi__) {
const type = e.data.__emnapi__.type
const payload = e.data.__emnapi__.payload

const onLoad = this.onLoad
if (type === 'load') {
if (this.instance !== undefined) return
let source: InstantiatedSource | Promise<InstantiatedSource>
try {
source = onLoad(payload)
} catch (err) {
onLoaded.call(this, err, null, payload)
return
}
const then = source && 'then' in source ? source.then : undefined
if (typeof then === 'function') {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
then.call(
source,
(source) => { onLoaded.call(this, null, source, payload) },
(err) => { onLoaded.call(this, err, null, payload) }
)
} else {
onLoaded.call(this, null, source as InstantiatedSource, payload)
}
} else if (type === 'start') {
handleAfterLoad.call(this, e, () => {
notifyPthreadCreateResult(payload.sab, 1)
this.napiModule!.startThread(payload.tid, payload.arg)
})
} else if (type === 'async-worker-init') {
handleAfterLoad.call(this, e, () => {
if (type === 'async-worker-init') {
this.handleAfterLoad(e, () => {
this.napiModule!.initWorker(payload.arg)
})
} else if (type === 'async-work-execute') {
handleAfterLoad.call(this, e, () => {
this.handleAfterLoad(e, () => {
this.napiModule!.executeAsyncWork(payload.work)
})
}
}
}
}

function handleAfterLoad (this: MessageHandler, e: any, f: (e: any) => void): void {
if (this.instance !== undefined) {
f.call(this, e)
} else {
this.messagesBeforeLoad.push(e.data)
}
}

interface LoadPayload {
wasmModule: WebAssembly.Module
wasmMemory: WebAssembly.Memory
sab?: Int32Array
}

function notifyPthreadCreateResult (sab: Int32Array | undefined, result: number): void {
if (sab) {
Atomics.store(sab, 0, result)
Atomics.notify(sab, 0)
}
}

function onLoaded (this: MessageHandler, err: Error | null, source: InstantiatedSource | null, payload: LoadPayload): void {
if (err) {
notifyPthreadCreateResult(payload.sab, 2)
throw err
}

if (source == null) {
notifyPthreadCreateResult(payload.sab, 2)
throw new TypeError('onLoad should return an object')
}

const instance = source.instance
const napiModule = source.napiModule

if (!instance) {
notifyPthreadCreateResult(payload.sab, 2)
throw new TypeError('onLoad should return an object which includes "instance"')
}
if (!napiModule) {
notifyPthreadCreateResult(payload.sab, 2)
throw new TypeError('onLoad should return an object which includes "napiModule"')
}
if (!napiModule.childThread) {
notifyPthreadCreateResult(payload.sab, 2)
throw new Error('napiModule should be created with `childThread: true`')
}

this.instance = instance
this.napiModule = napiModule

const postMessage = napiModule.postMessage!
postMessage({
__emnapi__: {
type: 'loaded',
payload: {}
}
})

const messages = this.messagesBeforeLoad
this.messagesBeforeLoad = []
for (let i = 0; i < messages.length; i++) {
const data = messages[i]
this.handle({ data })
protected override onLoadSuccess (source: InstantiatedSource): void {
this.napiModule = source.napiModule
}
}
1 change: 1 addition & 0 deletions packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"outDir": "lib",
"paths": {
"tslib" : ["../../node_modules/tslib/tslib.d.ts"],
"@emnapi/wasi-threads": ["../wasi-threads/lib/typings/index.d.ts"],
"@/*": ["./src/*"],
},
"lib": [
Expand Down
1 change: 1 addition & 0 deletions packages/emnapi/script/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ async function build () {
})
const parsedCode = compiler.parseCode(code)
return `import { _WebAssembly as WebAssembly } from '@/util'
import * as wasiThreads from '@emnapi/wasi-threads'
export function createNapiModule (options) {
${parsedCode}
Expand Down
2 changes: 1 addition & 1 deletion packages/emnapi/src/core/async-work.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ var emnapiAWMT = {
}
try {
for (let i = 0; i < n; ++i) {
const worker = onCreateWorker({ type: 'async-work' })
const worker = onCreateWorker({ type: 'async-work', name: 'emnapi-async-worker' })
const p = PThread.loadWasmModuleToWorker(worker)
emnapiAWMT.addListener(worker)
promises.push(p.then(() => {
Expand Down
Loading

0 comments on commit 01b5fdd

Please sign in to comment.