12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- import { WASI } from "@wasmer/wasi" ;
16
- import { WasmFs } from "@wasmer/wasmfs" ;
17
- import * as path from "path-browserify" ;
15
+ import { WASI , File , OpenFile , ConsoleStdout , PreopenDirectory } from "@bjorn3/browser_wasi_shim" ;
18
16
import type { SwiftRuntime , SwiftRuntimeConstructor } from "./JavaScriptKit_JavaScriptKit.resources/Runtime" ;
19
17
20
18
export type Options = {
@@ -35,38 +33,29 @@ export const WasmRunner = (rawOptions: Options | false, SwiftRuntime: SwiftRunti
35
33
swift = new SwiftRuntime ( ) ;
36
34
}
37
35
38
- const wasmFs = createWasmFS (
39
- ( stdout ) => {
36
+ const args = options . args || [ ] ;
37
+ const fds = [
38
+ new OpenFile ( new File ( [ ] ) ) , // stdin
39
+ ConsoleStdout . lineBuffered ( ( stdout ) => {
40
40
console . log ( stdout ) ;
41
41
options . onStdout ?. call ( undefined , stdout ) ;
42
- } ,
43
- ( stderr ) => {
42
+ } ) ,
43
+ ConsoleStdout . lineBuffered ( ( stderr ) => {
44
44
console . error ( stderr ) ;
45
45
options . onStderr ?. call ( undefined , stderr ) ;
46
- }
47
- ) ;
48
-
49
- wasmFs . fs . mkdirSync ( "/sandbox" ) ;
46
+ } ) ,
47
+ new PreopenDirectory ( "/" , new Map ( ) ) ,
48
+ ] ;
50
49
51
- const wasi = new WASI ( {
52
- args : options . args ,
53
- env : { } ,
54
- preopenDirectories : {
55
- "/" : "/sandbox" ,
56
- } ,
57
- bindings : {
58
- ...WASI . defaultBindings ,
59
- fs : wasmFs . fs ,
60
- path : path ,
61
- } ,
50
+ const wasi = new WASI ( args , [ ] , fds , {
51
+ debug : false
62
52
} ) ;
63
53
64
54
const createWasmImportObject = (
65
55
extraWasmImports : WebAssembly . Imports ,
66
- wasmModule : WebAssembly . Module
67
56
) : WebAssembly . Imports => {
68
57
const importObject : WebAssembly . Imports = {
69
- wasi_snapshot_preview1 : wrapWASI ( wasi , wasmModule ) ,
58
+ wasi_snapshot_preview1 : wasi . wasiImport ,
70
59
} ;
71
60
72
61
if ( swift ) {
@@ -94,19 +83,19 @@ export const WasmRunner = (rawOptions: Options | false, SwiftRuntime: SwiftRunti
94
83
} ,
95
84
} ;
96
85
const module = await WebAssembly . compile ( wasmBytes ) ;
97
- const importObject = createWasmImportObject ( extraWasmImports , module ) ;
86
+ const importObject = createWasmImportObject ( extraWasmImports ) ;
98
87
const instance = await WebAssembly . instantiate ( module , importObject ) ;
99
88
100
89
if ( swift && instance . exports . swjs_library_version ) {
101
90
swift . setInstance ( instance ) ;
102
91
}
103
92
104
- // Start the WebAssembly WASI instance
105
- wasi . start ( instance ) ;
106
-
107
- // Initialize and start Reactor
108
- if ( typeof instance . exports . _initialize == "function" ) {
109
- instance . exports . _initialize ( ) ;
93
+ if ( typeof instance . exports . _start === "function" ) {
94
+ // Start the WebAssembly WASI instance
95
+ wasi . start ( instance as any ) ;
96
+ } else if ( typeof instance . exports . _initialize == "function" ) {
97
+ // Initialize and start Reactor
98
+ wasi . initialize ( instance as any ) ;
110
99
if ( typeof instance . exports . main === "function" ) {
111
100
instance . exports . main ( ) ;
112
101
} else if ( typeof instance . exports . __main_argc_argv === "function" ) {
@@ -131,73 +120,3 @@ const defaultRunnerOptions = (options: Options | false): Options => {
131
120
}
132
121
return options ;
133
122
} ;
134
-
135
- const createWasmFS = (
136
- onStdout : ( text : string ) => void ,
137
- onStderr : ( text : string ) => void
138
- ) : WasmFs => {
139
- // Instantiate a new WASI Instance
140
- const wasmFs = new WasmFs ( ) ;
141
-
142
- // Output stdout and stderr to console
143
- const originalWriteSync = wasmFs . fs . writeSync ;
144
- ( wasmFs . fs as any ) . writeSync = (
145
- fd : number , buffer : Buffer | Uint8Array ,
146
- offset ?: number , length ?: number , position ?: number
147
- ) : number => {
148
- const text = new TextDecoder ( "utf-8" ) . decode ( buffer ) ;
149
- if ( text !== "\n" ) {
150
- switch ( fd ) {
151
- case 1 :
152
- onStdout ( text ) ;
153
- break ;
154
- case 2 :
155
- onStderr ( text ) ;
156
- break ;
157
- }
158
- }
159
- return originalWriteSync ( fd , buffer , offset , length , position ) ;
160
- } ;
161
-
162
- return wasmFs ;
163
- } ;
164
-
165
- const wrapWASI = ( wasiObject : WASI , wasmModule : WebAssembly . Module ) : WebAssembly . ModuleImports => {
166
- // PATCH: @wasmer -js/wasi@0.x forgets to call `refreshMemory` in `clock_res_get`,
167
- // which writes its result to memory view. Without the refresh the memory view,
168
- // it accesses a detached array buffer if the memory is grown by malloc.
169
- // But they wasmer team discarded the 0.x codebase at all and replaced it with
170
- // a new implementation written in Rust. The new version 1.x is really unstable
171
- // and not production-ready as far as katei investigated in Apr 2022.
172
- // So override the broken implementation of `clock_res_get` here instead of
173
- // fixing the wasi polyfill.
174
- // Reference: https://github.com/wasmerio/wasmer-js/blob/55fa8c17c56348c312a8bd23c69054b1aa633891/packages/wasi/src/index.ts#L557
175
- const original_clock_res_get = wasiObject . wasiImport [ "clock_res_get" ] ;
176
-
177
- wasiObject . wasiImport [ "clock_res_get" ] = ( clockId : number , resolution : number ) => {
178
- wasiObject . refreshMemory ( ) ;
179
- return original_clock_res_get ( clockId , resolution ) ;
180
- } ;
181
-
182
- // @wasmer -js/wasi polyfill does not support all WASI syscalls like `sock_accept`.
183
- // So we need to insert a dummy function for unimplemented syscalls.
184
- const __WASI_ERRNO_NOTSUP = 58 ;
185
- for ( const importEntry of WebAssembly . Module . imports ( wasmModule ) ) {
186
- const { module : importModule , name : importName , kind : importKind } = importEntry ;
187
- // Skip dummy import entries for non-WASI and already implemented syscalls.
188
- if (
189
- importModule !== "wasi_snapshot_preview1" ||
190
- importKind !== "function" ||
191
- wasiObject . wasiImport [ importName ]
192
- ) {
193
- continue ;
194
- }
195
-
196
- wasiObject . wasiImport [ importName ] = ( ) => {
197
- console . warn ( `WASI syscall ${ importModule } .${ importName } is not supported, returning ENOTSUP.` ) ;
198
- return __WASI_ERRNO_NOTSUP ;
199
- }
200
- }
201
-
202
- return wasiObject . wasiImport ;
203
- } ;
0 commit comments