@@ -25,6 +25,9 @@ var readFileAsync = promisify(fs.readFile)
2525var ArrayJoin = Function . call . bind ( Array . prototype . join ) ;
2626var ArrayMap = Function . call . bind ( Array . prototype . map ) ;
2727var reqOrig = require ;
28+ var frameWorkCache = { }
29+ var enableFrameworkCaching = undefined ;
30+ var keepFrameworksOnExit = undefined ;
2831
2932// Normalize the URL, for consistency. Remove the query part.
3033// All local URLs would have the 'file:' prefix.
@@ -350,10 +353,130 @@ var loadMjs = async function (source, url, context, modmap, version)
350353 return mod ;
351354}
352355
356+ function eligibleForFrameWorkCaching ( scene , url , name , hash )
357+ {
358+ if ( undefined == enableFrameworkCaching )
359+ {
360+ enableFrameworkCaching = scene . sparkSetting ( "enableFrameWorkCache" ) ;
361+ if ( undefined == enableFrameworkCaching )
362+ {
363+ enableFrameworkCaching = true ;
364+ }
365+ if ( false == enableFrameworkCaching ) {
366+ keepFrameworksOnExit = false ;
367+ }
368+ }
369+ if ( enableFrameworkCaching == true )
370+ {
371+ // currently enable only for .js file
372+ if ( ( / \. j s $ / . test ( url ) ) && ( hash != undefined ) && ( ( url != undefined ) || ( name != undefined ) ) )
373+ return true ;
374+ }
375+ return false ;
376+ }
377+
378+ function ensureUniqueFramework ( url )
379+ {
380+ var noentries = frameWorkCache [ url ] . length ;
381+ if ( noentries > 1 ) {
382+ var entriestoremove = [ ]
383+ for ( var i = 0 ; i < noentries ; i ++ ) {
384+ if ( frameWorkCache [ url ] [ i ] . numAppsUsing == 0 )
385+ {
386+ entriestoremove . push ( i )
387+ }
388+ }
389+ for ( var i = 0 ; i < entriestoremove . length - 1 ; i ++ ) {
390+ var index = entriestoremove [ i ] ;
391+ for ( key in frameWorkCache [ url ] [ index ] ) {
392+ delete frameWorkCache [ url ] [ index ] [ key ]
393+ }
394+ }
395+ for ( var i = 0 ; i < entriestoremove . length - 1 ; i ++ ) {
396+ var index = entriestoremove [ i ] ;
397+ index = index - i ;
398+ frameWorkCache [ url ] . splice ( entriestoremove [ index ] , 1 ) ;
399+ }
400+ entriestoremove = [ ]
401+ }
402+ }
403+
404+ function getCachePosition ( url , hash )
405+ {
406+ var cacheposition = - 1 ;
407+ if ( frameWorkCache [ url ] != undefined )
408+ {
409+ for ( var i = 0 ; i < frameWorkCache [ url ] . length ; i ++ ) {
410+ if ( frameWorkCache [ url ] [ i ] . hash == hash )
411+ {
412+ cacheposition = i ;
413+ break ;
414+ }
415+ }
416+ /*
417+ // means we got a requirement for a framework version not in cache
418+ // removing unsed earlier to handle any scenarios to unwanted memory removal
419+ ensureUniqueFramework(url);
420+ */
421+ }
422+ return cacheposition ;
423+ }
424+
425+ async function loadFrameWorks ( loadCtx , bootstrapUrl ) {
426+ const list = loadCtx . bootstrap . frameworks ;
427+ var frameWorkUsageInfo = { }
428+ for ( let i = 0 ; i < list . length ; i ++ ) {
429+ let _framework = list [ i ] ;
430+ let _url = _framework . url || _framework ;
431+ let _name = _framework . name
432+
433+ let _hash = _framework . md5
434+ let useFrameWorkCaching = eligibleForFrameWorkCaching ( loadCtx . sandbox . global . sparkscene , _url , _name , _hash )
435+
436+ // store framework compiled scripts only for js files
437+ if ( true == useFrameWorkCaching )
438+ {
439+ let _cachekey = ( undefined != _name ) ?_name :_url ;
440+ let _cachePostion = getCachePosition ( _cachekey , _hash ) ;
441+ if ( _cachePostion != - 1 )
442+ {
443+ frameWorkUsageInfo [ _cachekey ] = _cachePostion ;
444+ //console.log("framework "+ _cachekey + " available in cache at postion " + _cachePostion + " , no need to reload !!!!!!!!!!!!!!!!!!!");
445+ }
446+ else
447+ {
448+ if ( ! / ^ ( h t t p : | h t t p s : | f i l e : ) / . test ( _url ) )
449+ _url = urlmain . resolve ( bootstrapUrl , _url ) ;
450+
451+ var frameWorkSource = await getFile ( loadCtx . sandbox . global . sparkscene , _url ) ;
452+ var frameWorkScript = new vm . Script ( frameWorkSource ) ;
453+ if ( undefined == frameWorkCache [ _cachekey ] ) {
454+ frameWorkCache [ _cachekey ] = [ ]
455+ }
456+ frameWorkCache [ _cachekey ] . push ( { 'hash' : _hash , 'script' : frameWorkScript , 'numAppsUsing' : 0 } )
457+ frameWorkUsageInfo [ _cachekey ] = frameWorkCache [ _cachekey ] . length - 1 ;
458+ //console.log("Newly loaded cache for " + _cachekey + " at position " + frameWorkUsageInfo[_cachekey]);
459+ }
460+ }
461+ else
462+ {
463+ await importModuleDynamically ( _url , { url :bootstrapUrl , context :loadCtx . contextifiedSandbox } , _hash ) ;
464+ }
465+ }
466+ for ( var key in frameWorkUsageInfo )
467+ {
468+ var pos = frameWorkUsageInfo [ key ] ;
469+ frameWorkCache [ key ] [ pos ] . script . runInContext ( loadCtx . contextifiedSandbox ) ;
470+ frameWorkCache [ key ] [ pos ] . numAppsUsing = frameWorkCache [ key ] [ pos ] . numAppsUsing + 1 ;
471+ }
472+ loadCtx . frameWorkUsageInfo = frameWorkUsageInfo ;
473+ }
474+
353475function ESMLoader ( params ) {
354476 this . ctx = params
355477 this . loadESM = function ( filename ) {
356478 var loadCtx = this . ctx ;
479+ loadCtx . frameWorkUsageInfo = { }
357480 let url = filename2url ( filename ) ;
358481 const loc = / ^ f i l e : / . test ( url ) ? url . substring ( 7 ) : url ;
359482
@@ -381,12 +504,7 @@ function ESMLoader(params) {
381504 try {
382505 // When URL is .spark, frameworkURL-s are loaded like dynamic imports.
383506 if ( loadCtx . bootstrap && loadCtx . bootstrap . frameworks ) {
384- const list = loadCtx . bootstrap . frameworks ;
385- for ( let i = 0 ; i < list . length ; i ++ ) {
386- let _framework = list [ i ] ;
387- let _url = _framework . url || _framework ;
388- await importModuleDynamically ( _url , { url :bootstrapUrl , context :loadCtx . contextifiedSandbox } , _framework . md5 ) ;
389- }
507+ await loadFrameWorks ( loadCtx , bootstrapUrl ) ;
390508 }
391509 var source = await getFile ( loadCtx . global . sparkscene , url ) ;
392510 loadCtx . app = await loadMjs ( source , url , loadCtx . contextifiedSandbox , loadCtx . modmap ) ;
@@ -411,6 +529,47 @@ function ESMLoader(params) {
411529 }
412530 }
413531 this . clearResources = function ( ) {
532+ if ( enableFrameworkCaching == true )
533+ {
534+ if ( undefined == keepFrameworksOnExit )
535+ {
536+ keepFrameworksOnExit = this . ctx . global . sparkscene . sparkSetting ( "keepFrameworksOnExit" ) ;
537+ if ( undefined == keepFrameworksOnExit )
538+ {
539+ keepFrameworksOnExit = true ;
540+ }
541+ }
542+ if ( undefined != this . ctx . frameWorkUsageInfo ) {
543+ for ( key in this . ctx . frameWorkUsageInfo )
544+ {
545+ var pos = this . ctx . frameWorkUsageInfo [ key ] ;
546+ frameWorkCache [ key ] [ pos ] . numAppsUsing -- ;
547+ if ( false == keepFrameworksOnExit ) {
548+ // not deleting the cache entry if someone is using
549+ if ( frameWorkCache [ key ] [ pos ] . numAppsUsing == 0 )
550+ {
551+ for ( var k in frameWorkCache [ key ] [ pos ] )
552+ {
553+ delete frameWorkCache [ key ] [ pos ] [ k ] ;
554+ }
555+ frameWorkCache [ key ] . splice ( pos , 1 ) ;
556+ }
557+ if ( frameWorkCache [ key ] . length == 0 )
558+ {
559+ delete frameWorkCache [ key ] ;
560+ }
561+ }
562+ else {
563+ ensureUniqueFramework ( key ) ;
564+ }
565+ }
566+ this . ctx . frameWorkUsageInfo = { }
567+ delete this . ctx . frameWorkUsageInfo ;
568+ }
569+ }
570+ else {
571+ console . log ( "no framework manipulation !!!!!" ) ;
572+ }
414573 this . ctx = null
415574 }
416575}
0 commit comments