quickjs-emscripten-sync 1.5.1 → 1.6.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.
- package/dist/index.d.ts +128 -7
- package/dist/quickjs-emscripten-sync.mjs +694 -479
- package/dist/quickjs-emscripten-sync.umd.js +17 -10
- package/package.json +10 -10
- package/src/contextex.test.ts +43 -0
- package/src/contextex.ts +65 -0
- package/src/edge.test.ts +70 -0
- package/src/index.test.ts +324 -28
- package/src/index.ts +142 -2
- package/src/marshal/index.test.ts +2 -2
- package/src/vmmap.ts +1 -1
- package/src/wrapper.ts +44 -32
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(m,v){typeof exports=="object"&&typeof module!="undefined"?v(exports):typeof define=="function"&&define.amd?define(["exports"],v):(m=typeof globalThis!="undefined"?globalThis:m||self,v(m.QuickjsEmscriptenSync={}))})(this,(function(m){"use strict";var ve=Object.defineProperty;var we=(m,v,j)=>v in m?ve(m,v,{enumerable:!0,configurable:!0,writable:!0,value:j}):m[v]=j;var c=(m,v,j)=>we(m,typeof v!="symbol"?v+"":v,j);const v=n=>{const e=new j(n);return new Proxy(n,{get(t,r,s){return r in e?e[r]:Reflect.get(t,r,s)}})};class j{constructor(e){c(this,"context");c(this,"fn");c(this,"fnGenerator");c(this,"fnCounter",Number.MIN_SAFE_INTEGER);c(this,"fnMap",new Map);c(this,"newFunction",(e,t)=>{this.fnCounter++;const r=this.fnCounter;return this.fnMap.set(r,t),this.context.unwrapResult(this.context.callFunction(this.fnGenerator,this.context.undefined,this.context.newString(e),this.context.newNumber(t.length),this.context.newNumber(r),this.fn))});this.context=e;const t=this.fnMap;this.fn=this.context.newFunction("",function(r,...s){const o=e.getNumber(r),i=t.get(o);if(!i)throw new Error("function is not registered");return i.call(this,...s)}),this.fnGenerator=e.unwrapResult(e.evalCode(`((name, length, id, f) => {
|
|
2
|
+
const fn = function(...args) {
|
|
3
|
+
return f.call(this, id, ...args);
|
|
4
|
+
};
|
|
5
|
+
fn.name = name;
|
|
6
|
+
fn.length = length;
|
|
7
|
+
return fn;
|
|
8
|
+
})`))}disposeEx(){this.fnGenerator.dispose(),this.fn.dispose()}}const k=[[Symbol,"Symbol"],[Symbol.prototype,"Symbol.prototype"],[Object,"Object"],[Object.prototype,"Object.prototype"],[Function,"Function"],[Function.prototype,"Function.prototype"],[Boolean,"Boolean"],[Boolean.prototype,"Boolean.prototype"],[Array,"Array"],[Array.prototype,"Array.prototype"],[Error,"Error"],[Error.prototype,"Error.prototype"],[EvalError,"EvalError"],[EvalError.prototype,"EvalError.prototype"],[RangeError,"RangeError"],[RangeError.prototype,"RangeError.prototype"],[ReferenceError,"ReferenceError"],[ReferenceError.prototype,"ReferenceError.prototype"],[SyntaxError,"SyntaxError"],[SyntaxError.prototype,"SyntaxError.prototype"],[TypeError,"TypeError"],[TypeError.prototype,"TypeError.prototype"],[URIError,"URIError"],[URIError.prototype,"URIError.prototype"],...Object.getOwnPropertyNames(Symbol).filter(n=>typeof Symbol[n]=="symbol").map(n=>[Symbol[n],`Symbol.${n}`])];function J(n,e){const t=n.unwrapResult(n.evalCode(e)),r=(s,...o)=>n.unwrapResult(n.callFunction(t,s!=null?s:n.undefined,...o));return r.dispose=()=>t.dispose(),r.alive=!0,Object.defineProperty(r,"alive",{get:()=>t.alive}),r}function _(n,e,t,...r){const s=J(n,e);try{return s(t,...r)}finally{s.dispose()}}function C(n,e,t){return n.dump(_(n,"Object.is",void 0,e,t))}function W(n,e,t){return n.dump(_(n,"(a, b) => a instanceof b",void 0,e,t))}function F(n,e){return n.dump(_(n,'a => typeof a === "object" && a !== null || typeof a === "function"',void 0,e))}function H(n,e){const t=JSON.stringify(e);return t?_(n,"JSON.parse",void 0,n.newString(t)):n.undefined}function z(n,e){try{return e(n)}finally{for(const t of n)t.alive&&t.dispose()}}function $([n,e],t){try{return t(n)}finally{e&&n.dispose()}}function S(n,e){try{return e(...n.map(t=>t[0]))}finally{for(const[t,r]of n)r&&t.dispose()}}function q(n){return"handle"in n}function L(n){return q(n)?n.handle:n}function Q(n,e,t,r){var o;let s;for(const i of r)if(s=i(e,n),s)break;return s?(o=t(e,s))!=null?o:s:void 0}function V(n,e){return typeof n!="symbol"?void 0:_(e,"d => Symbol(d)",void 0,n.description?e.newString(n.description):e.undefined)}function X(n,e){return n instanceof Date?_(e,"d => new Date(d)",void 0,e.newNumber(n.getTime())):void 0}const Y=[V,X];function N(n){return typeof n=="function"&&/^class\s/.test(Function.prototype.toString.call(n))}function g(n){return typeof n=="function"||typeof n=="object"&&n!==null}function O(n,e){const t=new Set,r=s=>{if(!(!g(s)||t.has(s)||(e==null?void 0:e(s,t))===!1)){if(t.add(s),Array.isArray(s)){for(const o of s)r(o);return}if(typeof s=="object"){const o=Object.getPrototypeOf(s);o&&o!==Object.prototype&&r(o)}for(const o of Object.values(Object.getOwnPropertyDescriptors(s)))"value"in o&&r(o.value),"get"in o&&r(o.get),"set"in o&&r(o.set)}};return r(n),t}function Z(n,e){return O(n,e?(t,r)=>r.size<e:void 0).size}function K(){let n=()=>{},e=()=>{};return{promise:new Promise((r,s)=>{n=r,e=s}),resolve:n,reject:e}}function A(n,e,t,r){const s=n.newObject(),o=(a,u)=>{const p=r(a),l=typeof u.value=="undefined"?void 0:r(u.value),f=typeof u.get=="undefined"?void 0:r(u.get),d=typeof u.set=="undefined"?void 0:r(u.set);n.newObject().consume(h=>{Object.entries(u).forEach(([y,b])=>{const w=y==="value"?l:y==="get"?f:y==="set"?d:b?n.true:n.false;w&&n.setProp(h,y,w)}),n.setProp(s,p,h)})},i=Object.getOwnPropertyDescriptors(e);Object.entries(i).forEach(([a,u])=>o(a,u)),Object.getOwnPropertySymbols(i).forEach(a=>o(a,i[a])),_(n,"Object.defineProperties",void 0,t,s).dispose(),s.dispose()}function x(n,e,t,r,s,o){var u;if(typeof e!="function")return;const i=n.newFunction(e.name,function(...p){const l=r(this),f=p.map(d=>r(d));if(N(e)&&g(l)){const d=new e(...f);return Object.entries(d).forEach(([h,y])=>{n.setProp(this,h,t(y))}),this}return t(o?o(e,l,f):e.apply(l,f))}).consume(p=>_(n,`Cls => {
|
|
2
9
|
const fn = function(...args) { return Cls.apply(this, args); };
|
|
3
10
|
fn.name = Cls.name;
|
|
4
11
|
fn.length = Cls.length;
|
|
5
12
|
return fn;
|
|
6
|
-
}`,void 0,p)),
|
|
13
|
+
}`,void 0,p)),a=(u=s(e,i))!=null?u:i;return A(n,e,i,t),a}function ee(n,e,t){var o;const r=H(n,e);return(o=t(e,r))!=null?o:r}function te(n,e,t,r){var u;if(typeof e!="object"||e===null)return;const s=Array.isArray(e)?n.newArray():n.newObject(),o=(u=r(e,s))!=null?u:s,i=Object.getPrototypeOf(e),a=i&&i!==Object.prototype&&i!==Array.prototype?t(i):void 0;return a&&_(n,"Object.setPrototypeOf",void 0,o,a).dispose(),A(n,e,s,t),o}function ne(n,e){switch(typeof e){case"undefined":return n.undefined;case"number":return n.newNumber(e);case"string":return n.newString(e);case"boolean":return e?n.true:n.false;case"object":return e===null?n.null:void 0}}function re(n,e,t,r){var o;if(!(e instanceof Promise))return;const s=n.newPromise();return e.then(i=>s.resolve(t(i)),i=>s.reject(t(i))),(o=r(e,s))!=null?o:s.handle}function E(n,e){var l,f,d,h,y;const{ctx:t,unmarshal:r,isMarshalable:s,find:o,pre:i}=e;{const b=ne(t,n);if(b)return b}{const b=o(n);if(b)return b}const a=s==null?void 0:s(n);if(a===!1)return t.undefined;const u=(b,w)=>i(b,w,a);if(a==="json")return ee(t,n,u);const p=b=>E(b,e);return(y=(h=(d=(f=Q(t,n,u,[...Y,...(l=e.custom)!=null?l:[]]))!=null?f:re(t,n,p,u))!=null?d:x(t,n,p,r,u,e.preApply))!=null?h:te(t,n,p,u))!=null?y:t.undefined}function se(n,e,t,r){var o;let s;for(const i of r)if(s=i(e,n),s)break;return s?(o=t(s,e))!=null?o:s:void 0}function oe(n,e){if(e.typeof(n)!=="symbol")return;const t=e.getString(e.getProp(n,"description"));return Symbol(t)}function ie(n,e){if(!e.dump(_(e,"a => a instanceof Date",void 0,n)))return;const t=e.getNumber(_(e,"a => a.getTime()",void 0,n));return new Date(t)}const ue=[oe,ie];function D(n,e,t,r){n.newFunction("",(s,o)=>{const[i]=r(s);if(typeof i!="string"&&typeof i!="number"&&typeof i!="symbol")return;const a=[["value",!0],["get",!0],["set",!0],["configurable",!1],["enumerable",!1],["writable",!1]].reduce((u,[p,l])=>{const f=n.getProp(o,p),d=n.typeof(f);if(d==="undefined")return u;if(!l&&d==="boolean")return u[p]=n.dump(n.getProp(o,p)),u;const[h,y]=r(f);return y&&f.dispose(),u[p]=h,u},{});Object.defineProperty(t,i,a)}).consume(s=>{_(n,`(o, fn) => {
|
|
7
14
|
const descs = Object.getOwnPropertyDescriptors(o);
|
|
8
15
|
Object.entries(descs).forEach(([k, v]) => fn(k, v));
|
|
9
16
|
Object.getOwnPropertySymbols(descs).forEach(k => fn(k, descs[k]));
|
|
10
|
-
}`,void 0,e,
|
|
17
|
+
}`,void 0,e,s).dispose()})}function ae(n,e,t,r,s){var a;if(n.typeof(e)!=="function")return;const o=function(...u){return S([t(this),...u.map(p=>t(p))],(p,...l)=>{if(new.target){const[y]=r(_(n,"(Cls, ...args) => new Cls(...args)",p,e,...l));return Object.defineProperties(this,Object.getOwnPropertyDescriptors(y)),this}const f=n.unwrapResult(n.callFunction(e,p,...l)),[d,h]=r(f);return h&&f.dispose(),d})},i=(a=s(o,e))!=null?a:o;return D(n,e,o,r),i}function pe(n,e,t,r){var a;if(n.typeof(e)!=="object"||n.unwrapResult(n.evalCode("o => o === null")).consume(u=>n.dump(n.unwrapResult(n.callFunction(u,n.undefined,e)))))return;const s=_(n,"Array.isArray",void 0,e).consume(u=>n.dump(u))?[]:{},o=(a=r(s,e))!=null?a:s,i=_(n,`o => {
|
|
11
18
|
const p = Object.getPrototypeOf(o);
|
|
12
19
|
return !p || p === Object.prototype || p === Array.prototype ? undefined : p;
|
|
13
|
-
}`,void 0,e).consume(
|
|
20
|
+
}`,void 0,e).consume(u=>{if(n.typeof(u)==="undefined")return;const[p]=t(u);return p});return typeof i=="object"&&Object.setPrototypeOf(o,i),D(n,e,s,t),o}function fe(n,e){const t=n.typeof(e);return t==="undefined"||t==="number"||t==="string"||t==="boolean"?[n.dump(e),!0]:t==="object"&&n.unwrapResult(n.evalCode("a => a === null")).consume(s=>n.dump(n.unwrapResult(n.callFunction(s,n.undefined,e))))?[null,!0]:[void 0,!1]}function ce(n,e,t,r){var p;if(!le(n,e))return;const s=K(),[o,i]=t(s.resolve),[a,u]=t(s.reject);return _(n,"(p, res, rej) => { p.then(res, rej); }",void 0,e,o,a),i&&o.dispose(),u&&a.dispose(),(p=r(s.promise,e))!=null?p:s.promise}function le(n,e){return e.owner?n.unwrapResult(n.evalCode("Promise")).consume(t=>e.owner?W(n,e,t):!1):!1}function B(n,e){const[t]=T(n,e);return t}function T(n,e){var u,p,l,f;const{ctx:t,marshal:r,find:s,pre:o}=e;{const[d,h]=fe(t,n);if(h)return[d,!1]}{const d=s(n);if(d)return[d,!0]}const i=d=>T(d,e);return[(f=(l=(p=se(t,n,o,[...ue,...(u=e.custom)!=null?u:[]]))!=null?p:ce(t,n,r,o))!=null?l:ae(t,n,r,i,o))!=null?f:pe(t,n,i,o),!1]}class M{constructor(e){c(this,"ctx");c(this,"_map1",new Map);c(this,"_map2",new Map);c(this,"_map3",new Map);c(this,"_map4",new Map);c(this,"_counterMap",new Map);c(this,"_disposables",new Set);c(this,"_mapGet");c(this,"_mapSet");c(this,"_mapDelete");c(this,"_mapClear");c(this,"_counter",Number.MIN_SAFE_INTEGER);this.ctx=e;const t=e.unwrapResult(e.evalCode(`() => {
|
|
14
21
|
const mapSym = new Map();
|
|
15
22
|
let map = new WeakMap();
|
|
16
23
|
let map2 = new WeakMap();
|
|
@@ -33,7 +40,7 @@
|
|
|
33
40
|
map2 = new WeakMap();
|
|
34
41
|
}
|
|
35
42
|
};
|
|
36
|
-
}`)).consume(
|
|
43
|
+
}`)).consume(r=>this._call(r,void 0));this._mapGet=e.getProp(t,"get"),this._mapSet=e.getProp(t,"set"),this._mapDelete=e.getProp(t,"delete"),this._mapClear=e.getProp(t,"clear"),t.dispose(),this._disposables.add(this._mapGet),this._disposables.add(this._mapSet),this._disposables.add(this._mapDelete),this._disposables.add(this._mapClear)}set(e,t,r,s){var a;if(!t.alive||s&&!s.alive)return!1;const o=(a=this.get(e))!=null?a:this.get(r);if(o)return o===t||o===s;const i=this._counter++;return this._map1.set(e,i),this._map3.set(i,t),this._counterMap.set(i,e),r&&(this._map2.set(r,i),s&&this._map4.set(i,s)),this.ctx.newNumber(i).consume(u=>{this._call(this._mapSet,void 0,t,u,s!=null?s:this.ctx.undefined)}),!0}merge(e){if(e)for(const t of e)t&&t[1]&&this.set(t[0],t[1],t[2],t[3])}get(e){var s;const t=(s=this._map1.get(e))!=null?s:this._map2.get(e),r=typeof t=="number"?this._map3.get(t):void 0;if(r){if(!r.alive){this.delete(e);return}return r}}getByHandle(e){if(e.alive)return this._counterMap.get(this.ctx.getNumber(this._call(this._mapGet,void 0,e)))}has(e){return!!this.get(e)}hasHandle(e){return typeof this.getByHandle(e)!="undefined"}keys(){return this._map1.keys()}delete(e,t){var i;const r=(i=this._map1.get(e))!=null?i:this._map2.get(e);if(typeof r=="undefined")return;const s=this._map3.get(r),o=this._map4.get(r);this._call(this._mapDelete,void 0,...[s,o].filter(a=>!!(a!=null&&a.alive))),this._map1.delete(e),this._map2.delete(e),this._map3.delete(r),this._map4.delete(r);for(const[a,u]of this._map1)if(u===r){this._map1.delete(a);break}for(const[a,u]of this._map2)if(u===r){this._map2.delete(a);break}for(const[a,u]of this._counterMap)if(u===e){this._counterMap.delete(a);break}t&&(s!=null&&s.alive&&s.dispose(),o!=null&&o.alive&&o.dispose())}deleteByHandle(e,t){const r=this.getByHandle(e);typeof r!="undefined"&&this.delete(r,t)}clear(){this._counter=0,this._map1.clear(),this._map2.clear(),this._map3.clear(),this._map4.clear(),this._counterMap.clear(),this._mapClear.alive&&this._call(this._mapClear,void 0)}dispose(){for(const e of this._disposables.values())e.alive&&e.dispose();for(const e of this._map3.values())e.alive&&e.dispose();for(const e of this._map4.values())e.alive&&e.dispose();this._disposables.clear(),this.clear()}get size(){return this._map1.size}[Symbol.iterator](){const e=this._map1.keys();return{next:()=>{for(;;){const t=e.next();if(t.done)return{value:void 0,done:!0};const r=this._map1.get(t.value);if(typeof r=="undefined")continue;const s=this._map3.get(r),o=this._map4.get(r);if(!s)continue;const i=this._get2(r);return{value:[t.value,s,i,o],done:!1}}}}}_get2(e){for(const[t,r]of this._map2)if(r===e)return t}_call(e,t,...r){return this.ctx.unwrapResult(this.ctx.callFunction(e,typeof t=="undefined"?this.ctx.undefined:t,...r))}}function de(n,e,t,r,s,o,i){if(!g(e)||e instanceof Promise||e instanceof Date||i&&!i(e))return;if(he(e,t))return e;const a=new Proxy(e,{get(u,p){return p===t?u:Reflect.get(u,p)},set(u,p,l,f){var y;const d=P(l,t),h=(y=o==null?void 0:o(f))!=null?y:"host";return h!=="vm"&&!Reflect.set(u,p,d,f)||h==="host"||!n.alive||S([s(f),s(p),s(d)],(b,w,I)=>{const[G,_e]=R(n,b,r);_e?G.consume(be=>n.setProp(be,w,I)):n.setProp(G,w,I)}),!0},deleteProperty(u,p){var f;const l=(f=o==null?void 0:o(a))!=null?f:"host";return S([s(a),s(p)],(d,h)=>{const[y,b]=R(n,d,r);if(l==="vm"||Reflect.deleteProperty(u,p)){if(l==="host"||!n.alive)return!0;b?y.consume(w=>_(n,"(a, b) => delete a[b]",void 0,w,h)):_(n,"(a, b) => delete a[b]",void 0,y,h)}return!0})}});return a}function me(n,e,t,r,s,o,i){if(!F(n,e)||i&&!i(e,n))return[void 0,!1];if(U(n,e,r))return[e,!1];const a=l=>{const f=o==null?void 0:o(s(l));return typeof f=="string"?n.newString(f):n.undefined},u=(l,f,d)=>{const h=s(l);if(!h)return;const y=s(f);if(y==="__proto__")return;const b=s(d);P(h,t)[y]=b},p=(l,f)=>{const d=s(l);if(!d)return;const h=s(f);delete P(d,t)[h]};return n.newFunction("proxyFuncs",(l,...f)=>{switch(n.getNumber(l)){case 1:return a(f[0]);case 2:return u(f[0],f[1],f[2]);case 3:return p(f[0],f[1])}return n.undefined}).consume(l=>[_(n,`(target, sym, proxyFuncs) => {
|
|
37
44
|
const rec = new Proxy(target, {
|
|
38
45
|
get(obj, key, receiver) {
|
|
39
46
|
return key === sym ? obj : Reflect.get(obj, key, receiver)
|
|
@@ -42,23 +49,23 @@
|
|
|
42
49
|
const v = typeof value === "object" && value !== null || typeof value === "function"
|
|
43
50
|
? value[sym] ?? value
|
|
44
51
|
: value;
|
|
45
|
-
const sync =
|
|
52
|
+
const sync = proxyFuncs(1, receiver) ?? "vm";
|
|
46
53
|
if (sync === "host" || Reflect.set(obj, key, v, receiver)) {
|
|
47
54
|
if (sync !== "vm") {
|
|
48
|
-
|
|
55
|
+
proxyFuncs(2, receiver, key, v);
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
58
|
return true;
|
|
52
59
|
},
|
|
53
60
|
deleteProperty(obj, key) {
|
|
54
|
-
const sync =
|
|
61
|
+
const sync = proxyFuncs(1, rec) ?? "vm";
|
|
55
62
|
if (sync === "host" || Reflect.deleteProperty(obj, key)) {
|
|
56
63
|
if (sync !== "vm") {
|
|
57
|
-
|
|
64
|
+
proxyFuncs(3, rec, key);
|
|
58
65
|
}
|
|
59
66
|
}
|
|
60
67
|
return true;
|
|
61
68
|
},
|
|
62
69
|
});
|
|
63
70
|
return rec;
|
|
64
|
-
}`,void 0,e,
|
|
71
|
+
}`,void 0,e,r,l),!0])}function P(n,e){var t;return g(n)&&(t=n[e])!=null?t:n}function R(n,e,t){return U(n,e,t)?[n.getProp(e,t),!0]:[e,!1]}function he(n,e){return g(n)&&!!n[e]}function U(n,e,t){return!!n.dump(_(n,'(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]',void 0,e,t))}class ye{constructor(e,t){c(this,"context");c(this,"_map");c(this,"_registeredMap");c(this,"_registeredMapDispose",new Set);c(this,"_sync",new Set);c(this,"_temporalSync",new Set);c(this,"_symbol",Symbol());c(this,"_symbolHandle");c(this,"_options");c(this,"_isMarshalable",e=>{var r,s;const t=(r=this._options)==null?void 0:r.isMarshalable;return(s=typeof t=="function"?t(this._unwrap(e)):t)!=null?s:"json"});c(this,"_marshalFind",e=>{var s,o,i;const t=this._unwrap(e);return(i=(o=(s=this._registeredMap.get(e))!=null?s:t!==e?this._registeredMap.get(t):void 0)!=null?o:this._map.get(e))!=null?i:t!==e?this._map.get(t):void 0});c(this,"_marshalPre",(e,t,r)=>{var s;if(r!=="json")return(s=this._register(e,L(t),this._map))==null?void 0:s[1]});c(this,"_marshalPreApply",(e,t,r)=>{const s=g(t)?this._unwrap(t):void 0;s&&this._temporalSync.add(s);try{return e.apply(t,r)}finally{s&&this._temporalSync.delete(s)}});c(this,"_marshal",e=>{var s,o;const t=this._registeredMap.get(e);if(t)return[t,!1];const r=E((s=this._wrap(e))!=null?s:e,{ctx:this.context,unmarshal:this._unmarshal,isMarshalable:this._isMarshalable,find:this._marshalFind,pre:this._marshalPre,preApply:this._marshalPreApply,custom:(o=this._options)==null?void 0:o.customMarshaller});return[r,!this._map.hasHandle(r)]});c(this,"_preUnmarshal",(e,t)=>{var r;return(r=this._register(e,t,void 0,!0))==null?void 0:r[0]});c(this,"_unmarshalFind",e=>{var t;return(t=this._registeredMap.getByHandle(e))!=null?t:this._map.getByHandle(e)});c(this,"_unmarshal",e=>{var s;const t=this._registeredMap.getByHandle(e);if(typeof t!="undefined")return t;const[r]=this._wrapHandle(e);return B(r!=null?r:e,{ctx:this.context,marshal:this._marshal,find:this._unmarshalFind,pre:this._preUnmarshal,custom:(s=this._options)==null?void 0:s.customUnmarshaller})});c(this,"_syncMode",e=>{const t=this._unwrap(e);return this._sync.has(t)||this._temporalSync.has(t)?"both":void 0});c(this,"_unwrapIfNotSynced",e=>{const t=this._unwrap(e);return t instanceof Promise||!this._sync.has(t)?t:e});var r;t!=null&&t.compat&&!("runtime"in e)&&(e.runtime={hasPendingJob:()=>e.hasPendingJob(),executePendingJobs:s=>e.executePendingJobs(s)}),this.context=t!=null&&t.experimentalContextEx?v(e):e,this._options=t,this._symbolHandle=e.unwrapResult(e.evalCode("Symbol()")),this._map=new M(e),this._registeredMap=new M(e),this.registerAll((r=t==null?void 0:t.registeredObjects)!=null?r:k)}dispose(){var e,t;this._map.dispose(),this._registeredMap.dispose(),this._symbolHandle.dispose(),(t=(e=this.context).disposeEx)==null||t.call(e)}evalCode(e){const t=this.context.evalCode(e);return this._unwrapResultAndUnmarshal(t)}evalModule(e,t="module.js"){const r=this.context.evalCode(e,t,{type:"module"});this._unwrapResultAndUnmarshal(r)}executePendingJobs(e){const t=this.context.runtime.executePendingJobs(e);if("value"in t)return t.value;throw this._unwrapIfNotSynced(t.error.consume(this._unmarshal))}setMemoryLimit(e){this.context.runtime.setMemoryLimit(e)}setMaxStackSize(e){this.context.runtime.setMaxStackSize(e)}getMemoryUsage(){const e=this.context.runtime.computeMemoryUsage();try{return this.context.dump(e)}finally{e.dispose()}}dumpMemoryUsage(){return this.context.runtime.dumpMemoryUsage()}expose(e){for(const[t,r]of Object.entries(e))$(this._marshal(r),s=>{this.context.setProp(this.context.global,t,s)})}sync(e){const t=this._wrap(e);return typeof t=="undefined"?e:(O(t,r=>{const s=this._unwrap(r);this._sync.add(s)}),t)}register(e,t){if(this._registeredMap.has(e))return;const r=typeof t=="string"?this._unwrapResult(this.context.evalCode(t)):t;C(this.context,r,this.context.undefined)||(typeof t=="string"&&this._registeredMapDispose.add(e),this._registeredMap.set(e,r))}registerAll(e){for(const[t,r]of e)this.register(t,r)}unregister(e,t){this._registeredMap.delete(e,this._registeredMapDispose.has(e)||t),this._registeredMapDispose.delete(e)}unregisterAll(e,t){for(const r of e)this.unregister(r,t)}startSync(e){if(!g(e))return;const t=this._unwrap(e);this._sync.add(t)}endSync(e){this._sync.delete(this._unwrap(e))}_unwrapResult(e){if("value"in e)return e.value;throw this._unwrapIfNotSynced(e.error.consume(this._unmarshal))}_unwrapResultAndUnmarshal(e){if(e)return this._unwrapIfNotSynced(this._unwrapResult(e).consume(this._unmarshal))}_register(e,t,r=this._map,s){if(this._registeredMap.has(e)||this._registeredMap.hasHandle(t))return;let o=this._wrap(e);const[i]=this._wrapHandle(t),a=e instanceof Promise;if(!i||!o&&!a)return;a&&(o=e);const u=this._unwrap(e),[p,l]=this._unwrapHandle(t);if(r.set(o,i,u,p))s&&this._sync.add(u);else throw l&&p.dispose(),new Error("already registered");return[o,i]}_wrap(e){var t;return de(this.context,e,this._symbol,this._symbolHandle,this._marshal,this._syncMode,(t=this._options)==null?void 0:t.isWrappable)}_unwrap(e){return P(e,this._symbol)}_wrapHandle(e){var t;return me(this.context,e,this._symbol,this._symbolHandle,this._unmarshal,this._syncMode,(t=this._options)==null?void 0:t.isHandleWrappable)}_unwrapHandle(e){return R(this.context,e,this._symbolHandle)}}m.Arena=ye,m.VMMap=M,m.call=_,m.complexity=Z,m.consumeAll=z,m.defaultRegisteredObjects=k,m.eq=C,m.isES2015Class=N,m.isHandleObject=F,m.isObject=g,m.json=H,m.marshal=E,m.unmarshal=B,m.walkObject=O,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quickjs-emscripten-sync",
|
|
3
3
|
"author": "rot1024",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./dist/quickjs-emscripten-sync.umd.js",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"quickjs-emscripten": "*"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@vitest/coverage-c8": "^0.
|
|
35
|
-
"eslint": "^8.
|
|
36
|
-
"eslint-config-reearth": "^0.1
|
|
37
|
-
"prettier": "^2.
|
|
38
|
-
"quickjs-emscripten": "^0.
|
|
39
|
-
"typescript": "^
|
|
40
|
-
"vite": "^
|
|
41
|
-
"vite-plugin-dts": "^
|
|
42
|
-
"vitest": "^0.
|
|
34
|
+
"@vitest/coverage-c8": "^0.28.5",
|
|
35
|
+
"eslint": "^8.57.1",
|
|
36
|
+
"eslint-config-reearth": "^0.2.1",
|
|
37
|
+
"prettier": "^2.8.8",
|
|
38
|
+
"quickjs-emscripten": "^0.25.0",
|
|
39
|
+
"typescript": "^5.7.2",
|
|
40
|
+
"vite": "^6.0.3",
|
|
41
|
+
"vite-plugin-dts": "^4.3.0",
|
|
42
|
+
"vitest": "^0.28.5"
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { expect, test, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { ContextEx, wrapContext } from "./contextex";
|
|
5
|
+
|
|
6
|
+
test("wrapContext", async () => {
|
|
7
|
+
const ctx = (await getQuickJS()).newContext();
|
|
8
|
+
const c = wrapContext(ctx);
|
|
9
|
+
c.disposeEx?.();
|
|
10
|
+
ctx.dispose();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("ContextEx", async () => {
|
|
14
|
+
try {
|
|
15
|
+
const ctx = (await getQuickJS()).newContext();
|
|
16
|
+
const spy = vi.spyOn(ctx, "newFunction");
|
|
17
|
+
const ctxex = new ContextEx(ctx);
|
|
18
|
+
|
|
19
|
+
const handle = ctxex.newFunction("", function (handle) {
|
|
20
|
+
expect(ctx.getString(this)).toBe("this");
|
|
21
|
+
expect(ctx.getNumber(handle)).toBe(100);
|
|
22
|
+
return ctx.newString("result");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < 10000; i++) {
|
|
26
|
+
const res = ctx.unwrapResult(
|
|
27
|
+
ctx.callFunction(handle, ctx.newString("this"), ctx.newNumber(100)),
|
|
28
|
+
);
|
|
29
|
+
expect(ctx.getString(res)).toBe("result");
|
|
30
|
+
res.dispose();
|
|
31
|
+
}
|
|
32
|
+
expect(spy).toBeCalledTimes(1);
|
|
33
|
+
|
|
34
|
+
handle.dispose();
|
|
35
|
+
ctxex.disposeEx();
|
|
36
|
+
ctx.dispose();
|
|
37
|
+
} catch (err) {
|
|
38
|
+
// prevent freezing node when printing QuickJSContext
|
|
39
|
+
delete (err as any).context;
|
|
40
|
+
console.error(err);
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
});
|
package/src/contextex.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { QuickJSContext, QuickJSHandle, VmFunctionImplementation } from "quickjs-emscripten";
|
|
2
|
+
|
|
3
|
+
export type QuickJSContextEx = QuickJSContext & {
|
|
4
|
+
disposeEx?: () => void;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const wrapContext = (ctx: QuickJSContext): QuickJSContextEx => {
|
|
8
|
+
const ctxex = new ContextEx(ctx);
|
|
9
|
+
return new Proxy(ctx, {
|
|
10
|
+
get(target, p, receiver) {
|
|
11
|
+
return p in ctxex ? (ctxex as any)[p] : Reflect.get(target, p, receiver);
|
|
12
|
+
},
|
|
13
|
+
}) as QuickJSContextEx;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class ContextEx {
|
|
17
|
+
context: QuickJSContext;
|
|
18
|
+
fn: QuickJSHandle;
|
|
19
|
+
fnGenerator: QuickJSHandle;
|
|
20
|
+
fnCounter = Number.MIN_SAFE_INTEGER;
|
|
21
|
+
fnMap = new Map<number, VmFunctionImplementation<QuickJSHandle>>();
|
|
22
|
+
|
|
23
|
+
constructor(context: QuickJSContext) {
|
|
24
|
+
this.context = context;
|
|
25
|
+
const fnMap = this.fnMap;
|
|
26
|
+
this.fn = this.context.newFunction("", function (idHandle, ...argHandles) {
|
|
27
|
+
const id = context.getNumber(idHandle);
|
|
28
|
+
const f = fnMap.get(id);
|
|
29
|
+
if (!f) throw new Error("function is not registered");
|
|
30
|
+
return f.call(this, ...argHandles);
|
|
31
|
+
});
|
|
32
|
+
this.fnGenerator = context.unwrapResult(
|
|
33
|
+
context.evalCode(`((name, length, id, f) => {
|
|
34
|
+
const fn = function(...args) {
|
|
35
|
+
return f.call(this, id, ...args);
|
|
36
|
+
};
|
|
37
|
+
fn.name = name;
|
|
38
|
+
fn.length = length;
|
|
39
|
+
return fn;
|
|
40
|
+
})`),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
disposeEx(): void {
|
|
45
|
+
this.fnGenerator.dispose();
|
|
46
|
+
this.fn.dispose();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Similar to the original newFunction, but no matter how many new functions are generated, newFunction is called only once. */
|
|
50
|
+
newFunction = (name: string, fn: VmFunctionImplementation<QuickJSHandle>): QuickJSHandle => {
|
|
51
|
+
this.fnCounter++;
|
|
52
|
+
const id = this.fnCounter;
|
|
53
|
+
this.fnMap.set(id, fn);
|
|
54
|
+
return this.context.unwrapResult(
|
|
55
|
+
this.context.callFunction(
|
|
56
|
+
this.fnGenerator,
|
|
57
|
+
this.context.undefined,
|
|
58
|
+
this.context.newString(name),
|
|
59
|
+
this.context.newNumber(fn.length),
|
|
60
|
+
this.context.newNumber(id),
|
|
61
|
+
this.fn,
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/edge.test.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getQuickJS } from "quickjs-emscripten";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { Arena } from ".";
|
|
5
|
+
|
|
6
|
+
// tests for edge cases
|
|
7
|
+
|
|
8
|
+
describe("edge cases", () => {
|
|
9
|
+
// this test takes more than about 20s
|
|
10
|
+
test("getter", async () => {
|
|
11
|
+
const ctx = (await getQuickJS()).newContext();
|
|
12
|
+
const arena = new Arena(ctx, { isMarshalable: true });
|
|
13
|
+
|
|
14
|
+
const called: string[] = [];
|
|
15
|
+
const obj = { c: 0 };
|
|
16
|
+
const exposed = {
|
|
17
|
+
get a() {
|
|
18
|
+
called.push("a");
|
|
19
|
+
return {
|
|
20
|
+
get b() {
|
|
21
|
+
called.push("b");
|
|
22
|
+
return obj;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
const cb: { current?: () => any } = {};
|
|
28
|
+
const register = (fn: () => any) => {
|
|
29
|
+
cb.current = fn;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
arena.expose({ exposed, register });
|
|
33
|
+
expect(called).toEqual([]);
|
|
34
|
+
|
|
35
|
+
arena.evalCode(`register(() => exposed.a.b.c);`);
|
|
36
|
+
expect(cb.current?.()).toBe(0);
|
|
37
|
+
expect(called).toEqual(["a", "b"]);
|
|
38
|
+
|
|
39
|
+
obj.c = 1;
|
|
40
|
+
expect(cb.current?.()).toBe(1); // this line causes an error when context is disposed
|
|
41
|
+
expect(called).toEqual(["a", "b", "a", "b"]);
|
|
42
|
+
|
|
43
|
+
arena.dispose();
|
|
44
|
+
// ctx.dispose(); // reports an error
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("many newFunction", async () => {
|
|
48
|
+
const rt = (await getQuickJS()).newRuntime();
|
|
49
|
+
const ctx = rt.newContext();
|
|
50
|
+
const arena = new Arena(ctx, {
|
|
51
|
+
isMarshalable: true,
|
|
52
|
+
// enable this option to solve this problem
|
|
53
|
+
experimentalContextEx: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
arena.expose({
|
|
57
|
+
hoge: () => {},
|
|
58
|
+
});
|
|
59
|
+
// should have an object as an arg
|
|
60
|
+
const fn = arena.evalCode(`() => { hoge([]); }`);
|
|
61
|
+
// error happens from 3926 times
|
|
62
|
+
for (let i = 0; i < 10000; i++) {
|
|
63
|
+
fn();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
arena.dispose();
|
|
67
|
+
ctx.dispose();
|
|
68
|
+
rt.dispose();
|
|
69
|
+
});
|
|
70
|
+
});
|