Refactor the try statement analysis results.
In the dart2js CPS backend, move the frontend-specific try statement analysis results out of the frontend-independent IrBuilder and into the frontend-specific IrBuilderVisitor. BUG= R=johnniwinther@google.com Review URL: https://codereview.chromium.org//1075923002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45009 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -95,8 +95,8 @@ class CpsGeneratingVisitor extends SemanticVisitor<ir.Node>
|
||||
return withBuilder(
|
||||
new DartIrBuilder(DART_CONSTANT_SYSTEM,
|
||||
element,
|
||||
// TODO(johnniwinther): Supported closure variables.
|
||||
new NullCapturedVariables()),
|
||||
// TODO(johnniwinther): Support closure variables.
|
||||
new Set<dart2js.Local>()),
|
||||
() {
|
||||
irBuilder.buildFunctionHeader(
|
||||
constructor.parameters.map(converter.convertElement));
|
||||
@@ -114,8 +114,8 @@ class CpsGeneratingVisitor extends SemanticVisitor<ir.Node>
|
||||
return withBuilder(
|
||||
new DartIrBuilder(DART_CONSTANT_SYSTEM,
|
||||
element,
|
||||
// TODO(johnniwinther): Supported closure variables.
|
||||
new NullCapturedVariables()),
|
||||
// TODO(johnniwinther): Support closure variables.
|
||||
new Set<dart2js.Local>()),
|
||||
() {
|
||||
irBuilder.buildFieldInitializerHeader();
|
||||
ir.Primitive initializer = build(node.initializer);
|
||||
@@ -129,8 +129,8 @@ class CpsGeneratingVisitor extends SemanticVisitor<ir.Node>
|
||||
return withBuilder(
|
||||
new DartIrBuilder(DART_CONSTANT_SYSTEM,
|
||||
element,
|
||||
// TODO(johnniwinther): Supported closure variables.
|
||||
new NullCapturedVariables()),
|
||||
// TODO(johnniwinther): Support closure variables.
|
||||
new Set<dart2js.Local>()),
|
||||
() {
|
||||
irBuilder.buildFunctionHeader(
|
||||
function.parameters.map(converter.convertElement));
|
||||
@@ -585,7 +585,3 @@ class CpsGeneratingVisitor extends SemanticVisitor<ir.Node>
|
||||
catchClauseInfos: catchClauseInfos);
|
||||
}
|
||||
}
|
||||
|
||||
class NullCapturedVariables extends DartCapturedVariables {
|
||||
NullCapturedVariables() : super(null);
|
||||
}
|
||||
|
||||
@@ -416,17 +416,6 @@ class ThisParameterLocal implements Local {
|
||||
abstract class IrBuilder {
|
||||
IrBuilder _makeInstance();
|
||||
|
||||
// TODO(johnniwinther): Remove this from the [IrBuilder].
|
||||
/// A map from TryStatements in the AST to their analysis information.
|
||||
///
|
||||
/// This includes which variables should be copied into [ir.MutableVariable]s
|
||||
/// on entry to the try and copied out on exit.
|
||||
Map<ast.TryStatement, TryStatementInfo> get tryStatements;
|
||||
|
||||
/// The set of local variables that will spend their lifetime as
|
||||
/// [ir.MutableVariable]s due to being captured by a nested function.
|
||||
Set<Local> get mutableCapturedVariables;
|
||||
|
||||
/// True if [local] should currently be accessed from a [ir.MutableVariable].
|
||||
bool isInMutableVariable(Local local);
|
||||
|
||||
@@ -1593,11 +1582,7 @@ abstract class IrBuilder {
|
||||
// we can not identify all of them in the same pass where we identify the
|
||||
// variables assigned in the try (they may be captured by a closure after
|
||||
// the try statement).
|
||||
Iterable<LocalVariableElement> boxedOnEntry =
|
||||
tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) {
|
||||
return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
|
||||
});
|
||||
for (LocalVariableElement variable in boxedOnEntry) {
|
||||
for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
|
||||
assert(!tryCatchBuilder.isInMutableVariable(variable));
|
||||
ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
|
||||
tryCatchBuilder.makeMutableVariable(variable);
|
||||
@@ -1607,7 +1592,7 @@ abstract class IrBuilder {
|
||||
IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
|
||||
|
||||
void interceptJumps(JumpCollector collector) {
|
||||
collector.enterTry(boxedOnEntry);
|
||||
collector.enterTry(tryStatementInfo.boxedOnEntry);
|
||||
}
|
||||
void restoreJumps(JumpCollector collector) {
|
||||
collector.leaveTry();
|
||||
@@ -1624,7 +1609,7 @@ abstract class IrBuilder {
|
||||
tryBuilder.state.continueCollectors.forEach(restoreJumps);
|
||||
|
||||
IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
|
||||
for (LocalVariableElement variable in boxedOnEntry) {
|
||||
for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
|
||||
assert(catchBuilder.isInMutableVariable(variable));
|
||||
ir.Primitive value = catchBuilder.buildLocalGet(variable);
|
||||
// Note that we remove the variable from the set of mutable variables
|
||||
@@ -1902,9 +1887,6 @@ class DartIrBuilderSharedState {
|
||||
final Map<Local, ir.MutableVariable> local2mutable =
|
||||
<Local, ir.MutableVariable>{};
|
||||
|
||||
// Move this to the IrBuilderVisitor.
|
||||
final DartCapturedVariables capturedVariables;
|
||||
|
||||
/// Creates a [MutableVariable] for the given local.
|
||||
void makeMutableVariable(Local local) {
|
||||
ir.MutableVariable variable =
|
||||
@@ -1915,8 +1897,8 @@ class DartIrBuilderSharedState {
|
||||
/// [MutableVariable]s that should temporarily be treated as registers.
|
||||
final Set<Local> registerizedMutableVariables = new Set<Local>();
|
||||
|
||||
DartIrBuilderSharedState(this.capturedVariables) {
|
||||
capturedVariables.capturedVariables.forEach(makeMutableVariable);
|
||||
DartIrBuilderSharedState(Set<Local> capturedVariables) {
|
||||
capturedVariables.forEach(makeMutableVariable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1935,19 +1917,11 @@ class DartIrBuilder extends IrBuilder {
|
||||
|
||||
DartIrBuilder(ConstantSystem constantSystem,
|
||||
ExecutableElement currentElement,
|
||||
DartCapturedVariables capturedVariables)
|
||||
Set<Local> capturedVariables)
|
||||
: dartState = new DartIrBuilderSharedState(capturedVariables) {
|
||||
_init(constantSystem, currentElement);
|
||||
}
|
||||
|
||||
Map<ast.TryStatement, TryStatementInfo> get tryStatements {
|
||||
return dartState.capturedVariables.tryStatements;
|
||||
}
|
||||
|
||||
Set<Local> get mutableCapturedVariables {
|
||||
return dartState.capturedVariables.capturedVariables;
|
||||
}
|
||||
|
||||
bool isInMutableVariable(Local local) {
|
||||
return dartState.local2mutable.containsKey(local) &&
|
||||
!dartState.registerizedMutableVariables.contains(local);
|
||||
|
||||
@@ -142,6 +142,14 @@ abstract class IrBuilderVisitor extends SemanticVisitor<ir.Primitive, dynamic>
|
||||
final Compiler compiler;
|
||||
final SourceInformationBuilder sourceInformationBuilder;
|
||||
|
||||
/// A map from try statements in the source to analysis information about
|
||||
/// them.
|
||||
///
|
||||
/// The analysis information includes the set of variables that must be
|
||||
/// copied into [ir.MutableVariable]s on entry to the try and copied out on
|
||||
/// exit.
|
||||
Map<ast.TryStatement, TryStatementInfo> tryStatements = null;
|
||||
|
||||
// In SSA terms, join-point continuation parameters are the phis and the
|
||||
// continuation invocation arguments are the corresponding phi inputs. To
|
||||
// support name introduction and renaming for source level variables, we use
|
||||
@@ -471,7 +479,7 @@ abstract class IrBuilderVisitor extends SemanticVisitor<ir.Primitive, dynamic>
|
||||
|
||||
visitTryStatement(ast.TryStatement node) {
|
||||
// Try/catch is not yet implemented in the JS backend.
|
||||
if (this.irBuilder.tryStatements == null) {
|
||||
if (tryStatements == null) {
|
||||
return giveup(node, 'try/catch in the JS backend');
|
||||
}
|
||||
// Multiple catch blocks are not yet implemented.
|
||||
@@ -503,7 +511,7 @@ abstract class IrBuilderVisitor extends SemanticVisitor<ir.Primitive, dynamic>
|
||||
}
|
||||
|
||||
irBuilder.buildTry(
|
||||
tryStatementInfo: irBuilder.tryStatements[node],
|
||||
tryStatementInfo: tryStatements[node],
|
||||
buildTryBlock: subbuild(node.tryBlock),
|
||||
catchClauseInfos: catchClauseInfos);
|
||||
}
|
||||
@@ -1817,6 +1825,18 @@ class DartCapturedVariables extends ast.Visitor {
|
||||
capturedVariables.add(local);
|
||||
}
|
||||
|
||||
analyze(ast.Node node) {
|
||||
visit(node);
|
||||
// Variables that are captured by a closure are boxed for their entire
|
||||
// lifetime, so they never need to be boxed on entry to a try block.
|
||||
// They are not filtered out before this because we cannot identify all
|
||||
// of them in the same pass (they may be captured by a closure after the
|
||||
// try statement).
|
||||
for (TryStatementInfo info in tryStatements.values) {
|
||||
info.boxedOnEntry.removeAll(capturedVariables);
|
||||
}
|
||||
}
|
||||
|
||||
visit(ast.Node node) => node.accept(this);
|
||||
|
||||
visitNode(ast.Node node) {
|
||||
@@ -1942,19 +1962,25 @@ class DartIrBuilderVisitor extends IrBuilderVisitor {
|
||||
SourceInformationBuilder sourceInformationBuilder)
|
||||
: super(elements, compiler, sourceInformationBuilder);
|
||||
|
||||
DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
|
||||
DartCapturedVariables closures = new DartCapturedVariables(elements);
|
||||
DartIrBuilder makeIRBuilder(ExecutableElement element,
|
||||
Set<Local> capturedVariables) {
|
||||
return new DartIrBuilder(compiler.backend.constantSystem,
|
||||
element,
|
||||
capturedVariables);
|
||||
}
|
||||
|
||||
DartCapturedVariables _analyzeCapturedVariables(ExecutableElement element,
|
||||
ast.Node node) {
|
||||
DartCapturedVariables variables = new DartCapturedVariables(elements);
|
||||
if (!element.isSynthesized) {
|
||||
try {
|
||||
closures.visit(node);
|
||||
variables.analyze(node);
|
||||
} catch (e) {
|
||||
bailoutMessage = closures.bailoutMessage;
|
||||
bailoutMessage = variables.bailoutMessage;
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
return new DartIrBuilder(compiler.backend.constantSystem,
|
||||
element,
|
||||
closures);
|
||||
return variables;
|
||||
}
|
||||
|
||||
/// Recursively builds the IR for the given nested function.
|
||||
@@ -2003,7 +2029,10 @@ class DartIrBuilderVisitor extends IrBuilderVisitor {
|
||||
assert(fieldDefinition != null);
|
||||
assert(elements[fieldDefinition] != null);
|
||||
|
||||
IrBuilder builder = makeIRBuilder(fieldDefinition, element);
|
||||
DartCapturedVariables variables =
|
||||
_analyzeCapturedVariables(element, fieldDefinition);
|
||||
tryStatements = variables.tryStatements;
|
||||
IrBuilder builder = makeIRBuilder(element, variables.capturedVariables);
|
||||
|
||||
return withBuilder(builder, () {
|
||||
builder.buildFieldInitializerHeader(
|
||||
@@ -2034,7 +2063,10 @@ class DartIrBuilderVisitor extends IrBuilderVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
IrBuilder builder = makeIRBuilder(node, element);
|
||||
DartCapturedVariables variables =
|
||||
_analyzeCapturedVariables(element, node);
|
||||
tryStatements = variables.tryStatements;
|
||||
IrBuilder builder = makeIRBuilder(element, variables.capturedVariables);
|
||||
|
||||
return withBuilder(builder, () => _makeFunctionBody(element, node));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user