Chromium Code Reviews| Index: pkg/compiler/lib/src/closure.dart |
| diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart |
| index f7a0af62c9a1992e5d94f3c2630e72c066970a9e..9075e92c861527f3cb874b52f1dbe167a76bfe1f 100644 |
| --- a/pkg/compiler/lib/src/closure.dart |
| +++ b/pkg/compiler/lib/src/closure.dart |
| @@ -23,14 +23,47 @@ import 'tree/tree.dart'; |
| import 'util/util.dart'; |
| import 'world.dart' show ClosedWorldRefiner; |
| -abstract class ClosureClassMaps { |
| - ClosureClassMap getMemberMap(MemberEntity member); |
| - ClosureClassMap getLocalFunctionMap(Local localFunction); |
| +/// Where T is ir.Node or Node. |
| +// TODO(efortuna): Rename this class. |
| +abstract class ClosureClassMaps<T> { |
|
Johnni Winther
2017/05/31 12:39:51
I'd prefer if these new methods (eventually) are o
|
| + /// Currently, closures are rewritten in the form of classes that |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:38
Small suggestion: to make the docs a bit more comp
|
| + /// have fields to control the redirection and editing of variables that are |
| + /// "captured" inside a scope (declared in an outer scope but used in an |
| + /// inside scope). |
| + ClassEntity getClosureClassEntity(Local member); |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
minor naming ideas: these are totally optional, so
|
| + |
| + // TODO(efortuna): This should probably be renamed to something like |
| + // forEachCapturedVariable or something that's less implementation specific. |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
+1 I like that, also possible `forEachCapturedVari
|
| + void forEachClosureClassFieldEntity(Local entity, void f(FieldEntity field)); |
| + |
| + /// Closures are rewritten as classes with fields representing the local |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
Another though - we can explore moving the docs up
|
| + /// variables that the closure has "captured. Return the actual local |
|
Johnni Winther
2017/05/31 12:39:51
"captured -> captured
|
| + /// variable that a particular closure field is emulating. |
| + Local getLocalVarForClosureField(Local member, FieldEntity field); |
| + |
| + /// The method representing calling the closure to execute, provided the |
|
Johnni Winther
2017/05/31 12:39:51
Maybe rephrase as:
The function that implements t
|
| + /// original local entity. |
| + FunctionEntity getCallEntity(Local member); |
| + |
| + /// Accessor to the local environment in which a particular closure node is |
| + /// executed. This will encapsulate the value of any variables that have been |
| + /// scoped into this context from outside. |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
is "scoped" the same as captured here? or somethin
|
| + Local getExecutableContext(T node); |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:38
Open question: I wonder if we should introduce thi
|
| + |
| + // TODO(efortuna): Finish removing this method by exposing remining info in |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
remining => remaining
|
| + // this interface. |
| + ClosureClassMap getMemberMap(MemberElement member); |
| + |
| + /// Look up information about what variables are have been mutated that are |
|
Johnni Winther
2017/05/31 12:39:51
are have ... inside the -> have been mutated insid
|
| + /// used inside the scope of [node]. |
| + CapturedVariableInfo getCapturedVariableInfo(T node); |
| } |
| -class ClosureTask extends CompilerTask implements ClosureClassMaps { |
| +class ClosureTask extends CompilerTask implements ClosureClassMaps<Node> { |
| Map<Element, ClosureClassMap> _closureMappingCache = |
| <Element, ClosureClassMap>{}; |
| + Map<Node, Local> _executableContextCache = <Node, Local>{}; |
| + Map<Node, ClosureScope> _closureScopeCache = <Node, ClosureScope>{}; |
| Compiler compiler; |
| ClosureTask(Compiler compiler) |
| : compiler = compiler, |
| @@ -40,14 +73,52 @@ class ClosureTask extends CompilerTask implements ClosureClassMaps { |
| DiagnosticReporter get reporter => compiler.reporter; |
| + CapturedVariableInfo getCapturedVariableInfo(Node node) { |
| + ClosureScope scopeData = _closureScopeCache[node]; |
| + if (scopeData == null) return new CapturedVariableInfo(); |
|
Siggi Cherem (dart-lang)
2017/06/01 15:40:30
consider adding a const constructor to CapturedVar
|
| + return scopeData; |
| + } |
| + |
| ClosureClassMap getMemberMap(MemberElement member) { |
| return getClosureToClassMapping(member.resolvedAst); |
| } |
| - ClosureClassMap getLocalFunctionMap(LocalFunctionElement localFunction) { |
| + ClosureClassMap _getLocalFunctionMap(LocalFunctionElement localFunction) { |
| return getClosureToClassMapping(localFunction.resolvedAst); |
| } |
| + void forEachClosureClassFieldEntity( |
| + LocalFunctionElement entity, void f(FieldEntity field)) { |
| + ClosureClassElement classEntity = getClosureClassEntity(entity); |
| + classEntity.closureFields.forEach(f); |
| + } |
| + |
| + Local getExecutableContext(Node node) { |
| + return _executableContextCache[node]; |
| + } |
| + |
| + Local getLocalVarForClosureField( |
| + LocalFunctionElement member, FieldEntity field) { |
| + ClosureClassMap memberMap = _getLocalFunctionMap(member); |
| + assert(memberMap != null); |
| + assert(memberMap.closureClassElement != null); |
| + return memberMap.getLocalVariableForClosureField(field); |
| + } |
| + |
| + ClassEntity getClosureClassEntity(LocalFunctionElement member) { |
| + ClosureClassMap memberMap = _getLocalFunctionMap(member); |
| + assert(memberMap != null); |
| + assert(memberMap.closureClassElement != null); |
| + return memberMap.closureClassElement; |
| + } |
| + |
| + FunctionEntity getCallEntity(LocalFunctionElement member) { |
| + ClosureClassMap memberMap = _getLocalFunctionMap(member); |
| + assert(memberMap != null); |
| + assert(memberMap.closureClassElement != null); |
| + return memberMap.callElement; |
| + } |
| + |
| /// Returns the [ClosureClassMap] computed for [resolvedAst]. |
| ClosureClassMap getClosureToClassMapping(ResolvedAst resolvedAst) { |
| return measure(() { |
| @@ -94,7 +165,12 @@ class ClosureTask extends CompilerTask implements ClosureClassMaps { |
| TreeElements elements = resolvedAst.elements; |
| ClosureTranslator translator = new ClosureTranslator( |
| - compiler, closedWorldRefiner, elements, _closureMappingCache); |
| + compiler, |
| + closedWorldRefiner, |
| + elements, |
| + _closureMappingCache, |
| + _executableContextCache, |
| + _closureScopeCache); |
| // The translator will store the computed closure-mappings inside the |
| // cache. One for given node and one for each nested closure. |
| @@ -411,9 +487,21 @@ class SynthesizedCallMethodElementX extends BaseFunctionElementX |
| } |
| } |
| +/// Interface external classes can use to query information about what variables |
| +/// are mutated inside a scope. |
| +class CapturedVariableInfo { |
| + bool hasCapturedVariables() => false; |
|
Siggi Cherem (dart-lang)
2017/05/31 20:44:39
nit: turn these two into getters:
bool get hasCap
|
| + bool hasBoxedLoopVariables() => false; |
| + |
| + /// True if the specified variable has been mutated inside the scope of this |
| + /// closure. |
| + bool isCaptured(Local variable) => false; |
| + void forEachCapturedVariable(f(Entity from, Entity to)) {} |
| +} |
| + |
| // The box-element for a scope, and the captured variables that need to be |
| // stored in the box. |
| -class ClosureScope { |
| +class ClosureScope implements CapturedVariableInfo { |
| final BoxLocal boxElement; |
| final Map<Local, BoxFieldElement> capturedVariables; |
| @@ -424,9 +512,11 @@ class ClosureScope { |
| ClosureScope(this.boxElement, this.capturedVariables); |
| + bool hasCapturedVariables() => capturedVariables.keys.isNotEmpty; |
| + |
| bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
| - bool isCapturedVariable(VariableElement variable) { |
| + bool isCaptured(VariableElement variable) { |
|
Johnni Winther
2017/05/31 12:39:51
[VariableElement] -> [LocalVariableElement] to mak
|
| return capturedVariables.containsKey(variable); |
| } |
| @@ -591,8 +681,16 @@ class ClosureTranslator extends Visitor { |
| bool insideClosure = false; |
| - ClosureTranslator(this.compiler, this.closedWorldRefiner, this.elements, |
| - this.closureMappingCache); |
| + Map<Node, Local> executableContextCache; |
| + Map<Node, ClosureScopeCache> closureScopeCache; |
| + |
| + ClosureTranslator( |
| + this.compiler, |
| + this.closedWorldRefiner, |
| + this.elements, |
| + this.closureMappingCache, |
| + this.executableContextCache, |
| + this.closureScopeCache); |
| DiagnosticReporter get reporter => compiler.reporter; |
| @@ -976,6 +1074,10 @@ class ClosureTranslator extends Visitor { |
| if (!scopeMapping.isEmpty) { |
| ClosureScope scope = new ClosureScope(box, scopeMapping); |
| closureData.capturingScopes[node] = scope; |
| + assert(executableContextCache[node] == null); |
| + executableContextCache[node] = box; |
| + assert(closureScopeCache[node] == null); |
| + closureScopeCache[node] = scope; |
| } |
| } |