| Index: pkg/compiler/lib/src/closure.dart
|
| diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
|
| index 16e04cdb17dea8463ba9e8511640ab16f6d41f40..fe91dc9434b41525b105502c0844d2da107ce059 100644
|
| --- a/pkg/compiler/lib/src/closure.dart
|
| +++ b/pkg/compiler/lib/src/closure.dart
|
| @@ -43,6 +43,10 @@ abstract class ClosureDataLookup<T> {
|
| /// used inside the scope of [node].
|
| // TODO(johnniwinther): Split this up into two functions, one for members and
|
| // one for local functions.
|
| + ScopeInfo getScopeInfo(covariant Entity member);
|
| +
|
| + /// This returns the same information as ScopeInfo, but can be called in
|
| + /// situations when you are sure you are dealing with a closure specifically.
|
| ClosureRepresentationInfo getClosureRepresentationInfo(
|
| covariant Entity member);
|
|
|
| @@ -54,6 +58,35 @@ abstract class ClosureDataLookup<T> {
|
| ClosureAnalysisInfo getClosureAnalysisInfo(T node);
|
| }
|
|
|
| +/// Class that represents one level of scoping information, whether this scope
|
| +/// is a closure or not. This is specifically used to store information
|
| +/// about the usage of variables in try or sync blocks, because they need to be
|
| +/// boxed.
|
| +///
|
| +/// Variables that are used in a try must be treated as boxed because the
|
| +/// control flow can be non-linear. Also parameters to a `sync*` generator must
|
| +/// be boxed, because of the way we rewrite sync* functions. See also comments
|
| +/// in [ClosureClassMap.useLocal].
|
| +class ScopeInfo {
|
| + const ScopeInfo();
|
| +
|
| + /// Returns true if this [variable] is used inside a `try` block or a `sync*`
|
| + /// generator (this is important to know because boxing/redirection needs to
|
| + /// happen for those local variables).
|
| + ///
|
| + /// Variables that are used in a try must be treated as boxed because the
|
| + /// control flow can be non-linear.
|
| + ///
|
| + /// Also parameters to a `sync*` generator must be boxed, because of the way
|
| + /// we rewrite sync* functions. See also comments in
|
| + /// [ClosureClassMap.useLocal].
|
| + bool variableIsUsedInTryOrSync(Local variable) => false;
|
| +
|
| + /// Convenience reference pointer to the element representing `this`.
|
| + /// If this scope is not in an instance member, it will be null.
|
| + Local get thisLocal => null;
|
| +}
|
| +
|
| /// Class that provides a black-box interface to information gleaned from
|
| /// analyzing a closure's characteristics, most commonly used to influence how
|
| /// code should be generated in SSA builder stage.
|
| @@ -138,7 +171,7 @@ class LoopClosureRepresentationInfo extends ClosureAnalysisInfo {
|
| /// used in the inner scope of this closure, we say `y` is a "captured"
|
| /// variable.
|
| /// TODO(efortuna): Make interface simpler in subsequent refactorings.
|
| -class ClosureRepresentationInfo {
|
| +class ClosureRepresentationInfo extends ScopeInfo {
|
| const ClosureRepresentationInfo();
|
|
|
| /// The original local function before any translation.
|
| @@ -162,26 +195,10 @@ class ClosureRepresentationInfo {
|
| /// accessor to that set of fields.
|
| List<Local> get createdFieldEntities => const <Local>[];
|
|
|
| - /// Convenience reference pointer to the element representing `this`.
|
| - /// It is only set for instance-members.
|
| - Local get thisLocal => null;
|
| -
|
| /// Convenience pointer to the field entity representation in the closure
|
| /// class of the element representing `this`.
|
| FieldEntity get thisFieldEntity => null;
|
|
|
| - /// Returns true if this [variable] is used inside a `try` block or a `sync*`
|
| - /// generator (this is important to know because boxing/redirection needs to
|
| - /// happen for those local variables).
|
| - ///
|
| - /// Variables that are used in a try must be treated as boxed because the
|
| - /// control flow can be non-linear.
|
| - ///
|
| - /// Also parameters to a `sync*` generator must be boxed, because of the way
|
| - /// we rewrite sync* functions. See also comments in
|
| - /// [ClosureClassMap.useLocal].
|
| - bool variableIsUsedInTryOrSync(Local variable) => false;
|
| -
|
| /// Loop through every variable that has been captured in this closure. This
|
| /// consists of all the free variables (variables captured *just* in this
|
| /// closure) and all variables captured in nested scopes that we may be
|
| @@ -233,6 +250,10 @@ class ClosureTask extends ClosureConversionTask<Node> {
|
| return value == null ? const ClosureAnalysisInfo() : value;
|
| }
|
|
|
| + ScopeInfo getScopeInfo(Element member) {
|
| + return getClosureToClassMapping(member);
|
| + }
|
| +
|
| ClosureRepresentationInfo getClosureRepresentationInfo(Element member) {
|
| return getClosureToClassMapping(member);
|
| }
|
| @@ -690,13 +711,17 @@ class ClosureClassMap implements ClosureRepresentationInfo {
|
| /// not contain any nested closure.
|
| final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>();
|
|
|
| + /// Set of [variable]s referenced in this scope that are used inside a
|
| + /// `try` block or a `sync*` generator (this is important to know because
|
| + /// boxing/redirection needs to happen for those local variables).
|
| + ///
|
| /// Variables that are used in a try must be treated as boxed because the
|
| /// control flow can be non-linear.
|
| ///
|
| /// Also parameters to a `sync*` generator must be boxed, because of the way
|
| /// we rewrite sync* functions. See also comments in [useLocal].
|
| // TODO(johnniwinther): Add variables to this only if the variable is mutated.
|
| - final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>();
|
| + final Set<Local> variablesUsedInTryOrSync = new Set<Local>();
|
|
|
| ClosureClassMap(this.closureEntity, this.closureClassEntity, this.callMethod,
|
| this.thisLocal);
|
| @@ -728,7 +753,7 @@ class ClosureClassMap implements ClosureRepresentationInfo {
|
| FieldEntity get thisFieldEntity => freeVariableMap[thisLocal];
|
|
|
| bool variableIsUsedInTryOrSync(Local variable) =>
|
| - variablesUsedInTryOrGenerator.contains(variable);
|
| + variablesUsedInTryOrSync.contains(variable);
|
|
|
| Local getLocalVariableForClosureField(ClosureFieldElement field) {
|
| return field.local;
|
| @@ -969,13 +994,13 @@ class ClosureTranslator extends Visitor {
|
| if (variable != closureData.thisLocal &&
|
| variable != closureData.closureEntity &&
|
| variable is! TypeVariableLocal) {
|
| - closureData.variablesUsedInTryOrGenerator.add(variable);
|
| + closureData.variablesUsedInTryOrSync.add(variable);
|
| }
|
| } else if (variable is LocalParameterElement &&
|
| variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) {
|
| // Parameters in a sync* function are shared between each Iterator created
|
| // by the Iterable returned by the function, therefore they must be boxed.
|
| - closureData.variablesUsedInTryOrGenerator.add(variable);
|
| + closureData.variablesUsedInTryOrSync.add(variable);
|
| }
|
| }
|
|
|
|
|