@ruby/head-wasm-wasi 2.4.1 → 2.5.0

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.
@@ -1,1373 +1,1406 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["ruby-wasm-wasi"] = {}));
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["ruby-wasm-wasi"] = {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
- const CLOCKID_REALTIME=0;const CLOCKID_MONOTONIC=1;const ERRNO_SUCCESS=0;const ERRNO_BADF=8;const ERRNO_NOSYS=52;class Iovec{static read_bytes(view,ptr){const iovec=new Iovec;iovec.buf=view.getUint32(ptr,true);iovec.buf_len=view.getUint32(ptr+4,true);return iovec}static read_bytes_array(view,ptr,len){const iovecs=[];for(let i=0;i<len;i++){iovecs.push(Iovec.read_bytes(view,ptr+8*i));}return iovecs}}class Ciovec{static read_bytes(view,ptr){const iovec=new Ciovec;iovec.buf=view.getUint32(ptr,true);iovec.buf_len=view.getUint32(ptr+4,true);return iovec}static read_bytes_array(view,ptr,len){const iovecs=[];for(let i=0;i<len;i++){iovecs.push(Ciovec.read_bytes(view,ptr+8*i));}return iovecs}}
7
+ const CLOCKID_REALTIME=0;const CLOCKID_MONOTONIC=1;const ERRNO_SUCCESS=0;const ERRNO_BADF=8;const ERRNO_NOSYS=52;class Iovec{static read_bytes(view,ptr){const iovec=new Iovec;iovec.buf=view.getUint32(ptr,true);iovec.buf_len=view.getUint32(ptr+4,true);return iovec}static read_bytes_array(view,ptr,len){const iovecs=[];for(let i=0;i<len;i++){iovecs.push(Iovec.read_bytes(view,ptr+8*i));}return iovecs}}class Ciovec{static read_bytes(view,ptr){const iovec=new Ciovec;iovec.buf=view.getUint32(ptr,true);iovec.buf_len=view.getUint32(ptr+4,true);return iovec}static read_bytes_array(view,ptr,len){const iovecs=[];for(let i=0;i<len;i++){iovecs.push(Ciovec.read_bytes(view,ptr+8*i));}return iovecs}}
8
8
 
9
- let Debug=class Debug{enable(enabled){this.log=createLogger(enabled===undefined?true:enabled,this.prefix);}get enabled(){return this.isEnabled}constructor(isEnabled){this.isEnabled=isEnabled;this.prefix="wasi:";this.enable(isEnabled);}};function createLogger(enabled,prefix){if(enabled){const a=console.log.bind(console,"%c%s","color: #265BA0",prefix);return a}else {return ()=>{}}}const debug=new Debug(false);
9
+ let Debug=class Debug{enable(enabled){this.log=createLogger(enabled===undefined?true:enabled,this.prefix);}get enabled(){return this.isEnabled}constructor(isEnabled){this.isEnabled=isEnabled;this.prefix="wasi:";this.enable(isEnabled);}};function createLogger(enabled,prefix){if(enabled){const a=console.log.bind(console,"%c%s","color: #265BA0",prefix);return a}else {return ()=>{}}}const debug=new Debug(false);
10
10
 
11
- class WASIProcExit extends Error{constructor(code){super("exit with exit code "+code);this.code=code;}}let WASI=class WASI{start(instance){this.inst=instance;try{instance.exports._start();}catch(e){if(e instanceof WASIProcExit){return e.code}else {throw e}}}initialize(instance){this.inst=instance;instance.exports._initialize();}constructor(args,env,fds,options={}){this.args=[];this.env=[];this.fds=[];debug.enable(options.debug);this.args=args;this.env=env;this.fds=fds;const self=this;this.wasiImport={args_sizes_get(argc,argv_buf_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(argc,self.args.length,true);let buf_size=0;for(const arg of self.args){buf_size+=arg.length+1;}buffer.setUint32(argv_buf_size,buf_size,true);debug.log(buffer.getUint32(argc,true),buffer.getUint32(argv_buf_size,true));return 0},args_get(argv,argv_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_argv_buf=argv_buf;for(let i=0;i<self.args.length;i++){buffer.setUint32(argv,argv_buf,true);argv+=4;const arg=new TextEncoder().encode(self.args[i]);buffer8.set(arg,argv_buf);buffer.setUint8(argv_buf+arg.length,0);argv_buf+=arg.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_argv_buf,argv_buf)));}return 0},environ_sizes_get(environ_count,environ_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(environ_count,self.env.length,true);let buf_size=0;for(const environ of self.env){buf_size+=environ.length+1;}buffer.setUint32(environ_size,buf_size,true);debug.log(buffer.getUint32(environ_count,true),buffer.getUint32(environ_size,true));return 0},environ_get(environ,environ_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_environ_buf=environ_buf;for(let i=0;i<self.env.length;i++){buffer.setUint32(environ,environ_buf,true);environ+=4;const e=new TextEncoder().encode(self.env[i]);buffer8.set(e,environ_buf);buffer.setUint8(environ_buf+e.length,0);environ_buf+=e.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_environ_buf,environ_buf)));}return 0},clock_res_get(id,res_ptr){let resolutionValue;switch(id){case CLOCKID_MONOTONIC:{resolutionValue=5000n;break}case CLOCKID_REALTIME:{resolutionValue=1000000n;break}default:return ERRNO_NOSYS}const view=new DataView(self.inst.exports.memory.buffer);view.setBigUint64(res_ptr,resolutionValue,true);return ERRNO_SUCCESS},clock_time_get(id,precision,time){const buffer=new DataView(self.inst.exports.memory.buffer);if(id===CLOCKID_REALTIME){buffer.setBigUint64(time,BigInt(new Date().getTime())*1000000n,true);}else if(id==CLOCKID_MONOTONIC){let monotonic_time;try{monotonic_time=BigInt(Math.round(performance.now()*1e6));}catch(e){monotonic_time=0n;}buffer.setBigUint64(time,monotonic_time,true);}else {buffer.setBigUint64(time,0n,true);}return 0},fd_advise(fd,offset,len,advice){if(self.fds[fd]!=undefined){return self.fds[fd].fd_advise(offset,len,advice)}else {return ERRNO_BADF}},fd_allocate(fd,offset,len){if(self.fds[fd]!=undefined){return self.fds[fd].fd_allocate(offset,len)}else {return ERRNO_BADF}},fd_close(fd){if(self.fds[fd]!=undefined){const ret=self.fds[fd].fd_close();self.fds[fd]=undefined;return ret}else {return ERRNO_BADF}},fd_datasync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_datasync()}else {return ERRNO_BADF}},fd_fdstat_get(fd,fdstat_ptr){if(self.fds[fd]!=undefined){const{ret,fdstat}=self.fds[fd].fd_fdstat_get();if(fdstat!=null){fdstat.write_bytes(new DataView(self.inst.exports.memory.buffer),fdstat_ptr);}return ret}else {return ERRNO_BADF}},fd_fdstat_set_flags(fd,flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_flags(flags)}else {return ERRNO_BADF}},fd_fdstat_set_rights(fd,fs_rights_base,fs_rights_inheriting){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_rights(fs_rights_base,fs_rights_inheriting)}else {return ERRNO_BADF}},fd_filestat_get(fd,filestat_ptr){if(self.fds[fd]!=undefined){const{ret,filestat}=self.fds[fd].fd_filestat_get();if(filestat!=null){filestat.write_bytes(new DataView(self.inst.exports.memory.buffer),filestat_ptr);}return ret}else {return ERRNO_BADF}},fd_filestat_set_size(fd,size){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_size(size)}else {return ERRNO_BADF}},fd_filestat_set_times(fd,atim,mtim,fst_flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_times(atim,mtim,fst_flags)}else {return ERRNO_BADF}},fd_pread(fd,iovs_ptr,iovs_len,offset,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_pread(buffer8,iovecs,offset);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_prestat_get(fd,buf_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,prestat}=self.fds[fd].fd_prestat_get();if(prestat!=null){prestat.write_bytes(buffer,buf_ptr);}return ret}else {return ERRNO_BADF}},fd_prestat_dir_name(fd,path_ptr,path_len){if(self.fds[fd]!=undefined){const{ret,prestat_dir_name}=self.fds[fd].fd_prestat_dir_name();if(prestat_dir_name!=null){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);buffer8.set(prestat_dir_name,path_ptr);}return ret}else {return ERRNO_BADF}},fd_pwrite(fd,iovs_ptr,iovs_len,offset,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_pwrite(buffer8,iovecs,offset);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},fd_read(fd,iovs_ptr,iovs_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_read(buffer8,iovecs);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_readdir(fd,buf,buf_len,cookie,bufused_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){let bufused=0;while(true){const{ret,dirent}=self.fds[fd].fd_readdir_single(cookie);if(ret!=0){buffer.setUint32(bufused_ptr,bufused,true);return ret}if(dirent==null){break}if(buf_len-bufused<dirent.head_length()){bufused=buf_len;break}const head_bytes=new ArrayBuffer(dirent.head_length());dirent.write_head_bytes(new DataView(head_bytes),0);buffer8.set(new Uint8Array(head_bytes).slice(0,Math.min(head_bytes.byteLength,buf_len-bufused)),buf);buf+=dirent.head_length();bufused+=dirent.head_length();if(buf_len-bufused<dirent.name_length()){bufused=buf_len;break}dirent.write_name_bytes(buffer8,buf,buf_len-bufused);buf+=dirent.name_length();bufused+=dirent.name_length();cookie=dirent.d_next;}buffer.setUint32(bufused_ptr,bufused,true);return 0}else {return ERRNO_BADF}},fd_renumber(fd,to){if(self.fds[fd]!=undefined&&self.fds[to]!=undefined){const ret=self.fds[to].fd_close();if(ret!=0){return ret}self.fds[to]=self.fds[fd];self.fds[fd]=undefined;return 0}else {return ERRNO_BADF}},fd_seek(fd,offset,whence,offset_out_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset:offset_out}=self.fds[fd].fd_seek(offset,whence);buffer.setBigInt64(offset_out_ptr,offset_out,true);return ret}else {return ERRNO_BADF}},fd_sync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_sync()}else {return ERRNO_BADF}},fd_tell(fd,offset_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset}=self.fds[fd].fd_tell();buffer.setBigUint64(offset_ptr,offset,true);return ret}else {return ERRNO_BADF}},fd_write(fd,iovs_ptr,iovs_len,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_write(buffer8,iovecs);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},path_create_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_create_directory(path)}},path_filestat_get(fd,flags,path_ptr,path_len,filestat_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));const{ret,filestat}=self.fds[fd].path_filestat_get(flags,path);if(filestat!=null){filestat.write_bytes(buffer,filestat_ptr);}return ret}else {return ERRNO_BADF}},path_filestat_set_times(fd,flags,path_ptr,path_len,atim,mtim,fst_flags){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_filestat_set_times(flags,path,atim,mtim,fst_flags)}else {return ERRNO_BADF}},path_link(old_fd,old_flags,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[old_fd]!=undefined&&self.fds[new_fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[new_fd].path_link(old_fd,old_flags,old_path,new_path)}else {return ERRNO_BADF}},path_open(fd,dirflags,path_ptr,path_len,oflags,fs_rights_base,fs_rights_inheriting,fd_flags,opened_fd_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,fd_obj}=self.fds[fd].path_open(dirflags,path,oflags,fs_rights_base,fs_rights_inheriting,fd_flags);if(ret!=0){return ret}self.fds.push(fd_obj);const opened_fd=self.fds.length-1;buffer.setUint32(opened_fd_ptr,opened_fd,true);return 0}else {return ERRNO_BADF}},path_readlink(fd,path_ptr,path_len,buf_ptr,buf_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,data}=self.fds[fd].path_readlink(path);if(data!=null){if(data.length>buf_len){buffer.setUint32(nread_ptr,0,true);return ERRNO_BADF}buffer8.set(data,buf_ptr);buffer.setUint32(nread_ptr,data.length,true);}return ret}else {return ERRNO_BADF}},path_remove_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_remove_directory(path)}else {return ERRNO_BADF}},path_rename(fd,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){throw "FIXME what is the best abstraction for this?"},path_symlink(old_path_ptr,old_path_len,fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[fd].path_symlink(old_path,new_path)}else {return ERRNO_BADF}},path_unlink_file(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_unlink_file(path)}else {return ERRNO_BADF}},poll_oneoff(in_,out,nsubscriptions){throw "async io not supported"},proc_exit(exit_code){throw new WASIProcExit(exit_code)},proc_raise(sig){throw "raised signal "+sig},sched_yield(){},random_get(buf,buf_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);for(let i=0;i<buf_len;i++){buffer8[buf+i]=Math.random()*256|0;}},sock_recv(fd,ri_data,ri_flags){throw "sockets not supported"},sock_send(fd,si_data,si_flags){throw "sockets not supported"},sock_shutdown(fd,how){throw "sockets not supported"},sock_accept(fd,flags){throw "sockets not supported"}};}};
11
+ class WASIProcExit extends Error{constructor(code){super("exit with exit code "+code);this.code=code;}}let WASI=class WASI{start(instance){this.inst=instance;try{instance.exports._start();}catch(e){if(e instanceof WASIProcExit){return e.code}else {throw e}}}initialize(instance){this.inst=instance;instance.exports._initialize();}constructor(args,env,fds,options={}){this.args=[];this.env=[];this.fds=[];debug.enable(options.debug);this.args=args;this.env=env;this.fds=fds;const self=this;this.wasiImport={args_sizes_get(argc,argv_buf_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(argc,self.args.length,true);let buf_size=0;for(const arg of self.args){buf_size+=arg.length+1;}buffer.setUint32(argv_buf_size,buf_size,true);debug.log(buffer.getUint32(argc,true),buffer.getUint32(argv_buf_size,true));return 0},args_get(argv,argv_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_argv_buf=argv_buf;for(let i=0;i<self.args.length;i++){buffer.setUint32(argv,argv_buf,true);argv+=4;const arg=new TextEncoder().encode(self.args[i]);buffer8.set(arg,argv_buf);buffer.setUint8(argv_buf+arg.length,0);argv_buf+=arg.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_argv_buf,argv_buf)));}return 0},environ_sizes_get(environ_count,environ_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(environ_count,self.env.length,true);let buf_size=0;for(const environ of self.env){buf_size+=environ.length+1;}buffer.setUint32(environ_size,buf_size,true);debug.log(buffer.getUint32(environ_count,true),buffer.getUint32(environ_size,true));return 0},environ_get(environ,environ_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_environ_buf=environ_buf;for(let i=0;i<self.env.length;i++){buffer.setUint32(environ,environ_buf,true);environ+=4;const e=new TextEncoder().encode(self.env[i]);buffer8.set(e,environ_buf);buffer.setUint8(environ_buf+e.length,0);environ_buf+=e.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_environ_buf,environ_buf)));}return 0},clock_res_get(id,res_ptr){let resolutionValue;switch(id){case CLOCKID_MONOTONIC:{resolutionValue=5000n;break}case CLOCKID_REALTIME:{resolutionValue=1000000n;break}default:return ERRNO_NOSYS}const view=new DataView(self.inst.exports.memory.buffer);view.setBigUint64(res_ptr,resolutionValue,true);return ERRNO_SUCCESS},clock_time_get(id,precision,time){const buffer=new DataView(self.inst.exports.memory.buffer);if(id===CLOCKID_REALTIME){buffer.setBigUint64(time,BigInt(new Date().getTime())*1000000n,true);}else if(id==CLOCKID_MONOTONIC){let monotonic_time;try{monotonic_time=BigInt(Math.round(performance.now()*1e6));}catch(e){monotonic_time=0n;}buffer.setBigUint64(time,monotonic_time,true);}else {buffer.setBigUint64(time,0n,true);}return 0},fd_advise(fd,offset,len,advice){if(self.fds[fd]!=undefined){return self.fds[fd].fd_advise(offset,len,advice)}else {return ERRNO_BADF}},fd_allocate(fd,offset,len){if(self.fds[fd]!=undefined){return self.fds[fd].fd_allocate(offset,len)}else {return ERRNO_BADF}},fd_close(fd){if(self.fds[fd]!=undefined){const ret=self.fds[fd].fd_close();self.fds[fd]=undefined;return ret}else {return ERRNO_BADF}},fd_datasync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_datasync()}else {return ERRNO_BADF}},fd_fdstat_get(fd,fdstat_ptr){if(self.fds[fd]!=undefined){const{ret,fdstat}=self.fds[fd].fd_fdstat_get();if(fdstat!=null){fdstat.write_bytes(new DataView(self.inst.exports.memory.buffer),fdstat_ptr);}return ret}else {return ERRNO_BADF}},fd_fdstat_set_flags(fd,flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_flags(flags)}else {return ERRNO_BADF}},fd_fdstat_set_rights(fd,fs_rights_base,fs_rights_inheriting){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_rights(fs_rights_base,fs_rights_inheriting)}else {return ERRNO_BADF}},fd_filestat_get(fd,filestat_ptr){if(self.fds[fd]!=undefined){const{ret,filestat}=self.fds[fd].fd_filestat_get();if(filestat!=null){filestat.write_bytes(new DataView(self.inst.exports.memory.buffer),filestat_ptr);}return ret}else {return ERRNO_BADF}},fd_filestat_set_size(fd,size){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_size(size)}else {return ERRNO_BADF}},fd_filestat_set_times(fd,atim,mtim,fst_flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_times(atim,mtim,fst_flags)}else {return ERRNO_BADF}},fd_pread(fd,iovs_ptr,iovs_len,offset,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_pread(buffer8,iovecs,offset);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_prestat_get(fd,buf_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,prestat}=self.fds[fd].fd_prestat_get();if(prestat!=null){prestat.write_bytes(buffer,buf_ptr);}return ret}else {return ERRNO_BADF}},fd_prestat_dir_name(fd,path_ptr,path_len){if(self.fds[fd]!=undefined){const{ret,prestat_dir_name}=self.fds[fd].fd_prestat_dir_name();if(prestat_dir_name!=null){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);buffer8.set(prestat_dir_name,path_ptr);}return ret}else {return ERRNO_BADF}},fd_pwrite(fd,iovs_ptr,iovs_len,offset,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_pwrite(buffer8,iovecs,offset);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},fd_read(fd,iovs_ptr,iovs_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_read(buffer8,iovecs);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_readdir(fd,buf,buf_len,cookie,bufused_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){let bufused=0;while(true){const{ret,dirent}=self.fds[fd].fd_readdir_single(cookie);if(ret!=0){buffer.setUint32(bufused_ptr,bufused,true);return ret}if(dirent==null){break}if(buf_len-bufused<dirent.head_length()){bufused=buf_len;break}const head_bytes=new ArrayBuffer(dirent.head_length());dirent.write_head_bytes(new DataView(head_bytes),0);buffer8.set(new Uint8Array(head_bytes).slice(0,Math.min(head_bytes.byteLength,buf_len-bufused)),buf);buf+=dirent.head_length();bufused+=dirent.head_length();if(buf_len-bufused<dirent.name_length()){bufused=buf_len;break}dirent.write_name_bytes(buffer8,buf,buf_len-bufused);buf+=dirent.name_length();bufused+=dirent.name_length();cookie=dirent.d_next;}buffer.setUint32(bufused_ptr,bufused,true);return 0}else {return ERRNO_BADF}},fd_renumber(fd,to){if(self.fds[fd]!=undefined&&self.fds[to]!=undefined){const ret=self.fds[to].fd_close();if(ret!=0){return ret}self.fds[to]=self.fds[fd];self.fds[fd]=undefined;return 0}else {return ERRNO_BADF}},fd_seek(fd,offset,whence,offset_out_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset:offset_out}=self.fds[fd].fd_seek(offset,whence);buffer.setBigInt64(offset_out_ptr,offset_out,true);return ret}else {return ERRNO_BADF}},fd_sync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_sync()}else {return ERRNO_BADF}},fd_tell(fd,offset_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset}=self.fds[fd].fd_tell();buffer.setBigUint64(offset_ptr,offset,true);return ret}else {return ERRNO_BADF}},fd_write(fd,iovs_ptr,iovs_len,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_write(buffer8,iovecs);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},path_create_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_create_directory(path)}},path_filestat_get(fd,flags,path_ptr,path_len,filestat_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));const{ret,filestat}=self.fds[fd].path_filestat_get(flags,path);if(filestat!=null){filestat.write_bytes(buffer,filestat_ptr);}return ret}else {return ERRNO_BADF}},path_filestat_set_times(fd,flags,path_ptr,path_len,atim,mtim,fst_flags){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_filestat_set_times(flags,path,atim,mtim,fst_flags)}else {return ERRNO_BADF}},path_link(old_fd,old_flags,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[old_fd]!=undefined&&self.fds[new_fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[new_fd].path_link(old_fd,old_flags,old_path,new_path)}else {return ERRNO_BADF}},path_open(fd,dirflags,path_ptr,path_len,oflags,fs_rights_base,fs_rights_inheriting,fd_flags,opened_fd_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,fd_obj}=self.fds[fd].path_open(dirflags,path,oflags,fs_rights_base,fs_rights_inheriting,fd_flags);if(ret!=0){return ret}self.fds.push(fd_obj);const opened_fd=self.fds.length-1;buffer.setUint32(opened_fd_ptr,opened_fd,true);return 0}else {return ERRNO_BADF}},path_readlink(fd,path_ptr,path_len,buf_ptr,buf_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,data}=self.fds[fd].path_readlink(path);if(data!=null){if(data.length>buf_len){buffer.setUint32(nread_ptr,0,true);return ERRNO_BADF}buffer8.set(data,buf_ptr);buffer.setUint32(nread_ptr,data.length,true);}return ret}else {return ERRNO_BADF}},path_remove_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_remove_directory(path)}else {return ERRNO_BADF}},path_rename(fd,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){throw "FIXME what is the best abstraction for this?"},path_symlink(old_path_ptr,old_path_len,fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[fd].path_symlink(old_path,new_path)}else {return ERRNO_BADF}},path_unlink_file(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_unlink_file(path)}else {return ERRNO_BADF}},poll_oneoff(in_,out,nsubscriptions){throw "async io not supported"},proc_exit(exit_code){throw new WASIProcExit(exit_code)},proc_raise(sig){throw "raised signal "+sig},sched_yield(){},random_get(buf,buf_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);for(let i=0;i<buf_len;i++){buffer8[buf+i]=Math.random()*256|0;}},sock_recv(fd,ri_data,ri_flags){throw "sockets not supported"},sock_send(fd,si_data,si_flags){throw "sockets not supported"},sock_shutdown(fd,how){throw "sockets not supported"},sock_accept(fd,flags){throw "sockets not supported"}};}};
12
12
 
13
- let DATA_VIEW = new DataView(new ArrayBuffer());
14
-
15
- function data_view(mem) {
16
- if (DATA_VIEW.buffer !== mem.buffer) DATA_VIEW = new DataView(mem.buffer);
17
- return DATA_VIEW;
18
- }
19
-
20
- function to_uint32(val) {
21
- return val >>> 0;
22
- }
23
- const UTF8_DECODER = new TextDecoder('utf-8');
13
+ /**
14
+ * Create a console printer that can be used as an overlay of WASI imports.
15
+ * See the example below for how to use it.
16
+ *
17
+ * ```javascript
18
+ * const imports = {
19
+ * "wasi_snapshot_preview1": wasi.wasiImport,
20
+ * }
21
+ * const printer = consolePrinter();
22
+ * printer.addToImports(imports);
23
+ *
24
+ * const instance = await WebAssembly.instantiate(module, imports);
25
+ * printer.setMemory(instance.exports.memory);
26
+ * ```
27
+ *
28
+ * Note that the `stdout` and `stderr` functions are called with text, not
29
+ * bytes. This means that bytes written to stdout/stderr will be decoded as
30
+ * UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
31
+ * occurs without buffering.
32
+ *
33
+ * @param stdout A function that will be called when stdout is written to.
34
+ * Defaults to `console.log`.
35
+ * @param stderr A function that will be called when stderr is written to.
36
+ * Defaults to `console.warn`.
37
+ * @returns An object that can be used as an overlay of WASI imports.
38
+ */
39
+ function consolePrinter({ stdout, stderr, } = {
40
+ stdout: console.log,
41
+ stderr: console.warn,
42
+ }) {
43
+ let memory = undefined;
44
+ let _view = undefined;
45
+ function getMemoryView() {
46
+ if (typeof memory === "undefined") {
47
+ throw new Error("Memory is not set");
48
+ }
49
+ if (_view === undefined || _view.buffer.byteLength === 0) {
50
+ _view = new DataView(memory.buffer);
51
+ }
52
+ return _view;
53
+ }
54
+ const decoder = new TextDecoder();
55
+ return {
56
+ addToImports(imports) {
57
+ const wasiImport = imports.wasi_snapshot_preview1;
58
+ const original_fd_write = wasiImport.fd_write;
59
+ wasiImport.fd_write = (fd, iovs, iovsLen, nwritten) => {
60
+ if (fd !== 1 && fd !== 2) {
61
+ return original_fd_write(fd, iovs, iovsLen, nwritten);
62
+ }
63
+ const view = getMemoryView();
64
+ const buffers = Array.from({ length: iovsLen }, (_, i) => {
65
+ const ptr = iovs + i * 8;
66
+ const buf = view.getUint32(ptr, true);
67
+ const bufLen = view.getUint32(ptr + 4, true);
68
+ return new Uint8Array(memory.buffer, buf, bufLen);
69
+ });
70
+ let written = 0;
71
+ let str = "";
72
+ for (const buffer of buffers) {
73
+ str += decoder.decode(buffer);
74
+ written += buffer.byteLength;
75
+ }
76
+ view.setUint32(nwritten, written, true);
77
+ const log = fd === 1 ? stdout : stderr;
78
+ log(str);
79
+ return 0;
80
+ };
81
+ const original_fd_filestat_get = wasiImport.fd_filestat_get;
82
+ wasiImport.fd_filestat_get = (fd, filestat) => {
83
+ if (fd !== 1 && fd !== 2) {
84
+ return original_fd_filestat_get(fd, filestat);
85
+ }
86
+ const view = getMemoryView();
87
+ const result = original_fd_filestat_get(fd, filestat);
88
+ if (result !== 0) {
89
+ return result;
90
+ }
91
+ const filetypePtr = filestat + 0;
92
+ view.setUint8(filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
93
+ return 0;
94
+ };
95
+ const original_fd_fdstat_get = wasiImport.fd_fdstat_get;
96
+ wasiImport.fd_fdstat_get = (fd, fdstat) => {
97
+ if (fd !== 1 && fd !== 2) {
98
+ return original_fd_fdstat_get(fd, fdstat);
99
+ }
100
+ const view = getMemoryView();
101
+ const fs_filetypePtr = fdstat + 0;
102
+ view.setUint8(fs_filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
103
+ const fs_rights_basePtr = fdstat + 8;
104
+ view.setBigUint64(fs_rights_basePtr, BigInt(1)); // RIGHTS_FD_WRITE
105
+ return 0;
106
+ };
107
+ },
108
+ setMemory(m) {
109
+ memory = m;
110
+ },
111
+ };
112
+ }
24
113
 
25
- const UTF8_ENCODER = new TextEncoder('utf-8');
114
+ let DATA_VIEW = new DataView(new ArrayBuffer());
26
115
 
27
- function utf8_encode(s, realloc, memory) {
28
- if (typeof s !== 'string') throw new TypeError('expected a string');
29
-
30
- if (s.length === 0) {
31
- UTF8_ENCODED_LEN = 0;
32
- return 1;
116
+ function data_view(mem) {
117
+ if (DATA_VIEW.buffer !== mem.buffer) DATA_VIEW = new DataView(mem.buffer);
118
+ return DATA_VIEW;
33
119
  }
34
-
35
- let alloc_len = 0;
36
- let ptr = 0;
37
- let writtenTotal = 0;
38
- while (s.length > 0) {
39
- ptr = realloc(ptr, alloc_len, 1, alloc_len + s.length);
40
- alloc_len += s.length;
41
- const { read, written } = UTF8_ENCODER.encodeInto(
42
- s,
43
- new Uint8Array(memory.buffer, ptr + writtenTotal, alloc_len - writtenTotal),
44
- );
45
- writtenTotal += written;
46
- s = s.slice(read);
47
- }
48
- if (alloc_len > writtenTotal)
49
- ptr = realloc(ptr, alloc_len, 1, writtenTotal);
50
- UTF8_ENCODED_LEN = writtenTotal;
51
- return ptr;
52
- }
53
- let UTF8_ENCODED_LEN = 0;
54
120
 
55
- class Slab {
56
- constructor() {
57
- this.list = [];
58
- this.head = 0;
59
- }
60
-
61
- insert(val) {
62
- if (this.head >= this.list.length) {
63
- this.list.push({
64
- next: this.list.length + 1,
65
- val: undefined,
66
- });
67
- }
68
- const ret = this.head;
69
- const slot = this.list[ret];
70
- this.head = slot.next;
71
- slot.next = -1;
72
- slot.val = val;
73
- return ret;
121
+ function to_uint32(val) {
122
+ return val >>> 0;
74
123
  }
75
-
76
- get(idx) {
77
- if (idx >= this.list.length)
78
- throw new RangeError('handle index not valid');
79
- const slot = this.list[idx];
80
- if (slot.next === -1)
81
- return slot.val;
82
- throw new RangeError('handle index not valid');
83
- }
84
-
85
- remove(idx) {
86
- const ret = this.get(idx); // validate the slot
87
- const slot = this.list[idx];
88
- slot.val = undefined;
89
- slot.next = this.head;
90
- this.head = idx;
91
- return ret;
92
- }
93
- }
124
+ const UTF8_DECODER = new TextDecoder('utf-8');
94
125
 
95
- function throw_invalid_bool() {
96
- throw new RangeError("invalid variant discriminant for bool");
97
- }
126
+ const UTF8_ENCODER = new TextEncoder('utf-8');
98
127
 
99
- class RbAbiGuest {
100
- constructor() {
101
- this._resource0_slab = new Slab();
102
- this._resource1_slab = new Slab();
103
- }
104
- addToImports(imports) {
105
- if (!("canonical_abi" in imports)) imports["canonical_abi"] = {};
128
+ function utf8_encode(s, realloc, memory) {
129
+ if (typeof s !== 'string') throw new TypeError('expected a string');
106
130
 
107
- imports.canonical_abi['resource_drop_rb-iseq'] = i => {
108
- this._resource0_slab.remove(i).drop();
109
- };
110
- imports.canonical_abi['resource_clone_rb-iseq'] = i => {
111
- const obj = this._resource0_slab.get(i);
112
- return this._resource0_slab.insert(obj.clone())
113
- };
114
- imports.canonical_abi['resource_get_rb-iseq'] = i => {
115
- return this._resource0_slab.get(i)._wasm_val;
116
- };
117
- imports.canonical_abi['resource_new_rb-iseq'] = i => {
118
- this._registry0;
119
- return this._resource0_slab.insert(new RbIseq(i, this));
120
- };
121
-
122
- imports.canonical_abi['resource_drop_rb-abi-value'] = i => {
123
- this._resource1_slab.remove(i).drop();
124
- };
125
- imports.canonical_abi['resource_clone_rb-abi-value'] = i => {
126
- const obj = this._resource1_slab.get(i);
127
- return this._resource1_slab.insert(obj.clone())
128
- };
129
- imports.canonical_abi['resource_get_rb-abi-value'] = i => {
130
- return this._resource1_slab.get(i)._wasm_val;
131
- };
132
- imports.canonical_abi['resource_new_rb-abi-value'] = i => {
133
- this._registry1;
134
- return this._resource1_slab.insert(new RbAbiValue(i, this));
135
- };
136
- }
137
-
138
- async instantiate(module, imports) {
139
- imports = imports || {};
140
- this.addToImports(imports);
131
+ if (s.length === 0) {
132
+ UTF8_ENCODED_LEN = 0;
133
+ return 1;
134
+ }
141
135
 
142
- if (module instanceof WebAssembly.Instance) {
143
- this.instance = module;
144
- } else if (module instanceof WebAssembly.Module) {
145
- this.instance = await WebAssembly.instantiate(module, imports);
146
- } else if (module instanceof ArrayBuffer || module instanceof Uint8Array) {
147
- const { instance } = await WebAssembly.instantiate(module, imports);
148
- this.instance = instance;
149
- } else {
150
- const { instance } = await WebAssembly.instantiateStreaming(module, imports);
151
- this.instance = instance;
136
+ let alloc_len = 0;
137
+ let ptr = 0;
138
+ let writtenTotal = 0;
139
+ while (s.length > 0) {
140
+ ptr = realloc(ptr, alloc_len, 1, alloc_len + s.length);
141
+ alloc_len += s.length;
142
+ const { read, written } = UTF8_ENCODER.encodeInto(
143
+ s,
144
+ new Uint8Array(memory.buffer, ptr + writtenTotal, alloc_len - writtenTotal),
145
+ );
146
+ writtenTotal += written;
147
+ s = s.slice(read);
152
148
  }
153
- this._exports = this.instance.exports;
154
- this._registry0 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-iseq']);
155
- this._registry1 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-abi-value']);
156
- }
157
- rubyShowVersion() {
158
- this._exports['ruby-show-version: func() -> ()']();
149
+ if (alloc_len > writtenTotal)
150
+ ptr = realloc(ptr, alloc_len, 1, writtenTotal);
151
+ UTF8_ENCODED_LEN = writtenTotal;
152
+ return ptr;
159
153
  }
160
- rubyInit() {
161
- this._exports['ruby-init: func() -> ()']();
162
- }
163
- rubySysinit(arg0) {
164
- const memory = this._exports.memory;
165
- const realloc = this._exports["cabi_realloc"];
166
- const vec1 = arg0;
167
- const len1 = vec1.length;
168
- const result1 = realloc(0, 0, 4, len1 * 8);
169
- for (let i = 0; i < vec1.length; i++) {
170
- const e = vec1[i];
171
- const base = result1 + i * 8;
172
- const ptr0 = utf8_encode(e, realloc, memory);
173
- const len0 = UTF8_ENCODED_LEN;
174
- data_view(memory).setInt32(base + 4, len0, true);
175
- data_view(memory).setInt32(base + 0, ptr0, true);
154
+ let UTF8_ENCODED_LEN = 0;
155
+
156
+ class Slab {
157
+ constructor() {
158
+ this.list = [];
159
+ this.head = 0;
176
160
  }
177
- this._exports['ruby-sysinit: func(args: list<string>) -> ()'](result1, len1);
178
- }
179
- rubyOptions(arg0) {
180
- const memory = this._exports.memory;
181
- const realloc = this._exports["cabi_realloc"];
182
- const vec1 = arg0;
183
- const len1 = vec1.length;
184
- const result1 = realloc(0, 0, 4, len1 * 8);
185
- for (let i = 0; i < vec1.length; i++) {
186
- const e = vec1[i];
187
- const base = result1 + i * 8;
188
- const ptr0 = utf8_encode(e, realloc, memory);
189
- const len0 = UTF8_ENCODED_LEN;
190
- data_view(memory).setInt32(base + 4, len0, true);
191
- data_view(memory).setInt32(base + 0, ptr0, true);
161
+
162
+ insert(val) {
163
+ if (this.head >= this.list.length) {
164
+ this.list.push({
165
+ next: this.list.length + 1,
166
+ val: undefined,
167
+ });
168
+ }
169
+ const ret = this.head;
170
+ const slot = this.list[ret];
171
+ this.head = slot.next;
172
+ slot.next = -1;
173
+ slot.val = val;
174
+ return ret;
192
175
  }
193
- const ret = this._exports['ruby-options: func(args: list<string>) -> handle<rb-iseq>'](result1, len1);
194
- return this._resource0_slab.remove(ret);
195
- }
196
- rubyScript(arg0) {
197
- const memory = this._exports.memory;
198
- const realloc = this._exports["cabi_realloc"];
199
- const ptr0 = utf8_encode(arg0, realloc, memory);
200
- const len0 = UTF8_ENCODED_LEN;
201
- this._exports['ruby-script: func(name: string) -> ()'](ptr0, len0);
202
- }
203
- rubyInitLoadpath() {
204
- this._exports['ruby-init-loadpath: func() -> ()']();
205
- }
206
- rbEvalStringProtect(arg0) {
207
- const memory = this._exports.memory;
208
- const realloc = this._exports["cabi_realloc"];
209
- const ptr0 = utf8_encode(arg0, realloc, memory);
210
- const len0 = UTF8_ENCODED_LEN;
211
- const ret = this._exports['rb-eval-string-protect: func(str: string) -> tuple<handle<rb-abi-value>, s32>'](ptr0, len0);
212
- return [this._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
213
- }
214
- rbFuncallvProtect(arg0, arg1, arg2) {
215
- const memory = this._exports.memory;
216
- const realloc = this._exports["cabi_realloc"];
217
- const obj0 = arg0;
218
- if (!(obj0 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
219
- const vec2 = arg2;
220
- const len2 = vec2.length;
221
- const result2 = realloc(0, 0, 4, len2 * 4);
222
- for (let i = 0; i < vec2.length; i++) {
223
- const e = vec2[i];
224
- const base = result2 + i * 4;
225
- const obj1 = e;
226
- if (!(obj1 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
227
- data_view(memory).setInt32(base + 0, this._resource1_slab.insert(obj1.clone()), true);
176
+
177
+ get(idx) {
178
+ if (idx >= this.list.length)
179
+ throw new RangeError('handle index not valid');
180
+ const slot = this.list[idx];
181
+ if (slot.next === -1)
182
+ return slot.val;
183
+ throw new RangeError('handle index not valid');
184
+ }
185
+
186
+ remove(idx) {
187
+ const ret = this.get(idx); // validate the slot
188
+ const slot = this.list[idx];
189
+ slot.val = undefined;
190
+ slot.next = this.head;
191
+ this.head = idx;
192
+ return ret;
228
193
  }
229
- const ret = this._exports['rb-funcallv-protect: func(recv: handle<rb-abi-value>, mid: u32, args: list<handle<rb-abi-value>>) -> tuple<handle<rb-abi-value>, s32>'](this._resource1_slab.insert(obj0.clone()), to_uint32(arg1), result2, len2);
230
- return [this._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
231
- }
232
- rbIntern(arg0) {
233
- const memory = this._exports.memory;
234
- const realloc = this._exports["cabi_realloc"];
235
- const ptr0 = utf8_encode(arg0, realloc, memory);
236
- const len0 = UTF8_ENCODED_LEN;
237
- const ret = this._exports['rb-intern: func(name: string) -> u32'](ptr0, len0);
238
- return ret >>> 0;
239
- }
240
- rbErrinfo() {
241
- const ret = this._exports['rb-errinfo: func() -> handle<rb-abi-value>']();
242
- return this._resource1_slab.remove(ret);
243
- }
244
- rbClearErrinfo() {
245
- this._exports['rb-clear-errinfo: func() -> ()']();
246
- }
247
- rstringPtr(arg0) {
248
- const memory = this._exports.memory;
249
- const obj0 = arg0;
250
- if (!(obj0 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
251
- const ret = this._exports['rstring-ptr: func(value: handle<rb-abi-value>) -> string'](this._resource1_slab.insert(obj0.clone()));
252
- const ptr1 = data_view(memory).getInt32(ret + 0, true);
253
- const len1 = data_view(memory).getInt32(ret + 4, true);
254
- const result1 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr1, len1));
255
- this._exports["cabi_post_rstring-ptr"](ret);
256
- return result1;
257
- }
258
- rbVmBugreport() {
259
- this._exports['rb-vm-bugreport: func() -> ()']();
260
- }
261
- rbGcEnable() {
262
- const ret = this._exports['rb-gc-enable: func() -> bool']();
263
- const bool0 = ret;
264
- return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
265
- }
266
- rbGcDisable() {
267
- const ret = this._exports['rb-gc-disable: func() -> bool']();
268
- const bool0 = ret;
269
- return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
270
- }
271
- rbSetShouldProhibitRewind(arg0) {
272
- const ret = this._exports['rb-set-should-prohibit-rewind: func(new-value: bool) -> bool'](arg0 ? 1 : 0);
273
- const bool0 = ret;
274
- return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
275
- }
276
- }
277
-
278
- class RbIseq {
279
- constructor(wasm_val, obj) {
280
- this._wasm_val = wasm_val;
281
- this._obj = obj;
282
- this._refcnt = 1;
283
- obj._registry0.register(this, wasm_val, this);
284
- }
285
-
286
- clone() {
287
- this._refcnt += 1;
288
- return this;
289
- }
290
-
291
- drop() {
292
- this._refcnt -= 1;
293
- if (this._refcnt !== 0)
294
- return;
295
- this._obj._registry0.unregister(this);
296
- const dtor = this._obj._exports['canonical_abi_drop_rb-iseq'];
297
- const wasm_val = this._wasm_val;
298
- delete this._obj;
299
- delete this._refcnt;
300
- delete this._wasm_val;
301
- dtor(wasm_val);
302
194
  }
303
- }
304
195
 
305
- class RbAbiValue {
306
- constructor(wasm_val, obj) {
307
- this._wasm_val = wasm_val;
308
- this._obj = obj;
309
- this._refcnt = 1;
310
- obj._registry1.register(this, wasm_val, this);
311
- }
312
-
313
- clone() {
314
- this._refcnt += 1;
315
- return this;
196
+ function throw_invalid_bool() {
197
+ throw new RangeError("invalid variant discriminant for bool");
316
198
  }
317
-
318
- drop() {
319
- this._refcnt -= 1;
320
- if (this._refcnt !== 0)
321
- return;
322
- this._obj._registry1.unregister(this);
323
- const dtor = this._obj._exports['canonical_abi_drop_rb-abi-value'];
324
- const wasm_val = this._wasm_val;
325
- delete this._obj;
326
- delete this._refcnt;
327
- delete this._wasm_val;
328
- dtor(wasm_val);
329
- }
330
- }
331
199
 
332
- function addRbJsAbiHostToImports(imports, obj, get_export) {
333
- if (!("rb-js-abi-host" in imports)) imports["rb-js-abi-host"] = {};
334
- imports["rb-js-abi-host"]["eval-js: func(code: string) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2) {
335
- const memory = get_export("memory");
336
- const ptr0 = arg0;
337
- const len0 = arg1;
338
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
339
- const ret0 = obj.evalJs(result0);
340
- const variant1 = ret0;
341
- switch (variant1.tag) {
342
- case "success": {
343
- const e = variant1.val;
344
- data_view(memory).setInt8(arg2 + 0, 0, true);
345
- data_view(memory).setInt32(arg2 + 4, resources0.insert(e), true);
346
- break;
347
- }
348
- case "failure": {
349
- const e = variant1.val;
350
- data_view(memory).setInt8(arg2 + 0, 1, true);
351
- data_view(memory).setInt32(arg2 + 4, resources0.insert(e), true);
352
- break;
353
- }
354
- default:
355
- throw new RangeError("invalid variant specified for JsAbiResult");
356
- }
357
- };
358
- imports["rb-js-abi-host"]["is-js: func(value: handle<js-abi-value>) -> bool"] = function(arg0) {
359
- const ret0 = obj.isJs(resources0.get(arg0));
360
- return ret0 ? 1 : 0;
361
- };
362
- imports["rb-js-abi-host"]["instance-of: func(value: handle<js-abi-value>, klass: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
363
- const ret0 = obj.instanceOf(resources0.get(arg0), resources0.get(arg1));
364
- return ret0 ? 1 : 0;
365
- };
366
- imports["rb-js-abi-host"]["global-this: func() -> handle<js-abi-value>"] = function() {
367
- const ret0 = obj.globalThis();
368
- return resources0.insert(ret0);
369
- };
370
- imports["rb-js-abi-host"]["int-to-js-number: func(value: s32) -> handle<js-abi-value>"] = function(arg0) {
371
- const ret0 = obj.intToJsNumber(arg0);
372
- return resources0.insert(ret0);
373
- };
374
- imports["rb-js-abi-host"]["float-to-js-number: func(value: float64) -> handle<js-abi-value>"] = function(arg0) {
375
- const ret0 = obj.floatToJsNumber(arg0);
376
- return resources0.insert(ret0);
377
- };
378
- imports["rb-js-abi-host"]["string-to-js-string: func(value: string) -> handle<js-abi-value>"] = function(arg0, arg1) {
379
- const memory = get_export("memory");
380
- const ptr0 = arg0;
381
- const len0 = arg1;
382
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
383
- const ret0 = obj.stringToJsString(result0);
384
- return resources0.insert(ret0);
385
- };
386
- imports["rb-js-abi-host"]["bool-to-js-bool: func(value: bool) -> handle<js-abi-value>"] = function(arg0) {
387
- const bool0 = arg0;
388
- const ret0 = obj.boolToJsBool(bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool()));
389
- return resources0.insert(ret0);
390
- };
391
- imports["rb-js-abi-host"]["proc-to-js-function: func(value: u32) -> handle<js-abi-value>"] = function(arg0) {
392
- const ret0 = obj.procToJsFunction(arg0 >>> 0);
393
- return resources0.insert(ret0);
394
- };
395
- imports["rb-js-abi-host"]["rb-object-to-js-rb-value: func(raw-rb-abi-value: u32) -> handle<js-abi-value>"] = function(arg0) {
396
- const ret0 = obj.rbObjectToJsRbValue(arg0 >>> 0);
397
- return resources0.insert(ret0);
398
- };
399
- imports["rb-js-abi-host"]["js-value-to-string: func(value: handle<js-abi-value>) -> string"] = function(arg0, arg1) {
400
- const memory = get_export("memory");
401
- const realloc = get_export("cabi_realloc");
402
- const ret0 = obj.jsValueToString(resources0.get(arg0));
403
- const ptr0 = utf8_encode(ret0, realloc, memory);
404
- const len0 = UTF8_ENCODED_LEN;
405
- data_view(memory).setInt32(arg1 + 4, len0, true);
406
- data_view(memory).setInt32(arg1 + 0, ptr0, true);
407
- };
408
- imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { f64(float64), bignum(string) }"] = function(arg0, arg1) {
409
- const memory = get_export("memory");
410
- const realloc = get_export("cabi_realloc");
411
- const ret0 = obj.jsValueToInteger(resources0.get(arg0));
412
- const variant1 = ret0;
413
- switch (variant1.tag) {
414
- case "f64": {
415
- const e = variant1.val;
416
- data_view(memory).setInt8(arg1 + 0, 0, true);
417
- data_view(memory).setFloat64(arg1 + 8, +e, true);
418
- break;
419
- }
420
- case "bignum": {
421
- const e = variant1.val;
422
- data_view(memory).setInt8(arg1 + 0, 1, true);
423
- const ptr0 = utf8_encode(e, realloc, memory);
424
- const len0 = UTF8_ENCODED_LEN;
425
- data_view(memory).setInt32(arg1 + 12, len0, true);
426
- data_view(memory).setInt32(arg1 + 8, ptr0, true);
427
- break;
428
- }
429
- default:
430
- throw new RangeError("invalid variant specified for RawInteger");
200
+ class RbAbiGuest {
201
+ constructor() {
202
+ this._resource0_slab = new Slab();
203
+ this._resource1_slab = new Slab();
431
204
  }
432
- };
433
- imports["rb-js-abi-host"]["export-js-value-to-host: func(value: handle<js-abi-value>) -> ()"] = function(arg0) {
434
- obj.exportJsValueToHost(resources0.get(arg0));
435
- };
436
- imports["rb-js-abi-host"]["import-js-value-from-host: func() -> handle<js-abi-value>"] = function() {
437
- const ret0 = obj.importJsValueFromHost();
438
- return resources0.insert(ret0);
439
- };
440
- imports["rb-js-abi-host"]["js-value-typeof: func(value: handle<js-abi-value>) -> string"] = function(arg0, arg1) {
441
- const memory = get_export("memory");
442
- const realloc = get_export("cabi_realloc");
443
- const ret0 = obj.jsValueTypeof(resources0.get(arg0));
444
- const ptr0 = utf8_encode(ret0, realloc, memory);
445
- const len0 = UTF8_ENCODED_LEN;
446
- data_view(memory).setInt32(arg1 + 4, len0, true);
447
- data_view(memory).setInt32(arg1 + 0, ptr0, true);
448
- };
449
- imports["rb-js-abi-host"]["js-value-equal: func(lhs: handle<js-abi-value>, rhs: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
450
- const ret0 = obj.jsValueEqual(resources0.get(arg0), resources0.get(arg1));
451
- return ret0 ? 1 : 0;
452
- };
453
- imports["rb-js-abi-host"]["js-value-strictly-equal: func(lhs: handle<js-abi-value>, rhs: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
454
- const ret0 = obj.jsValueStrictlyEqual(resources0.get(arg0), resources0.get(arg1));
455
- return ret0 ? 1 : 0;
456
- };
457
- imports["rb-js-abi-host"]["reflect-apply: func(target: handle<js-abi-value>, this-argument: handle<js-abi-value>, arguments: list<handle<js-abi-value>>) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3, arg4) {
458
- const memory = get_export("memory");
459
- const len0 = arg3;
460
- const base0 = arg2;
461
- const result0 = [];
462
- for (let i = 0; i < len0; i++) {
463
- const base = base0 + i * 4;
464
- result0.push(resources0.get(data_view(memory).getInt32(base + 0, true)));
205
+ addToImports(imports) {
206
+ if (!("canonical_abi" in imports)) imports["canonical_abi"] = {};
207
+
208
+ imports.canonical_abi['resource_drop_rb-iseq'] = i => {
209
+ this._resource0_slab.remove(i).drop();
210
+ };
211
+ imports.canonical_abi['resource_clone_rb-iseq'] = i => {
212
+ const obj = this._resource0_slab.get(i);
213
+ return this._resource0_slab.insert(obj.clone())
214
+ };
215
+ imports.canonical_abi['resource_get_rb-iseq'] = i => {
216
+ return this._resource0_slab.get(i)._wasm_val;
217
+ };
218
+ imports.canonical_abi['resource_new_rb-iseq'] = i => {
219
+ this._registry0;
220
+ return this._resource0_slab.insert(new RbIseq(i, this));
221
+ };
222
+
223
+ imports.canonical_abi['resource_drop_rb-abi-value'] = i => {
224
+ this._resource1_slab.remove(i).drop();
225
+ };
226
+ imports.canonical_abi['resource_clone_rb-abi-value'] = i => {
227
+ const obj = this._resource1_slab.get(i);
228
+ return this._resource1_slab.insert(obj.clone())
229
+ };
230
+ imports.canonical_abi['resource_get_rb-abi-value'] = i => {
231
+ return this._resource1_slab.get(i)._wasm_val;
232
+ };
233
+ imports.canonical_abi['resource_new_rb-abi-value'] = i => {
234
+ this._registry1;
235
+ return this._resource1_slab.insert(new RbAbiValue(i, this));
236
+ };
465
237
  }
466
- const ret0 = obj.reflectApply(resources0.get(arg0), resources0.get(arg1), result0);
467
- const variant1 = ret0;
468
- switch (variant1.tag) {
469
- case "success": {
470
- const e = variant1.val;
471
- data_view(memory).setInt8(arg4 + 0, 0, true);
472
- data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
473
- break;
474
- }
475
- case "failure": {
476
- const e = variant1.val;
477
- data_view(memory).setInt8(arg4 + 0, 1, true);
478
- data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
479
- break;
238
+
239
+ async instantiate(module, imports) {
240
+ imports = imports || {};
241
+ this.addToImports(imports);
242
+
243
+ if (module instanceof WebAssembly.Instance) {
244
+ this.instance = module;
245
+ } else if (module instanceof WebAssembly.Module) {
246
+ this.instance = await WebAssembly.instantiate(module, imports);
247
+ } else if (module instanceof ArrayBuffer || module instanceof Uint8Array) {
248
+ const { instance } = await WebAssembly.instantiate(module, imports);
249
+ this.instance = instance;
250
+ } else {
251
+ const { instance } = await WebAssembly.instantiateStreaming(module, imports);
252
+ this.instance = instance;
480
253
  }
481
- default:
482
- throw new RangeError("invalid variant specified for JsAbiResult");
254
+ this._exports = this.instance.exports;
255
+ this._registry0 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-iseq']);
256
+ this._registry1 = new FinalizationRegistry(this._exports['canonical_abi_drop_rb-abi-value']);
483
257
  }
484
- };
485
- imports["rb-js-abi-host"]["reflect-construct: func(target: handle<js-abi-value>, arguments: list<handle<js-abi-value>>) -> handle<js-abi-value>"] = function(arg0, arg1, arg2) {
486
- const memory = get_export("memory");
487
- const len0 = arg2;
488
- const base0 = arg1;
489
- const result0 = [];
490
- for (let i = 0; i < len0; i++) {
491
- const base = base0 + i * 4;
492
- result0.push(resources0.get(data_view(memory).getInt32(base + 0, true)));
258
+ rubyShowVersion() {
259
+ this._exports['ruby-show-version: func() -> ()']();
493
260
  }
494
- const ret0 = obj.reflectConstruct(resources0.get(arg0), result0);
495
- return resources0.insert(ret0);
496
- };
497
- imports["rb-js-abi-host"]["reflect-delete-property: func(target: handle<js-abi-value>, property-key: string) -> bool"] = function(arg0, arg1, arg2) {
498
- const memory = get_export("memory");
499
- const ptr0 = arg1;
500
- const len0 = arg2;
501
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
502
- const ret0 = obj.reflectDeleteProperty(resources0.get(arg0), result0);
503
- return ret0 ? 1 : 0;
504
- };
505
- imports["rb-js-abi-host"]["reflect-get: func(target: handle<js-abi-value>, property-key: string) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3) {
506
- const memory = get_export("memory");
507
- const ptr0 = arg1;
508
- const len0 = arg2;
509
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
510
- const ret0 = obj.reflectGet(resources0.get(arg0), result0);
511
- const variant1 = ret0;
512
- switch (variant1.tag) {
513
- case "success": {
514
- const e = variant1.val;
515
- data_view(memory).setInt8(arg3 + 0, 0, true);
516
- data_view(memory).setInt32(arg3 + 4, resources0.insert(e), true);
517
- break;
518
- }
519
- case "failure": {
520
- const e = variant1.val;
521
- data_view(memory).setInt8(arg3 + 0, 1, true);
522
- data_view(memory).setInt32(arg3 + 4, resources0.insert(e), true);
523
- break;
524
- }
525
- default:
526
- throw new RangeError("invalid variant specified for JsAbiResult");
527
- }
528
- };
529
- imports["rb-js-abi-host"]["reflect-get-own-property-descriptor: func(target: handle<js-abi-value>, property-key: string) -> handle<js-abi-value>"] = function(arg0, arg1, arg2) {
530
- const memory = get_export("memory");
531
- const ptr0 = arg1;
532
- const len0 = arg2;
533
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
534
- const ret0 = obj.reflectGetOwnPropertyDescriptor(resources0.get(arg0), result0);
535
- return resources0.insert(ret0);
536
- };
537
- imports["rb-js-abi-host"]["reflect-get-prototype-of: func(target: handle<js-abi-value>) -> handle<js-abi-value>"] = function(arg0) {
538
- const ret0 = obj.reflectGetPrototypeOf(resources0.get(arg0));
539
- return resources0.insert(ret0);
540
- };
541
- imports["rb-js-abi-host"]["reflect-has: func(target: handle<js-abi-value>, property-key: string) -> bool"] = function(arg0, arg1, arg2) {
542
- const memory = get_export("memory");
543
- const ptr0 = arg1;
544
- const len0 = arg2;
545
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
546
- const ret0 = obj.reflectHas(resources0.get(arg0), result0);
547
- return ret0 ? 1 : 0;
548
- };
549
- imports["rb-js-abi-host"]["reflect-is-extensible: func(target: handle<js-abi-value>) -> bool"] = function(arg0) {
550
- const ret0 = obj.reflectIsExtensible(resources0.get(arg0));
551
- return ret0 ? 1 : 0;
552
- };
553
- imports["rb-js-abi-host"]["reflect-own-keys: func(target: handle<js-abi-value>) -> list<handle<js-abi-value>>"] = function(arg0, arg1) {
554
- const memory = get_export("memory");
555
- const realloc = get_export("cabi_realloc");
556
- const ret0 = obj.reflectOwnKeys(resources0.get(arg0));
557
- const vec0 = ret0;
558
- const len0 = vec0.length;
559
- const result0 = realloc(0, 0, 4, len0 * 4);
560
- for (let i = 0; i < vec0.length; i++) {
561
- const e = vec0[i];
562
- const base = result0 + i * 4;
563
- data_view(memory).setInt32(base + 0, resources0.insert(e), true);
261
+ rubyInit() {
262
+ this._exports['ruby-init: func() -> ()']();
564
263
  }
565
- data_view(memory).setInt32(arg1 + 4, len0, true);
566
- data_view(memory).setInt32(arg1 + 0, result0, true);
567
- };
568
- imports["rb-js-abi-host"]["reflect-prevent-extensions: func(target: handle<js-abi-value>) -> bool"] = function(arg0) {
569
- const ret0 = obj.reflectPreventExtensions(resources0.get(arg0));
570
- return ret0 ? 1 : 0;
571
- };
572
- imports["rb-js-abi-host"]["reflect-set: func(target: handle<js-abi-value>, property-key: string, value: handle<js-abi-value>) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3, arg4) {
573
- const memory = get_export("memory");
574
- const ptr0 = arg1;
575
- const len0 = arg2;
576
- const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
577
- const ret0 = obj.reflectSet(resources0.get(arg0), result0, resources0.get(arg3));
578
- const variant1 = ret0;
579
- switch (variant1.tag) {
580
- case "success": {
581
- const e = variant1.val;
582
- data_view(memory).setInt8(arg4 + 0, 0, true);
583
- data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
584
- break;
585
- }
586
- case "failure": {
587
- const e = variant1.val;
588
- data_view(memory).setInt8(arg4 + 0, 1, true);
589
- data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
590
- break;
264
+ rubySysinit(arg0) {
265
+ const memory = this._exports.memory;
266
+ const realloc = this._exports["cabi_realloc"];
267
+ const vec1 = arg0;
268
+ const len1 = vec1.length;
269
+ const result1 = realloc(0, 0, 4, len1 * 8);
270
+ for (let i = 0; i < vec1.length; i++) {
271
+ const e = vec1[i];
272
+ const base = result1 + i * 8;
273
+ const ptr0 = utf8_encode(e, realloc, memory);
274
+ const len0 = UTF8_ENCODED_LEN;
275
+ data_view(memory).setInt32(base + 4, len0, true);
276
+ data_view(memory).setInt32(base + 0, ptr0, true);
591
277
  }
592
- default:
593
- throw new RangeError("invalid variant specified for JsAbiResult");
594
- }
595
- };
596
- imports["rb-js-abi-host"]["reflect-set-prototype-of: func(target: handle<js-abi-value>, prototype: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
597
- const ret0 = obj.reflectSetPrototypeOf(resources0.get(arg0), resources0.get(arg1));
598
- return ret0 ? 1 : 0;
599
- };
600
- if (!("canonical_abi" in imports)) imports["canonical_abi"] = {};
601
-
602
- const resources0 = new Slab();
603
- imports.canonical_abi["resource_drop_js-abi-value"] = (i) => {
604
- const val = resources0.remove(i);
605
- if (obj.dropJsAbiValue)
606
- obj.dropJsAbiValue(val);
607
- };
608
- }
609
-
610
- /**
611
- * Create a console printer that can be used as an overlay of WASI imports.
612
- * See the example below for how to use it.
613
- *
614
- * ```javascript
615
- * const imports = {
616
- * "wasi_snapshot_preview1": wasi.wasiImport,
617
- * }
618
- * const printer = consolePrinter();
619
- * printer.addToImports(imports);
620
- *
621
- * const instance = await WebAssembly.instantiate(module, imports);
622
- * printer.setMemory(instance.exports.memory);
623
- * ```
624
- *
625
- * Note that the `stdout` and `stderr` functions are called with text, not
626
- * bytes. This means that bytes written to stdout/stderr will be decoded as
627
- * UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
628
- * occurs without buffering.
629
- *
630
- * @param stdout A function that will be called when stdout is written to.
631
- * Defaults to `console.log`.
632
- * @param stderr A function that will be called when stderr is written to.
633
- * Defaults to `console.warn`.
634
- * @returns An object that can be used as an overlay of WASI imports.
635
- */
636
- function consolePrinter({ stdout, stderr, } = {
637
- stdout: console.log,
638
- stderr: console.warn,
639
- }) {
640
- let memory = undefined;
641
- let _view = undefined;
642
- function getMemoryView() {
643
- if (typeof memory === "undefined") {
644
- throw new Error("Memory is not set");
645
- }
646
- if (_view === undefined || _view.buffer.byteLength === 0) {
647
- _view = new DataView(memory.buffer);
648
- }
649
- return _view;
278
+ this._exports['ruby-sysinit: func(args: list<string>) -> ()'](result1, len1);
650
279
  }
651
- const decoder = new TextDecoder();
652
- return {
653
- addToImports(imports) {
654
- const wasiImport = imports.wasi_snapshot_preview1;
655
- const original_fd_write = wasiImport.fd_write;
656
- wasiImport.fd_write = (fd, iovs, iovsLen, nwritten) => {
657
- if (fd !== 1 && fd !== 2) {
658
- return original_fd_write(fd, iovs, iovsLen, nwritten);
659
- }
660
- const view = getMemoryView();
661
- const buffers = Array.from({ length: iovsLen }, (_, i) => {
662
- const ptr = iovs + i * 8;
663
- const buf = view.getUint32(ptr, true);
664
- const bufLen = view.getUint32(ptr + 4, true);
665
- return new Uint8Array(memory.buffer, buf, bufLen);
666
- });
667
- let written = 0;
668
- let str = "";
669
- for (const buffer of buffers) {
670
- str += decoder.decode(buffer);
671
- written += buffer.byteLength;
672
- }
673
- view.setUint32(nwritten, written, true);
674
- const log = fd === 1 ? stdout : stderr;
675
- log(str);
676
- return 0;
677
- };
678
- const original_fd_filestat_get = wasiImport.fd_filestat_get;
679
- wasiImport.fd_filestat_get = (fd, filestat) => {
680
- if (fd !== 1 && fd !== 2) {
681
- return original_fd_filestat_get(fd, filestat);
682
- }
683
- const view = getMemoryView();
684
- const result = original_fd_filestat_get(fd, filestat);
685
- if (result !== 0) {
686
- return result;
687
- }
688
- const filetypePtr = filestat + 0;
689
- view.setUint8(filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
690
- return 0;
691
- };
692
- const original_fd_fdstat_get = wasiImport.fd_fdstat_get;
693
- wasiImport.fd_fdstat_get = (fd, fdstat) => {
694
- if (fd !== 1 && fd !== 2) {
695
- return original_fd_fdstat_get(fd, fdstat);
696
- }
697
- const view = getMemoryView();
698
- const fs_filetypePtr = fdstat + 0;
699
- view.setUint8(fs_filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
700
- const fs_rights_basePtr = fdstat + 8;
701
- view.setBigUint64(fs_rights_basePtr, BigInt(1)); // RIGHTS_FD_WRITE
702
- return 0;
703
- };
704
- },
705
- setMemory(m) {
706
- memory = m;
707
- },
708
- };
709
- }
710
-
711
- /**
712
- * A Ruby VM instance
713
- *
714
- * @example
715
- *
716
- * const wasi = new WASI();
717
- * const vm = new RubyVM();
718
- * const imports = {
719
- * wasi_snapshot_preview1: wasi.wasiImport,
720
- * };
721
- *
722
- * vm.addToImports(imports);
723
- *
724
- * const instance = await WebAssembly.instantiate(rubyModule, imports);
725
- * await vm.setInstance(instance);
726
- * wasi.initialize(instance);
727
- * vm.initialize();
728
- *
729
- */
730
- class RubyVM {
731
- constructor() {
732
- this.instance = null;
733
- this.interfaceState = {
734
- hasJSFrameAfterRbFrame: false,
735
- };
736
- // Wrap exported functions from Ruby VM to prohibit nested VM operation
737
- // if the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby.
738
- const proxyExports = (exports) => {
739
- const excludedMethods = [
740
- "addToImports",
741
- "instantiate",
742
- "rbSetShouldProhibitRewind",
743
- "rbGcDisable",
744
- "rbGcEnable",
745
- ];
746
- const excluded = ["constructor"].concat(excludedMethods);
747
- // wrap all methods in RbAbi.RbAbiGuest class
748
- for (const key of Object.getOwnPropertyNames(RbAbiGuest.prototype)) {
749
- if (excluded.includes(key)) {
750
- continue;
751
- }
752
- const value = exports[key];
753
- if (typeof value === "function") {
754
- exports[key] = (...args) => {
755
- const isNestedVMCall = this.interfaceState.hasJSFrameAfterRbFrame;
756
- if (isNestedVMCall) {
757
- const oldShouldProhibitRewind = this.guest.rbSetShouldProhibitRewind(true);
758
- const oldIsDisabledGc = this.guest.rbGcDisable();
759
- const result = Reflect.apply(value, exports, args);
760
- this.guest.rbSetShouldProhibitRewind(oldShouldProhibitRewind);
761
- if (!oldIsDisabledGc) {
762
- this.guest.rbGcEnable();
763
- }
764
- return result;
765
- }
766
- else {
767
- return Reflect.apply(value, exports, args);
768
- }
769
- };
770
- }
771
- }
772
- return exports;
773
- };
774
- this.guest = proxyExports(new RbAbiGuest());
775
- this.transport = new JsValueTransport();
776
- this.exceptionFormatter = new RbExceptionFormatter();
777
- }
778
- /**
779
- * Initialize the Ruby VM with the given command line arguments
780
- * @param args The command line arguments to pass to Ruby. Must be
781
- * an array of strings starting with the Ruby program name.
782
- */
783
- initialize(args = ["ruby.wasm", "--disable-gems", "-EUTF-8", "-e_=0"]) {
784
- const c_args = args.map((arg) => arg + "\0");
785
- this.guest.rubyInit();
786
- this.guest.rubySysinit(c_args);
787
- this.guest.rubyOptions(c_args);
788
- }
789
- /**
790
- * Set a given instance to interact JavaScript and Ruby's
791
- * WebAssembly instance. This method must be called before calling
792
- * Ruby API.
793
- *
794
- * @param instance The WebAssembly instance to interact with. Must
795
- * be instantiated from a Ruby built with JS extension, and built
796
- * with Reactor ABI instead of command line.
797
- */
798
- async setInstance(instance) {
799
- this.instance = instance;
800
- await this.guest.instantiate(instance);
801
- }
802
- /**
803
- * Add intrinsic import entries, which is necessary to interact JavaScript
804
- * and Ruby's WebAssembly instance.
805
- * @param imports The import object to add to the WebAssembly instance
806
- */
807
- addToImports(imports) {
808
- this.guest.addToImports(imports);
809
- function wrapTry(f) {
810
- return (...args) => {
811
- try {
812
- return { tag: "success", val: f(...args) };
813
- }
814
- catch (e) {
815
- if (e instanceof RbFatalError) {
816
- // RbFatalError should not be caught by Ruby because it Ruby VM
817
- // can be already in an inconsistent state.
818
- throw e;
819
- }
820
- return { tag: "failure", val: e };
821
- }
822
- };
823
- }
824
- imports["rb-js-abi-host"] = {
825
- rb_wasm_throw_prohibit_rewind_exception: (messagePtr, messageLen) => {
826
- const memory = this.instance.exports.memory;
827
- const str = new TextDecoder().decode(new Uint8Array(memory.buffer, messagePtr, messageLen));
828
- throw new RbFatalError("Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
829
- `(${str})\n` +
830
- "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
831
- "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
832
- "\n" +
833
- "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
834
- " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
835
- " Note that `evalAsync` JS API switches fibers internally\n" +
836
- " 2. Raising uncaught exceptions\n" +
837
- " Please catch all exceptions inside the nested operation\n" +
838
- " 3. Calling Continuation APIs\n");
839
- },
840
- };
841
- // NOTE: The GC may collect objects that are still referenced by Wasm
842
- // locals because Asyncify cannot scan the Wasm stack above the JS frame.
843
- // So we need to keep track whether the JS frame is sandwitched by Ruby
844
- // frames or not, and prohibit nested VM operation if it is.
845
- const proxyImports = (imports) => {
846
- for (const [key, value] of Object.entries(imports)) {
847
- if (typeof value === "function") {
848
- imports[key] = (...args) => {
849
- const oldValue = this.interfaceState.hasJSFrameAfterRbFrame;
850
- this.interfaceState.hasJSFrameAfterRbFrame = true;
851
- const result = Reflect.apply(value, imports, args);
852
- this.interfaceState.hasJSFrameAfterRbFrame = oldValue;
853
- return result;
854
- };
855
- }
856
- }
857
- return imports;
858
- };
859
- addRbJsAbiHostToImports(imports, proxyImports({
860
- evalJs: wrapTry((code) => {
861
- return Function(code)();
862
- }),
863
- isJs: (value) => {
864
- // Just for compatibility with the old JS API
865
- return true;
866
- },
867
- globalThis: () => {
868
- if (typeof globalThis !== "undefined") {
869
- return globalThis;
870
- }
871
- else if (typeof global !== "undefined") {
872
- return global;
873
- }
874
- else if (typeof window !== "undefined") {
875
- return window;
876
- }
877
- throw new Error("unable to locate global object");
878
- },
879
- intToJsNumber: (value) => {
880
- return value;
881
- },
882
- floatToJsNumber: (value) => {
883
- return value;
884
- },
885
- stringToJsString: (value) => {
886
- return value;
887
- },
888
- boolToJsBool: (value) => {
889
- return value;
890
- },
891
- procToJsFunction: (rawRbAbiValue) => {
892
- const rbValue = this.rbValueOfPointer(rawRbAbiValue);
893
- return (...args) => {
894
- rbValue.call("call", ...args.map((arg) => this.wrap(arg)));
895
- };
896
- },
897
- rbObjectToJsRbValue: (rawRbAbiValue) => {
898
- return this.rbValueOfPointer(rawRbAbiValue);
899
- },
900
- jsValueToString: (value) => {
901
- // According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
902
- // `String(value)` always returns a string.
903
- return String(value);
904
- },
905
- jsValueToInteger(value) {
906
- if (typeof value === "number") {
907
- return { tag: "f64", val: value };
908
- }
909
- else if (typeof value === "bigint") {
910
- return { tag: "bignum", val: BigInt(value).toString(10) + "\0" };
911
- }
912
- else if (typeof value === "string") {
913
- return { tag: "bignum", val: value + "\0" };
914
- }
915
- else if (typeof value === "undefined") {
916
- return { tag: "f64", val: 0 };
917
- }
918
- else {
919
- return { tag: "f64", val: Number(value) };
920
- }
921
- },
922
- exportJsValueToHost: (value) => {
923
- // See `JsValueExporter` for the reason why we need to do this
924
- this.transport.takeJsValue(value);
925
- },
926
- importJsValueFromHost: () => {
927
- return this.transport.consumeJsValue();
928
- },
929
- instanceOf: (value, klass) => {
930
- if (typeof klass === "function") {
931
- return value instanceof klass;
932
- }
933
- else {
934
- return false;
935
- }
936
- },
937
- jsValueTypeof(value) {
938
- return typeof value;
939
- },
940
- jsValueEqual(lhs, rhs) {
941
- return lhs == rhs;
942
- },
943
- jsValueStrictlyEqual(lhs, rhs) {
944
- return lhs === rhs;
945
- },
946
- reflectApply: wrapTry((target, thisArgument, args) => {
947
- return Reflect.apply(target, thisArgument, args);
948
- }),
949
- reflectConstruct: function (target, args) {
950
- throw new Error("Function not implemented.");
951
- },
952
- reflectDeleteProperty: function (target, propertyKey) {
953
- throw new Error("Function not implemented.");
954
- },
955
- reflectGet: wrapTry((target, propertyKey) => {
956
- return target[propertyKey];
957
- }),
958
- reflectGetOwnPropertyDescriptor: function (target, propertyKey) {
959
- throw new Error("Function not implemented.");
960
- },
961
- reflectGetPrototypeOf: function (target) {
962
- throw new Error("Function not implemented.");
963
- },
964
- reflectHas: function (target, propertyKey) {
965
- throw new Error("Function not implemented.");
966
- },
967
- reflectIsExtensible: function (target) {
968
- throw new Error("Function not implemented.");
969
- },
970
- reflectOwnKeys: function (target) {
971
- throw new Error("Function not implemented.");
972
- },
973
- reflectPreventExtensions: function (target) {
974
- throw new Error("Function not implemented.");
975
- },
976
- reflectSet: wrapTry((target, propertyKey, value) => {
977
- return Reflect.set(target, propertyKey, value);
978
- }),
979
- reflectSetPrototypeOf: function (target, prototype) {
980
- throw new Error("Function not implemented.");
981
- },
982
- }), (name) => {
983
- return this.instance.exports[name];
984
- });
280
+ rubyOptions(arg0) {
281
+ const memory = this._exports.memory;
282
+ const realloc = this._exports["cabi_realloc"];
283
+ const vec1 = arg0;
284
+ const len1 = vec1.length;
285
+ const result1 = realloc(0, 0, 4, len1 * 8);
286
+ for (let i = 0; i < vec1.length; i++) {
287
+ const e = vec1[i];
288
+ const base = result1 + i * 8;
289
+ const ptr0 = utf8_encode(e, realloc, memory);
290
+ const len0 = UTF8_ENCODED_LEN;
291
+ data_view(memory).setInt32(base + 4, len0, true);
292
+ data_view(memory).setInt32(base + 0, ptr0, true);
293
+ }
294
+ const ret = this._exports['ruby-options: func(args: list<string>) -> handle<rb-iseq>'](result1, len1);
295
+ return this._resource0_slab.remove(ret);
985
296
  }
986
- /**
987
- * Print the Ruby version to stdout
988
- */
989
- printVersion() {
990
- this.guest.rubyShowVersion();
297
+ rubyScript(arg0) {
298
+ const memory = this._exports.memory;
299
+ const realloc = this._exports["cabi_realloc"];
300
+ const ptr0 = utf8_encode(arg0, realloc, memory);
301
+ const len0 = UTF8_ENCODED_LEN;
302
+ this._exports['ruby-script: func(name: string) -> ()'](ptr0, len0);
991
303
  }
992
- /**
993
- * Runs a string of Ruby code from JavaScript
994
- * @param code The Ruby code to run
995
- * @returns the result of the last expression
996
- *
997
- * @example
998
- * vm.eval("puts 'hello world'");
999
- * const result = vm.eval("1 + 2");
1000
- * console.log(result.toString()); // 3
1001
- *
1002
- */
1003
- eval(code) {
1004
- return evalRbCode(this, this.privateObject(), code);
304
+ rubyInitLoadpath() {
305
+ this._exports['ruby-init-loadpath: func() -> ()']();
1005
306
  }
1006
- /**
1007
- * Runs a string of Ruby code with top-level `JS::Object#await`
1008
- * Returns a promise that resolves when execution completes.
1009
- * @param code The Ruby code to run
1010
- * @returns a promise that resolves to the result of the last expression
1011
- *
1012
- * @example
1013
- * const text = await vm.evalAsync(`
1014
- * require 'js'
1015
- * response = JS.global.fetch('https://example.com').await
1016
- * response.text.await
1017
- * `);
1018
- * console.log(text.toString()); // <html>...</html>
1019
- */
1020
- evalAsync(code) {
1021
- const JS = this.eval("require 'js'; JS");
1022
- return new Promise((resolve, reject) => {
1023
- JS.call("__eval_async_rb", this.wrap(code), this.wrap({
1024
- resolve,
1025
- reject: (error) => {
1026
- reject(new RbError(this.exceptionFormatter.format(error, this, this.privateObject())));
1027
- },
1028
- }));
1029
- });
307
+ rbEvalStringProtect(arg0) {
308
+ const memory = this._exports.memory;
309
+ const realloc = this._exports["cabi_realloc"];
310
+ const ptr0 = utf8_encode(arg0, realloc, memory);
311
+ const len0 = UTF8_ENCODED_LEN;
312
+ const ret = this._exports['rb-eval-string-protect: func(str: string) -> tuple<handle<rb-abi-value>, s32>'](ptr0, len0);
313
+ return [this._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
1030
314
  }
1031
- /**
1032
- * Wrap a JavaScript value into a Ruby JS::Object
1033
- * @param value The value to convert to RbValue
1034
- * @returns the RbValue object representing the given JS value
1035
- *
1036
- * @example
1037
- * const hash = vm.eval(`Hash.new`)
1038
- * hash.call("store", vm.eval(`"key1"`), vm.wrap(new Object()));
1039
- */
1040
- wrap(value) {
1041
- return this.transport.importJsValue(value, this);
315
+ rbFuncallvProtect(arg0, arg1, arg2) {
316
+ const memory = this._exports.memory;
317
+ const realloc = this._exports["cabi_realloc"];
318
+ const obj0 = arg0;
319
+ if (!(obj0 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
320
+ const vec2 = arg2;
321
+ const len2 = vec2.length;
322
+ const result2 = realloc(0, 0, 4, len2 * 4);
323
+ for (let i = 0; i < vec2.length; i++) {
324
+ const e = vec2[i];
325
+ const base = result2 + i * 4;
326
+ const obj1 = e;
327
+ if (!(obj1 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
328
+ data_view(memory).setInt32(base + 0, this._resource1_slab.insert(obj1.clone()), true);
329
+ }
330
+ const ret = this._exports['rb-funcallv-protect: func(recv: handle<rb-abi-value>, mid: u32, args: list<handle<rb-abi-value>>) -> tuple<handle<rb-abi-value>, s32>'](this._resource1_slab.insert(obj0.clone()), to_uint32(arg1), result2, len2);
331
+ return [this._resource1_slab.remove(data_view(memory).getInt32(ret + 0, true)), data_view(memory).getInt32(ret + 4, true)];
1042
332
  }
1043
- /** @private */
1044
- privateObject() {
1045
- return {
1046
- transport: this.transport,
1047
- exceptionFormatter: this.exceptionFormatter,
1048
- };
333
+ rbIntern(arg0) {
334
+ const memory = this._exports.memory;
335
+ const realloc = this._exports["cabi_realloc"];
336
+ const ptr0 = utf8_encode(arg0, realloc, memory);
337
+ const len0 = UTF8_ENCODED_LEN;
338
+ const ret = this._exports['rb-intern: func(name: string) -> u32'](ptr0, len0);
339
+ return ret >>> 0;
1049
340
  }
1050
- /** @private */
1051
- rbValueOfPointer(pointer) {
1052
- const abiValue = new RbAbiValue(pointer, this.guest);
1053
- return new RbValue(abiValue, this, this.privateObject());
341
+ rbErrinfo() {
342
+ const ret = this._exports['rb-errinfo: func() -> handle<rb-abi-value>']();
343
+ return this._resource1_slab.remove(ret);
1054
344
  }
1055
- }
1056
- /**
1057
- * Export a JS value held by the Ruby VM to the JS environment.
1058
- * This is implemented in a dirty way since wit cannot reference resources
1059
- * defined in other interfaces.
1060
- * In our case, we can't express `function(v: rb-abi-value) -> js-abi-value`
1061
- * because `rb-js-abi-host.wit`, that defines `js-abi-value`, is implemented
1062
- * by embedder side (JS) but `rb-abi-guest.wit`, that defines `rb-abi-value`
1063
- * is implemented by guest side (Wasm).
1064
- *
1065
- * This class is a helper to export by:
1066
- * 1. Call `function __export_to_js(v: rb-abi-value)` defined in guest from embedder side.
1067
- * 2. Call `function takeJsValue(v: js-abi-value)` defined in embedder from guest side with
1068
- * underlying JS value of given `rb-abi-value`.
1069
- * 3. Then `takeJsValue` implementation escapes the given JS value to the `_takenJsValues`
1070
- * stored in embedder side.
1071
- * 4. Finally, embedder side can take `_takenJsValues`.
1072
- *
1073
- * Note that `exportJsValue` is not reentrant.
1074
- *
1075
- * @private
1076
- */
1077
- class JsValueTransport {
1078
- constructor() {
1079
- this._takenJsValue = null;
345
+ rbClearErrinfo() {
346
+ this._exports['rb-clear-errinfo: func() -> ()']();
1080
347
  }
1081
- takeJsValue(value) {
1082
- this._takenJsValue = value;
348
+ rstringPtr(arg0) {
349
+ const memory = this._exports.memory;
350
+ const obj0 = arg0;
351
+ if (!(obj0 instanceof RbAbiValue)) throw new TypeError('expected instance of RbAbiValue');
352
+ const ret = this._exports['rstring-ptr: func(value: handle<rb-abi-value>) -> string'](this._resource1_slab.insert(obj0.clone()));
353
+ const ptr1 = data_view(memory).getInt32(ret + 0, true);
354
+ const len1 = data_view(memory).getInt32(ret + 4, true);
355
+ const result1 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr1, len1));
356
+ this._exports["cabi_post_rstring-ptr"](ret);
357
+ return result1;
1083
358
  }
1084
- consumeJsValue() {
1085
- return this._takenJsValue;
359
+ rbVmBugreport() {
360
+ this._exports['rb-vm-bugreport: func() -> ()']();
1086
361
  }
1087
- exportJsValue(value) {
1088
- value.call("__export_to_js");
1089
- return this._takenJsValue;
362
+ rbGcEnable() {
363
+ const ret = this._exports['rb-gc-enable: func() -> bool']();
364
+ const bool0 = ret;
365
+ return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
1090
366
  }
1091
- importJsValue(value, vm) {
1092
- this._takenJsValue = value;
1093
- return vm.eval('require "js"; JS::Object').call("__import_from_js");
367
+ rbGcDisable() {
368
+ const ret = this._exports['rb-gc-disable: func() -> bool']();
369
+ const bool0 = ret;
370
+ return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
1094
371
  }
1095
- }
1096
- /**
1097
- * A RbValue is an object that represents a value in Ruby
1098
- */
1099
- class RbValue {
1100
- /**
1101
- * @hideconstructor
1102
- */
1103
- constructor(inner, vm, privateObject) {
1104
- this.inner = inner;
1105
- this.vm = vm;
1106
- this.privateObject = privateObject;
372
+ rbSetShouldProhibitRewind(arg0) {
373
+ const ret = this._exports['rb-set-should-prohibit-rewind: func(new-value: bool) -> bool'](arg0 ? 1 : 0);
374
+ const bool0 = ret;
375
+ return bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool());
1107
376
  }
1108
- /**
1109
- * Call a given method with given arguments
1110
- *
1111
- * @param callee name of the Ruby method to call
1112
- * @param args arguments to pass to the method. Must be an array of RbValue
1113
- *
1114
- * @example
1115
- * const ary = vm.eval("[1, 2, 3]");
1116
- * ary.call("push", 4);
1117
- * console.log(ary.call("sample").toString());
1118
- *
1119
- */
1120
- call(callee, ...args) {
1121
- const innerArgs = args.map((arg) => arg.inner);
1122
- return new RbValue(callRbMethod(this.vm, this.privateObject, this.inner, callee, innerArgs), this.vm, this.privateObject);
377
+ }
378
+
379
+ class RbIseq {
380
+ constructor(wasm_val, obj) {
381
+ this._wasm_val = wasm_val;
382
+ this._obj = obj;
383
+ this._refcnt = 1;
384
+ obj._registry0.register(this, wasm_val, this);
1123
385
  }
1124
- /**
1125
- * @see {@link https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive}
1126
- * @param hint Preferred type of the result primitive value. `"number"`, `"string"`, or `"default"`.
1127
- */
1128
- [Symbol.toPrimitive](hint) {
1129
- if (hint === "string" || hint === "default") {
1130
- return this.toString();
1131
- }
1132
- else if (hint === "number") {
1133
- return null;
1134
- }
1135
- return null;
386
+
387
+ clone() {
388
+ this._refcnt += 1;
389
+ return this;
1136
390
  }
1137
- /**
1138
- * Returns a string representation of the value by calling `to_s`
1139
- */
1140
- toString() {
1141
- const rbString = callRbMethod(this.vm, this.privateObject, this.inner, "to_s", []);
1142
- return this.vm.guest.rstringPtr(rbString);
391
+
392
+ drop() {
393
+ this._refcnt -= 1;
394
+ if (this._refcnt !== 0)
395
+ return;
396
+ this._obj._registry0.unregister(this);
397
+ const dtor = this._obj._exports['canonical_abi_drop_rb-iseq'];
398
+ const wasm_val = this._wasm_val;
399
+ delete this._obj;
400
+ delete this._refcnt;
401
+ delete this._wasm_val;
402
+ dtor(wasm_val);
1143
403
  }
1144
- /**
1145
- * Returns a JavaScript object representation of the value
1146
- * by calling `to_js`.
1147
- *
1148
- * Returns null if the value is not convertible to a JavaScript object.
1149
- */
1150
- toJS() {
1151
- const JS = this.vm.eval("JS");
1152
- const jsValue = JS.call("try_convert", this);
1153
- if (jsValue.call("nil?").toString() === "true") {
1154
- return null;
1155
- }
1156
- return this.privateObject.transport.exportJsValue(jsValue);
404
+ }
405
+
406
+ class RbAbiValue {
407
+ constructor(wasm_val, obj) {
408
+ this._wasm_val = wasm_val;
409
+ this._obj = obj;
410
+ this._refcnt = 1;
411
+ obj._registry1.register(this, wasm_val, this);
1157
412
  }
1158
- }
1159
- var ruby_tag_type;
1160
- (function (ruby_tag_type) {
1161
- ruby_tag_type[ruby_tag_type["None"] = 0] = "None";
1162
- ruby_tag_type[ruby_tag_type["Return"] = 1] = "Return";
1163
- ruby_tag_type[ruby_tag_type["Break"] = 2] = "Break";
1164
- ruby_tag_type[ruby_tag_type["Next"] = 3] = "Next";
1165
- ruby_tag_type[ruby_tag_type["Retry"] = 4] = "Retry";
1166
- ruby_tag_type[ruby_tag_type["Redo"] = 5] = "Redo";
1167
- ruby_tag_type[ruby_tag_type["Raise"] = 6] = "Raise";
1168
- ruby_tag_type[ruby_tag_type["Throw"] = 7] = "Throw";
1169
- ruby_tag_type[ruby_tag_type["Fatal"] = 8] = "Fatal";
1170
- ruby_tag_type[ruby_tag_type["Mask"] = 15] = "Mask";
1171
- })(ruby_tag_type || (ruby_tag_type = {}));
1172
- class RbExceptionFormatter {
1173
- constructor() {
1174
- this.literalsCache = null;
1175
- this.isFormmatting = false;
413
+
414
+ clone() {
415
+ this._refcnt += 1;
416
+ return this;
1176
417
  }
1177
- format(error, vm, privateObject) {
1178
- // All Ruby exceptions raised during formatting exception message should
1179
- // be caught and return a fallback message.
1180
- // Therefore, we don't need to worry about infinite recursion here ideally
1181
- // but checking re-entrancy just in case.
1182
- class RbExceptionFormatterError extends Error {
1183
- }
1184
- if (this.isFormmatting) {
1185
- throw new RbExceptionFormatterError("Unexpected exception occurred during formatting exception message");
1186
- }
1187
- this.isFormmatting = true;
1188
- try {
1189
- return this._format(error, vm, privateObject);
1190
- }
1191
- finally {
1192
- this.isFormmatting = false;
1193
- }
418
+
419
+ drop() {
420
+ this._refcnt -= 1;
421
+ if (this._refcnt !== 0)
422
+ return;
423
+ this._obj._registry1.unregister(this);
424
+ const dtor = this._obj._exports['canonical_abi_drop_rb-abi-value'];
425
+ const wasm_val = this._wasm_val;
426
+ delete this._obj;
427
+ delete this._refcnt;
428
+ delete this._wasm_val;
429
+ dtor(wasm_val);
1194
430
  }
1195
- _format(error, vm, privateObject) {
1196
- const [zeroLiteral, oneLiteral, newLineLiteral] = (() => {
1197
- if (this.literalsCache == null) {
1198
- const zeroOneNewLine = [
1199
- evalRbCode(vm, privateObject, "0"),
1200
- evalRbCode(vm, privateObject, "1"),
1201
- evalRbCode(vm, privateObject, `"\n"`),
1202
- ];
1203
- this.literalsCache = zeroOneNewLine;
1204
- return zeroOneNewLine;
1205
- }
1206
- else {
1207
- return this.literalsCache;
1208
- }
1209
- })();
1210
- let className;
1211
- let backtrace;
1212
- let message;
1213
- try {
1214
- className = error.call("class").toString();
1215
- }
1216
- catch (e) {
1217
- className = "unknown";
1218
- }
1219
- try {
1220
- message = error.toString();
1221
- }
1222
- catch (e) {
1223
- message = "unknown";
431
+ }
432
+
433
+ function addRbJsAbiHostToImports(imports, obj, get_export) {
434
+ if (!("rb-js-abi-host" in imports)) imports["rb-js-abi-host"] = {};
435
+ imports["rb-js-abi-host"]["eval-js: func(code: string) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2) {
436
+ const memory = get_export("memory");
437
+ const ptr0 = arg0;
438
+ const len0 = arg1;
439
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
440
+ const ret0 = obj.evalJs(result0);
441
+ const variant1 = ret0;
442
+ switch (variant1.tag) {
443
+ case "success": {
444
+ const e = variant1.val;
445
+ data_view(memory).setInt8(arg2 + 0, 0, true);
446
+ data_view(memory).setInt32(arg2 + 4, resources0.insert(e), true);
447
+ break;
1224
448
  }
1225
- try {
1226
- backtrace = error.call("backtrace");
449
+ case "failure": {
450
+ const e = variant1.val;
451
+ data_view(memory).setInt8(arg2 + 0, 1, true);
452
+ data_view(memory).setInt32(arg2 + 4, resources0.insert(e), true);
453
+ break;
1227
454
  }
1228
- catch (e) {
1229
- return this.formatString(className, message);
455
+ default:
456
+ throw new RangeError("invalid variant specified for JsAbiResult");
457
+ }
458
+ };
459
+ imports["rb-js-abi-host"]["is-js: func(value: handle<js-abi-value>) -> bool"] = function(arg0) {
460
+ const ret0 = obj.isJs(resources0.get(arg0));
461
+ return ret0 ? 1 : 0;
462
+ };
463
+ imports["rb-js-abi-host"]["instance-of: func(value: handle<js-abi-value>, klass: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
464
+ const ret0 = obj.instanceOf(resources0.get(arg0), resources0.get(arg1));
465
+ return ret0 ? 1 : 0;
466
+ };
467
+ imports["rb-js-abi-host"]["global-this: func() -> handle<js-abi-value>"] = function() {
468
+ const ret0 = obj.globalThis();
469
+ return resources0.insert(ret0);
470
+ };
471
+ imports["rb-js-abi-host"]["int-to-js-number: func(value: s32) -> handle<js-abi-value>"] = function(arg0) {
472
+ const ret0 = obj.intToJsNumber(arg0);
473
+ return resources0.insert(ret0);
474
+ };
475
+ imports["rb-js-abi-host"]["float-to-js-number: func(value: float64) -> handle<js-abi-value>"] = function(arg0) {
476
+ const ret0 = obj.floatToJsNumber(arg0);
477
+ return resources0.insert(ret0);
478
+ };
479
+ imports["rb-js-abi-host"]["string-to-js-string: func(value: string) -> handle<js-abi-value>"] = function(arg0, arg1) {
480
+ const memory = get_export("memory");
481
+ const ptr0 = arg0;
482
+ const len0 = arg1;
483
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
484
+ const ret0 = obj.stringToJsString(result0);
485
+ return resources0.insert(ret0);
486
+ };
487
+ imports["rb-js-abi-host"]["bool-to-js-bool: func(value: bool) -> handle<js-abi-value>"] = function(arg0) {
488
+ const bool0 = arg0;
489
+ const ret0 = obj.boolToJsBool(bool0 == 0 ? false : (bool0 == 1 ? true : throw_invalid_bool()));
490
+ return resources0.insert(ret0);
491
+ };
492
+ imports["rb-js-abi-host"]["proc-to-js-function: func(value: u32) -> handle<js-abi-value>"] = function(arg0) {
493
+ const ret0 = obj.procToJsFunction(arg0 >>> 0);
494
+ return resources0.insert(ret0);
495
+ };
496
+ imports["rb-js-abi-host"]["rb-object-to-js-rb-value: func(raw-rb-abi-value: u32) -> handle<js-abi-value>"] = function(arg0) {
497
+ const ret0 = obj.rbObjectToJsRbValue(arg0 >>> 0);
498
+ return resources0.insert(ret0);
499
+ };
500
+ imports["rb-js-abi-host"]["js-value-to-string: func(value: handle<js-abi-value>) -> string"] = function(arg0, arg1) {
501
+ const memory = get_export("memory");
502
+ const realloc = get_export("cabi_realloc");
503
+ const ret0 = obj.jsValueToString(resources0.get(arg0));
504
+ const ptr0 = utf8_encode(ret0, realloc, memory);
505
+ const len0 = UTF8_ENCODED_LEN;
506
+ data_view(memory).setInt32(arg1 + 4, len0, true);
507
+ data_view(memory).setInt32(arg1 + 0, ptr0, true);
508
+ };
509
+ imports["rb-js-abi-host"]["js-value-to-integer: func(value: handle<js-abi-value>) -> variant { f64(float64), bignum(string) }"] = function(arg0, arg1) {
510
+ const memory = get_export("memory");
511
+ const realloc = get_export("cabi_realloc");
512
+ const ret0 = obj.jsValueToInteger(resources0.get(arg0));
513
+ const variant1 = ret0;
514
+ switch (variant1.tag) {
515
+ case "f64": {
516
+ const e = variant1.val;
517
+ data_view(memory).setInt8(arg1 + 0, 0, true);
518
+ data_view(memory).setFloat64(arg1 + 8, +e, true);
519
+ break;
1230
520
  }
1231
- if (backtrace.call("nil?").toString() === "true") {
1232
- return this.formatString(className, message);
521
+ case "bignum": {
522
+ const e = variant1.val;
523
+ data_view(memory).setInt8(arg1 + 0, 1, true);
524
+ const ptr0 = utf8_encode(e, realloc, memory);
525
+ const len0 = UTF8_ENCODED_LEN;
526
+ data_view(memory).setInt32(arg1 + 12, len0, true);
527
+ data_view(memory).setInt32(arg1 + 8, ptr0, true);
528
+ break;
1233
529
  }
1234
- try {
1235
- const firstLine = backtrace.call("at", zeroLiteral);
1236
- const restLines = backtrace
1237
- .call("drop", oneLiteral)
1238
- .call("join", newLineLiteral);
1239
- return this.formatString(className, message, [
1240
- firstLine.toString(),
1241
- restLines.toString(),
1242
- ]);
530
+ default:
531
+ throw new RangeError("invalid variant specified for RawInteger");
532
+ }
533
+ };
534
+ imports["rb-js-abi-host"]["export-js-value-to-host: func(value: handle<js-abi-value>) -> ()"] = function(arg0) {
535
+ obj.exportJsValueToHost(resources0.get(arg0));
536
+ };
537
+ imports["rb-js-abi-host"]["import-js-value-from-host: func() -> handle<js-abi-value>"] = function() {
538
+ const ret0 = obj.importJsValueFromHost();
539
+ return resources0.insert(ret0);
540
+ };
541
+ imports["rb-js-abi-host"]["js-value-typeof: func(value: handle<js-abi-value>) -> string"] = function(arg0, arg1) {
542
+ const memory = get_export("memory");
543
+ const realloc = get_export("cabi_realloc");
544
+ const ret0 = obj.jsValueTypeof(resources0.get(arg0));
545
+ const ptr0 = utf8_encode(ret0, realloc, memory);
546
+ const len0 = UTF8_ENCODED_LEN;
547
+ data_view(memory).setInt32(arg1 + 4, len0, true);
548
+ data_view(memory).setInt32(arg1 + 0, ptr0, true);
549
+ };
550
+ imports["rb-js-abi-host"]["js-value-equal: func(lhs: handle<js-abi-value>, rhs: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
551
+ const ret0 = obj.jsValueEqual(resources0.get(arg0), resources0.get(arg1));
552
+ return ret0 ? 1 : 0;
553
+ };
554
+ imports["rb-js-abi-host"]["js-value-strictly-equal: func(lhs: handle<js-abi-value>, rhs: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
555
+ const ret0 = obj.jsValueStrictlyEqual(resources0.get(arg0), resources0.get(arg1));
556
+ return ret0 ? 1 : 0;
557
+ };
558
+ imports["rb-js-abi-host"]["reflect-apply: func(target: handle<js-abi-value>, this-argument: handle<js-abi-value>, arguments: list<handle<js-abi-value>>) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3, arg4) {
559
+ const memory = get_export("memory");
560
+ const len0 = arg3;
561
+ const base0 = arg2;
562
+ const result0 = [];
563
+ for (let i = 0; i < len0; i++) {
564
+ const base = base0 + i * 4;
565
+ result0.push(resources0.get(data_view(memory).getInt32(base + 0, true)));
566
+ }
567
+ const ret0 = obj.reflectApply(resources0.get(arg0), resources0.get(arg1), result0);
568
+ const variant1 = ret0;
569
+ switch (variant1.tag) {
570
+ case "success": {
571
+ const e = variant1.val;
572
+ data_view(memory).setInt8(arg4 + 0, 0, true);
573
+ data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
574
+ break;
1243
575
  }
1244
- catch (e) {
1245
- return this.formatString(className, message);
576
+ case "failure": {
577
+ const e = variant1.val;
578
+ data_view(memory).setInt8(arg4 + 0, 1, true);
579
+ data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
580
+ break;
1246
581
  }
1247
- }
1248
- formatString(klass, message, backtrace) {
1249
- if (backtrace) {
1250
- return `${backtrace[0]}: ${message} (${klass})\n${backtrace[1]}`;
582
+ default:
583
+ throw new RangeError("invalid variant specified for JsAbiResult");
584
+ }
585
+ };
586
+ imports["rb-js-abi-host"]["reflect-construct: func(target: handle<js-abi-value>, arguments: list<handle<js-abi-value>>) -> handle<js-abi-value>"] = function(arg0, arg1, arg2) {
587
+ const memory = get_export("memory");
588
+ const len0 = arg2;
589
+ const base0 = arg1;
590
+ const result0 = [];
591
+ for (let i = 0; i < len0; i++) {
592
+ const base = base0 + i * 4;
593
+ result0.push(resources0.get(data_view(memory).getInt32(base + 0, true)));
594
+ }
595
+ const ret0 = obj.reflectConstruct(resources0.get(arg0), result0);
596
+ return resources0.insert(ret0);
597
+ };
598
+ imports["rb-js-abi-host"]["reflect-delete-property: func(target: handle<js-abi-value>, property-key: string) -> bool"] = function(arg0, arg1, arg2) {
599
+ const memory = get_export("memory");
600
+ const ptr0 = arg1;
601
+ const len0 = arg2;
602
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
603
+ const ret0 = obj.reflectDeleteProperty(resources0.get(arg0), result0);
604
+ return ret0 ? 1 : 0;
605
+ };
606
+ imports["rb-js-abi-host"]["reflect-get: func(target: handle<js-abi-value>, property-key: string) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3) {
607
+ const memory = get_export("memory");
608
+ const ptr0 = arg1;
609
+ const len0 = arg2;
610
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
611
+ const ret0 = obj.reflectGet(resources0.get(arg0), result0);
612
+ const variant1 = ret0;
613
+ switch (variant1.tag) {
614
+ case "success": {
615
+ const e = variant1.val;
616
+ data_view(memory).setInt8(arg3 + 0, 0, true);
617
+ data_view(memory).setInt32(arg3 + 4, resources0.insert(e), true);
618
+ break;
1251
619
  }
1252
- else {
1253
- return `${klass}: ${message}`;
620
+ case "failure": {
621
+ const e = variant1.val;
622
+ data_view(memory).setInt8(arg3 + 0, 1, true);
623
+ data_view(memory).setInt32(arg3 + 4, resources0.insert(e), true);
624
+ break;
1254
625
  }
1255
- }
1256
- }
1257
- const checkStatusTag = (rawTag, vm, privateObject) => {
1258
- switch (rawTag & ruby_tag_type.Mask) {
1259
- case ruby_tag_type.None:
1260
- break;
1261
- case ruby_tag_type.Return:
1262
- throw new RbError("unexpected return");
1263
- case ruby_tag_type.Next:
1264
- throw new RbError("unexpected next");
1265
- case ruby_tag_type.Break:
1266
- throw new RbError("unexpected break");
1267
- case ruby_tag_type.Redo:
1268
- throw new RbError("unexpected redo");
1269
- case ruby_tag_type.Retry:
1270
- throw new RbError("retry outside of rescue clause");
1271
- case ruby_tag_type.Throw:
1272
- throw new RbError("unexpected throw");
1273
- case ruby_tag_type.Raise:
1274
- case ruby_tag_type.Fatal:
1275
- const error = new RbValue(vm.guest.rbErrinfo(), vm, privateObject);
1276
- if (error.call("nil?").toString() === "true") {
1277
- throw new RbError("no exception object");
1278
- }
1279
- // clear errinfo if got exception due to no rb_jump_tag
1280
- vm.guest.rbClearErrinfo();
1281
- throw new RbError(privateObject.exceptionFormatter.format(error, vm, privateObject));
1282
626
  default:
1283
- throw new RbError(`unknown error tag: ${rawTag}`);
1284
- }
1285
- };
1286
- function wrapRbOperation(vm, body) {
1287
- try {
1288
- return body();
1289
- }
1290
- catch (e) {
1291
- if (e instanceof RbError) {
1292
- throw e;
1293
- }
1294
- // All JS exceptions triggered by Ruby code are translated to Ruby exceptions,
1295
- // so non-RbError exceptions are unexpected.
1296
- vm.guest.rbVmBugreport();
1297
- if (e instanceof WebAssembly.RuntimeError && e.message === "unreachable") {
1298
- const error = new RbError(`Something went wrong in Ruby VM: ${e}`);
1299
- error.stack = e.stack;
1300
- throw error;
627
+ throw new RangeError("invalid variant specified for JsAbiResult");
628
+ }
629
+ };
630
+ imports["rb-js-abi-host"]["reflect-get-own-property-descriptor: func(target: handle<js-abi-value>, property-key: string) -> handle<js-abi-value>"] = function(arg0, arg1, arg2) {
631
+ const memory = get_export("memory");
632
+ const ptr0 = arg1;
633
+ const len0 = arg2;
634
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
635
+ const ret0 = obj.reflectGetOwnPropertyDescriptor(resources0.get(arg0), result0);
636
+ return resources0.insert(ret0);
637
+ };
638
+ imports["rb-js-abi-host"]["reflect-get-prototype-of: func(target: handle<js-abi-value>) -> handle<js-abi-value>"] = function(arg0) {
639
+ const ret0 = obj.reflectGetPrototypeOf(resources0.get(arg0));
640
+ return resources0.insert(ret0);
641
+ };
642
+ imports["rb-js-abi-host"]["reflect-has: func(target: handle<js-abi-value>, property-key: string) -> bool"] = function(arg0, arg1, arg2) {
643
+ const memory = get_export("memory");
644
+ const ptr0 = arg1;
645
+ const len0 = arg2;
646
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
647
+ const ret0 = obj.reflectHas(resources0.get(arg0), result0);
648
+ return ret0 ? 1 : 0;
649
+ };
650
+ imports["rb-js-abi-host"]["reflect-is-extensible: func(target: handle<js-abi-value>) -> bool"] = function(arg0) {
651
+ const ret0 = obj.reflectIsExtensible(resources0.get(arg0));
652
+ return ret0 ? 1 : 0;
653
+ };
654
+ imports["rb-js-abi-host"]["reflect-own-keys: func(target: handle<js-abi-value>) -> list<handle<js-abi-value>>"] = function(arg0, arg1) {
655
+ const memory = get_export("memory");
656
+ const realloc = get_export("cabi_realloc");
657
+ const ret0 = obj.reflectOwnKeys(resources0.get(arg0));
658
+ const vec0 = ret0;
659
+ const len0 = vec0.length;
660
+ const result0 = realloc(0, 0, 4, len0 * 4);
661
+ for (let i = 0; i < vec0.length; i++) {
662
+ const e = vec0[i];
663
+ const base = result0 + i * 4;
664
+ data_view(memory).setInt32(base + 0, resources0.insert(e), true);
665
+ }
666
+ data_view(memory).setInt32(arg1 + 4, len0, true);
667
+ data_view(memory).setInt32(arg1 + 0, result0, true);
668
+ };
669
+ imports["rb-js-abi-host"]["reflect-prevent-extensions: func(target: handle<js-abi-value>) -> bool"] = function(arg0) {
670
+ const ret0 = obj.reflectPreventExtensions(resources0.get(arg0));
671
+ return ret0 ? 1 : 0;
672
+ };
673
+ imports["rb-js-abi-host"]["reflect-set: func(target: handle<js-abi-value>, property-key: string, value: handle<js-abi-value>) -> variant { success(handle<js-abi-value>), failure(handle<js-abi-value>) }"] = function(arg0, arg1, arg2, arg3, arg4) {
674
+ const memory = get_export("memory");
675
+ const ptr0 = arg1;
676
+ const len0 = arg2;
677
+ const result0 = UTF8_DECODER.decode(new Uint8Array(memory.buffer, ptr0, len0));
678
+ const ret0 = obj.reflectSet(resources0.get(arg0), result0, resources0.get(arg3));
679
+ const variant1 = ret0;
680
+ switch (variant1.tag) {
681
+ case "success": {
682
+ const e = variant1.val;
683
+ data_view(memory).setInt8(arg4 + 0, 0, true);
684
+ data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
685
+ break;
1301
686
  }
1302
- else {
1303
- throw e;
687
+ case "failure": {
688
+ const e = variant1.val;
689
+ data_view(memory).setInt8(arg4 + 0, 1, true);
690
+ data_view(memory).setInt32(arg4 + 4, resources0.insert(e), true);
691
+ break;
1304
692
  }
1305
- }
1306
- }
1307
- const callRbMethod = (vm, privateObject, recv, callee, args) => {
1308
- const mid = vm.guest.rbIntern(callee + "\0");
1309
- return wrapRbOperation(vm, () => {
1310
- const [value, status] = vm.guest.rbFuncallvProtect(recv, mid, args);
1311
- checkStatusTag(status, vm, privateObject);
1312
- return value;
1313
- });
1314
- };
1315
- const evalRbCode = (vm, privateObject, code) => {
1316
- return wrapRbOperation(vm, () => {
1317
- const [value, status] = vm.guest.rbEvalStringProtect(code + "\0");
1318
- checkStatusTag(status, vm, privateObject);
1319
- return new RbValue(value, vm, privateObject);
1320
- });
1321
- };
1322
- /**
1323
- * Error class thrown by Ruby execution
1324
- */
1325
- class RbError extends Error {
1326
- /**
1327
- * @hideconstructor
1328
- */
1329
- constructor(message) {
1330
- super(message);
1331
- }
1332
- }
1333
- /**
1334
- * Error class thrown by Ruby execution when it is not possible to recover.
1335
- * This is usually caused when Ruby VM is in an inconsistent state.
1336
- */
1337
- class RbFatalError extends RbError {
1338
- /**
1339
- * @hideconstructor
1340
- */
1341
- constructor(message) {
1342
- super("Ruby Fatal Error: " + message);
1343
- }
1344
- }
1345
-
1346
- const DefaultRubyVM = async (rubyModule, options = {}) => {
1347
- var _a, _b;
1348
- const args = [];
1349
- const env = Object.entries((_a = options.env) !== null && _a !== void 0 ? _a : {}).map(([k, v]) => `${k}=${v}`);
1350
- const fds = [];
1351
- const wasi = new WASI(args, env, fds, { debug: false });
1352
- const vm = new RubyVM();
1353
- const imports = {
1354
- wasi_snapshot_preview1: wasi.wasiImport,
693
+ default:
694
+ throw new RangeError("invalid variant specified for JsAbiResult");
695
+ }
696
+ };
697
+ imports["rb-js-abi-host"]["reflect-set-prototype-of: func(target: handle<js-abi-value>, prototype: handle<js-abi-value>) -> bool"] = function(arg0, arg1) {
698
+ const ret0 = obj.reflectSetPrototypeOf(resources0.get(arg0), resources0.get(arg1));
699
+ return ret0 ? 1 : 0;
1355
700
  };
1356
- vm.addToImports(imports);
1357
- const printer = ((_b = options.consolePrint) !== null && _b !== void 0 ? _b : true) ? consolePrinter() : undefined;
1358
- printer === null || printer === void 0 ? void 0 : printer.addToImports(imports);
1359
- const instance = await WebAssembly.instantiate(rubyModule, imports);
1360
- await vm.setInstance(instance);
1361
- printer === null || printer === void 0 ? void 0 : printer.setMemory(instance.exports.memory);
1362
- wasi.initialize(instance);
1363
- vm.initialize();
1364
- return {
1365
- vm,
1366
- wasi,
1367
- instance,
701
+ if (!("canonical_abi" in imports)) imports["canonical_abi"] = {};
702
+
703
+ const resources0 = new Slab();
704
+ imports.canonical_abi["resource_drop_js-abi-value"] = (i) => {
705
+ const val = resources0.remove(i);
706
+ if (obj.dropJsAbiValue)
707
+ obj.dropJsAbiValue(val);
1368
708
  };
1369
- };
709
+ }
710
+
711
+ /**
712
+ * A Ruby VM instance
713
+ *
714
+ * @example
715
+ *
716
+ * const wasi = new WASI();
717
+ * const vm = new RubyVM();
718
+ * const imports = {
719
+ * wasi_snapshot_preview1: wasi.wasiImport,
720
+ * };
721
+ *
722
+ * vm.addToImports(imports);
723
+ *
724
+ * const instance = await WebAssembly.instantiate(rubyModule, imports);
725
+ * await vm.setInstance(instance);
726
+ * wasi.initialize(instance);
727
+ * vm.initialize();
728
+ *
729
+ */
730
+ class RubyVM {
731
+ constructor() {
732
+ this.instance = null;
733
+ this.interfaceState = {
734
+ hasJSFrameAfterRbFrame: false,
735
+ };
736
+ // Wrap exported functions from Ruby VM to prohibit nested VM operation
737
+ // if the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby.
738
+ const proxyExports = (exports) => {
739
+ const excludedMethods = [
740
+ "addToImports",
741
+ "instantiate",
742
+ "rbSetShouldProhibitRewind",
743
+ "rbGcDisable",
744
+ "rbGcEnable",
745
+ ];
746
+ const excluded = ["constructor"].concat(excludedMethods);
747
+ // wrap all methods in RbAbi.RbAbiGuest class
748
+ for (const key of Object.getOwnPropertyNames(RbAbiGuest.prototype)) {
749
+ if (excluded.includes(key)) {
750
+ continue;
751
+ }
752
+ const value = exports[key];
753
+ if (typeof value === "function") {
754
+ exports[key] = (...args) => {
755
+ const isNestedVMCall = this.interfaceState.hasJSFrameAfterRbFrame;
756
+ if (isNestedVMCall) {
757
+ const oldShouldProhibitRewind = this.guest.rbSetShouldProhibitRewind(true);
758
+ const oldIsDisabledGc = this.guest.rbGcDisable();
759
+ const result = Reflect.apply(value, exports, args);
760
+ this.guest.rbSetShouldProhibitRewind(oldShouldProhibitRewind);
761
+ if (!oldIsDisabledGc) {
762
+ this.guest.rbGcEnable();
763
+ }
764
+ return result;
765
+ }
766
+ else {
767
+ return Reflect.apply(value, exports, args);
768
+ }
769
+ };
770
+ }
771
+ }
772
+ return exports;
773
+ };
774
+ this.guest = proxyExports(new RbAbiGuest());
775
+ this.transport = new JsValueTransport();
776
+ this.exceptionFormatter = new RbExceptionFormatter();
777
+ }
778
+ /**
779
+ * Initialize the Ruby VM with the given command line arguments
780
+ * @param args The command line arguments to pass to Ruby. Must be
781
+ * an array of strings starting with the Ruby program name.
782
+ */
783
+ initialize(args = ["ruby.wasm", "-EUTF-8", "-e_=0"]) {
784
+ const c_args = args.map((arg) => arg + "\0");
785
+ this.guest.rubyInit();
786
+ this.guest.rubySysinit(c_args);
787
+ this.guest.rubyOptions(c_args);
788
+ this.eval(`require "/bundle/setup"`);
789
+ }
790
+ /**
791
+ * Set a given instance to interact JavaScript and Ruby's
792
+ * WebAssembly instance. This method must be called before calling
793
+ * Ruby API.
794
+ *
795
+ * @param instance The WebAssembly instance to interact with. Must
796
+ * be instantiated from a Ruby built with JS extension, and built
797
+ * with Reactor ABI instead of command line.
798
+ */
799
+ async setInstance(instance) {
800
+ this.instance = instance;
801
+ await this.guest.instantiate(instance);
802
+ }
803
+ /**
804
+ * Add intrinsic import entries, which is necessary to interact JavaScript
805
+ * and Ruby's WebAssembly instance.
806
+ * @param imports The import object to add to the WebAssembly instance
807
+ */
808
+ addToImports(imports) {
809
+ this.guest.addToImports(imports);
810
+ function wrapTry(f) {
811
+ return (...args) => {
812
+ try {
813
+ return { tag: "success", val: f(...args) };
814
+ }
815
+ catch (e) {
816
+ if (e instanceof RbFatalError) {
817
+ // RbFatalError should not be caught by Ruby because it Ruby VM
818
+ // can be already in an inconsistent state.
819
+ throw e;
820
+ }
821
+ return { tag: "failure", val: e };
822
+ }
823
+ };
824
+ }
825
+ imports["rb-js-abi-host"] = {
826
+ rb_wasm_throw_prohibit_rewind_exception: (messagePtr, messageLen) => {
827
+ const memory = this.instance.exports.memory;
828
+ const str = new TextDecoder().decode(new Uint8Array(memory.buffer, messagePtr, messageLen));
829
+ throw new RbFatalError("Ruby APIs that may rewind the VM stack are prohibited under nested VM operation " +
830
+ `(${str})\n` +
831
+ "Nested VM operation means that the call stack has sandwitched JS frames like JS -> Ruby -> JS -> Ruby " +
832
+ "caused by something like `window.rubyVM.eval(\"JS.global[:rubyVM].eval('Fiber.yield')\")`\n" +
833
+ "\n" +
834
+ "Please check your call stack and make sure that you are **not** doing any of the following inside the nested Ruby frame:\n" +
835
+ " 1. Switching fibers (e.g. Fiber#resume, Fiber.yield, and Fiber#transfer)\n" +
836
+ " Note that `evalAsync` JS API switches fibers internally\n" +
837
+ " 2. Raising uncaught exceptions\n" +
838
+ " Please catch all exceptions inside the nested operation\n" +
839
+ " 3. Calling Continuation APIs\n");
840
+ },
841
+ };
842
+ // NOTE: The GC may collect objects that are still referenced by Wasm
843
+ // locals because Asyncify cannot scan the Wasm stack above the JS frame.
844
+ // So we need to keep track whether the JS frame is sandwitched by Ruby
845
+ // frames or not, and prohibit nested VM operation if it is.
846
+ const proxyImports = (imports) => {
847
+ for (const [key, value] of Object.entries(imports)) {
848
+ if (typeof value === "function") {
849
+ imports[key] = (...args) => {
850
+ const oldValue = this.interfaceState.hasJSFrameAfterRbFrame;
851
+ this.interfaceState.hasJSFrameAfterRbFrame = true;
852
+ const result = Reflect.apply(value, imports, args);
853
+ this.interfaceState.hasJSFrameAfterRbFrame = oldValue;
854
+ return result;
855
+ };
856
+ }
857
+ }
858
+ return imports;
859
+ };
860
+ addRbJsAbiHostToImports(imports, proxyImports({
861
+ evalJs: wrapTry((code) => {
862
+ return Function(code)();
863
+ }),
864
+ isJs: (value) => {
865
+ // Just for compatibility with the old JS API
866
+ return true;
867
+ },
868
+ globalThis: () => {
869
+ if (typeof globalThis !== "undefined") {
870
+ return globalThis;
871
+ }
872
+ else if (typeof global !== "undefined") {
873
+ return global;
874
+ }
875
+ else if (typeof window !== "undefined") {
876
+ return window;
877
+ }
878
+ throw new Error("unable to locate global object");
879
+ },
880
+ intToJsNumber: (value) => {
881
+ return value;
882
+ },
883
+ floatToJsNumber: (value) => {
884
+ return value;
885
+ },
886
+ stringToJsString: (value) => {
887
+ return value;
888
+ },
889
+ boolToJsBool: (value) => {
890
+ return value;
891
+ },
892
+ procToJsFunction: (rawRbAbiValue) => {
893
+ const rbValue = this.rbValueOfPointer(rawRbAbiValue);
894
+ return (...args) => {
895
+ rbValue.call("call", ...args.map((arg) => this.wrap(arg)));
896
+ };
897
+ },
898
+ rbObjectToJsRbValue: (rawRbAbiValue) => {
899
+ return this.rbValueOfPointer(rawRbAbiValue);
900
+ },
901
+ jsValueToString: (value) => {
902
+ // According to the [spec](https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value)
903
+ // `String(value)` always returns a string.
904
+ return String(value);
905
+ },
906
+ jsValueToInteger(value) {
907
+ if (typeof value === "number") {
908
+ return { tag: "f64", val: value };
909
+ }
910
+ else if (typeof value === "bigint") {
911
+ return { tag: "bignum", val: BigInt(value).toString(10) + "\0" };
912
+ }
913
+ else if (typeof value === "string") {
914
+ return { tag: "bignum", val: value + "\0" };
915
+ }
916
+ else if (typeof value === "undefined") {
917
+ return { tag: "f64", val: 0 };
918
+ }
919
+ else {
920
+ return { tag: "f64", val: Number(value) };
921
+ }
922
+ },
923
+ exportJsValueToHost: (value) => {
924
+ // See `JsValueExporter` for the reason why we need to do this
925
+ this.transport.takeJsValue(value);
926
+ },
927
+ importJsValueFromHost: () => {
928
+ return this.transport.consumeJsValue();
929
+ },
930
+ instanceOf: (value, klass) => {
931
+ if (typeof klass === "function") {
932
+ return value instanceof klass;
933
+ }
934
+ else {
935
+ return false;
936
+ }
937
+ },
938
+ jsValueTypeof(value) {
939
+ return typeof value;
940
+ },
941
+ jsValueEqual(lhs, rhs) {
942
+ return lhs == rhs;
943
+ },
944
+ jsValueStrictlyEqual(lhs, rhs) {
945
+ return lhs === rhs;
946
+ },
947
+ reflectApply: wrapTry((target, thisArgument, args) => {
948
+ return Reflect.apply(target, thisArgument, args);
949
+ }),
950
+ reflectConstruct: function (target, args) {
951
+ throw new Error("Function not implemented.");
952
+ },
953
+ reflectDeleteProperty: function (target, propertyKey) {
954
+ throw new Error("Function not implemented.");
955
+ },
956
+ reflectGet: wrapTry((target, propertyKey) => {
957
+ return target[propertyKey];
958
+ }),
959
+ reflectGetOwnPropertyDescriptor: function (target, propertyKey) {
960
+ throw new Error("Function not implemented.");
961
+ },
962
+ reflectGetPrototypeOf: function (target) {
963
+ throw new Error("Function not implemented.");
964
+ },
965
+ reflectHas: function (target, propertyKey) {
966
+ throw new Error("Function not implemented.");
967
+ },
968
+ reflectIsExtensible: function (target) {
969
+ throw new Error("Function not implemented.");
970
+ },
971
+ reflectOwnKeys: function (target) {
972
+ throw new Error("Function not implemented.");
973
+ },
974
+ reflectPreventExtensions: function (target) {
975
+ throw new Error("Function not implemented.");
976
+ },
977
+ reflectSet: wrapTry((target, propertyKey, value) => {
978
+ return Reflect.set(target, propertyKey, value);
979
+ }),
980
+ reflectSetPrototypeOf: function (target, prototype) {
981
+ throw new Error("Function not implemented.");
982
+ },
983
+ }), (name) => {
984
+ return this.instance.exports[name];
985
+ });
986
+ }
987
+ /**
988
+ * Print the Ruby version to stdout
989
+ */
990
+ printVersion() {
991
+ this.guest.rubyShowVersion();
992
+ }
993
+ /**
994
+ * Runs a string of Ruby code from JavaScript
995
+ * @param code The Ruby code to run
996
+ * @returns the result of the last expression
997
+ *
998
+ * @example
999
+ * vm.eval("puts 'hello world'");
1000
+ * const result = vm.eval("1 + 2");
1001
+ * console.log(result.toString()); // 3
1002
+ *
1003
+ */
1004
+ eval(code) {
1005
+ return evalRbCode(this, this.privateObject(), code);
1006
+ }
1007
+ /**
1008
+ * Runs a string of Ruby code with top-level `JS::Object#await`
1009
+ * Returns a promise that resolves when execution completes.
1010
+ * @param code The Ruby code to run
1011
+ * @returns a promise that resolves to the result of the last expression
1012
+ *
1013
+ * @example
1014
+ * const text = await vm.evalAsync(`
1015
+ * require 'js'
1016
+ * response = JS.global.fetch('https://example.com').await
1017
+ * response.text.await
1018
+ * `);
1019
+ * console.log(text.toString()); // <html>...</html>
1020
+ */
1021
+ evalAsync(code) {
1022
+ const JS = this.eval("require 'js'; JS");
1023
+ return newRbPromise(this, this.privateObject(), (future) => {
1024
+ JS.call("__eval_async_rb", this.wrap(code), future);
1025
+ });
1026
+ }
1027
+ /**
1028
+ * Wrap a JavaScript value into a Ruby JS::Object
1029
+ * @param value The value to convert to RbValue
1030
+ * @returns the RbValue object representing the given JS value
1031
+ *
1032
+ * @example
1033
+ * const hash = vm.eval(`Hash.new`)
1034
+ * hash.call("store", vm.eval(`"key1"`), vm.wrap(new Object()));
1035
+ */
1036
+ wrap(value) {
1037
+ return this.transport.importJsValue(value, this);
1038
+ }
1039
+ /** @private */
1040
+ privateObject() {
1041
+ return {
1042
+ transport: this.transport,
1043
+ exceptionFormatter: this.exceptionFormatter,
1044
+ };
1045
+ }
1046
+ /** @private */
1047
+ rbValueOfPointer(pointer) {
1048
+ const abiValue = new RbAbiValue(pointer, this.guest);
1049
+ return new RbValue(abiValue, this, this.privateObject());
1050
+ }
1051
+ }
1052
+ /**
1053
+ * Export a JS value held by the Ruby VM to the JS environment.
1054
+ * This is implemented in a dirty way since wit cannot reference resources
1055
+ * defined in other interfaces.
1056
+ * In our case, we can't express `function(v: rb-abi-value) -> js-abi-value`
1057
+ * because `rb-js-abi-host.wit`, that defines `js-abi-value`, is implemented
1058
+ * by embedder side (JS) but `rb-abi-guest.wit`, that defines `rb-abi-value`
1059
+ * is implemented by guest side (Wasm).
1060
+ *
1061
+ * This class is a helper to export by:
1062
+ * 1. Call `function __export_to_js(v: rb-abi-value)` defined in guest from embedder side.
1063
+ * 2. Call `function takeJsValue(v: js-abi-value)` defined in embedder from guest side with
1064
+ * underlying JS value of given `rb-abi-value`.
1065
+ * 3. Then `takeJsValue` implementation escapes the given JS value to the `_takenJsValues`
1066
+ * stored in embedder side.
1067
+ * 4. Finally, embedder side can take `_takenJsValues`.
1068
+ *
1069
+ * Note that `exportJsValue` is not reentrant.
1070
+ *
1071
+ * @private
1072
+ */
1073
+ class JsValueTransport {
1074
+ constructor() {
1075
+ this._takenJsValue = null;
1076
+ }
1077
+ takeJsValue(value) {
1078
+ this._takenJsValue = value;
1079
+ }
1080
+ consumeJsValue() {
1081
+ return this._takenJsValue;
1082
+ }
1083
+ exportJsValue(value) {
1084
+ value.call("__export_to_js");
1085
+ return this._takenJsValue;
1086
+ }
1087
+ importJsValue(value, vm) {
1088
+ this._takenJsValue = value;
1089
+ return vm.eval('require "js"; JS::Object').call("__import_from_js");
1090
+ }
1091
+ }
1092
+ /**
1093
+ * A RbValue is an object that represents a value in Ruby
1094
+ */
1095
+ class RbValue {
1096
+ /**
1097
+ * @hideconstructor
1098
+ */
1099
+ constructor(inner, vm, privateObject) {
1100
+ this.inner = inner;
1101
+ this.vm = vm;
1102
+ this.privateObject = privateObject;
1103
+ }
1104
+ /**
1105
+ * Call a given method with given arguments
1106
+ *
1107
+ * @param callee name of the Ruby method to call
1108
+ * @param args arguments to pass to the method. Must be an array of RbValue
1109
+ * @returns The result of the method call as a new RbValue.
1110
+ *
1111
+ * @example
1112
+ * const ary = vm.eval("[1, 2, 3]");
1113
+ * ary.call("push", 4);
1114
+ * console.log(ary.call("sample").toString());
1115
+ */
1116
+ call(callee, ...args) {
1117
+ const innerArgs = args.map((arg) => arg.inner);
1118
+ return new RbValue(callRbMethod(this.vm, this.privateObject, this.inner, callee, innerArgs), this.vm, this.privateObject);
1119
+ }
1120
+ /**
1121
+ * Call a given method that may call `JS::Object#await` with given arguments
1122
+ *
1123
+ * @param callee name of the Ruby method to call
1124
+ * @param args arguments to pass to the method. Must be an array of RbValue
1125
+ * @returns A Promise that resolves to the result of the method call as a new RbValue.
1126
+ *
1127
+ * @example
1128
+ * const client = vm.eval(`
1129
+ * require 'js'
1130
+ * class HttpClient
1131
+ * def get(url)
1132
+ * JS.global.fetch(url).await
1133
+ * end
1134
+ * end
1135
+ * HttpClient.new
1136
+ * `);
1137
+ * const response = await client.callAsync("get", vm.eval(`"https://example.com"`));
1138
+ */
1139
+ callAsync(callee, ...args) {
1140
+ const JS = this.vm.eval("require 'js'; JS");
1141
+ return newRbPromise(this.vm, this.privateObject, (future) => {
1142
+ JS.call("__call_async_method", this, this.vm.wrap(callee), future, ...args);
1143
+ });
1144
+ }
1145
+ /**
1146
+ * @see {@link https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive}
1147
+ * @param hint Preferred type of the result primitive value. `"number"`, `"string"`, or `"default"`.
1148
+ */
1149
+ [Symbol.toPrimitive](hint) {
1150
+ if (hint === "string" || hint === "default") {
1151
+ return this.toString();
1152
+ }
1153
+ else if (hint === "number") {
1154
+ return null;
1155
+ }
1156
+ return null;
1157
+ }
1158
+ /**
1159
+ * Returns a string representation of the value by calling `to_s`
1160
+ */
1161
+ toString() {
1162
+ const rbString = callRbMethod(this.vm, this.privateObject, this.inner, "to_s", []);
1163
+ return this.vm.guest.rstringPtr(rbString);
1164
+ }
1165
+ /**
1166
+ * Returns a JavaScript object representation of the value
1167
+ * by calling `to_js`.
1168
+ *
1169
+ * Returns null if the value is not convertible to a JavaScript object.
1170
+ */
1171
+ toJS() {
1172
+ const JS = this.vm.eval("JS");
1173
+ const jsValue = JS.call("try_convert", this);
1174
+ if (jsValue.call("nil?").toString() === "true") {
1175
+ return null;
1176
+ }
1177
+ return this.privateObject.transport.exportJsValue(jsValue);
1178
+ }
1179
+ }
1180
+ var ruby_tag_type;
1181
+ (function (ruby_tag_type) {
1182
+ ruby_tag_type[ruby_tag_type["None"] = 0] = "None";
1183
+ ruby_tag_type[ruby_tag_type["Return"] = 1] = "Return";
1184
+ ruby_tag_type[ruby_tag_type["Break"] = 2] = "Break";
1185
+ ruby_tag_type[ruby_tag_type["Next"] = 3] = "Next";
1186
+ ruby_tag_type[ruby_tag_type["Retry"] = 4] = "Retry";
1187
+ ruby_tag_type[ruby_tag_type["Redo"] = 5] = "Redo";
1188
+ ruby_tag_type[ruby_tag_type["Raise"] = 6] = "Raise";
1189
+ ruby_tag_type[ruby_tag_type["Throw"] = 7] = "Throw";
1190
+ ruby_tag_type[ruby_tag_type["Fatal"] = 8] = "Fatal";
1191
+ ruby_tag_type[ruby_tag_type["Mask"] = 15] = "Mask";
1192
+ })(ruby_tag_type || (ruby_tag_type = {}));
1193
+ class RbExceptionFormatter {
1194
+ constructor() {
1195
+ this.literalsCache = null;
1196
+ this.isFormmatting = false;
1197
+ }
1198
+ format(error, vm, privateObject) {
1199
+ // All Ruby exceptions raised during formatting exception message should
1200
+ // be caught and return a fallback message.
1201
+ // Therefore, we don't need to worry about infinite recursion here ideally
1202
+ // but checking re-entrancy just in case.
1203
+ class RbExceptionFormatterError extends Error {
1204
+ }
1205
+ if (this.isFormmatting) {
1206
+ throw new RbExceptionFormatterError("Unexpected exception occurred during formatting exception message");
1207
+ }
1208
+ this.isFormmatting = true;
1209
+ try {
1210
+ return this._format(error, vm, privateObject);
1211
+ }
1212
+ finally {
1213
+ this.isFormmatting = false;
1214
+ }
1215
+ }
1216
+ _format(error, vm, privateObject) {
1217
+ const [zeroLiteral, oneLiteral, newLineLiteral] = (() => {
1218
+ if (this.literalsCache == null) {
1219
+ const zeroOneNewLine = [
1220
+ evalRbCode(vm, privateObject, "0"),
1221
+ evalRbCode(vm, privateObject, "1"),
1222
+ evalRbCode(vm, privateObject, `"\n"`),
1223
+ ];
1224
+ this.literalsCache = zeroOneNewLine;
1225
+ return zeroOneNewLine;
1226
+ }
1227
+ else {
1228
+ return this.literalsCache;
1229
+ }
1230
+ })();
1231
+ let className;
1232
+ let backtrace;
1233
+ let message;
1234
+ try {
1235
+ className = error.call("class").toString();
1236
+ }
1237
+ catch (e) {
1238
+ className = "unknown";
1239
+ }
1240
+ try {
1241
+ message = error.toString();
1242
+ }
1243
+ catch (e) {
1244
+ message = "unknown";
1245
+ }
1246
+ try {
1247
+ backtrace = error.call("backtrace");
1248
+ }
1249
+ catch (e) {
1250
+ return this.formatString(className, message);
1251
+ }
1252
+ if (backtrace.call("nil?").toString() === "true") {
1253
+ return this.formatString(className, message);
1254
+ }
1255
+ try {
1256
+ const firstLine = backtrace.call("at", zeroLiteral);
1257
+ const restLines = backtrace
1258
+ .call("drop", oneLiteral)
1259
+ .call("join", newLineLiteral);
1260
+ return this.formatString(className, message, [
1261
+ firstLine.toString(),
1262
+ restLines.toString(),
1263
+ ]);
1264
+ }
1265
+ catch (e) {
1266
+ return this.formatString(className, message);
1267
+ }
1268
+ }
1269
+ formatString(klass, message, backtrace) {
1270
+ if (backtrace) {
1271
+ return `${backtrace[0]}: ${message} (${klass})\n${backtrace[1]}`;
1272
+ }
1273
+ else {
1274
+ return `${klass}: ${message}`;
1275
+ }
1276
+ }
1277
+ }
1278
+ const checkStatusTag = (rawTag, vm, privateObject) => {
1279
+ switch (rawTag & ruby_tag_type.Mask) {
1280
+ case ruby_tag_type.None:
1281
+ break;
1282
+ case ruby_tag_type.Return:
1283
+ throw new RbError("unexpected return");
1284
+ case ruby_tag_type.Next:
1285
+ throw new RbError("unexpected next");
1286
+ case ruby_tag_type.Break:
1287
+ throw new RbError("unexpected break");
1288
+ case ruby_tag_type.Redo:
1289
+ throw new RbError("unexpected redo");
1290
+ case ruby_tag_type.Retry:
1291
+ throw new RbError("retry outside of rescue clause");
1292
+ case ruby_tag_type.Throw:
1293
+ throw new RbError("unexpected throw");
1294
+ case ruby_tag_type.Raise:
1295
+ case ruby_tag_type.Fatal:
1296
+ const error = new RbValue(vm.guest.rbErrinfo(), vm, privateObject);
1297
+ if (error.call("nil?").toString() === "true") {
1298
+ throw new RbError("no exception object");
1299
+ }
1300
+ // clear errinfo if got exception due to no rb_jump_tag
1301
+ vm.guest.rbClearErrinfo();
1302
+ throw new RbError(privateObject.exceptionFormatter.format(error, vm, privateObject));
1303
+ default:
1304
+ throw new RbError(`unknown error tag: ${rawTag}`);
1305
+ }
1306
+ };
1307
+ function wrapRbOperation(vm, body) {
1308
+ try {
1309
+ return body();
1310
+ }
1311
+ catch (e) {
1312
+ if (e instanceof RbError) {
1313
+ throw e;
1314
+ }
1315
+ // All JS exceptions triggered by Ruby code are translated to Ruby exceptions,
1316
+ // so non-RbError exceptions are unexpected.
1317
+ vm.guest.rbVmBugreport();
1318
+ if (e instanceof WebAssembly.RuntimeError && e.message === "unreachable") {
1319
+ const error = new RbError(`Something went wrong in Ruby VM: ${e}`);
1320
+ error.stack = e.stack;
1321
+ throw error;
1322
+ }
1323
+ else {
1324
+ throw e;
1325
+ }
1326
+ }
1327
+ }
1328
+ const callRbMethod = (vm, privateObject, recv, callee, args) => {
1329
+ const mid = vm.guest.rbIntern(callee + "\0");
1330
+ return wrapRbOperation(vm, () => {
1331
+ const [value, status] = vm.guest.rbFuncallvProtect(recv, mid, args);
1332
+ checkStatusTag(status, vm, privateObject);
1333
+ return value;
1334
+ });
1335
+ };
1336
+ const evalRbCode = (vm, privateObject, code) => {
1337
+ return wrapRbOperation(vm, () => {
1338
+ const [value, status] = vm.guest.rbEvalStringProtect(code + "\0");
1339
+ checkStatusTag(status, vm, privateObject);
1340
+ return new RbValue(value, vm, privateObject);
1341
+ });
1342
+ };
1343
+ function newRbPromise(vm, privateObject, body) {
1344
+ return new Promise((resolve, reject) => {
1345
+ const future = vm.wrap({
1346
+ resolve,
1347
+ reject: (error) => {
1348
+ const rbError = new RbError(privateObject.exceptionFormatter.format(error, vm, privateObject));
1349
+ reject(rbError);
1350
+ },
1351
+ });
1352
+ body(future);
1353
+ });
1354
+ }
1355
+ /**
1356
+ * Error class thrown by Ruby execution
1357
+ */
1358
+ class RbError extends Error {
1359
+ /**
1360
+ * @hideconstructor
1361
+ */
1362
+ constructor(message) {
1363
+ super(message);
1364
+ }
1365
+ }
1366
+ /**
1367
+ * Error class thrown by Ruby execution when it is not possible to recover.
1368
+ * This is usually caused when Ruby VM is in an inconsistent state.
1369
+ */
1370
+ class RbFatalError extends RbError {
1371
+ /**
1372
+ * @hideconstructor
1373
+ */
1374
+ constructor(message) {
1375
+ super("Ruby Fatal Error: " + message);
1376
+ }
1377
+ }
1378
+
1379
+ const DefaultRubyVM = async (rubyModule, options = {}) => {
1380
+ var _a, _b;
1381
+ const args = [];
1382
+ const env = Object.entries((_a = options.env) !== null && _a !== void 0 ? _a : {}).map(([k, v]) => `${k}=${v}`);
1383
+ const fds = [];
1384
+ const wasi = new WASI(args, env, fds, { debug: false });
1385
+ const vm = new RubyVM();
1386
+ const imports = {
1387
+ wasi_snapshot_preview1: wasi.wasiImport,
1388
+ };
1389
+ vm.addToImports(imports);
1390
+ const printer = ((_b = options.consolePrint) !== null && _b !== void 0 ? _b : true) ? consolePrinter() : undefined;
1391
+ printer === null || printer === void 0 ? void 0 : printer.addToImports(imports);
1392
+ const instance = await WebAssembly.instantiate(rubyModule, imports);
1393
+ await vm.setInstance(instance);
1394
+ printer === null || printer === void 0 ? void 0 : printer.setMemory(instance.exports.memory);
1395
+ wasi.initialize(instance);
1396
+ vm.initialize();
1397
+ return {
1398
+ vm,
1399
+ wasi,
1400
+ instance,
1401
+ };
1402
+ };
1370
1403
 
1371
- exports.DefaultRubyVM = DefaultRubyVM;
1404
+ exports.DefaultRubyVM = DefaultRubyVM;
1372
1405
 
1373
1406
  }));