@@ -89,12 +89,16 @@ export class RubyVM {
8989 } ) : Promise < RubyVM > {
9090 const binding = new ComponentBinding ( )
9191 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 ) ;
9296 const component = await initComponent ( {
93- ...vm . getImports ( ) ,
97+ ...imports ,
9498 throwProhibitRewindException : ( message : string ) => {
9599 vm . throwProhibitRewindException ( message ) ;
96100 } ,
97- JsAbiValue : Object ,
101+ JsAbiValue : JsAbiValue as any ,
98102 } ) ;
99103 binding . setUnderlying ( component ) ;
100104 vm . initialize ( options . args ) ;
@@ -147,6 +151,16 @@ export class RubyVM {
147151 this . throwProhibitRewindException ( str ) ;
148152 } ,
149153 } ;
154+
155+ addRbJsAbiHostToImports (
156+ imports ,
157+ this . getImports ( ( value ) => value , ( value ) => value ) ,
158+ ( name ) => {
159+ return this . instance . exports [ name ] ;
160+ } ,
161+ ) ;
162+ }
163+
150164 private throwProhibitRewindException ( str : string ) {
151165 let message = "Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
152166 `(${ str } )\n` +
@@ -167,6 +181,7 @@ export class RubyVM {
167181 throw new RbFatalError ( message ) ;
168182 }
169183
184+ private getImports ( toJSAbiValue : ( _ : any ) => any , fromJSAbiValue : ( _ : any ) => any ) : RbJsAbiHost {
170185 // NOTE: The GC may collect objects that are still referenced by Wasm
171186 // locals because Asyncify cannot scan the Wasm stack above the JS frame.
172187 // So we need to keep track whether the JS frame is sandwitched by Ruby
@@ -185,17 +200,6 @@ export class RubyVM {
185200 }
186201 return imports ;
187202 } ;
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 {
199203 function wrapTry ( f : ( ...args : any [ ] ) => JsAbiValue ) : ( ) => JsAbiResult {
200204 return ( ...args ) => {
201205 try {
@@ -206,55 +210,57 @@ export class RubyVM {
206210 // can be already in an inconsistent state.
207211 throw e ;
208212 }
209- return { tag : "failure" , val : e } ;
213+ return { tag : "failure" , val : toJSAbiValue ( e ) } ;
210214 }
211215 } ;
212216 }
213- return {
217+ return proxyImports ( {
214218 evalJs : wrapTry ( ( code ) => {
215- return Function ( code ) ( ) ;
219+ return toJSAbiValue ( Function ( code ) ( ) ) ;
216220 } ) ,
217221 isJs : ( value ) => {
218222 // Just for compatibility with the old JS API
219223 return true ;
220224 } ,
221225 globalThis : ( ) => {
222226 if ( typeof globalThis !== "undefined" ) {
223- return globalThis ;
227+ return toJSAbiValue ( globalThis ) ;
224228 } else if ( typeof global !== "undefined" ) {
225- return global ;
229+ return toJSAbiValue ( global ) ;
226230 } else if ( typeof window !== "undefined" ) {
227- return window ;
231+ return toJSAbiValue ( window ) ;
228232 }
229233 throw new Error ( "unable to locate global object" ) ;
230234 } ,
231235 intToJsNumber : ( value ) => {
232- return value ;
236+ return toJSAbiValue ( value ) ;
233237 } ,
234238 floatToJsNumber : ( value ) => {
235- return value ;
239+ return toJSAbiValue ( value ) ;
236240 } ,
237241 stringToJsString : ( value ) => {
238- return value ;
242+ return toJSAbiValue ( value ) ;
239243 } ,
240244 boolToJsBool : ( value ) => {
241- return value ;
245+ return toJSAbiValue ( value ) ;
242246 } ,
243247 procToJsFunction : ( rawRbAbiValue ) => {
244248 const rbValue = this . rbValueOfPointer ( rawRbAbiValue ) ;
245- return ( ...args ) => {
249+ return toJSAbiValue ( ( ...args ) => {
246250 return rbValue . call ( "call" , ...args . map ( ( arg ) => this . wrap ( arg ) ) ) . toJS ( ) ;
247- } ;
251+ } ) ;
248252 } ,
249253 rbObjectToJsRbValue : ( rawRbAbiValue ) => {
250- return this . rbValueOfPointer ( rawRbAbiValue ) ;
254+ return toJSAbiValue ( this . rbValueOfPointer ( rawRbAbiValue ) ) ;
251255 } ,
252256 jsValueToString : ( value ) => {
257+ value = fromJSAbiValue ( value )
253258 // According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
254259 // `String(value)` always returns a string.
255260 return String ( value ) ;
256261 } ,
257262 jsValueToInteger ( value ) {
263+ value = fromJSAbiValue ( value )
258264 if ( typeof value === "number" ) {
259265 return { tag : "as-float" , val : value } ;
260266 } else if ( typeof value === "bigint" ) {
@@ -269,10 +275,10 @@ export class RubyVM {
269275 } ,
270276 exportJsValueToHost : ( value ) => {
271277 // See `JsValueExporter` for the reason why we need to do this
272- this . transport . takeJsValue ( value ) ;
278+ this . transport . takeJsValue ( fromJSAbiValue ( value ) ) ;
273279 } ,
274280 importJsValueFromHost : ( ) => {
275- return this . transport . consumeJsValue ( ) ;
281+ return toJSAbiValue ( this . transport . consumeJsValue ( ) ) ;
276282 } ,
277283 instanceOf : ( value , klass ) => {
278284 if ( typeof klass === "function" ) {
@@ -282,16 +288,17 @@ export class RubyVM {
282288 }
283289 } ,
284290 jsValueTypeof ( value ) {
285- return typeof value ;
291+ return typeof fromJSAbiValue ( value ) ;
286292 } ,
287293 jsValueEqual ( lhs , rhs ) {
288- return lhs == rhs ;
294+ return fromJSAbiValue ( lhs ) == fromJSAbiValue ( rhs ) ;
289295 } ,
290296 jsValueStrictlyEqual ( lhs , rhs ) {
291- return lhs === rhs ;
297+ return fromJSAbiValue ( lhs ) === fromJSAbiValue ( rhs ) ;
292298 } ,
293299 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 ) ) ;
295302 } ) ,
296303 reflectConstruct : function ( target , args ) {
297304 throw new Error ( "Function not implemented." ) ;
@@ -300,7 +307,7 @@ export class RubyVM {
300307 throw new Error ( "Function not implemented." ) ;
301308 } ,
302309 reflectGet : wrapTry ( ( target , propertyKey ) => {
303- return target [ propertyKey ] ;
310+ return toJSAbiValue ( fromJSAbiValue ( target ) [ propertyKey ] ) ;
304311 } ) ,
305312 reflectGetOwnPropertyDescriptor : function (
306313 target ,
@@ -324,12 +331,12 @@ export class RubyVM {
324331 throw new Error ( "Function not implemented." ) ;
325332 } ,
326333 reflectSet : wrapTry ( ( target , propertyKey , value ) => {
327- return Reflect . set ( target , propertyKey , value ) ;
334+ return toJSAbiValue ( Reflect . set ( fromJSAbiValue ( target ) , propertyKey , fromJSAbiValue ( value ) ) ) ;
328335 } ) ,
329336 reflectSetPrototypeOf : function ( target , prototype ) : boolean {
330337 throw new Error ( "Function not implemented." ) ;
331338 } ,
332- }
339+ } )
333340 }
334341
335342 /**
0 commit comments