@@ -10,6 +10,8 @@ export interface CompileOptions {
1010 sandbox ?: Context ;
1111}
1212
13+ const SANDBOX_FUNCTION_PREFIX = '__degeneratorSandboxFunction:' ;
14+
1315export function compile < R = unknown , A extends unknown [ ] = [ ] > (
1416 vm : QuickJS ,
1517 code : string ,
@@ -26,17 +28,12 @@ export function compile<R = unknown, A extends unknown[] = []>(
2628 `Expected a "function" for sandbox property \`${ name } \`, but got "${ typeof value } "`
2729 ) ;
2830 }
29- const fnHandle = vm . newFunction ( name , ( _this , ...args ) => {
30- const result = value ( ...args . map ( ( arg ) => vm . dump ( arg ) ) ) ;
31- vm . executePendingJobs ( ) ;
32- return hostToQuickJSHandle ( vm , result ) ;
33- } ) ;
31+ const fnHandle = getOrCreateSandboxFunction ( vm , name , value ) ;
3432 fnHandle . consume ( ( handle ) => vm . setProp ( vm . global , name , handle ) ) ;
3533 }
3634 }
3735
38- const fnResult = vm . evalCode ( `${ compiled } ;${ returnName } ` , options . filename ) ;
39- const fn = vm . unwrapResult ( fnResult ) ;
36+ const fn = vm . evalCode ( `${ compiled } ;${ returnName } ` , options . filename ) ;
4037
4138 const t = vm . typeof ( fn ) ;
4239 if ( t !== 'function' ) {
@@ -53,7 +50,7 @@ export function compile<R = unknown, A extends unknown[] = []>(
5350 vm . undefined ,
5451 ...args . map ( ( arg ) => hostToQuickJSHandle ( vm , arg ) )
5552 ) ;
56- promiseHandle = vm . unwrapResult ( result ) ;
53+ promiseHandle = result ;
5754 const resolvedResultP = vm . resolvePromise ( promiseHandle ) ;
5855 vm . executePendingJobs ( ) ;
5956 const resolvedResult = await resolvedResultP ;
@@ -102,6 +99,41 @@ export function compile<R = unknown, A extends unknown[] = []>(
10299 return r ;
103100}
104101
102+ function getOrCreateSandboxFunction (
103+ vm : QuickJS ,
104+ name : string ,
105+ value : ( ...args : unknown [ ] ) => unknown
106+ ) : JSValueHandle {
107+ const callback = ( ...args : JSValueHandle [ ] ) => {
108+ const result = value ( ...args . map ( ( arg ) => vm . dump ( arg ) ) ) ;
109+ vm . executePendingJobs ( ) ;
110+ return hostToQuickJSHandle ( vm , result ) ;
111+ } ;
112+
113+ const globalFunctionName = `${ SANDBOX_FUNCTION_PREFIX } ${ name } ` ;
114+ const keyHandle = vm . newString ( globalFunctionName ) ;
115+ let existingHandle : JSValueHandle | undefined ;
116+ try {
117+ existingHandle = vm . getProp ( vm . global , keyHandle ) ;
118+ if ( vm . typeof ( existingHandle ) === 'function' ) {
119+ vm . registerHostCallback ( name , callback ) ;
120+ return existingHandle ;
121+ }
122+ existingHandle . dispose ( ) ;
123+ existingHandle = undefined ;
124+
125+ const fnHandle = vm . newFunction ( name , callback ) ;
126+ vm . defineProp ( vm . global , globalFunctionName , fnHandle , {
127+ writable : false ,
128+ enumerable : false ,
129+ configurable : false ,
130+ } ) ;
131+ return fnHandle ;
132+ } finally {
133+ keyHandle . dispose ( ) ;
134+ }
135+ }
136+
105137function hostToQuickJSHandle ( vm : QuickJS , val : unknown ) : JSValueHandle {
106138 if ( typeof val === 'undefined' ) {
107139 return vm . undefined ;
0 commit comments