| // Copyright 2015 The Emscripten Authors. All rights reserved. |
| // Emscripten is available under two separate licenses, the MIT license and the |
| // University of Illinois/NCSA Open Source License. Both these licenses can be |
| // found in the LICENSE file. |
| |
| //============================================================================== |
| // Optimizer tool. This is meant to be run after the emscripten compiler has |
| // finished generating code. These optimizations are done on the generated |
| // code to further improve it. |
| // |
| // Be aware that this is *not* a general JS optimizer. It assumes that the |
| // input is valid asm.js and makes strong assumptions based on this. It may do |
| // anything from crashing to optimizing incorrectly if the input is not valid! |
| //============================================================================== |
| |
| #include "simple_ast.h" |
| #include "optimizer.h" |
| |
| #include <string.h> // only use this for param checking |
| |
| using namespace cashew; |
| |
| int main(int argc, char **argv) { |
| // Read directives |
| for (int i = 2; i < argc; i++) { |
| std::string str(argv[i]); |
| if (str == "asm") {} // the only possibility for us |
| else if (str == "asmPreciseF32") preciseF32 = true; |
| else if (str == "receiveJSON") receiveJSON = true; |
| else if (str == "emitJSON") emitJSON = true; |
| else if (str == "minifyWhitespace") minifyWhitespace = true; |
| else if (str == "last") last = true; |
| } |
| |
| #ifdef PROFILING |
| std::string str("reading and parsing"); |
| clock_t start = clock(); |
| errv("starting %s", str.c_str()); |
| #endif |
| |
| // Read input file |
| FILE *f = fopen(argv[1], "r"); |
| assert(f); |
| fseek(f, 0, SEEK_END); |
| int size = ftell(f); |
| char *input = new char[size+1]; |
| rewind(f); |
| int num = fread(input, 1, size, f); |
| // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when |
| // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one), |
| // so return value of fread can be less than size reported by ftell, and that is normal. |
| assert((num > 0 || size == 0) && num <= size); |
| fclose(f); |
| input[num] = 0; |
| |
| char *extraInfoStart = strstr(input, "// EXTRA_INFO:"); |
| if (extraInfoStart) { |
| extraInfo = arena.alloc(); |
| extraInfo->parse(extraInfoStart + 14); |
| *extraInfoStart = 0; // ignore extra info when parsing |
| } |
| |
| Ref doc; |
| |
| if (receiveJSON) { |
| // Parse JSON source into the document |
| doc = arena.alloc(); |
| doc->parse(input); |
| } else { |
| cashew::Parser<Ref, ValueBuilder> builder; |
| doc = builder.parseToplevel(input); |
| } |
| // do not free input, its contents are used as strings |
| |
| #ifdef PROFILING |
| errv(" %s took %lu milliseconds", str.c_str(), (clock() - start)/1000); |
| #endif |
| |
| // Run passes on the Document |
| for (int i = 2; i < argc; i++) { |
| std::string str(argv[i]); |
| #ifdef PROFILING |
| clock_t start = clock(); |
| errv("starting %s", str.c_str()); |
| #endif |
| bool worked = true; |
| if (str == "asm") { worked = false; } // the default for us |
| else if (str == "asmPreciseF32") { worked = false; } |
| else if (str == "receiveJSON" || str == "emitJSON") { worked = false; } |
| else if (str == "eliminateDeadFuncs") eliminateDeadFuncs(doc); |
| else if (str == "eliminate") eliminate(doc); |
| else if (str == "eliminateMemSafe") eliminateMemSafe(doc); |
| else if (str == "simplifyExpressions") simplifyExpressions(doc); |
| else if (str == "optimizeFrounds") optimizeFrounds(doc); |
| else if (str == "simplifyIfs") simplifyIfs(doc); |
| else if (str == "registerize") registerize(doc); |
| else if (str == "registerizeHarder") registerizeHarder(doc); |
| else if (str == "minifyLocals") minifyLocals(doc); |
| else if (str == "minifyWhitespace") { worked = false; } |
| else if (str == "asmLastOpts") asmLastOpts(doc); |
| else if (str == "last") { worked = false; } |
| else if (str == "noop") { worked = false; } |
| else { |
| fprintf(stderr, "unrecognized argument: %s\n", str.c_str()); |
| abort(); |
| } |
| #ifdef PROFILING |
| errv(" %s took %lu milliseconds", str.c_str(), (clock() - start)/1000); |
| #endif |
| #ifdef DEBUGGING |
| if (worked) { |
| std::cerr << "ast after " << str << ":\n"; |
| doc->stringify(std::cerr); |
| std::cerr << "\n"; |
| } |
| #endif |
| } |
| |
| // Emit |
| if (emitJSON) { |
| doc->stringify(std::cout); |
| std::cout << "\n"; |
| } else { |
| JSPrinter jser(!minifyWhitespace, last, doc); |
| jser.printAst(); |
| std::cout << jser.buffer << "\n"; |
| } |
| return 0; |
| } |
| |