Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(655)

Unified Diff: pkg/compiler/lib/src/js_model/closure.dart

Issue 2988553003: Compute closure model purely from IR nodes (Closed)
Patch Set: Updated cf. comments Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/js_model/closure.dart
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 829010a6598cae42972183dbde8bf921d027a1b6..6cccab98e8c8d6fb3a291a2c0a30d5522db518e9 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -61,7 +61,17 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
@override
void convertClosures(Iterable<MemberEntity> processedEntities,
ClosedWorldRefiner closedWorldRefiner) {
- var closuresToGenerate = <MemberEntity, Map<ir.TreeNode, ScopeInfo>>{};
+ Map<MemberEntity, ClosureModel> closureModels =
+ _computeClosureModels(processedEntities);
+ _createClosureEntities(closureModels, closedWorldRefiner);
+ }
+
+ // TODO(johnniwinther,efortuna): Compute this during resolution. See
+ // documentation on [convertClosures].
+ Map<MemberEntity, ClosureModel> _computeClosureModels(
+ Iterable<MemberEntity> processedEntities) {
+ Map<MemberEntity, ClosureModel> closureModels =
+ <MemberEntity, ClosureModel>{};
processedEntities.forEach((MemberEntity kEntity) {
MemberEntity entity = _kToJElementMap.toBackendMember(kEntity);
@@ -74,12 +84,31 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
// Skip top-level/static fields without an initializer.
if (field.initializer == null) return;
}
- closuresToGenerate[entity] =
- _buildClosureModel(entity, closedWorldRefiner);
+ closureModels[entity] = _buildClosureModel(entity);
});
+ return closureModels;
+ }
+
+ void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels,
+ ClosedWorldRefiner closedWorldRefiner) {
+ closureModels.forEach((MemberEntity member, ClosureModel model) {
+ KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
+ if (model.scopeInfo != null) {
+ _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap);
+ }
- closuresToGenerate.forEach(
- (MemberEntity member, Map<ir.TreeNode, ScopeInfo> closuresToGenerate) {
+ model.capturedScopesMap
+ .forEach((ir.Node node, KernelCapturedScope scope) {
+ if (scope is KernelCapturedLoopScope) {
+ _capturedScopesMap[node] =
+ new JsCapturedLoopScope.from(scope, localsMap);
+ } else {
+ _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap);
+ }
+ });
+
+ Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
+ model.closuresToGenerate;
for (ir.TreeNode node in closuresToGenerate.keys) {
_produceSyntheticElements(
member, node, closuresToGenerate[node], closedWorldRefiner);
@@ -89,11 +118,8 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
/// Inspect members and mark if those members capture any state that needs to
/// be marked as free variables.
- Map<ir.TreeNode, ScopeInfo> _buildClosureModel(
- MemberEntity entity, ClosedWorldRefiner closedWorldRefiner) {
- assert(!_scopeMap.containsKey(entity),
- failedAt(entity, "ScopeInfo already computed for $entity."));
- Map<ir.TreeNode, ScopeInfo> closuresToGenerate = <ir.TreeNode, ScopeInfo>{};
+ ClosureModel _buildClosureModel(MemberEntity entity) {
+ ClosureModel model = new ClosureModel();
MemberDefinition definition = _elementMap.getMemberDefinition(entity);
switch (definition.kind) {
case MemberKind.regular:
@@ -103,14 +129,8 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
failedAt(entity, "Unexpected member definition $definition");
}
ir.Node node = definition.node;
- assert(!_scopeMap.containsKey(entity),
- failedAt(entity, "CaptureScope already computed for $node."));
- CapturedScopeBuilder translator = new CapturedScopeBuilder(
- entity,
- _capturedScopesMap,
- _scopeMap,
- closuresToGenerate,
- _globalLocalsMap.getLocalsMap(entity));
+ CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
+ hasThisLocal: entity.isInstanceMember || entity.isConstructor);
if (entity.isField) {
if (node is ir.Field && node.initializer != null) {
translator.translateLazyInitializer(node);
@@ -119,7 +139,7 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
assert(node is ir.Procedure || node is ir.Constructor);
translator.translateConstructorOrProcedure(node);
}
- return closuresToGenerate;
+ return model;
}
/// Given what variables are captured at each point, construct closure classes
@@ -131,7 +151,7 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
void _produceSyntheticElements(
MemberEntity member,
ir.TreeNode /* ir.Member | ir.FunctionNode */ node,
- ScopeInfo info,
+ KernelScopeInfo info,
ClosedWorldRefiner closedWorldRefiner) {
String name = _computeClosureName(node);
KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
@@ -240,25 +260,55 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
}
}
-class KernelScopeInfo extends ScopeInfo {
- final Set<Local> localsUsedInTryOrSync;
- final Local thisLocal;
- final Set<Local> boxedVariables;
+class KernelScopeInfo {
+ final Set<ir.VariableDeclaration> localsUsedInTryOrSync;
+ final bool hasThisLocal;
+ final Set<ir.VariableDeclaration> boxedVariables;
/// The set of variables that were defined in another scope, but are used in
/// this scope.
Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();
- KernelScopeInfo(this.thisLocal)
- : localsUsedInTryOrSync = new Set<Local>(),
- boxedVariables = new Set<Local>();
+ KernelScopeInfo(this.hasThisLocal)
+ : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(),
+ boxedVariables = new Set<ir.VariableDeclaration>();
- KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info)
+ KernelScopeInfo.from(this.hasThisLocal, KernelScopeInfo info)
: localsUsedInTryOrSync = info.localsUsedInTryOrSync,
boxedVariables = info.boxedVariables;
KernelScopeInfo.withBoxedVariables(this.boxedVariables,
- this.localsUsedInTryOrSync, this.freeVariables, this.thisLocal);
+ this.localsUsedInTryOrSync, this.freeVariables, this.hasThisLocal);
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write('this=$hasThisLocal,');
+ sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
+ return sb.toString();
+ }
+}
+
+class JsScopeInfo extends ScopeInfo {
+ final Set<Local> localsUsedInTryOrSync;
+ final Local thisLocal;
+ final Set<Local> boxedVariables;
+
+ /// The set of variables that were defined in another scope, but are used in
+ /// this scope.
+ final Set<Local> freeVariables;
+
+ JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables,
+ this.freeVariables);
+
+ JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
+ : this.thisLocal =
+ info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
+ this.localsUsedInTryOrSync =
+ info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
+ this.boxedVariables =
+ info.boxedVariables.map(localsMap.getLocalVariable).toSet(),
+ this.freeVariables =
+ info.freeVariables.map(localsMap.getLocalVariable).toSet();
void forEachBoxedVariable(f(Local local, FieldEntity field)) {
boxedVariables.forEach((Local l) {
@@ -280,40 +330,63 @@ class KernelScopeInfo extends ScopeInfo {
bool isBoxed(Local variable) => boxedVariables.contains(variable);
}
-class KernelCapturedScope extends KernelScopeInfo implements CapturedScope {
- final Local context;
+class KernelCapturedScope extends KernelScopeInfo {
+ final ir.TreeNode context;
KernelCapturedScope(
- Set<Local> boxedVariables,
+ Set<ir.VariableDeclaration> boxedVariables,
this.context,
- Set<Local> localsUsedInTryOrSync,
+ Set<ir.VariableDeclaration> localsUsedInTryOrSync,
Set<ir.VariableDeclaration> freeVariables,
- Local thisLocal)
+ bool hasThisLocal)
: super.withBoxedVariables(
- boxedVariables, localsUsedInTryOrSync, freeVariables, thisLocal);
+ boxedVariables, localsUsedInTryOrSync, freeVariables, hasThisLocal);
bool get requiresContextBox => boxedVariables.isNotEmpty;
}
-class KernelCapturedLoopScope extends KernelCapturedScope
- implements CapturedLoopScope {
- final List<Local> boxedLoopVariables;
+class JsCapturedScope extends JsScopeInfo implements CapturedScope {
+ final Local context;
+
+ JsCapturedScope.from(
+ KernelCapturedScope capturedScope, KernelToLocalsMap localsMap)
+ : this.context = localsMap.getLocalVariable(capturedScope.context),
+ super.from(capturedScope, localsMap);
+
+ bool get requiresContextBox => boxedVariables.isNotEmpty;
+}
+
+class KernelCapturedLoopScope extends KernelCapturedScope {
+ final List<ir.VariableDeclaration> boxedLoopVariables;
KernelCapturedLoopScope(
- Set<Local> boxedVariables,
+ Set<ir.VariableDeclaration> boxedVariables,
this.boxedLoopVariables,
- Local context,
- Set<Local> localsUsedInTryOrSync,
+ ir.TreeNode context,
+ Set<ir.VariableDeclaration> localsUsedInTryOrSync,
Set<ir.VariableDeclaration> freeVariables,
- Local thisLocal)
+ bool hasThisLocal)
: super(boxedVariables, context, localsUsedInTryOrSync, freeVariables,
- thisLocal);
+ hasThisLocal);
+
+ bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
+}
+
+class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
+ final List<Local> boxedLoopVariables;
+
+ JsCapturedLoopScope.from(
+ KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap)
+ : this.boxedLoopVariables = capturedScope.boxedLoopVariables
+ .map(localsMap.getLocalVariable)
+ .toList(),
+ super.from(capturedScope, localsMap);
bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
}
// TODO(johnniwinther): Add unittest for the computed [ClosureClass].
-class KernelClosureClass extends KernelScopeInfo
+class KernelClosureClass extends JsScopeInfo
implements ClosureRepresentationInfo, JClass {
final ir.Location location;
@@ -328,7 +401,7 @@ class KernelClosureClass extends KernelScopeInfo
KernelClosureClass.fromScopeInfo(this.name, this.library,
KernelScopeInfo info, this.location, KernelToLocalsMap localsMap)
- : super.from(info.thisLocal, info) {
+ : super.from(info, localsMap) {
// Make a corresponding field entity in this closure class for every single
// freeVariable in the KernelScopeInfo.freeVariable.
int i = 0;
@@ -337,7 +410,7 @@ class KernelClosureClass extends KernelScopeInfo
// old Element version. The old version did all the boxed items and then
// all the others.
Local capturedLocal = localsMap.getLocalVariable(variable);
- if (info.isBoxed(capturedLocal)) {
+ if (isBoxed(capturedLocal)) {
// TODO(efortuna): Coming soon.
} else {
localToFieldMap[capturedLocal] = new ClosureField(
@@ -422,3 +495,20 @@ class ClosureClassDefinition implements ClassDefinition {
String toString() =>
'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)';
}
+
+/// Collection of closure data collected for a single member.
+class ClosureModel {
+ /// Collection [ScopeInfo] data for the member, if any.
+ // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields
+ // without initializers; we shouldn't even create a [ClosureModel] in these
+ // cases.
+ KernelScopeInfo scopeInfo;
+
+ /// Collected [CapturedScope] data for nodes.
+ Map<ir.Node, KernelCapturedScope> capturedScopesMap =
+ <ir.Node, KernelCapturedScope>{};
+
+ /// Collected [ScopeInfo] data for nodes.
+ Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
+ <ir.TreeNode, KernelScopeInfo>{};
+}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698