@tybys/wasm-util 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # @tybys/wasm-util
2
+
3
+ WebAssembly related utils for browser environment
4
+
5
+ **The output code is ES2019**
6
+
7
+ ## Features
8
+
9
+ All example code below need to be bundled by ES module bundlers like `webpack` / `rollup`, or specify import map in browser native ES module runtime.
10
+
11
+ ### `load` / `loadSync`
12
+
13
+ `loadSync` has 4KB wasm size limit in browser.
14
+
15
+ ```js
16
+ // bundler
17
+ import { load, loadSync } from '@tybys/wasm-util'
18
+
19
+ const imports = { /* ... */ }
20
+
21
+ // using path
22
+ const { module, instance } = await load('/path/to/file.wasm', imports)
23
+ const { module, instance } = loadSync('/path/to/file.wasm', imports)
24
+
25
+ // using URL
26
+ const { module, instance } = await load(new URL('./file.wasm', import.meta.url), imports)
27
+ const { module, instance } = loadSync(new URL('./file.wasm', import.meta.url), imports)
28
+
29
+ // using Uint8Array
30
+ const buffer = new Uint8Array([
31
+ 0x00, 0x61, 0x73, 0x6d,
32
+ 0x01, 0x00, 0x00, 0x00
33
+ ])
34
+ const { module, instance } = await load(buffer, imports)
35
+ const { module, instance } = loadSync(buffer, imports)
36
+
37
+ // auto asyncify
38
+ const {
39
+ module,
40
+ instance: asyncifiedInstance
41
+ } = await load(buffer, imports, { /* asyncify options */})
42
+ asyncifiedInstance.exports.fn() // => return Promise
43
+ ```
44
+
45
+ ### Extend Memory instance
46
+
47
+ ```js
48
+ import { Memory, extendMemory } from '@tybys/wasm-util'
49
+
50
+ const memory = new WebAssembly.Memory({ initial: 256 })
51
+ // const memory = instance.exports.memory
52
+
53
+ extendMemory(memory)
54
+ console.log(memory instanceof Memory)
55
+ console.log(memory instanceof WebAssembly.Memory)
56
+ // expose memory view getters like Emscripten
57
+ const { HEAPU8, HEAPU32, view } = memory
58
+ ```
59
+
60
+ ### Asyncify wrap
61
+
62
+ Build the C code using `clang`, `wasm-ld` and `wasm-opt`
63
+
64
+ ```c
65
+ void async_sleep(int ms);
66
+
67
+ int main() {
68
+ async_sleep(200);
69
+ return 0;
70
+ }
71
+ ```
72
+
73
+ ```js
74
+ import { Asyncify } from '@tybys/wasm-util'
75
+
76
+ const asyncify = new Asyncify()
77
+
78
+ const imports = {
79
+ env: {
80
+ async_sleep: asyncify.wrapImportFunction(function (ms) {
81
+ return new Promise((resolve) => {
82
+ setTimeout(resolve, ms)
83
+ })
84
+ })
85
+ }
86
+ }
87
+
88
+ // async_sleep(200)
89
+ const bytes = await (await fetch('/asyncfied_by_wasm-opt.wasm')).arrayBuffer()
90
+ const { instance } = await WebAssembly.instantiate(bytes, imports)
91
+ const asyncifiedInstance = asyncify.init(instance.exports.memory, instance, {
92
+ wrapExports: ['_start']
93
+ })
94
+
95
+ const p = asyncifedInstance._start()
96
+ console.log(typeof p.then === 'function')
97
+ const now = Date.now()
98
+ await p
99
+ console.log(Date.now() - now >= 200)
100
+ ```
101
+
102
+ ### WASI polyfill for browser
103
+
104
+ The API is similar to the `require('wasi').WASI` in Node.js.
105
+
106
+ You can use `memfs-browser` to provide filesystem capability.
107
+
108
+ ```js
109
+ import { load, WASI } from '@tybys/wasm-util'
110
+ import { Volumn, createFsFromVolume } from 'memfs-browser'
111
+
112
+ const fs = createFsFromVolume(Volume.from({
113
+ '/home/wasi': null
114
+ }))
115
+
116
+ const wasi = new WASI({
117
+ args: ['chrome', 'file.wasm'],
118
+ env: {
119
+ NODE_ENV: 'development',
120
+ WASI_SDK_PATH: '/opt/wasi-sdk'
121
+ },
122
+ preopens: {
123
+ '/': '/'
124
+ },
125
+ filesystem: { type: 'memfs', fs },
126
+
127
+ // redirect stdout / stderr
128
+
129
+ // print (text) { console.log(text) },
130
+ // printErr (text) { console.error(text) }
131
+ })
132
+
133
+ const imports = {
134
+ wasi_snapshot_preview1: wasi.wasiImport
135
+ }
136
+
137
+ const { module, instance } = await load('/path/to/file.wasm', imports)
138
+ wasi.start(instance)
139
+ // wasi.initialize(instance)
140
+ ```
141
+
142
+ Implemented syscalls:
143
+
144
+ #### wasi_snapshot_preview1
145
+
146
+ - [x] args_get
147
+ - [x] args_sizes_get
148
+ - [x] environ_get
149
+ - [x] environ_sizes_get
150
+ - [x] clock_res_get
151
+ - [x] clock_time_get
152
+ - [ ] ~~fd_advise~~
153
+ - [x] fd_allocate
154
+ - [x] fd_close
155
+ - [x] fd_datasync
156
+ - [x] fd_fdstat_get
157
+ - [ ] ~~fd_fdstat_set_flags~~
158
+ - [x] fd_fdstat_set_rights
159
+ - [x] fd_filestat_get
160
+ - [x] fd_filestat_set_size
161
+ - [x] fd_filestat_set_times
162
+ - [x] fd_pread
163
+ - [x] fd_prestat_get
164
+ - [x] fd_prestat_dir_name
165
+ - [x] fd_pwrite
166
+ - [x] fd_read
167
+ - [x] fd_readdir
168
+ - [x] fd_renumber
169
+ - [x] fd_seek
170
+ - [x] fd_sync
171
+ - [x] fd_tell
172
+ - [x] fd_write
173
+ - [x] path_create_directory
174
+ - [x] path_filestat_get
175
+ - [x] path_filestat_set_times
176
+ - [x] path_link
177
+ - [x] path_open
178
+ - [x] path_readlink
179
+ - [x] path_remove_directory
180
+ - [x] path_rename
181
+ - [x] path_symlink
182
+ - [x] path_unlink_file
183
+ - [ ] ~~poll_oneoff~~
184
+ - [x] proc_exit
185
+ - [ ] ~~proc_raise~~
186
+ - [x] sched_yield
187
+ - [x] random_get
188
+ - [ ] ~~sock_recv~~
189
+ - [ ] ~~sock_send~~
190
+ - [ ] ~~sock_shutdown~~
@@ -0,0 +1,11 @@
1
+ // This file is read by tools that parse documentation comments conforming to the TSDoc standard.
2
+ // It should be published with your NPM package. It should not be tracked by Git.
3
+ {
4
+ "tsdocVersion": "0.12",
5
+ "toolPackages": [
6
+ {
7
+ "packageName": "@microsoft/api-extractor",
8
+ "packageVersion": "7.33.4"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @packageDocumentation
3
+ */
4
+
5
+ import type { IFs } from 'memfs-browser';
6
+
7
+ /** @public */
8
+ export declare class Asyncify {
9
+ private value;
10
+ private exports;
11
+ private dataPtr;
12
+ init<T extends WebAssembly.Exports, U extends Array<Exclude<keyof T, AsyncifyExportName>>>(memory: WebAssembly.Memory, instance: {
13
+ readonly exports: T;
14
+ }, options: AsyncifyOptions): {
15
+ readonly exports: AsyncifyExports<T, U>;
16
+ };
17
+ private assertState;
18
+ wrapImportFunction<T extends Function>(f: T): T;
19
+ wrapImports<T extends WebAssembly.Imports>(imports: T): T;
20
+ wrapExportFunction<T extends Function>(f: T): AsyncifyExportFunction<T>;
21
+ wrapExports<T extends WebAssembly.Exports>(exports: T): AsyncifyExports<T, void>;
22
+ wrapExports<T extends WebAssembly.Exports, U extends Array<Exclude<keyof T, AsyncifyExportName>>>(exports: T, needWrap: U): AsyncifyExports<T, U>;
23
+ }
24
+
25
+ /** @public */
26
+ export declare type AsyncifyExportFunction<T> = T extends Callable ? (...args: Parameters<T>) => Promise<ReturnType<T>> : T;
27
+
28
+ /** @public */
29
+ export declare type AsyncifyExportName = 'asyncify_get_state' | 'asyncify_start_unwind' | 'asyncify_stop_unwind' | 'asyncify_start_rewind' | 'asyncify_stop_rewind';
30
+
31
+ /** @public */
32
+ export declare type AsyncifyExports<T, U> = T extends Record<string, any> ? {
33
+ [P in keyof T]: T[P] extends Callable ? U extends Array<Exclude<keyof T, AsyncifyExportName>> ? P extends U[number] ? AsyncifyExportFunction<T[P]> : T[P] : AsyncifyExportFunction<T[P]> : T[P];
34
+ } : T;
35
+
36
+ /** @public */
37
+ export declare interface AsyncifyOptions {
38
+ wasm64?: boolean;
39
+ tryAllocate?: boolean | {
40
+ size?: number;
41
+ name?: string;
42
+ };
43
+ wrapExports?: string[];
44
+ }
45
+
46
+ /** @public */
47
+ export declare type Callable = (...args: any[]) => any;
48
+
49
+ /** @public */
50
+ export declare function extendMemory(memory: WebAssembly.Memory): Memory;
51
+
52
+ declare const kExitCode: unique symbol;
53
+
54
+ declare const kInstance: unique symbol;
55
+
56
+ declare const kSetMemory: unique symbol;
57
+
58
+ declare const kStarted: unique symbol;
59
+
60
+ /** @public */
61
+ export declare function load(urlOrBuffer: string | URL | BufferSource, imports?: WebAssembly.Imports, asyncify?: AsyncifyOptions): Promise<WebAssembly.WebAssemblyInstantiatedSource>;
62
+
63
+ /** @public */
64
+ export declare function loadSync(buffer: BufferSource, imports?: WebAssembly.Imports, asyncify?: AsyncifyOptions): WebAssembly.WebAssemblyInstantiatedSource;
65
+
66
+ /** @public */
67
+ export declare class Memory extends WebAssembly.Memory {
68
+ constructor(descriptor: WebAssembly.MemoryDescriptor);
69
+ get HEAP8(): Int8Array;
70
+ get HEAPU8(): Uint8Array;
71
+ get HEAP16(): Int16Array;
72
+ get HEAPU16(): Uint16Array;
73
+ get HEAP32(): Int32Array;
74
+ get HEAPU32(): Uint32Array;
75
+ get HEAP64(): BigInt64Array;
76
+ get HEAPU64(): BigUint64Array;
77
+ get HEAPF32(): Float32Array;
78
+ get HEAPF64(): Float64Array;
79
+ get view(): DataView;
80
+ }
81
+
82
+ /** @public */
83
+ export declare class WASI {
84
+ private [kSetMemory];
85
+ private [kStarted];
86
+ private [kExitCode];
87
+ private [kInstance];
88
+ readonly wasiImport: Record<string, any>;
89
+ constructor(options?: WASIOptions);
90
+ start(instance: WebAssembly.Instance): number | undefined | Promise<number> | Promise<undefined>;
91
+ initialize(instance: WebAssembly.Instance): void | Promise<void>;
92
+ }
93
+
94
+ /** @public */
95
+ export declare interface WASIOptions {
96
+ args?: string[] | undefined;
97
+ env?: Record<string, string> | undefined;
98
+ preopens?: Record<string, string> | undefined;
99
+ /**
100
+ * @defaultValue `false`
101
+ */
102
+ returnOnExit?: boolean | undefined;
103
+ print?: (str: string) => void;
104
+ printErr?: (str: string) => void;
105
+ filesystem?: {
106
+ type: 'memfs';
107
+ fs: IFs;
108
+ };
109
+ }
110
+
111
+ export { }
112
+
113
+ export as namespace wasmUtil;