@@ -20,7 +20,6 @@ import {
2020 ATPOSTRUNS ,
2121 defineI64Param ,
2222 indentify ,
23- isSymbolNeeded ,
2423 makeReturn64 ,
2524 modifyJSFunction ,
2625 preprocess ,
@@ -47,6 +46,8 @@ import {
4746import { extraExports , LibraryManager , librarySymbols , nativeAliases } from './modules.mjs' ;
4847
4948const addedLibraryItems = { } ;
49+ const emittedLibraryItems = new Set ( ) ;
50+ const deferredAliases = { } ;
5051
5152// Some JS-implemented library functions are proxied to be called on the main
5253// browser thread, if the Emscripten runtime is executing in a Web Worker.
@@ -301,15 +302,17 @@ function calculateDeps(snippet, deps, symbol, symbolsOnly = false) {
301302 dep = name . slice ( 1 ) ;
302303 }
303304
304- if ( dep && dep !== symbol ) {
305+ // $noExitRuntime cannot be referenced via __deps (it must be included via
306+ // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE or EXPORTED_RUNTIME_METHODS).
307+ if ( dep && dep !== symbol && dep !== '$noExitRuntime' ) {
305308 found . add ( dep ) ;
306309 }
307310 }
308311
309312 const isUserSymbol = symbol && LibraryManager . library [ symbol + '__user' ] ;
310313 for ( const dep of found ) {
311314 if ( deps . includes ( dep ) ) {
312- if ( ! symbolsOnly && symbol && isUserSymbol && STRICT && LibraryManager . library [ symbol ] !== dep ) {
315+ if ( ! symbolsOnly && symbol && ( STRICT || ! isUserSymbol ) && LibraryManager . library [ symbol ] !== dep ) {
313316 warn ( `${ symbol } : redundant __deps entry: ${ dep } ` ) ;
314317 }
315318 } else {
@@ -771,11 +774,12 @@ function(${args}) {
771774 }
772775 }
773776
777+ let aliasTarget ;
774778 if ( LibraryManager . isAlias ( snippet ) ) {
775779 // Redirection for aliases. We include the parent, and at runtime
776780 // make ourselves equal to it. This avoid having duplicate
777781 // functions with identical content.
778- const aliasTarget = snippet ;
782+ aliasTarget = snippet ;
779783 if ( WASM_EXPORTS . has ( aliasTarget ) ) {
780784 debugLog ( `native alias: ${ mangled } -> ${ aliasTarget } ` ) ;
781785 nativeAliases [ mangled ] = aliasTarget ;
@@ -818,8 +822,10 @@ function(${args}) {
818822
819823 const isUserSymbol = LibraryManager . library [ symbol + '__user' ] ;
820824 // Check for dependencies on `__internal` symbols from user libraries.
825+ // Exclude `implicitSnippetDeps` (such as `$getWasmTableEntry`, which is
826+ // injected by the `{{{ makeDynCall }}}` macro).
821827 for ( const dep of deps ) {
822- if ( isUserSymbol && LibraryManager . library [ dep + '__internal' ] ) {
828+ if ( isUserSymbol && LibraryManager . library [ dep + '__internal' ] && ! implicitSnippetDeps . has ( dep . slice ( 1 ) ) ) {
823829 warn ( `user library symbol '${ symbol } ' depends on internal symbol '${ dep } '` ) ;
824830 }
825831 }
@@ -833,7 +839,7 @@ function(${args}) {
833839 // $noExitRuntime is special since there are conditional usages of it
834840 // in libcore.js and libpthread.js. These happen before deps are
835841 // processed so depending on it via `__deps` doesn't work.
836- if ( dep === '$noExitRuntime' && ! isSymbolNeeded ( '$noExitRuntime' ) ) {
842+ if ( dep === '$noExitRuntime' ) {
837843 error ( 'noExitRuntime cannot be referenced via __deps mechanism. Use DEFAULT_LIBRARY_FUNCS_TO_INCLUDE or EXPORTED_RUNTIME_METHODS' ) ;
838844 }
839845 return addFromLibrary ( dep , `${ symbol } , referenced by ${ dependent } ` ) ;
@@ -938,7 +944,23 @@ function(${args}) {
938944 . filter ( ( x ) => x != '' )
939945 . join ( '\n' ) + '\n'
940946 : '' ;
941- return depsText + commentText + contentText ;
947+ if ( aliasTarget && ! isNativeAlias && ! isFunction && ! emittedLibraryItems . has ( aliasTarget ) ) {
948+ // If `aliasTarget` is not yet emitted, we are in a dependency cycle
949+ // where `aliasTarget` is an ancestor on the recursion stack. Defer
950+ // emitting `var _alias = _target;` until immediately after `_target`
951+ // is defined so `_target` is not referenced before its initialization.
952+ ( deferredAliases [ aliasTarget ] ??= [ ] ) . push ( { symbol, text : commentText + contentText } ) ;
953+ return depsText . trim ( ) ;
954+ }
955+ function flushDeferred ( sym ) {
956+ emittedLibraryItems . add ( sym ) ;
957+ let res = '' ;
958+ for ( const item of deferredAliases [ sym ] ?? [ ] ) {
959+ res += '\n' + item . text + flushDeferred ( item . symbol ) ;
960+ }
961+ return res ;
962+ }
963+ return depsText + commentText + contentText + flushDeferred ( symbol ) ;
942964 }
943965
944966 const JS = addFromLibrary ( symbol , 'root reference (e.g. compiled C/C++ code)' ) ;
0 commit comments