[vm/aot] Eliminate unnecessary try/catch and try/finally

This change adds an ability to replace

try {
  <body>
} catch (...) {
 throw;
}

and

try {
  <body>
} finally {
}

with <body> into unreachable code elimination kernel transformation,
which is used in AOT. These constructs can appear after assert code is
removed.

Issue: https://github.com/dart-lang/sdk/issues/40925
Change-Id: I7940aab316aac3a9aeadb9b506b9c0ef3f79610d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138890
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2020-03-10 21:44:43 +00:00 committed by commit-bot@chromium.org
parent ace1d9b921
commit 2397862762
3 changed files with 39 additions and 4 deletions

View file

@ -136,6 +136,37 @@ class SimpleUnreachableCodeElimination extends Transformer {
return super.visitAssertInitializer(node);
}
@override
TreeNode visitTryFinally(TryFinally node) {
node.transformChildren(this);
final fin = node.finalizer;
if (fin == null || (fin is Block && fin.statements.isEmpty)) {
return node.body;
}
return node;
}
bool _isRethrow(Statement body) {
if (body is ExpressionStatement && body.expression is Rethrow) {
return true;
} else if (body is Block && body.statements.length == 1) {
return _isRethrow(body.statements.single);
}
return false;
}
@override
TreeNode visitTryCatch(TryCatch node) {
node.transformChildren(this);
// Can replace try/catch with its body if all catches are just rethow.
for (Catch catchClause in node.catches) {
if (!_isRethrow(catchClause.body)) {
return node;
}
}
return node.body;
}
// Make sure we're not generating `null` bodies.
// Try/catch, try/finally and switch/case statements
// always have a Block in a body, so there is no

View file

@ -96,6 +96,12 @@ testRemovalOfStatementBodies() {
} catch (e) {
assert(foo());
}
try {
assert(foo());
} catch (e) {
assert(foo());
rethrow;
}
switch (42) {
case 10:
assert(foo());

View file

@ -63,14 +63,12 @@ static method testRemovalOfStatementBodies() → dynamic {
core::int* i = :sync-for-iterator.{core::Iterator::current};
}
}
try {
}
finally {
}
{}
try {
}
on dynamic catch(final dynamic e) {
}
{}
switch(42) {
#L1:
case #C3: