@@ -171,28 +171,34 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
171171 // from the start
172172 size_t reduceDestructively (int factor_) {
173173 factor = factor_;
174- Module wasm;
175- ModuleReader reader;
176- reader.read (working, wasm);
177174 // prepare
175+ loadWorking ();
178176 reduced = 0 ;
179- builder = make_unique<Builder>(wasm);
180177 funcsSeen = 0 ;
181178 // before we do any changes, it should be valid to write out the module:
182179 // size should be as expected, and output should be as expected
183- setModule (&wasm);
184180 if (!writeAndTestReduction ()) {
185181 std::cerr << " \n |! WARNING: writing before destructive reduction fails, very unlikely reduction can work\n\n " ;
186182 }
187183 // destroy!
188- walkModule (&wasm );
184+ walkModule (getModule () );
189185 return reduced;
190186 }
191187
188+ void loadWorking () {
189+ module = make_unique<Module>();
190+ Module wasm;
191+ ModuleReader reader;
192+ reader.read (working, *module );
193+ builder = make_unique<Builder>(*module );
194+ setModule (module .get ());
195+ }
196+
192197 // destructive reduction state
193198
194199 size_t reduced;
195200 Expression* beforeReduction;
201+ std::unique_ptr<Module> module ;
196202 std::unique_ptr<Builder> builder;
197203 Index funcsSeen;
198204 int factor;
@@ -240,8 +246,8 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
240246 return true ;
241247 }
242248
243- void noteReduction () {
244- reduced++ ;
249+ void noteReduction (size_t amount = 1 ) {
250+ reduced += amount ;
245251 copy_file (test, working);
246252 }
247253
@@ -393,38 +399,99 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<
393399 }
394400
395401 void visitModule (Module* curr) {
402+ assert (curr == module .get ());
403+ // try to remove functions
404+ std::cerr << " | try to remove functions\n " ;
405+ std::vector<Name> functionNames;
406+ for (auto & func : module ->functions ) {
407+ functionNames.push_back (func->name );
408+ }
409+ size_t skip = 1 ;
410+ for (size_t i = 0 ; i < functionNames.size (); i++) {
411+ if (!shouldTryToReduce (std::max ((factor / 100 ) + 1 , 10000 ))) continue ;
412+ std::vector<Name> names;
413+ for (size_t j = 0 ; names.size () < skip && i + j < functionNames.size (); j++) {
414+ auto name = functionNames[i + j];
415+ if (module ->getFunctionOrNull (name)) {
416+ names.push_back (name);
417+ }
418+ }
419+ if (names.size () == 0 ) continue ;
420+ if (tryToRemoveFunctions (names)) {
421+ noteReduction (names.size ());
422+ skip = std::min (size_t (factor), 2 * skip);
423+ } else {
424+ skip = std::max (skip / 2 , size_t (1 )); // or 1?
425+ }
426+ std::cout << " | (new skip: " << skip << " )\n " ;
427+ }
396428 // try to remove exports
397- std::cerr << " | try to remove exports\n " ;
429+ std::cerr << " | try to remove exports (with factor " << factor << " ) \n " ;
398430 std::vector<Export> exports;
399- for (auto & exp : curr->exports ) {
400- if (!shouldTryToReduce (10000 )) continue ;
431+ for (auto & exp : module ->exports ) {
401432 exports.push_back (*exp);
402433 }
403434 for (auto & exp : exports) {
404- curr->removeExport (exp.name );
405- if (!writeAndTestReduction ()) {
406- curr->addExport (new Export (exp));
435+ module ->removeExport (exp.name );
436+ ProgramResult result;
437+ if (!writeAndTestReduction (result)) {
438+ module ->addExport (new Export (exp));
407439 } else {
408440 std::cerr << " | removed export " << exp.name << ' \n ' ;
409441 noteReduction ();
410442 }
411443 }
412- // try to remove functions
413- std::cerr << " | try to remove functions\n " ;
414- std::vector<Function> functions;
415- for (auto & func : curr->functions ) {
416- if (!shouldTryToReduce (10000 )) continue ;
417- functions.push_back (*func);
444+ }
445+
446+ bool tryToRemoveFunctions (std::vector<Name> names) {
447+ for (auto name : names) {
448+ module ->removeFunction (name);
418449 }
419- for (auto & func : functions) {
420- curr->removeFunction (func.name );
421- if (WasmValidator ().validate (*curr, Feature::MVP, WasmValidator::Globally | WasmValidator::Quiet) &&
422- writeAndTestReduction ()) {
423- std::cerr << " | removed function " << func.name << ' \n ' ;
424- noteReduction ();
425- } else {
426- curr->addFunction (new Function (func));
450+
451+ // remove all references to them
452+ struct FunctionReferenceRemover : public PostWalker <FunctionReferenceRemover> {
453+ std::unordered_set<Name> names;
454+ FunctionReferenceRemover (std::vector<Name>& vec) {
455+ for (auto name : vec) {
456+ names.insert (name);
457+ }
458+ }
459+ void visitCall (Call* curr) {
460+ if (names.count (curr->target )) {
461+ replaceCurrent (Builder (*getModule ()).replaceWithIdenticalType (curr));
462+ }
463+ }
464+ void visitTable (Table* curr) {
465+ Name other;
466+ for (auto & segment : curr->segments ) {
467+ for (auto name : segment.data ) {
468+ if (!names.count (name)) {
469+ other = name;
470+ break ;
471+ }
472+ }
473+ if (!other.isNull ()) break ;
474+ }
475+ if (other.isNull ()) return ; // we failed to find a replacement
476+ for (auto & segment : curr->segments ) {
477+ for (auto & name : segment.data ) {
478+ if (names.count (name)) {
479+ name = other;
480+ }
481+ }
482+ }
427483 }
484+ };
485+ FunctionReferenceRemover referenceRemover (names);
486+ referenceRemover.walkModule (module .get ());
487+
488+ if (WasmValidator ().validate (*module , Feature::MVP, WasmValidator::Globally | WasmValidator::Quiet) &&
489+ writeAndTestReduction ()) {
490+ std::cerr << " | removed " << names.size () << " functions\n " ;
491+ return true ;
492+ } else {
493+ loadWorking (); // restore it from orbit
494+ return false ;
428495 }
429496 }
430497
@@ -545,6 +612,7 @@ int main(int argc, const char* argv[]) {
545612 if (test.size () == 0 ) Fatal () << " test file not provided\n " ;
546613 if (working.size () == 0 ) Fatal () << " working file not provided\n " ;
547614
615+ std::cerr << " |wasm-reduce\n " ;
548616 std::cerr << " |input: " << input << ' \n ' ;
549617 std::cerr << " |test: " << test << ' \n ' ;
550618 std::cerr << " |working: " << working << ' \n ' ;
@@ -589,11 +657,12 @@ int main(int argc, const char* argv[]) {
589657 }
590658
591659 copy_file (input, working);
592- std::cerr << " |input size: " << file_size (working) << " \n " ;
660+ auto workingSize = file_size (working);
661+ std::cerr << " |input size: " << workingSize << " \n " ;
593662
594663 std::cerr << " |starting reduction!\n " ;
595664
596- int factor = 4096 ;
665+ int factor = workingSize * 2 ;
597666 size_t lastDestructiveReductions = 0 ;
598667 size_t lastPostPassesSize = 0 ;
599668
0 commit comments