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