@ruby/head-wasm-wasi 2.5.1 → 2.5.2

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.
Files changed (35) hide show
  1. package/dist/browser.script.iife.js +183 -68
  2. package/dist/browser.script.umd.js +181 -66
  3. package/dist/browser.umd.js +181 -66
  4. package/dist/component/interfaces/ruby-js-js-runtime.d.ts +45 -0
  5. package/dist/component/interfaces/ruby-js-ruby-runtime.d.ts +31 -0
  6. package/dist/component/interfaces/wasi-cli-environment.d.ts +3 -0
  7. package/dist/component/interfaces/wasi-cli-exit.d.ts +4 -0
  8. package/dist/component/interfaces/wasi-cli-stderr.d.ts +5 -0
  9. package/dist/component/interfaces/wasi-cli-stdin.d.ts +5 -0
  10. package/dist/component/interfaces/wasi-cli-stdout.d.ts +5 -0
  11. package/dist/component/interfaces/wasi-cli-terminal-input.d.ts +6 -0
  12. package/dist/component/interfaces/wasi-cli-terminal-output.d.ts +6 -0
  13. package/dist/component/interfaces/wasi-cli-terminal-stderr.d.ts +5 -0
  14. package/dist/component/interfaces/wasi-cli-terminal-stdin.d.ts +5 -0
  15. package/dist/component/interfaces/wasi-cli-terminal-stdout.d.ts +5 -0
  16. package/dist/component/interfaces/wasi-clocks-monotonic-clock.d.ts +10 -0
  17. package/dist/component/interfaces/wasi-clocks-wall-clock.d.ts +8 -0
  18. package/dist/component/interfaces/wasi-filesystem-preopens.d.ts +5 -0
  19. package/dist/component/interfaces/wasi-filesystem-types.d.ts +205 -0
  20. package/dist/component/interfaces/wasi-io-error.d.ts +6 -0
  21. package/dist/component/interfaces/wasi-io-poll.d.ts +7 -0
  22. package/dist/component/interfaces/wasi-io-streams.d.ts +30 -0
  23. package/dist/component/interfaces/wasi-random-random.d.ts +3 -0
  24. package/dist/component/package.json +1 -0
  25. package/dist/component/ruby.component.core.wasm +0 -0
  26. package/dist/component/ruby.component.core2.wasm +0 -0
  27. package/dist/component/ruby.component.core3.wasm +0 -0
  28. package/dist/component/ruby.component.core4.wasm +0 -0
  29. package/dist/component/ruby.component.d.ts +71 -0
  30. package/dist/component/ruby.component.js +7523 -0
  31. package/dist/index.umd.js +169 -63
  32. package/dist/ruby+stdlib.wasm +0 -0
  33. package/dist/ruby.debug+stdlib.wasm +0 -0
  34. package/dist/ruby.wasm +0 -0
  35. package/package.json +2 -2
package/dist/index.umd.js CHANGED
@@ -503,13 +503,13 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
503
503
  data_view(memory).setInt32(arg1 + 4, len0, true);
504
504
  data_view(memory).setInt32(arg1 + 0, ptr0, true);
505
505
  };
506
- imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { f64(float64), bignum(string) }"] = function(arg0, arg1) {
506
+ imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { as-float(float64), bignum(string) }"] = function(arg0, arg1) {
507
507
  const memory = get_export("memory");
508
508
  const realloc = get_export("cabi_realloc");
509
509
  const ret0 = obj.jsValueToInteger(resources0.get(arg0));
510
510
  const variant1 = ret0;
511
511
  switch (variant1.tag) {
512
- case "f64": {
512
+ case "as-float": {
513
513
  const e = variant1.val;
514
514
  data_view(memory).setInt8(arg1 + 0, 0, true);
515
515
  data_view(memory).setFloat64(arg1 + 8, +e, true);
@@ -705,6 +705,72 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
705
705
  };
706
706
  }
707
707
 
708
+ class LegacyBinding extends RbAbiGuest {
709
+ async setInstance(instance) {
710
+ await this.instantiate(instance);
711
+ }
712
+ }
713
+ class ComponentBinding {
714
+ constructor() { }
715
+ setUnderlying(underlying) {
716
+ this.underlying = underlying;
717
+ }
718
+ rubyShowVersion() {
719
+ this.underlying.rubyShowVersion();
720
+ }
721
+ rubyInit() {
722
+ this.underlying.rubyInit();
723
+ }
724
+ rubySysinit(args) {
725
+ this.underlying.rubySysinit(args);
726
+ }
727
+ rubyOptions(args) {
728
+ this.underlying.rubyOptions(args);
729
+ }
730
+ rubyScript(name) {
731
+ this.underlying.rubyScript(name);
732
+ }
733
+ rubyInitLoadpath() {
734
+ this.underlying.rubyInitLoadpath();
735
+ }
736
+ rbEvalStringProtect(str) {
737
+ return this.underlying.rbEvalStringProtect(str);
738
+ }
739
+ rbFuncallvProtect(recv, mid, args) {
740
+ return this.underlying.rbFuncallvProtect(recv, mid, args);
741
+ }
742
+ rbIntern(name) {
743
+ return this.underlying.rbIntern(name);
744
+ }
745
+ rbErrinfo() {
746
+ return this.underlying.rbErrinfo();
747
+ }
748
+ rbClearErrinfo() {
749
+ return this.underlying.rbClearErrinfo();
750
+ }
751
+ rstringPtr(value) {
752
+ return this.underlying.rstringPtr(value);
753
+ }
754
+ rbVmBugreport() {
755
+ this.underlying.rbVmBugreport();
756
+ }
757
+ rbGcEnable() {
758
+ return this.underlying.rbGcEnable();
759
+ }
760
+ rbGcDisable() {
761
+ return this.underlying.rbGcDisable();
762
+ }
763
+ rbSetShouldProhibitRewind(newValue) {
764
+ return this.underlying.rbSetShouldProhibitRewind(newValue);
765
+ }
766
+ async setInstance(instance) {
767
+ // No-op
768
+ }
769
+ addToImports(imports) {
770
+ // No-op
771
+ }
772
+ }
773
+
708
774
  /**
709
775
  * A Ruby VM instance
710
776
  *
@@ -725,7 +791,7 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
725
791
  *
726
792
  */
727
793
  class RubyVM {
728
- constructor() {
794
+ constructor(binding) {
729
795
  this.instance = null;
730
796
  this.interfaceState = {
731
797
  hasJSFrameAfterRbFrame: false,
@@ -734,6 +800,7 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
734
800
  // if the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby.
735
801
  const proxyExports = (exports) => {
736
802
  const excludedMethods = [
803
+ "setInstance",
737
804
  "addToImports",
738
805
  "instantiate",
739
806
  "rbSetShouldProhibitRewind",
@@ -768,10 +835,34 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
768
835
  }
769
836
  return exports;
770
837
  };
771
- this.guest = proxyExports(new RbAbiGuest());
838
+ this.guest = proxyExports(binding !== null && binding !== void 0 ? binding : new LegacyBinding());
772
839
  this.transport = new JsValueTransport();
773
840
  this.exceptionFormatter = new RbExceptionFormatter();
774
841
  }
842
+ static async _instantiate(initComponent, options) {
843
+ const binding = new ComponentBinding();
844
+ const vm = new RubyVM(binding);
845
+ class JsAbiValue {
846
+ constructor(underlying) {
847
+ this.underlying = underlying;
848
+ }
849
+ }
850
+ const imports = vm.getImports((from) => new JsAbiValue(from), (to) => to.underlying);
851
+ const component = await initComponent(Object.assign(Object.assign({}, imports), { throwProhibitRewindException: (message) => {
852
+ vm.throwProhibitRewindException(message);
853
+ }, procToJsFunction: () => {
854
+ const rbValue = new RbValue(component.exportRbValueToJs(), vm, vm.privateObject());
855
+ return new JsAbiValue((...args) => {
856
+ return rbValue.call("call", ...args.map((arg) => vm.wrap(arg))).toJS();
857
+ });
858
+ }, rbObjectToJsRbValue: () => {
859
+ const rbValue = new RbValue(component.exportRbValueToJs(), vm, vm.privateObject());
860
+ return new JsAbiValue(rbValue);
861
+ }, JsAbiValue: JsAbiValue }));
862
+ binding.setUnderlying(component);
863
+ vm.initialize(options.args);
864
+ return vm;
865
+ }
775
866
  /**
776
867
  * Initialize the Ruby VM with the given command line arguments
777
868
  * @param args The command line arguments to pass to Ruby. Must be
@@ -795,7 +886,7 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
795
886
  */
796
887
  async setInstance(instance) {
797
888
  this.instance = instance;
798
- await this.guest.instantiate(instance);
889
+ await this.guest.setInstance(instance);
799
890
  }
800
891
  /**
801
892
  * Add intrinsic import entries, which is necessary to interact JavaScript
@@ -804,43 +895,36 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
804
895
  */
805
896
  addToImports(imports) {
806
897
  this.guest.addToImports(imports);
807
- function wrapTry(f) {
808
- return (...args) => {
809
- try {
810
- return { tag: "success", val: f(...args) };
811
- }
812
- catch (e) {
813
- if (e instanceof RbFatalError) {
814
- // RbFatalError should not be caught by Ruby because it Ruby VM
815
- // can be already in an inconsistent state.
816
- throw e;
817
- }
818
- return { tag: "failure", val: e };
819
- }
820
- };
821
- }
822
898
  imports["rb-js-abi-host"] = {
823
899
  rb_wasm_throw_prohibit_rewind_exception: (messagePtr, messageLen) => {
824
900
  const memory = this.instance.exports.memory;
825
901
  const str = new TextDecoder().decode(new Uint8Array(memory.buffer, messagePtr, messageLen));
826
- let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
827
- `(${str})\n` +
828
- "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
829
- "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
830
- "\n" +
831
- "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
832
- " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
833
- " Note that `evalAsync` JS API switches fibers internally\n" +
834
- " 2. Raising uncaught exceptions\n" +
835
- " Please catch all exceptions inside the nested operation\n" +
836
- " 3. Calling Continuation APIs\n";
837
- const error = new RbValue(this.guest.rbErrinfo(), this, this.privateObject());
838
- if (error.call("nil?").toString() === "false") {
839
- message += "\n" + this.exceptionFormatter.format(error, this, this.privateObject());
840
- }
841
- throw new RbFatalError(message);
902
+ this.throwProhibitRewindException(str);
842
903
  },
843
904
  };
905
+ addRbJsAbiHostToImports(imports, this.getImports((value) => value, (value) => value), (name) => {
906
+ return this.instance.exports[name];
907
+ });
908
+ }
909
+ throwProhibitRewindException(str) {
910
+ let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
911
+ `(${str})\n` +
912
+ "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
913
+ "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
914
+ "\n" +
915
+ "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
916
+ " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
917
+ " Note that `evalAsync` JS API switches fibers internally\n" +
918
+ " 2. Raising uncaught exceptions\n" +
919
+ " Please catch all exceptions inside the nested operation\n" +
920
+ " 3. Calling Continuation APIs\n";
921
+ const error = new RbValue(this.guest.rbErrinfo(), this, this.privateObject());
922
+ if (error.call("nil?").toString() === "false") {
923
+ message += "\n" + this.exceptionFormatter.format(error, this, this.privateObject());
924
+ }
925
+ throw new RbFatalError(message);
926
+ }
927
+ getImports(toJSAbiValue, fromJSAbiValue) {
844
928
  // NOTE: The GC may collect objects that are still referenced by Wasm
845
929
  // locals because Asyncify cannot scan the Wasm stack above the JS frame.
846
930
  // So we need to keep track whether the JS frame is sandwitched by Ruby
@@ -859,9 +943,24 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
859
943
  }
860
944
  return imports;
861
945
  };
862
- addRbJsAbiHostToImports(imports, proxyImports({
946
+ function wrapTry(f) {
947
+ return (...args) => {
948
+ try {
949
+ return { tag: "success", val: f(...args) };
950
+ }
951
+ catch (e) {
952
+ if (e instanceof RbFatalError) {
953
+ // RbFatalError should not be caught by Ruby because it Ruby VM
954
+ // can be already in an inconsistent state.
955
+ throw e;
956
+ }
957
+ return { tag: "failure", val: toJSAbiValue(e) };
958
+ }
959
+ };
960
+ }
961
+ return proxyImports({
863
962
  evalJs: wrapTry((code) => {
864
- return Function(code)();
963
+ return toJSAbiValue(Function(code)());
865
964
  }),
866
965
  isJs: (value) => {
867
966
  // Just for compatibility with the old JS API
@@ -869,45 +968,47 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
869
968
  },
870
969
  globalThis: () => {
871
970
  if (typeof globalThis !== "undefined") {
872
- return globalThis;
971
+ return toJSAbiValue(globalThis);
873
972
  }
874
973
  else if (typeof global !== "undefined") {
875
- return global;
974
+ return toJSAbiValue(global);
876
975
  }
877
976
  else if (typeof window !== "undefined") {
878
- return window;
977
+ return toJSAbiValue(window);
879
978
  }
880
979
  throw new Error("unable to locate global object");
881
980
  },
882
981
  intToJsNumber: (value) => {
883
- return value;
982
+ return toJSAbiValue(value);
884
983
  },
885
984
  floatToJsNumber: (value) => {
886
- return value;
985
+ return toJSAbiValue(value);
887
986
  },
888
987
  stringToJsString: (value) => {
889
- return value;
988
+ return toJSAbiValue(value);
890
989
  },
891
990
  boolToJsBool: (value) => {
892
- return value;
991
+ return toJSAbiValue(value);
893
992
  },
894
993
  procToJsFunction: (rawRbAbiValue) => {
895
994
  const rbValue = this.rbValueOfPointer(rawRbAbiValue);
896
- return (...args) => {
995
+ return toJSAbiValue((...args) => {
897
996
  return rbValue.call("call", ...args.map((arg) => this.wrap(arg))).toJS();
898
- };
997
+ });
899
998
  },
900
999
  rbObjectToJsRbValue: (rawRbAbiValue) => {
901
- return this.rbValueOfPointer(rawRbAbiValue);
1000
+ return toJSAbiValue(this.rbValueOfPointer(rawRbAbiValue));
902
1001
  },
903
1002
  jsValueToString: (value) => {
1003
+ value = fromJSAbiValue(value);
904
1004
  // According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
905
1005
  // `String(value)` always returns a string.
906
1006
  return String(value);
907
1007
  },
908
1008
  jsValueToInteger(value) {
1009
+ value = fromJSAbiValue(value);
909
1010
  if (typeof value === "number") {
910
- return { tag: "f64", val: value };
1011
+ return { tag: "as-float", val: value };
911
1012
  }
912
1013
  else if (typeof value === "bigint") {
913
1014
  return { tag: "bignum", val: BigInt(value).toString(10) + "\0" };
@@ -916,38 +1017,40 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
916
1017
  return { tag: "bignum", val: value + "\0" };
917
1018
  }
918
1019
  else if (typeof value === "undefined") {
919
- return { tag: "f64", val: 0 };
1020
+ return { tag: "as-float", val: 0 };
920
1021
  }
921
1022
  else {
922
- return { tag: "f64", val: Number(value) };
1023
+ return { tag: "as-float", val: Number(value) };
923
1024
  }
924
1025
  },
925
1026
  exportJsValueToHost: (value) => {
926
1027
  // See `JsValueExporter` for the reason why we need to do this
927
- this.transport.takeJsValue(value);
1028
+ this.transport.takeJsValue(fromJSAbiValue(value));
928
1029
  },
929
1030
  importJsValueFromHost: () => {
930
- return this.transport.consumeJsValue();
1031
+ return toJSAbiValue(this.transport.consumeJsValue());
931
1032
  },
932
1033
  instanceOf: (value, klass) => {
1034
+ klass = fromJSAbiValue(klass);
933
1035
  if (typeof klass === "function") {
934
- return value instanceof klass;
1036
+ return fromJSAbiValue(value) instanceof klass;
935
1037
  }
936
1038
  else {
937
1039
  return false;
938
1040
  }
939
1041
  },
940
1042
  jsValueTypeof(value) {
941
- return typeof value;
1043
+ return typeof fromJSAbiValue(value);
942
1044
  },
943
1045
  jsValueEqual(lhs, rhs) {
944
- return lhs == rhs;
1046
+ return fromJSAbiValue(lhs) == fromJSAbiValue(rhs);
945
1047
  },
946
1048
  jsValueStrictlyEqual(lhs, rhs) {
947
- return lhs === rhs;
1049
+ return fromJSAbiValue(lhs) === fromJSAbiValue(rhs);
948
1050
  },
949
1051
  reflectApply: wrapTry((target, thisArgument, args) => {
950
- return Reflect.apply(target, thisArgument, args);
1052
+ const jsArgs = args.map((arg) => fromJSAbiValue(arg));
1053
+ return toJSAbiValue(Reflect.apply(fromJSAbiValue(target), fromJSAbiValue(thisArgument), jsArgs));
951
1054
  }),
952
1055
  reflectConstruct: function (target, args) {
953
1056
  throw new Error("Function not implemented.");
@@ -956,7 +1059,7 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
956
1059
  throw new Error("Function not implemented.");
957
1060
  },
958
1061
  reflectGet: wrapTry((target, propertyKey) => {
959
- return target[propertyKey];
1062
+ return toJSAbiValue(fromJSAbiValue(target)[propertyKey]);
960
1063
  }),
961
1064
  reflectGetOwnPropertyDescriptor: function (target, propertyKey) {
962
1065
  throw new Error("Function not implemented.");
@@ -977,13 +1080,11 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
977
1080
  throw new Error("Function not implemented.");
978
1081
  },
979
1082
  reflectSet: wrapTry((target, propertyKey, value) => {
980
- return Reflect.set(target, propertyKey, value);
1083
+ return toJSAbiValue(Reflect.set(fromJSAbiValue(target), propertyKey, fromJSAbiValue(value)));
981
1084
  }),
982
1085
  reflectSetPrototypeOf: function (target, prototype) {
983
1086
  throw new Error("Function not implemented.");
984
1087
  },
985
- }), (name) => {
986
- return this.instance.exports[name];
987
1088
  });
988
1089
  }
989
1090
  /**
@@ -1316,7 +1417,12 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/index.umd');\` with \`re
1316
1417
  }
1317
1418
  // All JS exceptions triggered by Ruby code are translated to Ruby exceptions,
1318
1419
  // so non-RbError exceptions are unexpected.
1319
- vm.guest.rbVmBugreport();
1420
+ try {
1421
+ vm.guest.rbVmBugreport();
1422
+ }
1423
+ catch (e) {
1424
+ console.error("Tried to report internal Ruby VM state but failed: ", e);
1425
+ }
1320
1426
  if (e instanceof WebAssembly.RuntimeError && e.message === "unreachable") {
1321
1427
  const error = new RbError(`Something went wrong in Ruby VM: ${e}`);
1322
1428
  error.stack = e.stack;
Binary file
Binary file
package/dist/ruby.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruby/head-wasm-wasi",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "Ruby head built on WASI",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -29,7 +29,7 @@
29
29
  "README.md"
30
30
  ],
31
31
  "scripts": {
32
- "test": "RUBY_NPM_PACKAGE_ROOT=../ruby-head-wasm-wasi npm -C ../ruby-wasm-wasi run test:run",
32
+ "test": "RUBY_NPM_PACKAGE_ROOT=../ruby-head-wasm-wasi npm -C ../ruby-wasm-wasi run test:run:all",
33
33
  "build:deps": "cd ../ruby-wasm-wasi && npm run build",
34
34
  "build:static:files": "../ruby-wasm-wasi/tools/pack-static-files.sh ./dist",
35
35
  "build:static:compat": "../ruby-wasm-wasi/tools/pack-compat-shim.mjs --dist=./dist --pkg=ruby-head-wasm-wasi",