diff options
-rwxr-xr-x | build-js.sh | 1 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/Inlining.cpp | 4 | ||||
-rw-r--r-- | src/passes/MergeBlocks.cpp | 2 | ||||
-rw-r--r-- | src/passes/Metrics.cpp | 4 | ||||
-rw-r--r-- | src/passes/NoExitRuntime.cpp | 60 | ||||
-rw-r--r-- | src/passes/pass.cpp | 1 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | test/passes/no-exit-runtime.txt | 32 | ||||
-rw-r--r-- | test/passes/no-exit-runtime.wast | 15 |
10 files changed, 116 insertions, 5 deletions
diff --git a/build-js.sh b/build-js.sh index 808329386..f9553e3e4 100755 --- a/build-js.sh +++ b/build-js.sh @@ -115,6 +115,7 @@ echo "building shared bitcode" $BINARYEN_SRC/passes/Metrics.cpp \ $BINARYEN_SRC/passes/MinifyImportsAndExports.cpp \ $BINARYEN_SRC/passes/NameList.cpp \ + $BINARYEN_SRC/passes/NoExitRuntime.cpp \ $BINARYEN_SRC/passes/OptimizeInstructions.cpp \ $BINARYEN_SRC/passes/PickLoadSigns.cpp \ $BINARYEN_SRC/passes/PostEmscripten.cpp \ diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index b4e396750..0ad9dbf05 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -30,6 +30,7 @@ SET(passes_SOURCES Metrics.cpp MinifyImportsAndExports.cpp NameList.cpp + NoExitRuntime.cpp OptimizeInstructions.cpp PickLoadSigns.cpp PostEmscripten.cpp diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index ebc33bf97..35afc5776 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -349,11 +349,11 @@ struct Inlining : public Pass { } }; -Pass *createInliningPass() { +Pass* createInliningPass() { return new Inlining(); } -Pass *createInliningOptimizingPass() { +Pass* createInliningOptimizingPass() { auto* ret = new Inlining(); ret->optimize = true; return ret; diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp index 57f8b7e41..38e9fc6a2 100644 --- a/src/passes/MergeBlocks.cpp +++ b/src/passes/MergeBlocks.cpp @@ -373,7 +373,7 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> { Pass* create() override { return new MergeBlocks; } - void visitBlock(Block *curr) { + void visitBlock(Block* curr) { optimizeBlock(curr, getModule(), getPassOptions()); } diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp index 5176f8762..b794ea32d 100644 --- a/src/passes/Metrics.cpp +++ b/src/passes/Metrics.cpp @@ -194,11 +194,11 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor< } }; -Pass *createMetricsPass() { +Pass* createMetricsPass() { return new Metrics(false); } -Pass *createFunctionMetricsPass() { +Pass* createFunctionMetricsPass() { return new Metrics(true); } diff --git a/src/passes/NoExitRuntime.cpp b/src/passes/NoExitRuntime.cpp new file mode 100644 index 000000000..d76bb34ba --- /dev/null +++ b/src/passes/NoExitRuntime.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Assumes the program will never exit the runtime (as in the emscripten +// NO_EXIT_RUNTIME option). That means that atexit()s do not need to be +// run. +// + +#include <pass.h> +#include <wasm.h> +#include <wasm-builder.h> +#include <asmjs/shared-constants.h> + +using namespace std; + +namespace wasm { + +struct NoExitRuntime : public WalkerPass<PostWalker<NoExitRuntime>> { + bool isFunctionParallel() override { return true; } + + Pass* create() override { return new NoExitRuntime; } + + void visitCall(Call* curr) { + auto* import = getModule()->getFunctionOrNull(curr->target); + if (!import || !import->imported() || import->module != ENV) return; + // Remove all possible manifestations of atexit, across asm2wasm and llvm wasm backend. + for (auto* name : { + "___cxa_atexit", + "_atexit", + "__cxa_atexit", + "atexit", + }) { + if (strcmp(name, import->base.str) == 0) { + replaceCurrent( + Builder(*getModule()).replaceWithIdenticalType(curr) + ); + } + } + } +}; + +Pass* createNoExitRuntimePass() { + return new NoExitRuntime(); +} + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index c42a3d144..f250b7de6 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -98,6 +98,7 @@ void PassRegistry::registerPasses() { registerPass("minify-imports", "minifies import names (only those, and not export names), and emits a mapping to the minified ones", createMinifyImportsPass); registerPass("minify-imports-and-exports", "minifies both import and export names, and emits a mapping to the minified ones", createMinifyImportsAndExportsPass); registerPass("nm", "name list", createNameListPass); + registerPass("no-exit-runtime", "removes calls to atexit(), which is valid if the C runtime will never be exited", createNoExitRuntimePass); registerPass("optimize-instructions", "optimizes instruction combinations", createOptimizeInstructionsPass); registerPass("optimize-stack-ir", "optimize Stack IR", createOptimizeStackIRPass); registerPass("pick-load-signs", "pick load signs based on their uses", createPickLoadSignsPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index 8f5ca7e0a..df4322eee 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -55,6 +55,7 @@ Pass* createMinifyImportsPass(); Pass* createMinifyImportsAndExportsPass(); Pass* createMetricsPass(); Pass* createNameListPass(); +Pass* createNoExitRuntimePass(); Pass* createOptimizeInstructionsPass(); Pass* createOptimizeStackIRPass(); Pass* createPickLoadSignsPass(); diff --git a/test/passes/no-exit-runtime.txt b/test/passes/no-exit-runtime.txt new file mode 100644 index 000000000..c8913d32a --- /dev/null +++ b/test/passes/no-exit-runtime.txt @@ -0,0 +1,32 @@ +(module + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $1 (func)) + (import "env" "atexit" (func $fimport$0 (param i32 i32) (result i32))) + (import "env" "__cxa_atexit" (func $fimport$1 (param i32 i32) (result i32))) + (import "env" "_atexit" (func $fimport$2 (param i32 i32) (result i32))) + (import "env" "___cxa_atexit" (func $fimport$3 (param i32 i32) (result i32))) + (import "env" "other" (func $fimport$4 (param i32 i32) (result i32))) + (func $caller (; 5 ;) (type $1) + (drop + (i32.const 0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 0) + ) + (drop + (i32.const 0) + ) + (drop + (call $fimport$4 + (i32.const 0) + (i32.const 1) + ) + ) + (drop + (unreachable) + ) + ) +) diff --git a/test/passes/no-exit-runtime.wast b/test/passes/no-exit-runtime.wast new file mode 100644 index 000000000..1afe5ef8d --- /dev/null +++ b/test/passes/no-exit-runtime.wast @@ -0,0 +1,15 @@ +(module + (import "env" "atexit" (func $fimport$0 (param i32 i32) (result i32))) + (import "env" "__cxa_atexit" (func $fimport$1 (param i32 i32) (result i32))) + (import "env" "_atexit" (func $fimport$2 (param i32 i32) (result i32))) + (import "env" "___cxa_atexit" (func $fimport$3 (param i32 i32) (result i32))) + (import "env" "other" (func $fimport$4 (param i32 i32) (result i32))) + (func $caller + (drop (call $fimport$0 (i32.const 0) (i32.const 1))) + (drop (call $fimport$1 (i32.const 0) (i32.const 1))) + (drop (call $fimport$2 (i32.const 0) (i32.const 1))) + (drop (call $fimport$3 (i32.const 0) (i32.const 1))) + (drop (call $fimport$4 (i32.const 0) (i32.const 1))) + (drop (call $fimport$0 (unreachable) (i32.const 1))) + ) +) |