Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi committed May 10, 2024
1 parent f49d0eb commit c41ccc8
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 106 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ env:

jobs:
build:
timeout-minutes: 15
name: Build
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -93,6 +94,12 @@ jobs:
shell: bash
run: npm run test -w packages/ts-transform-emscripten-esm-library

- name: Test @emnapi/wasi-threads
if: ${{ !contains(matrix.target, 'emscripten') }}
shell: bash
run: npm run test -w packages/wasi-threads
timeout-minutes: 1

# - name: Lint
# run: npm run lint

Expand Down
38 changes: 23 additions & 15 deletions packages/core/src/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,8 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
}

const wasi = options!.wasi
const wasiThreads = new WASIThreads(
napiModule.childThread
? {
childThread: true,
postMessage: napiModule.postMessage!
}
: {
threadManager: napiModule.PThread,
waitThreadStart: napiModule.waitThreadStart
}
)
let wasiThreads: WASIThreads | undefined

let importObject: WebAssembly.Imports = {
env: napiModule.imports.env,
napi: napiModule.imports.napi,
Expand All @@ -92,9 +83,20 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
? wasi.getImportObject()
: { wasi_snapshot_preview1: wasi.wasiImport }
)
}

Object.assign(importObject, wasiThreads.getImportObject())
wasiThreads = new WASIThreads(
napiModule.childThread
? {
childThread: true,
postMessage: napiModule.postMessage!
}
: {
threadManager: napiModule.PThread,
waitThreadStart: napiModule.waitThreadStart
}
)
Object.assign(importObject, wasiThreads.getImportObject())
}

const overwriteImports = options!.overwriteImports
if (typeof overwriteImports === 'function') {
Expand Down Expand Up @@ -136,9 +138,15 @@ function loadNapiModuleImpl (loadFn: Function, userNapiModule: NapiModule | unde
if (napiModule.childThread) {
instance = createInstanceProxy(instance, memory)
}
wasi.initialize(instance)
wasiThreads!.setup(instance, module, memory)
if ('_start' in originalExports) {
wasi.start(instance)
} else {
wasi.initialize(instance)
}
} else {
napiModule.PThread.setup(module, memory)
}
wasiThreads.setup(instance, module, memory)

if (beforeInit) {
beforeInit({
Expand Down
128 changes: 75 additions & 53 deletions packages/wasi-threads/test/index.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,86 @@
(function () {
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null && typeof process.versions === 'object' && process.versions !== null && typeof process.versions.node === 'string'
(function (main) {
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string'

let Worker, WASI, WASIThreads
if (ENVIRONMENT_IS_NODE) {
const nodeWorkerThreads = require('worker_threads')
Worker = nodeWorkerThreads.Worker
WASI = require('node:wasi').WASI
WASIThreads = require('..').WASIThreads
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return require('..')
return require(request)
}
main(_require, process, __dirname)
} else {
if (typeof importScripts === 'function') {
// eslint-disable-next-line no-undef
importScripts('../../../node_modules/@tybys/wasm-util/dist/wasm-util.min.js')
// eslint-disable-next-line no-undef
importScripts('../dist/wasi-threads.js')
}
Worker = class MainThreadWorker {
constructor (url, options) {
this.id = String(Math.random())
self.addEventListener('message', ({ data }) => {
if (data.type === 'onmessage' && data.payload.id === this.id) {
this.onmessage?.({ data: data.payload.data })
}
})
postMessage({
type: 'new',
payload: {
id: this.id,
url,
options
}
})
}

postMessage (data) {
postMessage({
type: 'postMessage',
payload: {
id: this.id,
data
}
})
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const nodePath = {
join: function () {
return Array.prototype.join.call(arguments, '/')
}
}
const nodeWorkerThreads = {
Worker: class MainThreadWorker {
constructor (url, options) {
this.id = String(Math.random())
self.addEventListener('message', ({ data }) => {
if (data.type === 'onmessage' && data.payload.id === this.id) {
this.onmessage?.({ data: data.payload.data })
}
})
postMessage({
type: 'new',
payload: {
id: this.id,
url,
options
}
})
}

terminate () {
postMessage({
type: 'terminate',
payload: {
id: this.id
}
})
postMessage (data) {
postMessage({
type: 'postMessage',
payload: {
id: this.id,
data
}
})
}

terminate () {
postMessage({
type: 'terminate',
payload: {
id: this.id
}
})
}
}
}
WASI = globalThis.wasmUtil.WASI
WASIThreads = globalThis.wasiThreads.WASIThreads
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
if (request === 'node:path' || request === 'path') return nodePath
throw new Error('Can not find module: ' + request)
}
const _process = {
env: {},
exit: () => {}
}
main(_require, _process, '.')
}
})(function (require, process, __dirname) {
const { WASI } = require('node:wasi')
const { WASIThreads } = require('@emnapi/wasi-threads')
const { Worker } = require('node:worker_threads')
const { join } = require('node:path')

const ExecutionModel = {
Command: 'command',
Expand All @@ -65,19 +92,16 @@
const wasi = new WASI({
version: 'preview1',
args: [file, 'node'],
...(ENVIRONMENT_IS_NODE ? { env: process.env } : {})
env: process.env
})
const wasiThreads = new WASIThreads({
onCreateWorker: ({ name }) => {
const workerjs = ENVIRONMENT_IS_NODE
? require('node:path').join(__dirname, 'worker.js')
: './worker.js'
return new Worker(workerjs, {
return new Worker(join(__dirname, 'worker.js'), {
name,
workerData: {
name
},
...(ENVIRONMENT_IS_NODE ? { env: process.env } : {}),
env: process.env,
execArgv: ['--experimental-wasi-unstable-preview1']
})
},
Expand All @@ -90,9 +114,9 @@
shared: true
})
let input
if (ENVIRONMENT_IS_NODE) {
try {
input = require('node:fs').readFileSync(require('node:path').join(__dirname, file))
} else {
} catch (_) {
const response = await fetch(file)
input = await response.arrayBuffer()
}
Expand Down Expand Up @@ -122,8 +146,6 @@

main().catch(err => {
console.error(err)
if (ENVIRONMENT_IS_NODE) {
process.exit(1)
}
process.exit(1)
})
})()
})
95 changes: 57 additions & 38 deletions packages/wasi-threads/test/worker.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,88 @@
/* eslint-disable no-eval */
/* eslint-disable no-undef */

(function () {
let WASI, wasiThreads, name

(function (main) {
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string'

if (ENVIRONMENT_IS_NODE) {
const nodeWorkerThreads = require('worker_threads')
name = nodeWorkerThreads.workerData.name

const parentPort = nodeWorkerThreads.parentPort

wasiThreads = require('..')

parentPort.on('message', (data) => {
globalThis.onmessage({ data })
})

Object.assign(globalThis, {
self: globalThis,
require,
Worker: nodeWorkerThreads.Worker,
importScripts: function (f) {
(0, eval)(fs.readFileSync(f, 'utf8') + '//# sourceURL=' + f)
},
postMessage: function (msg) {
parentPort.postMessage(msg)
}
})
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return require('..')
return require(request)
}

const _init = function () {
const nodeWorkerThreads = require('node:worker_threads')
const parentPort = nodeWorkerThreads.parentPort

parentPort.on('message', (data) => {
globalThis.onmessage({ data })
})

Object.assign(globalThis, {
self: globalThis,
require,
Worker: nodeWorkerThreads.Worker,
importScripts: function (f) {
(0, eval)(require('node:fs').readFileSync(f, 'utf8') + '//# sourceURL=' + f)
},
postMessage: function (msg) {
parentPort.postMessage(msg)
}
})
}

WASI = require('node:wasi').WASI
main(_require, _init)
} else {
// eslint-disable-next-line no-undef
importScripts('../../../node_modules/@tybys/wasm-util/dist/wasm-util.min.js')
// eslint-disable-next-line no-undef
importScripts('../dist/wasi-threads.js')
WASI = globalThis.wasmUtil.WASI
name = globalThis.name
wasiThreads = globalThis.wasiThreads

const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const nodeWorkerThreads = {
workerData: {
name: globalThis.name
}
}
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
throw new Error('Can not find module: ' + request)
}
const _init = function () {}
main(_require, _init)
}
})(function main (require, init) {
init()

console.log(`name: ${name}`)
const { WASI } = require('node:wasi')
const { workerData } = require('node:worker_threads')
const { ThreadMessageHandler, WASIThreads, createInstanceProxy } = require('@emnapi/wasi-threads')

const { ThreadMessageHandler, WASIThreads, createInstanceProxy } = wasiThreads
console.log(`name: ${workerData.name}`)

const handler = new ThreadMessageHandler({
onLoad ({ wasmModule, wasmMemory }) {
async onLoad ({ wasmModule, wasmMemory }) {
const wasi = new WASI({
version: 'preview1',
...(ENVIRONMENT_IS_NODE ? { env: process.env } : {})
version: 'preview1'
})

const wasiThreads = new WASIThreads({
childThread: true
})

const instance = createInstanceProxy(new WebAssembly.Instance(wasmModule, {
const originalInstance = await WebAssembly.instantiate(wasmModule, {
env: {
memory: wasmMemory
},
...wasi.getImportObject(),
...wasiThreads.getImportObject()
}), wasmMemory)
})

const instance = createInstanceProxy(originalInstance, wasmMemory)

wasiThreads.setup(instance, wasmModule, wasmMemory)
if ('_start' in instance.exports) {
Expand All @@ -80,4 +99,4 @@
handler.handle(e)
// handle other messages
}
})()
})

0 comments on commit c41ccc8

Please sign in to comment.