@@ -89,12 +89,16 @@ export class RubyVM {
89
89
} ) : Promise < RubyVM > {
90
90
const binding = new ComponentBinding ( )
91
91
const vm = new RubyVM ( binding ) ;
92
+ class JsAbiValue {
93
+ constructor ( public readonly underlying : any ) { }
94
+ }
95
+ const imports = vm . getImports ( ( from ) => new JsAbiValue ( from ) , ( to ) => to . underlying ) ;
92
96
const component = await initComponent ( {
93
- ...vm . getImports ( ) ,
97
+ ...imports ,
94
98
throwProhibitRewindException : ( message : string ) => {
95
99
vm . throwProhibitRewindException ( message ) ;
96
100
} ,
97
- JsAbiValue : Object ,
101
+ JsAbiValue : JsAbiValue as any ,
98
102
} ) ;
99
103
binding . setUnderlying ( component ) ;
100
104
vm . initialize ( options . args ) ;
@@ -147,6 +151,16 @@ export class RubyVM {
147
151
this . throwProhibitRewindException ( str ) ;
148
152
} ,
149
153
} ;
154
+
155
+ addRbJsAbiHostToImports (
156
+ imports ,
157
+ this . getImports ( ( value ) => value , ( value ) => value ) ,
158
+ ( name ) => {
159
+ return this . instance . exports [ name ] ;
160
+ } ,
161
+ ) ;
162
+ }
163
+
150
164
private throwProhibitRewindException ( str : string ) {
151
165
let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
152
166
`(${ str } )\n` +
@@ -167,6 +181,7 @@ export class RubyVM {
167
181
throw new RbFatalError ( message ) ;
168
182
}
169
183
184
+ private getImports ( toJSAbiValue : ( _ : any ) => any , fromJSAbiValue : ( _ : any ) => any ) : RbJsAbiHost {
170
185
// NOTE: The GC may collect objects that are still referenced by Wasm
171
186
// locals because Asyncify cannot scan the Wasm stack above the JS frame.
172
187
// So we need to keep track whether the JS frame is sandwitched by Ruby
@@ -185,17 +200,6 @@ export class RubyVM {
185
200
}
186
201
return imports ;
187
202
} ;
188
-
189
- addRbJsAbiHostToImports (
190
- imports ,
191
- proxyImports ( this . getImports ( ) ) ,
192
- ( name ) => {
193
- return this . instance . exports [ name ] ;
194
- } ,
195
- ) ;
196
- }
197
-
198
- private getImports ( ) : RbJsAbiHost {
199
203
function wrapTry ( f : ( ...args : any [ ] ) => JsAbiValue ) : ( ) => JsAbiResult {
200
204
return ( ...args ) => {
201
205
try {
@@ -206,55 +210,57 @@ export class RubyVM {
206
210
// can be already in an inconsistent state.
207
211
throw e ;
208
212
}
209
- return { tag : "failure" , val : e } ;
213
+ return { tag : "failure" , val : toJSAbiValue ( e ) } ;
210
214
}
211
215
} ;
212
216
}
213
- return {
217
+ return proxyImports ( {
214
218
evalJs : wrapTry ( ( code ) => {
215
- return Function ( code ) ( ) ;
219
+ return toJSAbiValue ( Function ( code ) ( ) ) ;
216
220
} ) ,
217
221
isJs : ( value ) => {
218
222
// Just for compatibility with the old JS API
219
223
return true ;
220
224
} ,
221
225
globalThis : ( ) => {
222
226
if ( typeof globalThis !== "undefined" ) {
223
- return globalThis ;
227
+ return toJSAbiValue ( globalThis ) ;
224
228
} else if ( typeof global !== "undefined" ) {
225
- return global ;
229
+ return toJSAbiValue ( global ) ;
226
230
} else if ( typeof window !== "undefined" ) {
227
- return window ;
231
+ return toJSAbiValue ( window ) ;
228
232
}
229
233
throw new Error ( "unable to locate global object" ) ;
230
234
} ,
231
235
intToJsNumber : ( value ) => {
232
- return value ;
236
+ return toJSAbiValue ( value ) ;
233
237
} ,
234
238
floatToJsNumber : ( value ) => {
235
- return value ;
239
+ return toJSAbiValue ( value ) ;
236
240
} ,
237
241
stringToJsString : ( value ) => {
238
- return value ;
242
+ return toJSAbiValue ( value ) ;
239
243
} ,
240
244
boolToJsBool : ( value ) => {
241
- return value ;
245
+ return toJSAbiValue ( value ) ;
242
246
} ,
243
247
procToJsFunction : ( rawRbAbiValue ) => {
244
248
const rbValue = this . rbValueOfPointer ( rawRbAbiValue ) ;
245
- return ( ...args ) => {
249
+ return toJSAbiValue ( ( ...args ) => {
246
250
return rbValue . call ( "call" , ...args . map ( ( arg ) => this . wrap ( arg ) ) ) . toJS ( ) ;
247
- } ;
251
+ } ) ;
248
252
} ,
249
253
rbObjectToJsRbValue : ( rawRbAbiValue ) => {
250
- return this . rbValueOfPointer ( rawRbAbiValue ) ;
254
+ return toJSAbiValue ( this . rbValueOfPointer ( rawRbAbiValue ) ) ;
251
255
} ,
252
256
jsValueToString : ( value ) => {
257
+ value = fromJSAbiValue ( value )
253
258
// According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
254
259
// `String(value)` always returns a string.
255
260
return String ( value ) ;
256
261
} ,
257
262
jsValueToInteger ( value ) {
263
+ value = fromJSAbiValue ( value )
258
264
if ( typeof value === "number" ) {
259
265
return { tag : "as-float" , val : value } ;
260
266
} else if ( typeof value === "bigint" ) {
@@ -269,10 +275,10 @@ export class RubyVM {
269
275
} ,
270
276
exportJsValueToHost : ( value ) => {
271
277
// See `JsValueExporter` for the reason why we need to do this
272
- this . transport . takeJsValue ( value ) ;
278
+ this . transport . takeJsValue ( fromJSAbiValue ( value ) ) ;
273
279
} ,
274
280
importJsValueFromHost : ( ) => {
275
- return this . transport . consumeJsValue ( ) ;
281
+ return toJSAbiValue ( this . transport . consumeJsValue ( ) ) ;
276
282
} ,
277
283
instanceOf : ( value , klass ) => {
278
284
if ( typeof klass === "function" ) {
@@ -282,16 +288,17 @@ export class RubyVM {
282
288
}
283
289
} ,
284
290
jsValueTypeof ( value ) {
285
- return typeof value ;
291
+ return typeof fromJSAbiValue ( value ) ;
286
292
} ,
287
293
jsValueEqual ( lhs , rhs ) {
288
- return lhs == rhs ;
294
+ return fromJSAbiValue ( lhs ) == fromJSAbiValue ( rhs ) ;
289
295
} ,
290
296
jsValueStrictlyEqual ( lhs , rhs ) {
291
- return lhs === rhs ;
297
+ return fromJSAbiValue ( lhs ) === fromJSAbiValue ( rhs ) ;
292
298
} ,
293
299
reflectApply : wrapTry ( ( target , thisArgument , args ) => {
294
- return Reflect . apply ( target as any , thisArgument , args ) ;
300
+ const jsArgs = args . map ( ( arg ) => fromJSAbiValue ( arg ) ) ;
301
+ return toJSAbiValue ( Reflect . apply ( fromJSAbiValue ( target as any ) , fromJSAbiValue ( thisArgument ) , jsArgs ) ) ;
295
302
} ) ,
296
303
reflectConstruct : function ( target , args ) {
297
304
throw new Error ( "Function not implemented." ) ;
@@ -300,7 +307,7 @@ export class RubyVM {
300
307
throw new Error ( "Function not implemented." ) ;
301
308
} ,
302
309
reflectGet : wrapTry ( ( target , propertyKey ) => {
303
- return target [ propertyKey ] ;
310
+ return toJSAbiValue ( fromJSAbiValue ( target ) [ propertyKey ] ) ;
304
311
} ) ,
305
312
reflectGetOwnPropertyDescriptor : function (
306
313
target ,
@@ -324,12 +331,12 @@ export class RubyVM {
324
331
throw new Error ( "Function not implemented." ) ;
325
332
} ,
326
333
reflectSet : wrapTry ( ( target , propertyKey , value ) => {
327
- return Reflect . set ( target , propertyKey , value ) ;
334
+ return toJSAbiValue ( Reflect . set ( fromJSAbiValue ( target ) , propertyKey , fromJSAbiValue ( value ) ) ) ;
328
335
} ) ,
329
336
reflectSetPrototypeOf : function ( target , prototype ) : boolean {
330
337
throw new Error ( "Function not implemented." ) ;
331
338
} ,
332
- }
339
+ } )
333
340
}
334
341
335
342
/**
0 commit comments