@ruby/wasm-wasi 2.6.2 → 2.7.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.
@@ -18,7 +18,7 @@
18
18
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19
19
  PERFORMANCE OF THIS SOFTWARE.
20
20
  ***************************************************************************** */
21
- /* global Reflect, Promise, SuppressedError, Symbol */
21
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
22
22
 
23
23
 
24
24
  function __values(o) {
@@ -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-iseq'] = i => {
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-iseq'] = i => {
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._resource1_slab.get(i)._wasm_val;
263
+ return this._resource0_slab.get(i)._wasm_val;
280
264
  };
281
265
  imports.canonical_abi['resource_new_rb-abi-value'] = i => {
282
- this._registry1;
283
- return this._resource1_slab.insert(new RbAbiValue(i, this));
266
+ this._registry0;
267
+ return this._resource0_slab.insert(new RbAbiValue(i, this));
284
268
  };
285
269
  }
286
270
 
@@ -300,32 +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-iseq']);
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) {
313
- const memory = this._exports.memory;
314
- const realloc = this._exports["cabi_realloc"];
315
- const vec1 = arg0;
316
- const len1 = vec1.length;
317
- const result1 = realloc(0, 0, 4, len1 * 8);
318
- for (let i = 0; i < vec1.length; i++) {
319
- const e = vec1[i];
320
- const base = result1 + i * 8;
321
- const ptr0 = utf8_encode(e, realloc, memory);
322
- const len0 = UTF8_ENCODED_LEN;
323
- data_view(memory).setInt32(base + 4, len0, true);
324
- data_view(memory).setInt32(base + 0, ptr0, true);
325
- }
326
- this._exports['ruby-sysinit: func(args: list<string>) -> ()'](result1, len1);
327
- }
328
- rubyOptions(arg0) {
292
+ rubyInit(arg0) {
329
293
  const memory = this._exports.memory;
330
294
  const realloc = this._exports["cabi_realloc"];
331
295
  const vec1 = arg0;
@@ -339,15 +303,7 @@
339
303
  data_view(memory).setInt32(base + 4, len0, true);
340
304
  data_view(memory).setInt32(base + 0, ptr0, true);
341
305
  }
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._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
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._resource1_slab.insert(obj1.clone()), true);
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._resource1_slab.insert(obj0.clone()), to_uint32(arg1), result2, len2);
379
- return [this._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
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._resource1_slab.remove(ret);
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._resource1_slab.insert(obj0.clone()));
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 RbIseq {
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
- * @example
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(initComponent, options) {
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(`require "/bundle/setup"`);
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
- printer === null || printer === void 0 ? void 0 : printer.addToImports(imports);
1561
- const instance = await WebAssembly.instantiate(rubyModule, imports);
1562
- await vm.setInstance(instance);
1563
- printer === null || printer === void 0 ? void 0 : printer.setMemory(instance.exports.memory);
1564
- wasi.initialize(instance);
1565
- vm.initialize();
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,
@@ -1570,10 +1587,28 @@
1570
1587
  };
1571
1588
  };
1572
1589
 
1590
+ /**
1591
+ * The main entry point of `<script type="text/ruby">`-based scripting with WebAssembly Core Module.
1592
+ */
1573
1593
  const main = async (pkg, options) => {
1574
1594
  const response = fetch(`https://cdn.jsdelivr.net/npm/${pkg.name}@${pkg.version}/dist/ruby+stdlib.wasm`);
1575
1595
  const module = await compileWebAssemblyModule(response);
1576
1596
  const { vm } = await DefaultRubyVM(module, options);
1597
+ await mainWithRubyVM(vm);
1598
+ };
1599
+ /**
1600
+ * The main entry point of `<script type="text/ruby">`-based scripting with WebAssembly Component.
1601
+ */
1602
+ const componentMain = async (pkg, options) => {
1603
+ const componentUrl = `https://cdn.jsdelivr.net/npm/${pkg.name}@${pkg.version}/dist/component`;
1604
+ const fetchComponentFile = (relativePath) => fetch(`${componentUrl}/${relativePath}`);
1605
+ const { vm } = await RubyVM.instantiateComponent(Object.assign(Object.assign({}, options), { getCoreModule: (relativePath) => {
1606
+ const response = fetchComponentFile(relativePath);
1607
+ return compileWebAssemblyModule(response);
1608
+ } }));
1609
+ await mainWithRubyVM(vm);
1610
+ };
1611
+ const mainWithRubyVM = async (vm) => {
1577
1612
  vm.printVersion();
1578
1613
  globalThis.rubyVM = vm;
1579
1614
  // Wait for the text/ruby script tag to be read.
@@ -1655,6 +1690,7 @@
1655
1690
  }
1656
1691
  };
1657
1692
 
1693
+ exports.componentMain = componentMain;
1658
1694
  exports.main = main;
1659
1695
 
1660
1696
  }));