@ruby/wasm-wasi 2.6.2-2024-09-04-a → 2.6.2-2024-09-06-a
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 +1 -232
- package/dist/browser.script.umd.js +146 -129
- package/dist/browser.umd.js +146 -129
- package/dist/cjs/bindgen/interfaces/ruby-js-js-runtime.d.ts +1 -1
- package/dist/cjs/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +2 -9
- package/dist/cjs/bindgen/legacy/rb-abi-guest.d.ts +1 -31
- package/dist/cjs/bindgen/legacy/rb-abi-guest.js +16 -84
- package/dist/cjs/binding.d.ts +2 -8
- package/dist/cjs/binding.js +2 -11
- package/dist/cjs/browser.js +9 -11
- package/dist/cjs/node.js +1 -9
- package/dist/cjs/vm.d.ts +153 -19
- package/dist/cjs/vm.js +120 -21
- package/dist/esm/bindgen/interfaces/ruby-js-js-runtime.d.ts +1 -1
- package/dist/esm/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +2 -9
- package/dist/esm/bindgen/legacy/rb-abi-guest.d.ts +1 -31
- package/dist/esm/bindgen/legacy/rb-abi-guest.js +15 -82
- package/dist/esm/binding.d.ts +2 -8
- package/dist/esm/binding.js +2 -11
- package/dist/esm/browser.js +9 -11
- package/dist/esm/node.js +1 -9
- package/dist/esm/vm.d.ts +153 -19
- package/dist/esm/vm.js +120 -21
- package/dist/index.umd.js +137 -118
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,235 +16,4 @@ See [Cheat Sheet](https://github.com/ruby/ruby.wasm/blob/main/docs/cheat_sheet.m
|
|
|
16
16
|
|
|
17
17
|
## API
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
### consolePrinter
|
|
22
|
-
|
|
23
|
-
Create a console printer that can be used as an overlay of WASI imports.
|
|
24
|
-
See the example below for how to use it.
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
const imports = {
|
|
28
|
-
wasi_snapshot_preview1: wasi.wasiImport,
|
|
29
|
-
};
|
|
30
|
-
const printer = consolePrinter();
|
|
31
|
-
printer.addToImports(imports);
|
|
32
|
-
|
|
33
|
-
const instance = await WebAssembly.instantiate(module, imports);
|
|
34
|
-
printer.setMemory(instance.exports.memory);
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Note that the `stdout` and `stderr` functions are called with text, not
|
|
38
|
-
bytes. This means that bytes written to stdout/stderr will be decoded as
|
|
39
|
-
UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
|
|
40
|
-
occurs without buffering.
|
|
41
|
-
|
|
42
|
-
#### Parameters
|
|
43
|
-
|
|
44
|
-
- `$0` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** (optional, default `{stdout:console.log,stderr:console.warn}`)
|
|
45
|
-
|
|
46
|
-
- `$0.stdout`  
|
|
47
|
-
- `$0.stderr`  
|
|
48
|
-
|
|
49
|
-
- `stdout` A function that will be called when stdout is written to.
|
|
50
|
-
Defaults to `console.log`.
|
|
51
|
-
- `stderr` A function that will be called when stderr is written to.
|
|
52
|
-
Defaults to `console.warn`.
|
|
53
|
-
|
|
54
|
-
Returns **any** An object that can be used as an overlay of WASI imports.
|
|
55
|
-
|
|
56
|
-
### RubyVM
|
|
57
|
-
|
|
58
|
-
A Ruby VM instance
|
|
59
|
-
|
|
60
|
-
#### Examples
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
const wasi = new WASI();
|
|
64
|
-
const vm = new RubyVM();
|
|
65
|
-
const imports = {
|
|
66
|
-
wasi_snapshot_preview1: wasi.wasiImport,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
vm.addToImports(imports);
|
|
70
|
-
|
|
71
|
-
const instance = await WebAssembly.instantiate(rubyModule, imports);
|
|
72
|
-
await vm.setInstance(instance);
|
|
73
|
-
wasi.initialize(instance);
|
|
74
|
-
vm.initialize();
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
#### initialize
|
|
78
|
-
|
|
79
|
-
Initialize the Ruby VM with the given command line arguments
|
|
80
|
-
|
|
81
|
-
##### Parameters
|
|
82
|
-
|
|
83
|
-
- `args` The command line arguments to pass to Ruby. Must be
|
|
84
|
-
an array of strings starting with the Ruby program name. (optional, default `["ruby.wasm","-EUTF-8","-e_=0"]`)
|
|
85
|
-
|
|
86
|
-
#### setInstance
|
|
87
|
-
|
|
88
|
-
Set a given instance to interact JavaScript and Ruby's
|
|
89
|
-
WebAssembly instance. This method must be called before calling
|
|
90
|
-
Ruby API.
|
|
91
|
-
|
|
92
|
-
##### Parameters
|
|
93
|
-
|
|
94
|
-
- `instance` The WebAssembly instance to interact with. Must
|
|
95
|
-
be instantiated from a Ruby built with JS extension, and built
|
|
96
|
-
with Reactor ABI instead of command line.
|
|
97
|
-
|
|
98
|
-
#### addToImports
|
|
99
|
-
|
|
100
|
-
Add intrinsic import entries, which is necessary to interact JavaScript
|
|
101
|
-
and Ruby's WebAssembly instance.
|
|
102
|
-
|
|
103
|
-
##### Parameters
|
|
104
|
-
|
|
105
|
-
- `imports` The import object to add to the WebAssembly instance
|
|
106
|
-
|
|
107
|
-
#### printVersion
|
|
108
|
-
|
|
109
|
-
Print the Ruby version to stdout
|
|
110
|
-
|
|
111
|
-
#### eval
|
|
112
|
-
|
|
113
|
-
Runs a string of Ruby code from JavaScript
|
|
114
|
-
|
|
115
|
-
##### Parameters
|
|
116
|
-
|
|
117
|
-
- `code` The Ruby code to run
|
|
118
|
-
|
|
119
|
-
##### Examples
|
|
120
|
-
|
|
121
|
-
```javascript
|
|
122
|
-
vm.eval("puts 'hello world'");
|
|
123
|
-
const result = vm.eval("1 + 2");
|
|
124
|
-
console.log(result.toString()); // 3
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Returns **any** the result of the last expression
|
|
128
|
-
|
|
129
|
-
#### evalAsync
|
|
130
|
-
|
|
131
|
-
Runs a string of Ruby code with top-level `JS::Object#await`
|
|
132
|
-
Returns a promise that resolves when execution completes.
|
|
133
|
-
|
|
134
|
-
##### Parameters
|
|
135
|
-
|
|
136
|
-
- `code` The Ruby code to run
|
|
137
|
-
|
|
138
|
-
##### Examples
|
|
139
|
-
|
|
140
|
-
```javascript
|
|
141
|
-
const text = await vm.evalAsync(`
|
|
142
|
-
require 'js'
|
|
143
|
-
response = JS.global.fetch('https://example.com').await
|
|
144
|
-
response.text.await
|
|
145
|
-
`);
|
|
146
|
-
console.log(text.toString()); // <html>...</html>
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Returns **any** a promise that resolves to the result of the last expression
|
|
150
|
-
|
|
151
|
-
#### wrap
|
|
152
|
-
|
|
153
|
-
Wrap a JavaScript value into a Ruby JS::Object
|
|
154
|
-
|
|
155
|
-
##### Parameters
|
|
156
|
-
|
|
157
|
-
- `value` The value to convert to RbValue
|
|
158
|
-
|
|
159
|
-
##### Examples
|
|
160
|
-
|
|
161
|
-
```javascript
|
|
162
|
-
const hash = vm.eval(`Hash.new`);
|
|
163
|
-
hash.call("store", vm.eval(`"key1"`), vm.wrap(new Object()));
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Returns **any** the RbValue object representing the given JS value
|
|
167
|
-
|
|
168
|
-
### RbValue
|
|
169
|
-
|
|
170
|
-
A RbValue is an object that represents a value in Ruby
|
|
171
|
-
|
|
172
|
-
#### call
|
|
173
|
-
|
|
174
|
-
Call a given method with given arguments
|
|
175
|
-
|
|
176
|
-
##### Parameters
|
|
177
|
-
|
|
178
|
-
- `callee` name of the Ruby method to call
|
|
179
|
-
- `args` **...any** arguments to pass to the method. Must be an array of RbValue
|
|
180
|
-
|
|
181
|
-
##### Examples
|
|
182
|
-
|
|
183
|
-
```javascript
|
|
184
|
-
const ary = vm.eval("[1, 2, 3]");
|
|
185
|
-
ary.call("push", vm.wrap(4));
|
|
186
|
-
console.log(ary.call("sample").toString());
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
Returns **any** The result of the method call as a new RbValue.
|
|
190
|
-
|
|
191
|
-
#### callAsync
|
|
192
|
-
|
|
193
|
-
Call a given method that may call `JS::Object#await` with given arguments
|
|
194
|
-
|
|
195
|
-
##### Parameters
|
|
196
|
-
|
|
197
|
-
- `callee` name of the Ruby method to call
|
|
198
|
-
- `args` **...any** arguments to pass to the method. Must be an array of RbValue
|
|
199
|
-
|
|
200
|
-
##### Examples
|
|
201
|
-
|
|
202
|
-
```javascript
|
|
203
|
-
const client = vm.eval(`
|
|
204
|
-
require 'js'
|
|
205
|
-
class HttpClient
|
|
206
|
-
def get(url)
|
|
207
|
-
JS.global.fetch(url).await
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
HttpClient.new
|
|
211
|
-
`);
|
|
212
|
-
const response = await client.callAsync(
|
|
213
|
-
"get",
|
|
214
|
-
vm.eval(`"https://example.com"`),
|
|
215
|
-
);
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Returns **any** A Promise that resolves to the result of the method call as a new RbValue.
|
|
219
|
-
|
|
220
|
-
#### toPrimitive
|
|
221
|
-
|
|
222
|
-
- **See**: <https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive>
|
|
223
|
-
|
|
224
|
-
##### Parameters
|
|
225
|
-
|
|
226
|
-
- `hint` Preferred type of the result primitive value. `"number"`, `"string"`, or `"default"`.
|
|
227
|
-
|
|
228
|
-
#### toString
|
|
229
|
-
|
|
230
|
-
Returns a string representation of the value by calling `to_s`
|
|
231
|
-
|
|
232
|
-
#### toJS
|
|
233
|
-
|
|
234
|
-
Returns a JavaScript object representation of the value
|
|
235
|
-
by calling `to_js`.
|
|
236
|
-
|
|
237
|
-
Returns null if the value is not convertible to a JavaScript object.
|
|
238
|
-
|
|
239
|
-
### RbError
|
|
240
|
-
|
|
241
|
-
**Extends Error**
|
|
242
|
-
|
|
243
|
-
Error class thrown by Ruby execution
|
|
244
|
-
|
|
245
|
-
### RbFatalError
|
|
246
|
-
|
|
247
|
-
**Extends RbError**
|
|
248
|
-
|
|
249
|
-
Error class thrown by Ruby execution when it is not possible to recover.
|
|
250
|
-
This is usually caused when Ruby VM is in an inconsistent state.
|
|
19
|
+
See [API Documentation](https://ruby.github.io/ruby.wasm/npm/@ruby/wasm-wasi/) for details.
|
|
@@ -248,39 +248,23 @@
|
|
|
248
248
|
class RbAbiGuest {
|
|
249
249
|
constructor() {
|
|
250
250
|
this._resource0_slab = new Slab();
|
|
251
|
-
this._resource1_slab = new Slab();
|
|
252
251
|
}
|
|
253
252
|
addToImports(imports) {
|
|
254
253
|
if (!("canonical_abi" in imports)) imports["canonical_abi"] = {};
|
|
255
254
|
|
|
256
|
-
imports.canonical_abi['resource_drop_rb-
|
|
255
|
+
imports.canonical_abi['resource_drop_rb-abi-value'] = i => {
|
|
257
256
|
this._resource0_slab.remove(i).drop();
|
|
258
257
|
};
|
|
259
|
-
imports.canonical_abi['resource_clone_rb-
|
|
258
|
+
imports.canonical_abi['resource_clone_rb-abi-value'] = i => {
|
|
260
259
|
const obj = this._resource0_slab.get(i);
|
|
261
260
|
return this._resource0_slab.insert(obj.clone())
|
|
262
261
|
};
|
|
263
|
-
imports.canonical_abi['resource_get_rb-iseq'] = i => {
|
|
264
|
-
return this._resource0_slab.get(i)._wasm_val;
|
|
265
|
-
};
|
|
266
|
-
imports.canonical_abi['resource_new_rb-iseq'] = i => {
|
|
267
|
-
this._registry0;
|
|
268
|
-
return this._resource0_slab.insert(new RbIseq(i, this));
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
imports.canonical_abi['resource_drop_rb-abi-value'] = i => {
|
|
272
|
-
this._resource1_slab.remove(i).drop();
|
|
273
|
-
};
|
|
274
|
-
imports.canonical_abi['resource_clone_rb-abi-value'] = i => {
|
|
275
|
-
const obj = this._resource1_slab.get(i);
|
|
276
|
-
return this._resource1_slab.insert(obj.clone())
|
|
277
|
-
};
|
|
278
262
|
imports.canonical_abi['resource_get_rb-abi-value'] = i => {
|
|
279
|
-
return this.
|
|
263
|
+
return this._resource0_slab.get(i)._wasm_val;
|
|
280
264
|
};
|
|
281
265
|
imports.canonical_abi['resource_new_rb-abi-value'] = i => {
|
|
282
|
-
this.
|
|
283
|
-
return this.
|
|
266
|
+
this._registry0;
|
|
267
|
+
return this._resource0_slab.insert(new RbAbiValue(i, this));
|
|
284
268
|
};
|
|
285
269
|
}
|
|
286
270
|
|
|
@@ -300,16 +284,12 @@
|
|
|
300
284
|
this.instance = instance;
|
|
301
285
|
}
|
|
302
286
|
this._exports = this.instance.exports;
|
|
303
|
-
this._registry0 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-
|
|
304
|
-
this._registry1 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-abi-value']);
|
|
287
|
+
this._registry0 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-abi-value']);
|
|
305
288
|
}
|
|
306
289
|
rubyShowVersion() {
|
|
307
290
|
this._exports['ruby-show-version: func() -> ()']();
|
|
308
291
|
}
|
|
309
|
-
rubyInit() {
|
|
310
|
-
this._exports['ruby-init: func() -> ()']();
|
|
311
|
-
}
|
|
312
|
-
rubySysinit(arg0) {
|
|
292
|
+
rubyInit(arg0) {
|
|
313
293
|
const memory = this._exports.memory;
|
|
314
294
|
const realloc = this._exports["cabi_realloc"];
|
|
315
295
|
const vec1 = arg0;
|
|
@@ -323,31 +303,7 @@
|
|
|
323
303
|
data_view(memory).setInt32(base + 4, len0, true);
|
|
324
304
|
data_view(memory).setInt32(base + 0, ptr0, true);
|
|
325
305
|
}
|
|
326
|
-
this._exports['ruby-
|
|
327
|
-
}
|
|
328
|
-
rubyOptions(arg0) {
|
|
329
|
-
const memory = this._exports.memory;
|
|
330
|
-
const realloc = this._exports["cabi_realloc"];
|
|
331
|
-
const vec1 = arg0;
|
|
332
|
-
const len1 = vec1.length;
|
|
333
|
-
const result1 = realloc(0, 0, 4, len1 * 8);
|
|
334
|
-
for (let i = 0; i < vec1.length; i++) {
|
|
335
|
-
const e = vec1[i];
|
|
336
|
-
const base = result1 + i * 8;
|
|
337
|
-
const ptr0 = utf8_encode(e, realloc, memory);
|
|
338
|
-
const len0 = UTF8_ENCODED_LEN;
|
|
339
|
-
data_view(memory).setInt32(base + 4, len0, true);
|
|
340
|
-
data_view(memory).setInt32(base + 0, ptr0, true);
|
|
341
|
-
}
|
|
342
|
-
const ret = this._exports['ruby-options: func(args: list<string>) -> handle<rb-iseq>'](result1, len1);
|
|
343
|
-
return this._resource0_slab.remove(ret);
|
|
344
|
-
}
|
|
345
|
-
rubyScript(arg0) {
|
|
346
|
-
const memory = this._exports.memory;
|
|
347
|
-
const realloc = this._exports["cabi_realloc"];
|
|
348
|
-
const ptr0 = utf8_encode(arg0, realloc, memory);
|
|
349
|
-
const len0 = UTF8_ENCODED_LEN;
|
|
350
|
-
this._exports['ruby-script: func(name: string) -> ()'](ptr0, len0);
|
|
306
|
+
this._exports['ruby-init: func(args: list<string>) -> ()'](result1, len1);
|
|
351
307
|
}
|
|
352
308
|
rubyInitLoadpath() {
|
|
353
309
|
this._exports['ruby-init-loadpath: func() -> ()']();
|
|
@@ -358,7 +314,7 @@
|
|
|
358
314
|
const ptr0 = utf8_encode(arg0, realloc, memory);
|
|
359
315
|
const len0 = UTF8_ENCODED_LEN;
|
|
360
316
|
const ret = this._exports['rb-eval-string-protect: func(str: string) -> tuple<handle<rb-abi-value>, s32>'](ptr0, len0);
|
|
361
|
-
return [this.
|
|
317
|
+
return [this._resource0_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
|
|
362
318
|
}
|
|
363
319
|
rbFuncallvProtect(arg0, arg1, arg2) {
|
|
364
320
|
const memory = this._exports.memory;
|
|
@@ -373,10 +329,10 @@
|
|
|
373
329
|
const base = result2 + i * 4;
|
|
374
330
|
const obj1 = e;
|
|
375
331
|
if (!(obj1 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
|
|
376
|
-
data_view(memory).setInt32(base + 0, this.
|
|
332
|
+
data_view(memory).setInt32(base + 0, this._resource0_slab.insert(obj1.clone()), true);
|
|
377
333
|
}
|
|
378
|
-
const ret = this._exports['rb-funcallv-protect: func(recv: handle<rb-abi-value>, mid: u32, args: list<handle<rb-abi-value>>) -> tuple<handle<rb-abi-value>, s32>'](this.
|
|
379
|
-
return [this.
|
|
334
|
+
const ret = this._exports['rb-funcallv-protect: func(recv: handle<rb-abi-value>, mid: u32, args: list<handle<rb-abi-value>>) -> tuple<handle<rb-abi-value>, s32>'](this._resource0_slab.insert(obj0.clone()), to_uint32(arg1), result2, len2);
|
|
335
|
+
return [this._resource0_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
|
|
380
336
|
}
|
|
381
337
|
rbIntern(arg0) {
|
|
382
338
|
const memory = this._exports.memory;
|
|
@@ -388,7 +344,7 @@
|
|
|
388
344
|
}
|
|
389
345
|
rbErrinfo() {
|
|
390
346
|
const ret = this._exports['rb-errinfo: func() -> handle<rb-abi-value>']();
|
|
391
|
-
return this.
|
|
347
|
+
return this._resource0_slab.remove(ret);
|
|
392
348
|
}
|
|
393
349
|
rbClearErrinfo() {
|
|
394
350
|
this._exports['rb-clear-errinfo: func() -> ()']();
|
|
@@ -397,7 +353,7 @@
|
|
|
397
353
|
const memory = this._exports.memory;
|
|
398
354
|
const obj0 = arg0;
|
|
399
355
|
if (!(obj0 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
|
|
400
|
-
const ret = this._exports['rstring-ptr: func(value: handle<rb-abi-value>) -> string'](this.
|
|
356
|
+
const ret = this._exports['rstring-ptr: func(value: handle<rb-abi-value>) -> string'](this._resource0_slab.insert(obj0.clone()));
|
|
401
357
|
const ptr1 = data_view(memory).getInt32(ret + 0, true);
|
|
402
358
|
const len1 = data_view(memory).getInt32(ret + 4, true);
|
|
403
359
|
const result1 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr1, len1));
|
|
@@ -424,7 +380,7 @@
|
|
|
424
380
|
}
|
|
425
381
|
}
|
|
426
382
|
|
|
427
|
-
class
|
|
383
|
+
class RbAbiValue {
|
|
428
384
|
constructor(wasm_val, obj) {
|
|
429
385
|
this._wasm_val = wasm_val;
|
|
430
386
|
this._obj = obj;
|
|
@@ -442,33 +398,6 @@
|
|
|
442
398
|
if (this._refcnt !== 0)
|
|
443
399
|
return;
|
|
444
400
|
this._obj._registry0.unregister(this);
|
|
445
|
-
const dtor = this._obj._exports['canonical_abi_drop_rb-iseq'];
|
|
446
|
-
const wasm_val = this._wasm_val;
|
|
447
|
-
delete this._obj;
|
|
448
|
-
delete this._refcnt;
|
|
449
|
-
delete this._wasm_val;
|
|
450
|
-
dtor(wasm_val);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
class RbAbiValue {
|
|
455
|
-
constructor(wasm_val, obj) {
|
|
456
|
-
this._wasm_val = wasm_val;
|
|
457
|
-
this._obj = obj;
|
|
458
|
-
this._refcnt = 1;
|
|
459
|
-
obj._registry1.register(this, wasm_val, this);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
clone() {
|
|
463
|
-
this._refcnt += 1;
|
|
464
|
-
return this;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
drop() {
|
|
468
|
-
this._refcnt -= 1;
|
|
469
|
-
if (this._refcnt !== 0)
|
|
470
|
-
return;
|
|
471
|
-
this._obj._registry1.unregister(this);
|
|
472
401
|
const dtor = this._obj._exports['canonical_abi_drop_rb-abi-value'];
|
|
473
402
|
const wasm_val = this._wasm_val;
|
|
474
403
|
delete this._obj;
|
|
@@ -769,17 +698,8 @@
|
|
|
769
698
|
rubyShowVersion() {
|
|
770
699
|
this.underlying.rubyShowVersion();
|
|
771
700
|
}
|
|
772
|
-
rubyInit() {
|
|
773
|
-
this.underlying.rubyInit();
|
|
774
|
-
}
|
|
775
|
-
rubySysinit(args) {
|
|
776
|
-
this.underlying.rubySysinit(args);
|
|
777
|
-
}
|
|
778
|
-
rubyOptions(args) {
|
|
779
|
-
this.underlying.rubyOptions(args);
|
|
780
|
-
}
|
|
781
|
-
rubyScript(name) {
|
|
782
|
-
this.underlying.rubyScript(name);
|
|
701
|
+
rubyInit(args) {
|
|
702
|
+
this.underlying.rubyInit(args);
|
|
783
703
|
}
|
|
784
704
|
rubyInitLoadpath() {
|
|
785
705
|
this.underlying.rubyInitLoadpath();
|
|
@@ -824,24 +744,111 @@
|
|
|
824
744
|
|
|
825
745
|
/**
|
|
826
746
|
* A Ruby VM instance
|
|
827
|
-
*
|
|
828
|
-
* @
|
|
829
|
-
*
|
|
830
|
-
* const wasi = new WASI();
|
|
831
|
-
* const vm = new RubyVM();
|
|
832
|
-
* const imports = {
|
|
833
|
-
* wasi_snapshot_preview1: wasi.wasiImport,
|
|
834
|
-
* };
|
|
835
|
-
*
|
|
836
|
-
* vm.addToImports(imports);
|
|
837
|
-
*
|
|
838
|
-
* const instance = await WebAssembly.instantiate(rubyModule, imports);
|
|
839
|
-
* await vm.setInstance(instance);
|
|
840
|
-
* wasi.initialize(instance);
|
|
841
|
-
* vm.initialize();
|
|
842
|
-
*
|
|
747
|
+
* @see {@link RubyVM.instantiateComponent} and {@link RubyVM.instantiateModule} to create a new instance
|
|
748
|
+
* @category Essentials
|
|
843
749
|
*/
|
|
844
750
|
class RubyVM {
|
|
751
|
+
/**
|
|
752
|
+
* Instantiate a Ruby VM with the given WebAssembly Core module with WASI Preview 1 implementation.
|
|
753
|
+
*
|
|
754
|
+
* @param options The options to instantiate the Ruby VM
|
|
755
|
+
* @returns A promise that resolves to the Ruby VM instance and the WebAssembly instance
|
|
756
|
+
* @category Essentials
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
*
|
|
760
|
+
* import { WASI } from "@bjorn3/browser_wasi_shim";
|
|
761
|
+
* const wasip1 = new WASI([], [], []);
|
|
762
|
+
* const module = await WebAssembly.compile("./path/to/ruby.wasm");
|
|
763
|
+
* const { vm } = await RubyVM.instantiateModule({ module, wasip1 });
|
|
764
|
+
*
|
|
765
|
+
*/
|
|
766
|
+
static async instantiateModule(options) {
|
|
767
|
+
var _a, _b;
|
|
768
|
+
const { module, wasip1 } = options;
|
|
769
|
+
const vm = new RubyVM();
|
|
770
|
+
const imports = {
|
|
771
|
+
wasi_snapshot_preview1: wasip1.wasiImport,
|
|
772
|
+
};
|
|
773
|
+
vm.addToImports(imports);
|
|
774
|
+
(_a = options.addToImports) === null || _a === void 0 ? void 0 : _a.call(options, imports);
|
|
775
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
776
|
+
await vm.setInstance(instance);
|
|
777
|
+
(_b = options.setMemory) === null || _b === void 0 ? void 0 : _b.call(options, instance.exports.memory);
|
|
778
|
+
wasip1.initialize(instance);
|
|
779
|
+
vm.initialize(options.args);
|
|
780
|
+
return { vm, instance };
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Instantiate a Ruby VM with the given WebAssembly component with WASI Preview 2 implementation.
|
|
784
|
+
*
|
|
785
|
+
* @param options The options to instantiate the Ruby VM
|
|
786
|
+
* @returns A promise that resolves to the Ruby VM instance
|
|
787
|
+
* @category Essentials
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
*
|
|
791
|
+
* // First, you need to transpile the Ruby component to a JavaScript module using jco.
|
|
792
|
+
* // $ jco transpile --no-wasi-shim --instantiation --valid-lifting-optimization ./ruby.component.wasm -o ./component
|
|
793
|
+
* // Then, you can instantiate the Ruby VM with the component:
|
|
794
|
+
*
|
|
795
|
+
* import * as wasip2 from "@bytecodealliance/preview2-shim"
|
|
796
|
+
* import fs from "fs/promises";
|
|
797
|
+
* import path from "path";
|
|
798
|
+
*
|
|
799
|
+
* const { instantiate } = await import("./component/ruby.component.js");
|
|
800
|
+
* const getCoreModule = async (relativePath) => {
|
|
801
|
+
* const buffer = await fs.readFile(path.join("./component", relativePath));
|
|
802
|
+
* return WebAssembly.compile(buffer);
|
|
803
|
+
* }
|
|
804
|
+
*
|
|
805
|
+
* const { vm } = await RubyVM.instantiateComponent({
|
|
806
|
+
* instantiate, getCoreModule, wasip2,
|
|
807
|
+
* });
|
|
808
|
+
*
|
|
809
|
+
*/
|
|
810
|
+
static async instantiateComponent(options) {
|
|
811
|
+
let initComponent;
|
|
812
|
+
if ("getCoreModule" in options) {
|
|
813
|
+
// A convenience overload to instantiate with "instantiate" function generated by jco
|
|
814
|
+
initComponent = async (jsRuntime) => {
|
|
815
|
+
const { instantiate, getCoreModule, wasip2 } = options;
|
|
816
|
+
const { cli, clocks, filesystem, io, random, sockets, http } = wasip2;
|
|
817
|
+
const importObject = {
|
|
818
|
+
"ruby:js/js-runtime": jsRuntime,
|
|
819
|
+
"wasi:cli/environment": cli.environment,
|
|
820
|
+
"wasi:cli/exit": cli.exit,
|
|
821
|
+
"wasi:cli/stderr": cli.stderr,
|
|
822
|
+
"wasi:cli/stdin": cli.stdin,
|
|
823
|
+
"wasi:cli/stdout": cli.stdout,
|
|
824
|
+
"wasi:cli/terminal-input": cli.terminalInput,
|
|
825
|
+
"wasi:cli/terminal-output": cli.terminalOutput,
|
|
826
|
+
"wasi:cli/terminal-stderr": cli.terminalStderr,
|
|
827
|
+
"wasi:cli/terminal-stdin": cli.terminalStdin,
|
|
828
|
+
"wasi:cli/terminal-stdout": cli.terminalStdout,
|
|
829
|
+
"wasi:clocks/monotonic-clock": clocks.monotonicClock,
|
|
830
|
+
"wasi:clocks/wall-clock": clocks.wallClock,
|
|
831
|
+
"wasi:filesystem/preopens": filesystem.preopens,
|
|
832
|
+
"wasi:filesystem/types": filesystem.types,
|
|
833
|
+
"wasi:io/error": io.error,
|
|
834
|
+
"wasi:io/poll": io.poll,
|
|
835
|
+
"wasi:io/streams": io.streams,
|
|
836
|
+
"wasi:random/random": random.random,
|
|
837
|
+
"wasi:sockets/tcp": sockets.tcp,
|
|
838
|
+
"wasi:http/types": http.types,
|
|
839
|
+
"wasi:http/incoming-handler": http.incomingHandler,
|
|
840
|
+
"wasi:http/outgoing-handler": http.outgoingHandler,
|
|
841
|
+
};
|
|
842
|
+
const component = await instantiate(getCoreModule, importObject, options.instantiateCore);
|
|
843
|
+
return component.rubyRuntime;
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
initComponent = options.instantiate;
|
|
848
|
+
}
|
|
849
|
+
const vm = await this._instantiate({}, initComponent);
|
|
850
|
+
return { vm };
|
|
851
|
+
}
|
|
845
852
|
constructor(binding) {
|
|
846
853
|
this.instance = null;
|
|
847
854
|
this.interfaceState = {
|
|
@@ -890,7 +897,7 @@
|
|
|
890
897
|
this.transport = new JsValueTransport();
|
|
891
898
|
this.exceptionFormatter = new RbExceptionFormatter();
|
|
892
899
|
}
|
|
893
|
-
static async _instantiate(
|
|
900
|
+
static async _instantiate(options, initComponent) {
|
|
894
901
|
const binding = new ComponentBinding();
|
|
895
902
|
const vm = new RubyVM(binding);
|
|
896
903
|
class JsAbiValue {
|
|
@@ -918,14 +925,21 @@
|
|
|
918
925
|
* Initialize the Ruby VM with the given command line arguments
|
|
919
926
|
* @param args The command line arguments to pass to Ruby. Must be
|
|
920
927
|
* an array of strings starting with the Ruby program name.
|
|
928
|
+
* @category Low-level initialization
|
|
921
929
|
*/
|
|
922
930
|
initialize(args = ["ruby.wasm", "-EUTF-8", "-e_=0"]) {
|
|
923
931
|
const c_args = args.map((arg) => arg + "\0");
|
|
924
|
-
this.guest.rubyInit();
|
|
925
|
-
this.guest.rubySysinit(c_args);
|
|
926
|
-
this.guest.rubyOptions(c_args);
|
|
932
|
+
this.guest.rubyInit(c_args);
|
|
927
933
|
try {
|
|
928
|
-
this.eval(`
|
|
934
|
+
this.eval(`
|
|
935
|
+
# Require Bundler standalone setup
|
|
936
|
+
if File.exist?("/bundle/bundler/setup.rb")
|
|
937
|
+
require "/bundle/bundler/setup.rb"
|
|
938
|
+
elsif File.exist?("/bundle/setup.rb")
|
|
939
|
+
# For non-CM builds, which doesn't use Bundler's standalone mode
|
|
940
|
+
require "/bundle/setup.rb"
|
|
941
|
+
end
|
|
942
|
+
`);
|
|
929
943
|
}
|
|
930
944
|
catch (e) {
|
|
931
945
|
console.warn("Failed to load /bundle/setup", e);
|
|
@@ -939,6 +953,7 @@
|
|
|
939
953
|
* @param instance The WebAssembly instance to interact with. Must
|
|
940
954
|
* be instantiated from a Ruby built with JS extension, and built
|
|
941
955
|
* with Reactor ABI instead of command line.
|
|
956
|
+
* @category Low-level initialization
|
|
942
957
|
*/
|
|
943
958
|
async setInstance(instance) {
|
|
944
959
|
this.instance = instance;
|
|
@@ -948,6 +963,7 @@
|
|
|
948
963
|
* Add intrinsic import entries, which is necessary to interact JavaScript
|
|
949
964
|
* and Ruby's WebAssembly instance.
|
|
950
965
|
* @param imports The import object to add to the WebAssembly instance
|
|
966
|
+
* @category Low-level initialization
|
|
951
967
|
*/
|
|
952
968
|
addToImports(imports) {
|
|
953
969
|
this.guest.addToImports(imports);
|
|
@@ -1153,6 +1169,7 @@
|
|
|
1153
1169
|
* Runs a string of Ruby code from JavaScript
|
|
1154
1170
|
* @param code The Ruby code to run
|
|
1155
1171
|
* @returns the result of the last expression
|
|
1172
|
+
* @category Essentials
|
|
1156
1173
|
*
|
|
1157
1174
|
* @example
|
|
1158
1175
|
* vm.eval("puts 'hello world'");
|
|
@@ -1168,6 +1185,7 @@
|
|
|
1168
1185
|
* Returns a promise that resolves when execution completes.
|
|
1169
1186
|
* @param code The Ruby code to run
|
|
1170
1187
|
* @returns a promise that resolves to the result of the last expression
|
|
1188
|
+
* @category Essentials
|
|
1171
1189
|
*
|
|
1172
1190
|
* @example
|
|
1173
1191
|
* const text = await vm.evalAsync(`
|
|
@@ -1250,6 +1268,7 @@
|
|
|
1250
1268
|
}
|
|
1251
1269
|
/**
|
|
1252
1270
|
* A RbValue is an object that represents a value in Ruby
|
|
1271
|
+
* @category Essentials
|
|
1253
1272
|
*/
|
|
1254
1273
|
class RbValue {
|
|
1255
1274
|
/**
|
|
@@ -1551,18 +1570,16 @@
|
|
|
1551
1570
|
new PreopenDirectory("/", new Map()),
|
|
1552
1571
|
];
|
|
1553
1572
|
const wasi = new WASI(args, env, fds, { debug: false });
|
|
1554
|
-
const vm = new RubyVM();
|
|
1555
|
-
const imports = {
|
|
1556
|
-
wasi_snapshot_preview1: wasi.wasiImport,
|
|
1557
|
-
};
|
|
1558
|
-
vm.addToImports(imports);
|
|
1559
1573
|
const printer = ((_b = options.consolePrint) !== null && _b !== void 0 ? _b : true) ? consolePrinter() : undefined;
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1574
|
+
const { vm, instance } = await RubyVM.instantiateModule({
|
|
1575
|
+
module: rubyModule, wasip1: wasi,
|
|
1576
|
+
addToImports: (imports) => {
|
|
1577
|
+
printer === null || printer === void 0 ? void 0 : printer.addToImports(imports);
|
|
1578
|
+
},
|
|
1579
|
+
setMemory: (memory) => {
|
|
1580
|
+
printer === null || printer === void 0 ? void 0 : printer.setMemory(memory);
|
|
1581
|
+
}
|
|
1582
|
+
});
|
|
1566
1583
|
return {
|
|
1567
1584
|
vm,
|
|
1568
1585
|
wasi,
|