@@ -3,6 +3,7 @@ const generator = require('@babel/generator').default
33const  traverse  =  require ( '@babel/traverse' ) . default 
44const  t  =  require ( '@babel/types' ) 
55const  ivm  =  require ( 'isolated-vm' ) 
6+ const  calculateConstantExp  =  require ( '../visitor/calculate-constant-exp' ) 
67
78const  isolate  =  new  ivm . Isolate ( ) 
89
@@ -22,6 +23,16 @@ function safeReplace(path, value) {
2223  path . replaceWithSourceString ( value ) 
2324} 
2425
26+ function  safeGetName ( path )  { 
27+   if  ( path . isIdentifier ( ) )  { 
28+     return  path . node . name 
29+   } 
30+   if  ( path . isLiteral ( ) )  { 
31+     return  path . node . value 
32+   } 
33+   return  null 
34+ } 
35+ 
2536function  deAntiToolingCheckFunc ( path )  { 
2637  if  ( path . node . params . length )  { 
2738    return  false 
@@ -299,6 +310,185 @@ function checkFuncLen(path) {
299310  } 
300311} 
301312
313+ /** 
314+  * type: param, value, ref, invalid 
315+  */ 
316+ function  initStackCache ( len )  { 
317+   const  cache  =  { } 
318+   for  ( let  i  =  0 ;  i  <  len ;  ++ i )  { 
319+     cache [ i ]  =  { 
320+       type : 'param' , 
321+     } 
322+   } 
323+   return  cache 
324+ } 
325+ 
326+ function  processAssignLeft ( vm ,  cache ,  path ,  prop_name ,  stk_name )  { 
327+   const  father  =  path . parentPath 
328+   const  right  =  father . get ( 'right' ) 
329+   if  ( right . isBinaryExpression ( ) )  { 
330+     return 
331+   } 
332+   if  ( right . isLiteral ( ) )  { 
333+     vm . evalSync ( generator ( father . node ) . code ) 
334+     cache [ prop_name ]  =  { 
335+       type : 'value' , 
336+       value : right . node . value , 
337+     } 
338+     return 
339+   } 
340+   if  ( right . isUnaryExpression ( )  &&  right . node . operator  ===  '-' )  { 
341+     const  value  =  vm . evalSync ( generator ( right . node ) . code ) 
342+     vm . evalSync ( generator ( father . node ) . code ) 
343+     cache [ prop_name ]  =  { 
344+       type : 'value' , 
345+       value : value , 
346+     } 
347+     return 
348+   } 
349+   if  ( right . isMemberExpression ( )  &&  right . node . object ?. name  ===  stk_name )  { 
350+     const  right_prop  =  right . get ( 'property' ) 
351+     if  ( right_prop . isBinaryExpression ( ) )  { 
352+       return 
353+     } 
354+     let  ref  =  safeGetName ( right_prop ) 
355+     if  ( ! Object . prototype . hasOwnProperty . call ( cache ,  ref ) )  { 
356+       vm . evalSync ( generator ( father . node ) . code ) 
357+       cache [ prop_name ]  =  { 
358+         type : 'value' , 
359+         value : undefined , 
360+       } 
361+       return 
362+     } 
363+     while  ( cache [ ref ] . type  ===  'ref' )  { 
364+       ref  =  cache [ ref ] . value 
365+     } 
366+     if  ( cache [ ref ] . type  ===  'value' )  { 
367+       safeReplace ( right ,  cache [ ref ] . value ) 
368+       vm . evalSync ( generator ( father . node ) . code ) 
369+       cache [ prop_name ]  =  { 
370+         type : 'value' , 
371+         value : cache [ ref ] . value , 
372+       } 
373+     }  else  { 
374+       cache [ prop_name ]  =  { 
375+         type : 'ref' , 
376+         value : ref , 
377+       } 
378+     } 
379+     return 
380+   } 
381+   cache [ prop_name ]  =  { 
382+     type : 'invalid' , 
383+   } 
384+ } 
385+ 
386+ function  processAssignInvalid ( cache ,  path ,  prop_name )  { 
387+   cache [ prop_name ]  =  { 
388+     type : 'invalid' , 
389+   } 
390+ } 
391+ 
392+ function  processReplace ( cache ,  path ,  prop_name )  { 
393+   const  value  =  cache [ prop_name ] . value 
394+   const  type  =  cache [ prop_name ] . type 
395+   if  ( type  ===  'ref' )  { 
396+     path . node . computed  =  true 
397+     safeReplace ( path . get ( 'property' ) ,  value ) 
398+     return  true 
399+   } 
400+   if  ( type  ===  'value' )  { 
401+     safeReplace ( path ,  value ) 
402+     return  true 
403+   } 
404+   return  false 
405+ } 
406+ 
407+ function  checkStackInvalid ( path )  { 
408+   const  stk_name  =  path . node . params [ 0 ] . argument . name 
409+   const  body_path  =  path . get ( 'body' ) 
410+   const  obj  =  { } 
411+   body_path . traverse ( { 
412+     MemberExpression : { 
413+       exit ( path )  { 
414+         if  ( path . node . object . name  !==  stk_name )  { 
415+           return 
416+         } 
417+         const  father  =  path . parentPath 
418+         if  ( body_path . scope  ==  father . scope )  { 
419+           return 
420+         } 
421+         if  ( ! father . isAssignmentExpression ( )  ||  path . key  !==  'left' )  { 
422+           return 
423+         } 
424+         const  prop  =  path . get ( 'property' ) 
425+         const  prop_name  =  safeGetName ( prop ) 
426+         obj [ prop_name ]  =  1 
427+       } , 
428+     } , 
429+   } ) 
430+   return  obj 
431+ } 
432+ 
433+ function  tryStackReplace ( path ,  len ,  invalid )  { 
434+   const  stk_name  =  path . node . params [ 0 ] . argument . name 
435+   const  body_path  =  path . get ( 'body' ) 
436+   const  cache  =  initStackCache ( len ) 
437+   const  vm  =  isolate . createContextSync ( ) 
438+   vm . evalSync ( `var ${ stk_name }  ) 
439+   let  changed  =  false 
440+   body_path . traverse ( { 
441+     MemberExpression : { 
442+       exit ( path )  { 
443+         if  ( path . node . object . name  !==  stk_name )  { 
444+           return 
445+         } 
446+         const  prop  =  path . get ( 'property' ) 
447+         if  ( prop . isBinaryExpression ( ) )  { 
448+           return 
449+         } 
450+         const  prop_name  =  safeGetName ( prop ) 
451+         if  ( ! prop_name )  { 
452+           return 
453+         } 
454+         if  ( Object . prototype . hasOwnProperty . call ( invalid ,  prop_name ) )  { 
455+           processAssignInvalid ( cache ,  path ,  prop_name ) 
456+           return 
457+         } 
458+         const  exist  =  Object . prototype . hasOwnProperty . call ( cache ,  prop_name ) 
459+         if  ( exist  &&  cache [ prop_name ] . type  ===  'param' )  { 
460+           return 
461+         } 
462+         const  father  =  path . parentPath 
463+         if  ( father . isAssignmentExpression ( )  &&  path . key  ===  'left' )  { 
464+           processAssignLeft ( vm ,  cache ,  path ,  prop_name ,  stk_name ) 
465+         }  else  if  ( exist )  { 
466+           changed  |=  processReplace ( cache ,  path ,  prop_name ) 
467+         } 
468+       } , 
469+     } , 
470+   } ) 
471+   const  binding  =  body_path . scope . getBinding ( stk_name ) 
472+   binding . scope . crawl ( ) 
473+   return  changed 
474+ } 
475+ 
476+ function  processStackParam ( path ,  len )  { 
477+   if  ( path . isArrowFunctionExpression ( ) )  { 
478+     console . log ( `Process arrowFunctionExpression, len: ${ len }  ) 
479+   }  else  if  ( path . isFunctionExpression ( ) )  { 
480+     console . log ( `Process functionExpression, len: ${ len }  ) 
481+   }  else  { 
482+     console . log ( `Process Function ${ path . node . id . name } ${ len }  ) 
483+   } 
484+   let  changed  =  true 
485+   const  invalid  =  checkStackInvalid ( path ) 
486+   while  ( changed )  { 
487+     changed  =  tryStackReplace ( path ,  len ,  invalid ) 
488+     path . traverse ( calculateConstantExp ) 
489+   } 
490+ } 
491+ 
302492const  deStackFuncLen  =  { 
303493  Identifier ( path )  { 
304494    let  obj  =  checkFuncLen ( path ) 
@@ -314,10 +504,15 @@ const deStackFuncLen = {
314504      } 
315505      const  repl_path  =  ref . parentPath 
316506      const  arg  =  repl_path . node . arguments [ 0 ] 
507+       const  len  =  repl_path . node . arguments [ 1 ] . value 
317508      if  ( t . isIdentifier ( arg ) )  { 
509+         const  func_name  =  arg . name 
510+         const  func_decl  =  repl_path . scope . getBinding ( func_name ) . path 
511+         processStackParam ( func_decl ,  len ) 
318512        repl_path . remove ( ) 
319513      }  else  { 
320514        repl_path . replaceWith ( arg ) 
515+         processStackParam ( repl_path ,  len ) 
321516      } 
322517    } 
323518    binding . scope . crawl ( ) 
0 commit comments