@@ -117,6 +117,11 @@ namespace {
117117// have it as a global rather than pass it around all the time.
118118Module merged;
119119
120+ // Everything we merge is accumulated into |merged|, aside from the start
121+ // functions. To avoid incrementally adding a call each time, which can end up
122+ // nested, we add them here and generate a series of flat calls at the end.
123+ std::vector<Name> startFunctions;
124+
120125// Name conflicts on functions etc. are resolved by renaming things in a way
121126// that only matters internally. Conflicting export names, however, are
122127// observable, and so the user must decide how they want wasm-merge to handle
@@ -363,26 +368,9 @@ void copyModuleContents(Module& input, Name inputName) {
363368 merged.addExport (std::move (copy));
364369 }
365370
366- // Start functions must be merged.
367- if (input.start .is ()) {
368- if (!merged.start .is ()) {
369- // No previous start; just refer to the new one.
370- merged.start = input.start ;
371- } else {
372- // Merge them, keeping the order. We add a new function that calls the two
373- // (leaving proper inlining, including handling of control flow etc., to
374- // the optimizer).
375- auto combinedName =
376- Names::getValidFunctionName (merged, " merged.start.combined" );
377- Builder builder (merged);
378- auto * callOld = builder.makeCall (merged.start , {}, Type::none);
379- auto * callNew = builder.makeCall (input.start , {}, Type::none);
380- auto * body = builder.makeSequence (callOld, callNew);
381- auto combined = builder.makeFunction (
382- combinedName, Signature (Type::none, Type::none), {}, body);
383- merged.addFunction (std::move (combined));
384- merged.start = combinedName;
385- }
371+ // Start functions are accumulated til the end.
372+ if (input.start ) {
373+ startFunctions.push_back (input.start );
386374 }
387375
388376 // TODO: type names, features, debug info, custom sections, dylink info, etc.
@@ -594,6 +582,34 @@ void updateTypes(Module& wasm) {
594582 updater.runOnModuleCode (&runner, &wasm);
595583}
596584
585+ // Merge the start functions, keeping the order. We add a new function that
586+ // calls them in sequence (leaving proper inlining, including handling of
587+ // control flow etc., to the optimizer).
588+ void mergeStartFunctions () {
589+ if (startFunctions.empty ()) {
590+ return ;
591+ }
592+
593+ if (startFunctions.size () == 1 ) {
594+ // Avoid adding a call here.
595+ merged.start = startFunctions[0 ];
596+ return ;
597+ }
598+
599+ auto combinedName =
600+ Names::getValidFunctionName (merged, " merged.start.combined" );
601+ Builder builder (merged);
602+ std::vector<Expression*> calls;
603+ for (auto start : startFunctions) {
604+ calls.push_back (builder.makeCall (start, {}, Type::none));
605+ }
606+ auto * body = builder.makeBlock (calls);
607+ auto combined = builder.makeFunction (
608+ combinedName, Signature (Type::none, Type::none), {}, body);
609+ merged.addFunction (std::move (combined));
610+ merged.start = combinedName;
611+ }
612+
597613// Merges an input module into an existing target module. The input module can
598614// be modified, as it will no longer be needed (so it is intentionally not
599615// marked as const here).
@@ -792,6 +808,13 @@ Input source maps can be specified by adding an -ism option right after the modu
792808 for (auto & curr : merged.exports ) {
793809 exportModuleMap[curr.get ()] = ExportInfo{inputFileName, curr->name };
794810 }
811+
812+ // Start functions are accumulated til the end.
813+ if (merged.start ) {
814+ startFunctions.push_back (merged.start );
815+ merged.start = Name ();
816+ }
817+
795818 } else {
796819 // This is a later module: do a full merge.
797820 mergeInto (*currModule, inputFileName);
@@ -825,6 +848,9 @@ Input source maps can be specified by adding an -ism option right after the modu
825848 // Update types after combing and linking everything.
826849 updateTypes (merged);
827850
851+ // Merge the start functions, after everything else is set up.
852+ mergeStartFunctions ();
853+
828854 {
829855 PassRunner passRunner (&merged);
830856 // We might have made some globals read from others that now appear after
0 commit comments