summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-03-01 19:33:10 +0000
committerGitHub <noreply@github.com>2021-03-01 11:33:10 -0800
commit575aec37f3fe4793b1d16275426c6369864e1540 (patch)
treeb9d047a7d56fb89c8f63c9ebdef99cd4f5a7886f
parent27a841eec6ceb171caae2a2cbd7c92ecdf8d78eb (diff)
downloadbinaryen-575aec37f3fe4793b1d16275426c6369864e1540.tar.gz
binaryen-575aec37f3fe4793b1d16275426c6369864e1540.tar.bz2
binaryen-575aec37f3fe4793b1d16275426c6369864e1540.zip
[Wasm Exceptions] Fix/work around delegate issues in Inlining pass (#3633)
1. Ignore the fake delegate target in the unique name mapper. The mapper is run after inlining, so this fixes inlining into a function that has a delegate to the caller. 2. Do not inline a function with a delegate. We should support this eventually, but for now I think this is good enough. After this Inlining should be safe to run on exceptions code.
-rw-r--r--src/parsing.h5
-rw-r--r--src/passes/Inlining.cpp12
-rw-r--r--test/passes/inlining_all-features.txt30
-rw-r--r--test/passes/inlining_all-features.wast27
4 files changed, 74 insertions, 0 deletions
diff --git a/src/parsing.h b/src/parsing.h
index 9c3e0cd19..a8ed8b13f 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -321,6 +321,11 @@ struct UniqueNameMapper {
}
Name sourceToUnique(Name sName) {
+ // DELEGATE_CALLER_TARGET is a fake target used to denote delegating to the
+ // caller. We do not need to modify it, as it has no definitions, only uses.
+ if (sName == DELEGATE_CALLER_TARGET) {
+ return DELEGATE_CALLER_TARGET;
+ }
if (labelMappings.find(sName) == labelMappings.end()) {
throw ParseException("bad label in sourceToUnique");
}
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 44ebbd54d..d0a69ea96 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -48,6 +48,7 @@ struct FunctionInfo {
Index size;
bool hasCalls;
bool hasLoops;
+ bool hasTryDelegate;
bool usedGlobally; // in a table or export
FunctionInfo() {
@@ -55,11 +56,16 @@ struct FunctionInfo {
size = 0;
hasCalls = false;
hasLoops = false;
+ hasTryDelegate = false;
usedGlobally = false;
}
// See pass.h for how defaults for these options were chosen.
bool worthInlining(PassOptions& options) {
+ // Until we have proper support for try-delegate, ignore such functions.
+ if (hasTryDelegate) {
+ return false;
+ }
// If it's small enough that we always want to inline such things, do so.
if (size <= options.inlining.alwaysInlineMaxSize) {
return true;
@@ -113,6 +119,12 @@ struct FunctionInfoScanner
(*infos)[getFunction()->name].hasCalls = true;
}
+ void visitTry(Try* curr) {
+ if (curr->isDelegate()) {
+ (*infos)[getFunction()->name].hasTryDelegate = true;
+ }
+ }
+
void visitRefFunc(RefFunc* curr) {
assert(infos->count(curr->func) > 0);
(*infos)[curr->func].refs++;
diff --git a/test/passes/inlining_all-features.txt b/test/passes/inlining_all-features.txt
index e0ecf57b5..f255ed8ff 100644
--- a/test/passes/inlining_all-features.txt
+++ b/test/passes/inlining_all-features.txt
@@ -79,3 +79,33 @@
)
)
)
+(module
+ (type $none_=>_none (func))
+ (func $0
+ (try $label$3
+ (do
+ (nop)
+ )
+ (delegate 0)
+ )
+ )
+ (func $1
+ (call $0)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $1 (result i32)
+ (try $label$3
+ (do
+ (nop)
+ )
+ (delegate 0)
+ )
+ (block (result i32)
+ (block $__inlined_func$0 (result i32)
+ (i32.const 42)
+ )
+ )
+ )
+)
diff --git a/test/passes/inlining_all-features.wast b/test/passes/inlining_all-features.wast
index 3890d63a1..4b20d4240 100644
--- a/test/passes/inlining_all-features.wast
+++ b/test/passes/inlining_all-features.wast
@@ -64,3 +64,30 @@
)
)
)
+;; for now, do not inline a try-delegate
+(module
+ (type $none_=>_none (func))
+ (func $0
+ (try $label$3
+ (do)
+ (delegate 0)
+ )
+ )
+ (func $1
+ (call $0)
+ )
+)
+;; properly support inlining into a function with a try-delegate
+(module
+ (type $none_=>_none (func))
+ (func $0 (result i32)
+ (i32.const 42)
+ )
+ (func $1 (result i32)
+ (try $label$3
+ (do)
+ (delegate 0)
+ )
+ (call $0)
+ )
+)