@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.
- package/dist/browser.script.umd.js +181 -66
- package/dist/browser.umd.js +181 -66
- package/dist/cjs/bindgen/interfaces/ruby-js-js-runtime.d.ts +45 -0
- package/dist/cjs/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +42 -0
- package/dist/cjs/bindgen/{rb-js-abi-host.d.ts → legacy/rb-js-abi-host.d.ts} +3 -3
- package/dist/cjs/bindgen/{rb-js-abi-host.js → legacy/rb-js-abi-host.js} +2 -2
- package/dist/cjs/binding.d.ts +54 -0
- package/dist/cjs/binding.js +72 -0
- package/dist/cjs/browser.js +6 -1
- package/dist/cjs/node.js +1 -1
- package/dist/cjs/vm.d.ts +12 -5
- package/dist/cjs/vm.js +104 -63
- package/dist/esm/bindgen/interfaces/ruby-js-js-runtime.d.ts +45 -0
- package/dist/esm/bindgen/interfaces/ruby-js-ruby-runtime.d.ts +42 -0
- package/dist/esm/bindgen/{rb-js-abi-host.d.ts → legacy/rb-js-abi-host.d.ts} +3 -3
- package/dist/esm/bindgen/{rb-js-abi-host.js → legacy/rb-js-abi-host.js} +2 -2
- package/dist/esm/binding.d.ts +54 -0
- package/dist/esm/binding.js +66 -0
- package/dist/esm/browser.js +7 -2
- package/dist/esm/node.js +1 -1
- package/dist/esm/vm.d.ts +12 -5
- package/dist/esm/vm.js +104 -63
- package/dist/index.umd.js +169 -63
- package/package.json +9 -8
- /package/dist/cjs/bindgen/{intrinsics.d.ts → legacy/intrinsics.d.ts} +0 -0
- /package/dist/cjs/bindgen/{intrinsics.js → legacy/intrinsics.js} +0 -0
- /package/dist/cjs/bindgen/{rb-abi-guest.d.ts → legacy/rb-abi-guest.d.ts} +0 -0
- /package/dist/cjs/bindgen/{rb-abi-guest.js → legacy/rb-abi-guest.js} +0 -0
- /package/dist/esm/bindgen/{intrinsics.d.ts → legacy/intrinsics.d.ts} +0 -0
- /package/dist/esm/bindgen/{intrinsics.js → legacy/intrinsics.js} +0 -0
- /package/dist/esm/bindgen/{rb-abi-guest.d.ts → legacy/rb-abi-guest.d.ts} +0 -0
- /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;
|
package/dist/cjs/browser.js
CHANGED
|
@@ -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
|
|
2
|
-
import {
|
|
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:
|
|
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:
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
(
|
|
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: "
|
|
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: "
|
|
254
|
+
return { tag: "as-float", val: 0 };
|
|
219
255
|
}
|
|
220
256
|
else {
|
|
221
|
-
return { tag: "
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
11
|
-
export interface
|
|
12
|
-
tag: "
|
|
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 {
|
|
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 "
|
|
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);
|