import { IWorkerRequest , WorkerCommand , IWorkerResponse } from "./message" ; declare var importScripts ; function assert ( c , message ? ) { if ( ! c ) { throw new Error ( message ) ; } } declare interface BinaryenModule { optimize ( ) : any ; validate ( ) : any ; emitBinary ( ) : ArrayBuffer ; emitText ( ) : string ; emitAsmjs ( ) : string ; runPasses ( passes ) : any ; } declare var Binaryen ; declare var wabt ; async function loadBinaryen ( ) { if ( typeof Binaryen === "undefined" ) { importScripts ( "../lib/binaryen.js" ) ; } } async function loadWabt ( ) { if ( typeof wabt === "undefined" ) { ( self as any ) . global = self ; importScripts ( "../lib/wabt.js" ) ; } } let Twiggy = null ; declare var wasm_bindgen ; async function loadTwiggy ( ) { if ( ! Twiggy ) { importScripts ( "../lib/twiggy_wasm_api.js" ) ; await wasm_bindgen ( "../lib/twiggy_wasm_api_bg.wasm" ) ; Twiggy = { Items : wasm_bindgen . Items , Top : wasm_bindgen . Top , Paths : wasm_bindgen . Paths , Monos : wasm_bindgen . Monos , Dominators : wasm_bindgen . Dominators } ; } } onmessage = ( e ) => { const fn = { [ WorkerCommand . OptimizeWasmWithBinaryen ] : optimizeWasmWithBinaryen , [ WorkerCommand . ValidateWasmWithBinaryen ] : validateWasmWithBinaryen , [ WorkerCommand . CreateWasmCallGraphWithBinaryen ] : createWasmCallGraphWithBinaryen , [ WorkerCommand . ConvertWasmToAsmWithBinaryen ] : convertWasmToAsmWithBinaryen , [ WorkerCommand . DisassembleWasmWithBinaryen ] : disassembleWasmWithBinaryen , [ WorkerCommand . AssembleWatWithBinaryen ] : assembleWatWithBinaryen , [ WorkerCommand . DisassembleWasmWithWabt ] : disassembleWasmWithWabt , [ WorkerCommand . AssembleWatWithWabt ] : assembleWatWithWabt , [ WorkerCommand . TwiggyWasm ] : twiggyWasm } [ e . data . command ] ; assert ( fn , `Command ${ e . data . command } not found.` ) ; processMessage ( e . data , fn ) ; } ; async function processMessage ( request , fn ) { const response = { id : request . id , payload : null , success : true } ; try { response . payload = await fn ( request . payload ) ; } catch ( e ) { response . payload = { message : e . message } ; response . success = false ; } postMessage ( response , undefined ) ; } async function optimizeWasmWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . readBinary ( new Uint8Array ( data ) ) ; module . optimize ( ) ; return Promise . resolve ( module . emitBinary ( ) ) ; } async function validateWasmWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . readBinary ( new Uint8Array ( data ) ) ; return Promise . resolve ( module . validate ( ) ) ; } async function createWasmCallGraphWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . readBinary ( new Uint8Array ( data ) ) ; const old = Binaryen . print ; let ret = "" ; Binaryen . print = ( x ) => { ret += x + "\n" ; } ; module . runPasses ( [ "print-call-graph" ] ) ; Binaryen . print = old ; return Promise . resolve ( ret ) ; } async function convertWasmToAsmWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . readBinary ( new Uint8Array ( data ) ) ; module . optimize ( ) ; return Promise . resolve ( module . emitAsmjs ( ) ) ; } async function disassembleWasmWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . readBinary ( new Uint8Array ( data ) ) ; return Promise . resolve ( module . emitText ( ) ) ; } async function assembleWatWithBinaryen ( data ) { await loadBinaryen ( ) ; const module = Binaryen . parseText ( data ) ; return Promise . resolve ( module . emitBinary ( ) ) ; } async function disassembleWasmWithWabt ( data ) { await loadWabt ( ) ; const module = wabt . readWasm ( data , { readDebugNames : true } ) ; module . generateNames ( ) ; module . applyNames ( ) ; return Promise . resolve ( module . toText ( { foldExprs : false , inlineExport : true } ) ) ; } async function assembleWatWithWabt ( data ) { await loadWabt ( ) ; const module = wabt . parseWat ( "test.wat" , data ) ; module . resolveNames ( ) ; module . validate ( ) ; return Promise . resolve ( module . toBinary ( { log : true , write_debug_names : true } ) . buffer ) ; } interface IDominator { children : IDominator [ ] ; name : string ; retained_size : number ; retained_size_percent : number ; shallow_size : number ; shallow_size_percent : number ; } async function twiggyWasm ( data ) { await loadTwiggy ( ) ; let opts ; const items = Twiggy . Items . parse ( new Uint8Array ( data ) ) ; let md = "# Twiggy Analysis\n\nTwiggy is a code size profiler, learn more about it [here](https://github.com/rustwasm/twiggy).\n\n" ; opts = Twiggy . Top . new ( ) ; const top = JSON . parse ( items . top ( opts ) ) ; md += "## Top\n\n" ; md += "| Shallow Bytes | Shallow % | Item |\n" ; md += "| ------------: | --------: | :--- |\n" ; let ignoreCount = 0 ; const shallowSizePercentIgnoreThreshold = 0.1 ; top . forEach ( entry => { if ( entry . shallow_size_percent >= shallowSizePercentIgnoreThreshold ) { md += `| ${ entry . shallow_size } | ${ entry . shallow_size_percent . toFixed ( 2 ) } | \`${ entry . name }\` |\n` ; } else { ignoreCount ++ ; } } ) ; if ( ignoreCount ) { md += `\n### Note:\n${ ignoreCount } items had a shallow size percent less than ${ shallowSizePercentIgnoreThreshold } and were not listed above.\n` ; } md += "\n\n## Dominators\n\n" ; md += "| Retained Bytes | Retained % | Dominator Tree |\n" ; md += "| ------------: | --------: | :--- |\n" ; const retainedSizePercentIgnoreThreshold = 0.1 ; ignoreCount = 0 ; opts = Twiggy . Dominators . new ( ) ; const dominator = JSON . parse ( items . dominators ( opts ) ) ; function printDominator ( dominator , depth ) { let prefix = "" ; for ( let i = 0 ; i < depth - 1 ; i ++ ) { prefix += "   " ; } if ( depth ) { prefix += "⤷ " ; } md += `| ${ dominator . retained_size } | ${ dominator . retained_size_percent . toFixed ( 2 ) } | \`${ prefix + dominator . name }\` |\n` ; if ( dominator . children ) { dominator . children . forEach ( child => { if ( child . retained_size_percent >= retainedSizePercentIgnoreThreshold ) { printDominator ( child , depth + 1 ) ; } else { ignoreCount ++ ; } } ) ; } } printDominator ( dominator , 0 ) ; if ( ignoreCount ) { md += `\n### Note:\n${ ignoreCount } items had a retained size percent less than ${ retainedSizePercentIgnoreThreshold } and were not listed above.\n` ; } return Promise . resolve ( md ) ; }