summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-04-05 14:49:25 -0700
committerGitHub <noreply@github.com>2018-04-05 14:49:25 -0700
commit5b5789495a97602869f18d552b2a9e1814edefae (patch)
treef70e304fc85dca03ebd6d2311007476700e1ffd0
parent82151243bbd4c018191721dce5381c8e449f3c77 (diff)
downloadbinaryen-5b5789495a97602869f18d552b2a9e1814edefae.tar.gz
binaryen-5b5789495a97602869f18d552b2a9e1814edefae.tar.bz2
binaryen-5b5789495a97602869f18d552b2a9e1814edefae.zip
when creating blocks in binary format parsing, we know if a block has a break to it - use that to avoid rescanning blocks for unreachability purposes (#1495)
-rw-r--r--src/wasm-binary.h1
-rw-r--r--src/wasm.h13
-rw-r--r--src/wasm/wasm-binary.cpp2
-rw-r--r--src/wasm/wasm.cpp28
4 files changed, 31 insertions, 13 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index e03fd29ea..b8eb86d31 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -890,6 +890,7 @@ public:
BreakTarget(Name name, int arity) : name(name), arity(arity) {}
};
std::vector<BreakTarget> breakStack;
+ // the names that breaks target. this lets us know if a block has breaks to it or not.
std::unordered_set<Name> breakTargetNames;
std::vector<Expression*> expressionStack;
diff --git a/src/wasm.h b/src/wasm.h
index f5802052b..9d8648308 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -250,13 +250,20 @@ public:
Name name;
ExpressionList list;
+ // set the type purely based on its contents. this scans the block, so it is not fast.
+ void finalize();
+
// set the type given you know its type, which is the case when parsing
// s-expression or binary, as explicit types are given. the only additional work
- // this does is to set the type to unreachable in the cases that is needed.
+ // this does is to set the type to unreachable in the cases that is needed
+ // (which may require scanning the block)
void finalize(Type type_);
- // set the type purely based on its contents. this scans the block, so it is not fast
- void finalize();
+ // set the type given you know its type, and you know if there is a break to this
+ // block. this avoids the need to scan the contents of the block in the case that
+ // it might be unreachable, so it is recommended if you already know the type
+ // and breakability anyhow.
+ void finalize(Type type_, bool hasBreak);
};
class If : public SpecificExpression<Expression::IfId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 7a459eb7f..f70f74c56 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -2375,7 +2375,7 @@ void WasmBinaryBuilder::visitBlock(Block *curr) {
throw ParseException("block cannot pop from outside");
}
pushBlockElements(curr, start, end);
- curr->finalize(curr->type);
+ curr->finalize(curr->type, breakTargetNames.find(curr->name) != breakTargetNames.end() /* hasBreak */);
breakStack.pop_back();
breakTargetNames.erase(curr->name);
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index cf847d5aa..5fc2ee715 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -171,7 +171,7 @@ static Type mergeTypes(std::vector<Type>& types) {
// a block is unreachable if one of its elements is unreachable,
// and there are no branches to it
-static void handleUnreachable(Block* block) {
+static void handleUnreachable(Block* block, bool breakabilityKnown=false, bool hasBreak=false) {
if (block->type == unreachable) return; // nothing to do
if (block->list.size() == 0) return; // nothing to do
// if we are concrete, stop - even an unreachable child
@@ -182,7 +182,10 @@ static void handleUnreachable(Block* block) {
for (auto* child : block->list) {
if (child->type == unreachable) {
// there is an unreachable child, so we are unreachable, unless we have a break
- if (!BranchUtils::BranchSeeker::hasNamed(block, block->name)) {
+ if (!breakabilityKnown) {
+ hasBreak = BranchUtils::BranchSeeker::hasNamed(block, block->name);
+ }
+ if (!hasBreak) {
block->type = unreachable;
}
return;
@@ -190,13 +193,6 @@ static void handleUnreachable(Block* block) {
}
}
-void Block::finalize(Type type_) {
- type = type_;
- if (type == none && list.size() > 0) {
- handleUnreachable(this);
- }
-}
-
void Block::finalize() {
if (!name.is()) {
if (list.size() > 0) {
@@ -231,6 +227,20 @@ void Block::finalize() {
handleUnreachable(this);
}
+void Block::finalize(Type type_) {
+ type = type_;
+ if (type == none && list.size() > 0) {
+ handleUnreachable(this);
+ }
+}
+
+void Block::finalize(Type type_, bool hasBreak) {
+ type = type_;
+ if (type == none && list.size() > 0) {
+ handleUnreachable(this, true, hasBreak);
+ }
+}
+
void If::finalize(Type type_) {
type = type_;
if (type == none && (condition->type == unreachable || (ifFalse && ifTrue->type == unreachable && ifFalse->type == unreachable))) {