@ruby/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 (32) hide show
  1. package/dist/browser.script.umd.js +181 -66
  2. package/dist/browser.umd.js +181 -66
  3. package/dist/cjs/bindgen/interfaces/ruby-js-js-runtime.d.ts +45 -0
  4. package/dist/cjs/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +42 -0
  5. package/dist/cjs/bindgen/{rb-js-abi-host.d.ts → legacy/rb-js-abi-host.d.ts} +3 -3
  6. package/dist/cjs/bindgen/{rb-js-abi-host.js → legacy/rb-js-abi-host.js} +2 -2
  7. package/dist/cjs/binding.d.ts +54 -0
  8. package/dist/cjs/binding.js +72 -0
  9. package/dist/cjs/browser.js +6 -1
  10. package/dist/cjs/node.js +1 -1
  11. package/dist/cjs/vm.d.ts +12 -5
  12. package/dist/cjs/vm.js +104 -63
  13. package/dist/esm/bindgen/interfaces/ruby-js-js-runtime.d.ts +45 -0
  14. package/dist/esm/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +42 -0
  15. package/dist/esm/bindgen/{rb-js-abi-host.d.ts → legacy/rb-js-abi-host.d.ts} +3 -3
  16. package/dist/esm/bindgen/{rb-js-abi-host.js → legacy/rb-js-abi-host.js} +2 -2
  17. package/dist/esm/binding.d.ts +54 -0
  18. package/dist/esm/binding.js +66 -0
  19. package/dist/esm/browser.js +7 -2
  20. package/dist/esm/node.js +1 -1
  21. package/dist/esm/vm.d.ts +12 -5
  22. package/dist/esm/vm.js +104 -63
  23. package/dist/index.umd.js +169 -63
  24. package/package.json +9 -8
  25. /package/dist/cjs/bindgen/{intrinsics.d.ts → legacy/intrinsics.d.ts} +0 -0
  26. /package/dist/cjs/bindgen/{intrinsics.js → legacy/intrinsics.js} +0 -0
  27. /package/dist/cjs/bindgen/{rb-abi-guest.d.ts → legacy/rb-abi-guest.d.ts} +0 -0
  28. /package/dist/cjs/bindgen/{rb-abi-guest.js → legacy/rb-abi-guest.js} +0 -0
  29. /package/dist/esm/bindgen/{intrinsics.d.ts → legacy/intrinsics.d.ts} +0 -0
  30. /package/dist/esm/bindgen/{intrinsics.js → legacy/intrinsics.js} +0 -0
  31. /package/dist/esm/bindgen/{rb-abi-guest.d.ts → legacy/rb-abi-guest.d.ts} +0 -0
  32. /package/dist/esm/bindgen/{rb-abi-guest.js → legacy/rb-abi-guest.js} +0 -0
@@ -0,0 +1,54 @@
1
+ import { RubyJsRubyRuntime } from "./bindgen/interfaces/ruby-js-ruby-runtime.js";
2
+ import * as RbAbi from "./bindgen/legacy/rb-abi-guest.js";
3
+ /**
4
+ * This interface bridges between the Ruby runtime and the JavaScript runtime
5
+ * and defines how to interact with underlying import/export functions.
6
+ */
7
+ export interface Binding {
8
+ rubyShowVersion(): void;
9
+ rubyInit(): void;
10
+ rubySysinit(args: string[]): void;
11
+ rubyOptions(args: string[]): void;
12
+ rubyScript(name: string): void;
13
+ rubyInitLoadpath(): void;
14
+ rbEvalStringProtect(str: string): [RbAbiValue, number];
15
+ rbFuncallvProtect(recv: RbAbiValue, mid: RbAbi.RbId, args: RbAbiValue[]): [RbAbiValue, number];
16
+ rbIntern(name: string): RbAbi.RbId;
17
+ rbErrinfo(): RbAbiValue;
18
+ rbClearErrinfo(): void;
19
+ rstringPtr(value: RbAbiValue): string;
20
+ rbVmBugreport(): void;
21
+ rbGcEnable(): boolean;
22
+ rbGcDisable(): boolean;
23
+ rbSetShouldProhibitRewind(newValue: boolean): boolean;
24
+ setInstance(instance: WebAssembly.Instance): Promise<void>;
25
+ addToImports(imports: WebAssembly.Imports): void;
26
+ }
27
+ export interface RbAbiValue {
28
+ }
29
+ export declare class LegacyBinding extends RbAbi.RbAbiGuest implements Binding {
30
+ setInstance(instance: WebAssembly.Instance): Promise<void>;
31
+ }
32
+ export declare class ComponentBinding implements Binding {
33
+ underlying: typeof RubyJsRubyRuntime;
34
+ constructor();
35
+ setUnderlying(underlying: typeof RubyJsRubyRuntime): void;
36
+ rubyShowVersion(): void;
37
+ rubyInit(): void;
38
+ rubySysinit(args: string[]): void;
39
+ rubyOptions(args: string[]): void;
40
+ rubyScript(name: string): void;
41
+ rubyInitLoadpath(): void;
42
+ rbEvalStringProtect(str: string): [RbAbiValue, number];
43
+ rbFuncallvProtect(recv: RbAbiValue, mid: number, args: RbAbiValue[]): [RbAbiValue, number];
44
+ rbIntern(name: string): number;
45
+ rbErrinfo(): RbAbiValue;
46
+ rbClearErrinfo(): void;
47
+ rstringPtr(value: RbAbiValue): string;
48
+ rbVmBugreport(): void;
49
+ rbGcEnable(): boolean;
50
+ rbGcDisable(): boolean;
51
+ rbSetShouldProhibitRewind(newValue: boolean): boolean;
52
+ setInstance(instance: WebAssembly.Instance): Promise<void>;
53
+ addToImports(imports: WebAssembly.Imports): void;
54
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComponentBinding = exports.LegacyBinding = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const RbAbi = tslib_1.__importStar(require("./bindgen/legacy/rb-abi-guest.js"));
6
+ class LegacyBinding extends RbAbi.RbAbiGuest {
7
+ async setInstance(instance) {
8
+ await this.instantiate(instance);
9
+ }
10
+ }
11
+ exports.LegacyBinding = LegacyBinding;
12
+ class ComponentBinding {
13
+ constructor() { }
14
+ setUnderlying(underlying) {
15
+ this.underlying = underlying;
16
+ }
17
+ rubyShowVersion() {
18
+ this.underlying.rubyShowVersion();
19
+ }
20
+ rubyInit() {
21
+ this.underlying.rubyInit();
22
+ }
23
+ rubySysinit(args) {
24
+ this.underlying.rubySysinit(args);
25
+ }
26
+ rubyOptions(args) {
27
+ this.underlying.rubyOptions(args);
28
+ }
29
+ rubyScript(name) {
30
+ this.underlying.rubyScript(name);
31
+ }
32
+ rubyInitLoadpath() {
33
+ this.underlying.rubyInitLoadpath();
34
+ }
35
+ rbEvalStringProtect(str) {
36
+ return this.underlying.rbEvalStringProtect(str);
37
+ }
38
+ rbFuncallvProtect(recv, mid, args) {
39
+ return this.underlying.rbFuncallvProtect(recv, mid, args);
40
+ }
41
+ rbIntern(name) {
42
+ return this.underlying.rbIntern(name);
43
+ }
44
+ rbErrinfo() {
45
+ return this.underlying.rbErrinfo();
46
+ }
47
+ rbClearErrinfo() {
48
+ return this.underlying.rbClearErrinfo();
49
+ }
50
+ rstringPtr(value) {
51
+ return this.underlying.rstringPtr(value);
52
+ }
53
+ rbVmBugreport() {
54
+ this.underlying.rbVmBugreport();
55
+ }
56
+ rbGcEnable() {
57
+ return this.underlying.rbGcEnable();
58
+ }
59
+ rbGcDisable() {
60
+ return this.underlying.rbGcDisable();
61
+ }
62
+ rbSetShouldProhibitRewind(newValue) {
63
+ return this.underlying.rbSetShouldProhibitRewind(newValue);
64
+ }
65
+ async setInstance(instance) {
66
+ // No-op
67
+ }
68
+ addToImports(imports) {
69
+ // No-op
70
+ }
71
+ }
72
+ exports.ComponentBinding = ComponentBinding;
@@ -8,7 +8,12 @@ const DefaultRubyVM = async (rubyModule, options = {}) => {
8
8
  var _a, _b;
9
9
  const args = [];
10
10
  const env = Object.entries((_a = options.env) !== null && _a !== void 0 ? _a : {}).map(([k, v]) => `${k}=${v}`);
11
- const fds = [];
11
+ const fds = [
12
+ new browser_wasi_shim_1.OpenFile(new browser_wasi_shim_1.File([])),
13
+ new browser_wasi_shim_1.OpenFile(new browser_wasi_shim_1.File([])),
14
+ new browser_wasi_shim_1.OpenFile(new browser_wasi_shim_1.File([])),
15
+ new browser_wasi_shim_1.PreopenDirectory("/", new Map()),
16
+ ];
12
17
  const wasi = new browser_wasi_shim_1.WASI(args, env, fds, { debug: false });
13
18
  const vm = new vm_js_1.RubyVM();
14
19
  const imports = {
package/dist/cjs/node.js CHANGED
@@ -4,7 +4,7 @@ exports.DefaultRubyVM = void 0;
4
4
  const wasi_1 = require("wasi");
5
5
  const vm_js_1 = require("./vm.js");
6
6
  const DefaultRubyVM = async (rubyModule, options = {}) => {
7
- const wasi = new wasi_1.WASI({ env: options.env, version: "preview1" });
7
+ const wasi = new wasi_1.WASI({ env: options.env, version: "preview1", returnOnExit: true });
8
8
  const vm = new vm_js_1.RubyVM();
9
9
  const imports = {
10
10
  wasi_snapshot_preview1: wasi.wasiImport,
package/dist/cjs/vm.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import * as RbAbi from "./bindgen/rb-abi-guest.js";
2
- import { JsAbiValue } from "./bindgen/rb-js-abi-host.js";
1
+ import type { RubyJsJsRuntime } from "./bindgen/interfaces/ruby-js-js-runtime.js";
2
+ import type { RubyJsRubyRuntime } from "./bindgen/interfaces/ruby-js-ruby-runtime.js";
3
+ import { JsAbiValue } from "./bindgen/legacy/rb-js-abi-host.js";
4
+ import { Binding, RbAbiValue } from "./binding.js";
3
5
  /**
4
6
  * A Ruby VM instance
5
7
  *
@@ -20,12 +22,15 @@ import { JsAbiValue } from "./bindgen/rb-js-abi-host.js";
20
22
  *
21
23
  */
22
24
  export declare class RubyVM {
23
- guest: RbAbi.RbAbiGuest;
25
+ guest: Binding;
24
26
  private instance;
25
27
  private transport;
26
28
  private exceptionFormatter;
27
29
  private interfaceState;
28
- constructor();
30
+ constructor(binding?: Binding);
31
+ static _instantiate(initComponent: (_: typeof RubyJsJsRuntime) => Promise<typeof RubyJsRubyRuntime>, options: {
32
+ args?: string[];
33
+ }): Promise<RubyVM>;
29
34
  /**
30
35
  * Initialize the Ruby VM with the given command line arguments
31
36
  * @param args The command line arguments to pass to Ruby. Must be
@@ -48,6 +53,8 @@ export declare class RubyVM {
48
53
  * @param imports The import object to add to the WebAssembly instance
49
54
  */
50
55
  addToImports(imports: WebAssembly.Imports): void;
56
+ private throwProhibitRewindException;
57
+ private getImports;
51
58
  /**
52
59
  * Print the Ruby version to stdout
53
60
  */
@@ -132,7 +139,7 @@ export declare class RbValue {
132
139
  /**
133
140
  * @hideconstructor
134
141
  */
135
- constructor(inner: RbAbi.RbAbiValue, vm: RubyVM, privateObject: RubyVMPrivate);
142
+ constructor(inner: RbAbiValue, vm: RubyVM, privateObject: RubyVMPrivate);
136
143
  /**
137
144
  * Call a given method with given arguments
138
145
  *
package/dist/cjs/vm.js CHANGED
@@ -2,8 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RbFatalError = exports.RbError = exports.RbValue = exports.RubyVM = void 0;
4
4
  const tslib_1 = require("tslib");
5
- const RbAbi = tslib_1.__importStar(require("./bindgen/rb-abi-guest.js"));
6
- const rb_js_abi_host_js_1 = require("./bindgen/rb-js-abi-host.js");
5
+ const RbAbi = tslib_1.__importStar(require("./bindgen/legacy/rb-abi-guest.js"));
6
+ const rb_js_abi_host_js_1 = require("./bindgen/legacy/rb-js-abi-host.js");
7
+ const binding_js_1 = require("./binding.js");
7
8
  /**
8
9
  * A Ruby VM instance
9
10
  *
@@ -24,7 +25,7 @@ const rb_js_abi_host_js_1 = require("./bindgen/rb-js-abi-host.js");
24
25
  *
25
26
  */
26
27
  class RubyVM {
27
- constructor() {
28
+ constructor(binding) {
28
29
  this.instance = null;
29
30
  this.interfaceState = {
30
31
  hasJSFrameAfterRbFrame: false,
@@ -33,6 +34,7 @@ class RubyVM {
33
34
  // if the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby.
34
35
  const proxyExports = (exports) => {
35
36
  const excludedMethods = [
37
+ "setInstance",
36
38
  "addToImports",
37
39
  "instantiate",
38
40
  "rbSetShouldProhibitRewind",
@@ -67,10 +69,34 @@ class RubyVM {
67
69
  }
68
70
  return exports;
69
71
  };
70
- this.guest = proxyExports(new RbAbi.RbAbiGuest());
72
+ this.guest = proxyExports(binding !== null && binding !== void 0 ? binding : new binding_js_1.LegacyBinding());
71
73
  this.transport = new JsValueTransport();
72
74
  this.exceptionFormatter = new RbExceptionFormatter();
73
75
  }
76
+ static async _instantiate(initComponent, options) {
77
+ const binding = new binding_js_1.ComponentBinding();
78
+ const vm = new RubyVM(binding);
79
+ class JsAbiValue {
80
+ constructor(underlying) {
81
+ this.underlying = underlying;
82
+ }
83
+ }
84
+ const imports = vm.getImports((from) => new JsAbiValue(from), (to) => to.underlying);
85
+ const component = await initComponent(Object.assign(Object.assign({}, imports), { throwProhibitRewindException: (message) => {
86
+ vm.throwProhibitRewindException(message);
87
+ }, procToJsFunction: () => {
88
+ const rbValue = new RbValue(component.exportRbValueToJs(), vm, vm.privateObject());
89
+ return new JsAbiValue((...args) => {
90
+ return rbValue.call("call", ...args.map((arg) => vm.wrap(arg))).toJS();
91
+ });
92
+ }, rbObjectToJsRbValue: () => {
93
+ const rbValue = new RbValue(component.exportRbValueToJs(), vm, vm.privateObject());
94
+ return new JsAbiValue(rbValue);
95
+ }, JsAbiValue: JsAbiValue }));
96
+ binding.setUnderlying(component);
97
+ vm.initialize(options.args);
98
+ return vm;
99
+ }
74
100
  /**
75
101
  * Initialize the Ruby VM with the given command line arguments
76
102
  * @param args The command line arguments to pass to Ruby. Must be
@@ -94,7 +120,7 @@ class RubyVM {
94
120
  */
95
121
  async setInstance(instance) {
96
122
  this.instance = instance;
97
- await this.guest.instantiate(instance);
123
+ await this.guest.setInstance(instance);
98
124
  }
99
125
  /**
100
126
  * Add intrinsic import entries, which is necessary to interact JavaScript
@@ -103,43 +129,36 @@ class RubyVM {
103
129
  */
104
130
  addToImports(imports) {
105
131
  this.guest.addToImports(imports);
106
- function wrapTry(f) {
107
- return (...args) => {
108
- try {
109
- return { tag: "success", val: f(...args) };
110
- }
111
- catch (e) {
112
- if (e instanceof RbFatalError) {
113
- // RbFatalError should not be caught by Ruby because it Ruby VM
114
- // can be already in an inconsistent state.
115
- throw e;
116
- }
117
- return { tag: "failure", val: e };
118
- }
119
- };
120
- }
121
132
  imports["rb-js-abi-host"] = {
122
133
  rb_wasm_throw_prohibit_rewind_exception: (messagePtr, messageLen) => {
123
134
  const memory = this.instance.exports.memory;
124
135
  const str = new TextDecoder().decode(new Uint8Array(memory.buffer, messagePtr, messageLen));
125
- let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
126
- `(${str})\n` +
127
- "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
128
- "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
129
- "\n" +
130
- "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
131
- " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
132
- " Note that `evalAsync` JS API switches fibers internally\n" +
133
- " 2. Raising uncaught exceptions\n" +
134
- " Please catch all exceptions inside the nested operation\n" +
135
- " 3. Calling Continuation APIs\n";
136
- const error = new RbValue(this.guest.rbErrinfo(), this, this.privateObject());
137
- if (error.call("nil?").toString() === "false") {
138
- message += "\n" + this.exceptionFormatter.format(error, this, this.privateObject());
139
- }
140
- throw new RbFatalError(message);
136
+ this.throwProhibitRewindException(str);
141
137
  },
142
138
  };
139
+ (0, rb_js_abi_host_js_1.addRbJsAbiHostToImports)(imports, this.getImports((value) => value, (value) => value), (name) => {
140
+ return this.instance.exports[name];
141
+ });
142
+ }
143
+ throwProhibitRewindException(str) {
144
+ let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
145
+ `(${str})\n` +
146
+ "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
147
+ "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
148
+ "\n" +
149
+ "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
150
+ " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
151
+ " Note that `evalAsync` JS API switches fibers internally\n" +
152
+ " 2. Raising uncaught exceptions\n" +
153
+ " Please catch all exceptions inside the nested operation\n" +
154
+ " 3. Calling Continuation APIs\n";
155
+ const error = new RbValue(this.guest.rbErrinfo(), this, this.privateObject());
156
+ if (error.call("nil?").toString() === "false") {
157
+ message += "\n" + this.exceptionFormatter.format(error, this, this.privateObject());
158
+ }
159
+ throw new RbFatalError(message);
160
+ }
161
+ getImports(toJSAbiValue, fromJSAbiValue) {
143
162
  // NOTE: The GC may collect objects that are still referenced by Wasm
144
163
  // locals because Asyncify cannot scan the Wasm stack above the JS frame.
145
164
  // So we need to keep track whether the JS frame is sandwitched by Ruby
@@ -158,9 +177,24 @@ class RubyVM {
158
177
  }
159
178
  return imports;
160
179
  };
161
- (0, rb_js_abi_host_js_1.addRbJsAbiHostToImports)(imports, proxyImports({
180
+ function wrapTry(f) {
181
+ return (...args) => {
182
+ try {
183
+ return { tag: "success", val: f(...args) };
184
+ }
185
+ catch (e) {
186
+ if (e instanceof RbFatalError) {
187
+ // RbFatalError should not be caught by Ruby because it Ruby VM
188
+ // can be already in an inconsistent state.
189
+ throw e;
190
+ }
191
+ return { tag: "failure", val: toJSAbiValue(e) };
192
+ }
193
+ };
194
+ }
195
+ return proxyImports({
162
196
  evalJs: wrapTry((code) => {
163
- return Function(code)();
197
+ return toJSAbiValue(Function(code)());
164
198
  }),
165
199
  isJs: (value) => {
166
200
  // Just for compatibility with the old JS API
@@ -168,45 +202,47 @@ class RubyVM {
168
202
  },
169
203
  globalThis: () => {
170
204
  if (typeof globalThis !== "undefined") {
171
- return globalThis;
205
+ return toJSAbiValue(globalThis);
172
206
  }
173
207
  else if (typeof global !== "undefined") {
174
- return global;
208
+ return toJSAbiValue(global);
175
209
  }
176
210
  else if (typeof window !== "undefined") {
177
- return window;
211
+ return toJSAbiValue(window);
178
212
  }
179
213
  throw new Error("unable to locate global object");
180
214
  },
181
215
  intToJsNumber: (value) => {
182
- return value;
216
+ return toJSAbiValue(value);
183
217
  },
184
218
  floatToJsNumber: (value) => {
185
- return value;
219
+ return toJSAbiValue(value);
186
220
  },
187
221
  stringToJsString: (value) => {
188
- return value;
222
+ return toJSAbiValue(value);
189
223
  },
190
224
  boolToJsBool: (value) => {
191
- return value;
225
+ return toJSAbiValue(value);
192
226
  },
193
227
  procToJsFunction: (rawRbAbiValue) => {
194
228
  const rbValue = this.rbValueOfPointer(rawRbAbiValue);
195
- return (...args) => {
229
+ return toJSAbiValue((...args) => {
196
230
  return rbValue.call("call", ...args.map((arg) => this.wrap(arg))).toJS();
197
- };
231
+ });
198
232
  },
199
233
  rbObjectToJsRbValue: (rawRbAbiValue) => {
200
- return this.rbValueOfPointer(rawRbAbiValue);
234
+ return toJSAbiValue(this.rbValueOfPointer(rawRbAbiValue));
201
235
  },
202
236
  jsValueToString: (value) => {
237
+ value = fromJSAbiValue(value);
203
238
  // According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
204
239
  // `String(value)` always returns a string.
205
240
  return String(value);
206
241
  },
207
242
  jsValueToInteger(value) {
243
+ value = fromJSAbiValue(value);
208
244
  if (typeof value === "number") {
209
- return { tag: "f64", val: value };
245
+ return { tag: "as-float", val: value };
210
246
  }
211
247
  else if (typeof value === "bigint") {
212
248
  return { tag: "bignum", val: BigInt(value).toString(10) + "\0" };
@@ -215,38 +251,40 @@ class RubyVM {
215
251
  return { tag: "bignum", val: value + "\0" };
216
252
  }
217
253
  else if (typeof value === "undefined") {
218
- return { tag: "f64", val: 0 };
254
+ return { tag: "as-float", val: 0 };
219
255
  }
220
256
  else {
221
- return { tag: "f64", val: Number(value) };
257
+ return { tag: "as-float", val: Number(value) };
222
258
  }
223
259
  },
224
260
  exportJsValueToHost: (value) => {
225
261
  // See `JsValueExporter` for the reason why we need to do this
226
- this.transport.takeJsValue(value);
262
+ this.transport.takeJsValue(fromJSAbiValue(value));
227
263
  },
228
264
  importJsValueFromHost: () => {
229
- return this.transport.consumeJsValue();
265
+ return toJSAbiValue(this.transport.consumeJsValue());
230
266
  },
231
267
  instanceOf: (value, klass) => {
268
+ klass = fromJSAbiValue(klass);
232
269
  if (typeof klass === "function") {
233
- return value instanceof klass;
270
+ return fromJSAbiValue(value) instanceof klass;
234
271
  }
235
272
  else {
236
273
  return false;
237
274
  }
238
275
  },
239
276
  jsValueTypeof(value) {
240
- return typeof value;
277
+ return typeof fromJSAbiValue(value);
241
278
  },
242
279
  jsValueEqual(lhs, rhs) {
243
- return lhs == rhs;
280
+ return fromJSAbiValue(lhs) == fromJSAbiValue(rhs);
244
281
  },
245
282
  jsValueStrictlyEqual(lhs, rhs) {
246
- return lhs === rhs;
283
+ return fromJSAbiValue(lhs) === fromJSAbiValue(rhs);
247
284
  },
248
285
  reflectApply: wrapTry((target, thisArgument, args) => {
249
- return Reflect.apply(target, thisArgument, args);
286
+ const jsArgs = args.map((arg) => fromJSAbiValue(arg));
287
+ return toJSAbiValue(Reflect.apply(fromJSAbiValue(target), fromJSAbiValue(thisArgument), jsArgs));
250
288
  }),
251
289
  reflectConstruct: function (target, args) {
252
290
  throw new Error("Function not implemented.");
@@ -255,7 +293,7 @@ class RubyVM {
255
293
  throw new Error("Function not implemented.");
256
294
  },
257
295
  reflectGet: wrapTry((target, propertyKey) => {
258
- return target[propertyKey];
296
+ return toJSAbiValue(fromJSAbiValue(target)[propertyKey]);
259
297
  }),
260
298
  reflectGetOwnPropertyDescriptor: function (target, propertyKey) {
261
299
  throw new Error("Function not implemented.");
@@ -276,13 +314,11 @@ class RubyVM {
276
314
  throw new Error("Function not implemented.");
277
315
  },
278
316
  reflectSet: wrapTry((target, propertyKey, value) => {
279
- return Reflect.set(target, propertyKey, value);
317
+ return toJSAbiValue(Reflect.set(fromJSAbiValue(target), propertyKey, fromJSAbiValue(value)));
280
318
  }),
281
319
  reflectSetPrototypeOf: function (target, prototype) {
282
320
  throw new Error("Function not implemented.");
283
321
  },
284
- }), (name) => {
285
- return this.instance.exports[name];
286
322
  });
287
323
  }
288
324
  /**
@@ -617,7 +653,12 @@ function wrapRbOperation(vm, body) {
617
653
  }
618
654
  // All JS exceptions triggered by Ruby code are translated to Ruby exceptions,
619
655
  // so non-RbError exceptions are unexpected.
620
- vm.guest.rbVmBugreport();
656
+ try {
657
+ vm.guest.rbVmBugreport();
658
+ }
659
+ catch (e) {
660
+ console.error("Tried to report internal Ruby VM state but failed: ", e);
661
+ }
621
662
  if (e instanceof WebAssembly.RuntimeError && e.message === "unreachable") {
622
663
  const error = new RbError(`Something went wrong in Ruby VM: ${e}`);
623
664
  error.stack = e.stack;
@@ -0,0 +1,45 @@
1
+ export namespace RubyJsJsRuntime {
2
+ export function evalJs(code: string): JsAbiResult;
3
+ export function isJs(value: JsAbiValue): boolean;
4
+ export function instanceOf(value: JsAbiValue, klass: JsAbiValue): boolean;
5
+ export function globalThis(): JsAbiValue;
6
+ export function intToJsNumber(value: number): JsAbiValue;
7
+ export function floatToJsNumber(value: number): JsAbiValue;
8
+ export function stringToJsString(value: string): JsAbiValue;
9
+ export function boolToJsBool(value: boolean): JsAbiValue;
10
+ export function procToJsFunction(): JsAbiValue;
11
+ export function rbObjectToJsRbValue(): JsAbiValue;
12
+ export function jsValueToString(value: JsAbiValue): string;
13
+ export function jsValueToInteger(value: JsAbiValue): RawInteger;
14
+ export function exportJsValueToHost(value: JsAbiValue): void;
15
+ export function importJsValueFromHost(): JsAbiValue;
16
+ export function jsValueTypeof(value: JsAbiValue): string;
17
+ export function jsValueEqual(lhs: JsAbiValue, rhs: JsAbiValue): boolean;
18
+ export function jsValueStrictlyEqual(lhs: JsAbiValue, rhs: JsAbiValue): boolean;
19
+ export function reflectApply(target: JsAbiValue, thisArgument: JsAbiValue, arguments: JsAbiValue[]): JsAbiResult;
20
+ export function reflectGet(target: JsAbiValue, propertyKey: string): JsAbiResult;
21
+ export function reflectSet(target: JsAbiValue, propertyKey: string, value: JsAbiValue): JsAbiResult;
22
+ export function throwProhibitRewindException(message: string): void;
23
+ export { JsAbiValue };
24
+ }
25
+ export type JsAbiResult = JsAbiResultSuccess | JsAbiResultFailure;
26
+ export interface JsAbiResultSuccess {
27
+ tag: 'success',
28
+ val: JsAbiValue,
29
+ }
30
+ export interface JsAbiResultFailure {
31
+ tag: 'failure',
32
+ val: JsAbiValue,
33
+ }
34
+ export type RawInteger = RawIntegerAsFloat | RawIntegerBignum;
35
+ export interface RawIntegerAsFloat {
36
+ tag: 'as-float',
37
+ val: number,
38
+ }
39
+ export interface RawIntegerBignum {
40
+ tag: 'bignum',
41
+ val: string,
42
+ }
43
+
44
+ export class JsAbiValue {
45
+ }
@@ -0,0 +1,42 @@
1
+ export namespace RubyJsRubyRuntime {
2
+ export function rubyShowVersion(): void;
3
+ export function rubyInit(): void;
4
+ export function rubySysinit(args: string[]): void;
5
+ export function rubyOptions(args: string[]): RbIseq;
6
+ export function rubyScript(name: string): void;
7
+ export function rubyInitLoadpath(): void;
8
+ export function rbEvalStringProtect(str: string): [RbAbiValue, number];
9
+ export function rbFuncallvProtect(recv: RbAbiValue, mid: RbId, args: RbAbiValue[]): [RbAbiValue, number];
10
+ export function rbIntern(name: string): RbId;
11
+ export function rbErrinfo(): RbAbiValue;
12
+ export function rbClearErrinfo(): void;
13
+ export function rstringPtr(value: RbAbiValue): string;
14
+ export function rbVmBugreport(): void;
15
+ export function rbGcEnable(): boolean;
16
+ export function rbGcDisable(): boolean;
17
+ export function rbSetShouldProhibitRewind(newValue: boolean): boolean;
18
+ /**
19
+ * XXX: Do we really need them?
20
+ * wrap-js-value: func(value: js-abi-value) -> rb-abi-value;
21
+ * to-js-value: func(value: borrow<rb-abi-value>) -> js-abi-value;
22
+ * Transfer the value from Ruby to JS
23
+ *
24
+ * 1. Ruby side registers the value in the stage
25
+ * 2. Ruby side calls JS's `import-rb-value-from-rb()`
26
+ * 3. `import-rb-value-from-rb()` calls `export-rb-value-to-js()`
27
+ * 4. `export-rb-value-to-js()` returns the staged value
28
+ */
29
+ export function exportRbValueToJs(): RbAbiValue;
30
+ export { RbIseq };
31
+ export { RbAbiValue };
32
+ }
33
+ import type { JsAbiValue } from './ruby-js-js-runtime.js';
34
+ export { JsAbiValue };
35
+ export type RbErrno = number;
36
+ export type RbId = number;
37
+
38
+ export class RbAbiValue {
39
+ }
40
+
41
+ export class RbIseq {
42
+ }
@@ -7,9 +7,9 @@ export interface JsAbiResultFailure {
7
7
  tag: "failure",
8
8
  val: JsAbiValue,
9
9
  }
10
- export type RawInteger = RawIntegerF64 | RawIntegerBignum;
11
- export interface RawIntegerF64 {
12
- tag: "f64",
10
+ export type RawInteger = RawIntegerAsFloat | RawIntegerBignum;
11
+ export interface RawIntegerAsFloat {
12
+ tag: "as-float",
13
13
  val: number,
14
14
  }
15
15
  export interface RawIntegerBignum {
@@ -76,13 +76,13 @@ export function addRbJsAbiHostToImports(imports, obj, get_export) {
76
76
  data_view(memory).setInt32(arg1 + 4, len0, true);
77
77
  data_view(memory).setInt32(arg1 + 0, ptr0, true);
78
78
  };
79
- imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { f64(float64), bignum(string) }"] = function (arg0, arg1) {
79
+ imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { as-float(float64), bignum(string) }"] = function (arg0, arg1) {
80
80
  const memory = get_export("memory");
81
81
  const realloc = get_export("cabi_realloc");
82
82
  const ret0 = obj.jsValueToInteger(resources0.get(arg0));
83
83
  const variant1 = ret0;
84
84
  switch (variant1.tag) {
85
- case "f64": {
85
+ case "as-float": {
86
86
  const e = variant1.val;
87
87
  data_view(memory).setInt8(arg1 + 0, 0, true);
88
88
  data_view(memory).setFloat64(arg1 + 8, +e, true);