@@ -710,179 +710,180 @@ function emitDCEGraph(ast) {
710710 // all content inside them as top-level, which means it is used.
711711 var specialScopes = 0 ;
712712
713- fullWalk ( ast , ( node ) => {
714- if ( isWasmImportsAssign ( node ) ) {
715- const assignedObject = getWasmImportsValue ( node ) ;
716- assignedObject . properties . forEach ( ( item ) => {
717- let value = item . value ;
718- if ( value . type === 'Literal' || value . type === 'FunctionExpression' ) {
719- return ; // if it's a numeric or function literal, nothing to do here
720- }
721- if ( value . type === 'LogicalExpression' ) {
722- // We may have something like wasmMemory || Module.wasmMemory in pthreads code;
723- // use the left hand identifier.
724- value = value . left ;
725- }
726- assertAt ( value . type === 'Identifier' , value ) ;
727- const nativeName = item . key . type == 'Literal' ? item . key . value : item . key . name ;
728- assert ( nativeName ) ;
729- imports . push ( [ value . name , nativeName ] ) ;
730- } ) ;
731- foundWasmImportsAssign = true ;
732- emptyOut ( node ) ; // ignore this in the second pass; this does not root
733- } else if ( node . type === 'AssignmentExpression' ) {
734- const target = node . left ;
735- // Ignore assignment to the wasmExports object (as happens in
736- // applySignatureConversions).
737- if ( isExportUse ( target ) ) {
738- emptyOut ( node ) ;
739- }
740- } else if ( node . type === 'VariableDeclaration' ) {
741- if ( node . declarations . length === 1 ) {
742- const item = node . declarations [ 0 ] ;
743- const name = item . id . name ;
744- const value = item . init ;
745- if ( value && isExportUse ( value ) ) {
746- const asmName = getExportOrModuleUseName ( value ) ;
747- // this is:
748- // var _x = wasmExports['x'];
749- saveAsmExport ( name , asmName ) ;
713+ fullWalk (
714+ ast ,
715+ ( node ) => {
716+ if ( isWasmImportsAssign ( node ) ) {
717+ const assignedObject = getWasmImportsValue ( node ) ;
718+ assignedObject . properties . forEach ( ( item ) => {
719+ let value = item . value ;
720+ if ( value . type === 'Literal' || value . type === 'FunctionExpression' ) {
721+ return ; // if it's a numeric or function literal, nothing to do here
722+ }
723+ if ( value . type === 'LogicalExpression' ) {
724+ // We may have something like wasmMemory || Module.wasmMemory in pthreads code;
725+ // use the left hand identifier.
726+ value = value . left ;
727+ }
728+ assertAt ( value . type === 'Identifier' , value ) ;
729+ const nativeName = item . key . type == 'Literal' ? item . key . value : item . key . name ;
730+ assert ( nativeName ) ;
731+ imports . push ( [ value . name , nativeName ] ) ;
732+ } ) ;
733+ foundWasmImportsAssign = true ;
734+ emptyOut ( node ) ; // ignore this in the second pass; this does not root
735+ } else if ( node . type === 'AssignmentExpression' ) {
736+ const target = node . left ;
737+ // Ignore assignment to the wasmExports object (as happens in
738+ // applySignatureConversions).
739+ if ( isExportUse ( target ) ) {
750740 emptyOut ( node ) ;
751- } else if ( value && value . type === 'ArrowFunctionExpression' ) {
752- // this is
753- // () => (x = wasmExports['x'])(..)
754- // or
755- // () => (x = Module['_x'] = wasmExports['x'])(..)
756- let asmName = isExportWrapperFunction ( value ) ;
757- if ( asmName ) {
741+ }
742+ } else if ( node . type === 'VariableDeclaration' ) {
743+ if ( node . declarations . length === 1 ) {
744+ const item = node . declarations [ 0 ] ;
745+ const name = item . id . name ;
746+ const value = item . init ;
747+ if ( value && isExportUse ( value ) ) {
748+ const asmName = getExportOrModuleUseName ( value ) ;
749+ // this is:
750+ // var _x = wasmExports['x'];
758751 saveAsmExport ( name , asmName ) ;
759752 emptyOut ( node ) ;
760- }
761- } else if ( value && value . type === 'AssignmentExpression' ) {
762- const assigned = value . left ;
763- if ( isModuleUse ( assigned ) && getExportOrModuleUseName ( assigned ) === name ) {
753+ } else if ( value && value . type === 'ArrowFunctionExpression' ) {
764754 // this is
765- // var x = Module['x'] = ?
766- // which looks like a wasm export being received. confirm with the asm use
767- let found = 0 ;
768- let asmName ;
769- fullWalk ( value . right , ( node ) => {
770- if ( isExportUse ( node ) ) {
771- found ++ ;
772- asmName = getExportOrModuleUseName ( node ) ;
773- }
774- } ) ;
775- // in the wasm backend, the asm name may have one fewer "_" prefixed
776- if ( found === 1 ) {
777- // this is indeed an export
778- // the asmName is what the wasm provides directly; the outside JS
779- // name may be slightly different (extra "_" in wasm backend)
755+ // () => (x = wasmExports['x'])(..)
756+ // or
757+ // () => (x = Module['_x'] = wasmExports['x'])(..)
758+ let asmName = isExportWrapperFunction ( value ) ;
759+ if ( asmName ) {
780760 saveAsmExport ( name , asmName ) ;
781- emptyOut ( node ) ; // ignore this in the second pass; this does not root
782- return ;
761+ emptyOut ( node ) ;
783762 }
784- if ( value . right . type === 'Literal' ) {
763+ } else if ( value && value . type === 'AssignmentExpression' ) {
764+ const assigned = value . left ;
765+ if ( isModuleUse ( assigned ) && getExportOrModuleUseName ( assigned ) === name ) {
785766 // this is
786- // var x = Module['x'] = 1234;
787- // this form occurs when global addresses are exported from the
788- // module. It doesn't constitute a usage.
789- assertAt ( typeof value . right . value === 'number' , value . right ) ;
790- emptyOut ( node ) ;
767+ // var x = Module['x'] = ?
768+ // which looks like a wasm export being received. confirm with the asm use
769+ let found = 0 ;
770+ let asmName ;
771+ fullWalk ( value . right , ( node ) => {
772+ if ( isExportUse ( node ) ) {
773+ found ++ ;
774+ asmName = getExportOrModuleUseName ( node ) ;
775+ }
776+ } ) ;
777+ // in the wasm backend, the asm name may have one fewer "_" prefixed
778+ if ( found === 1 ) {
779+ // this is indeed an export
780+ // the asmName is what the wasm provides directly; the outside JS
781+ // name may be slightly different (extra "_" in wasm backend)
782+ saveAsmExport ( name , asmName ) ;
783+ emptyOut ( node ) ; // ignore this in the second pass; this does not root
784+ return ;
785+ }
786+ if ( value . right . type === 'Literal' ) {
787+ // this is
788+ // var x = Module['x'] = 1234;
789+ // this form occurs when global addresses are exported from the
790+ // module. It doesn't constitute a usage.
791+ assertAt ( typeof value . right . value === 'number' , value . right ) ;
792+ emptyOut ( node ) ;
793+ }
791794 }
792795 }
793796 }
794- }
795- // A variable declaration that has no initial values can be ignored in
796- // the second pass, these are just declarations, not roots - an actual
797- // use must be found in order to root.
798- if ( ! node . declarations . reduce ( ( hasInit , decl ) => hasInit || ! ! decl . init , false ) ) {
799- emptyOut ( node ) ;
800- }
801- } else if ( node . type === 'FunctionDeclaration' ) {
802- if ( ! specialScopes ) {
803- defuns . push ( node ) ;
804- const name = node . id . name ;
805- nameToGraphName [ name ] = getGraphName ( name , 'defun' ) ;
806- emptyOut ( node ) ; // ignore this in the second pass; we scan defuns separately
807- }
808- } else if ( node . type === 'ArrowFunctionExpression' ) {
809- assert ( specialScopes > 0 ) ;
810- specialScopes -- ;
811- // Check if this is the minimal runtime exports function, which looks like
812- // (output) => { var wasmExports = output.instance.exports;
813- if (
814- node . params . length === 1 &&
815- node . params [ 0 ] . type === 'Identifier' &&
816- node . params [ 0 ] . name === 'output' &&
817- node . body . type === 'BlockStatement'
818- ) {
819- const body = node . body . body ;
820- if ( body . length >= 1 ) {
821- const first = body [ 0 ] ;
822- let target ;
823- let value ; // "(var?) target = value"
824- // Look either for var wasmExports = or just wasmExports =
825- if ( first . type === 'VariableDeclaration' && first . declarations . length === 1 ) {
826- const decl = first . declarations [ 0 ] ;
827- target = decl . id ;
828- value = decl . init ;
829- } else if (
830- first . type === 'ExpressionStatement' &&
831- first . expression . type === 'AssignmentExpression'
832- ) {
833- const assign = first . expression ;
834- if ( assign . operator === '=' ) {
835- target = assign . left ;
836- value = assign . right ;
837- }
838- }
839- if ( target && target . type === 'Identifier' && target . name === 'wasmExports' && value ) {
840- if (
841- value . type === 'MemberExpression' &&
842- value . object . type === 'MemberExpression' &&
843- value . object . object . type === 'Identifier' &&
844- value . object . object . name === 'output' &&
845- value . object . property . type === 'Identifier' &&
846- value . object . property . name === 'instance' &&
847- value . property . type === 'Identifier' &&
848- value . property . name === 'exports'
797+ // A variable declaration that has no initial values can be ignored in
798+ // the second pass, these are just declarations, not roots - an actual
799+ // use must be found in order to root.
800+ if ( ! node . declarations . reduce ( ( hasInit , decl ) => hasInit || ! ! decl . init , false ) ) {
801+ emptyOut ( node ) ;
802+ }
803+ } else if ( node . type === 'FunctionDeclaration' ) {
804+ if ( ! specialScopes ) {
805+ defuns . push ( node ) ;
806+ const name = node . id . name ;
807+ nameToGraphName [ name ] = getGraphName ( name , 'defun' ) ;
808+ emptyOut ( node ) ; // ignore this in the second pass; we scan defuns separately
809+ }
810+ } else if ( node . type === 'ArrowFunctionExpression' ) {
811+ specialScopes -- ;
812+ // Check if this is the minimal runtime exports function, which looks like
813+ // (output) => { var wasmExports = output.instance.exports;
814+ if (
815+ node . params . length === 1 &&
816+ node . params [ 0 ] . type === 'Identifier' &&
817+ node . params [ 0 ] . name === 'output' &&
818+ node . body . type === 'BlockStatement'
819+ ) {
820+ const body = node . body . body ;
821+ if ( body . length >= 1 ) {
822+ const first = body [ 0 ] ;
823+ let target ;
824+ let value ; // "(var?) target = value"
825+ // Look either for var wasmExports = or just wasmExports =
826+ if ( first . type === 'VariableDeclaration' && first . declarations . length === 1 ) {
827+ const decl = first . declarations [ 0 ] ;
828+ target = decl . id ;
829+ value = decl . init ;
830+ } else if (
831+ first . type === 'ExpressionStatement' &&
832+ first . expression . type === 'AssignmentExpression'
849833 ) {
850- // This looks very much like what we are looking for.
851- assert ( ! foundMinimalRuntimeExports ) ;
852- for ( let i = 1 ; i < body . length ; i ++ ) {
853- const item = body [ i ] ;
854- if (
855- item . type === 'ExpressionStatement' &&
856- item . expression . type === 'AssignmentExpression' &&
857- item . expression . operator === '=' &&
858- item . expression . left . type === 'Identifier' &&
859- item . expression . right . type === 'MemberExpression' &&
860- item . expression . right . object . type === 'Identifier' &&
861- item . expression . right . object . name === 'wasmExports' &&
862- item . expression . right . property . type === 'Literal'
863- ) {
864- const name = item . expression . left . name ;
865- const asmName = item . expression . right . property . value ;
866- saveAsmExport ( name , asmName ) ;
867- emptyOut ( item ) ; // ignore all this in the second pass; this does not root
834+ const assign = first . expression ;
835+ if ( assign . operator === '=' ) {
836+ target = assign . left ;
837+ value = assign . right ;
838+ }
839+ }
840+ if ( target && target . type === 'Identifier' && target . name === 'wasmExports' && value ) {
841+ if (
842+ value . type === 'MemberExpression' &&
843+ value . object . type === 'MemberExpression' &&
844+ value . object . object . type === 'Identifier' &&
845+ value . object . object . name === 'output' &&
846+ value . object . property . type === 'Identifier' &&
847+ value . object . property . name === 'instance' &&
848+ value . property . type === 'Identifier' &&
849+ value . property . name === 'exports'
850+ ) {
851+ // This looks very much like what we are looking for.
852+ assert ( ! foundMinimalRuntimeExports ) ;
853+ for ( let i = 1 ; i < body . length ; i ++ ) {
854+ const item = body [ i ] ;
855+ if (
856+ item . type === 'ExpressionStatement' &&
857+ item . expression . type === 'AssignmentExpression' &&
858+ item . expression . operator === '=' &&
859+ item . expression . left . type === 'Identifier' &&
860+ item . expression . right . type === 'MemberExpression' &&
861+ item . expression . right . object . type === 'Identifier' &&
862+ item . expression . right . object . name === 'wasmExports' &&
863+ item . expression . right . property . type === 'Literal'
864+ ) {
865+ const name = item . expression . left . name ;
866+ const asmName = item . expression . right . property . value ;
867+ saveAsmExport ( name , asmName ) ;
868+ emptyOut ( item ) ; // ignore all this in the second pass; this does not root
869+ }
868870 }
871+ foundMinimalRuntimeExports = true ;
869872 }
870- foundMinimalRuntimeExports = true ;
871873 }
872874 }
873875 }
876+ } else if ( node . type === 'Property' && node . method ) {
877+ specialScopes -- ;
874878 }
875- } else if ( node . type === 'Property' && node . method ) {
876- assert ( specialScopes > 0 ) ;
877- specialScopes -- ;
878- }
879- } , ( node ) => {
880- // Pre-walking logic. We note special scopes (see above).
881- if ( node . type === 'ArrowFunctionExpression' ||
882- ( node . type === 'Property' && node . method ) ) {
883- specialScopes ++ ;
884- }
885- } ) ;
879+ } ,
880+ ( node ) => {
881+ // Pre-walking logic. We note special scopes (see above).
882+ if ( node . type === 'ArrowFunctionExpression' || ( node . type === 'Property' && node . method ) ) {
883+ specialScopes ++ ;
884+ }
885+ } ,
886+ ) ;
886887 // Scoping must balance out.
887888 assert ( specialScopes === 0 ) ;
888889 // We must have found the info we need.
0 commit comments