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

Side by Side Diff: pkg/compiler/lib/src/js_model/closure.dart

Issue 2998673002: Added ThisVariable in scoping and the captured scope of initialized fields. (Closed)
Patch Set: . Created 3 years, 4 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../closure.dart'; 7 import '../closure.dart';
8 import '../common.dart'; 8 import '../common.dart';
9 import '../common/tasks.dart'; 9 import '../common/tasks.dart';
10 import '../constants/expressions.dart'; 10 import '../constants/expressions.dart';
11 import '../constants/values.dart'; 11 import '../constants/values.dart';
12 import '../elements/entities.dart'; 12 import '../elements/entities.dart';
13 import '../elements/names.dart' show Name; 13 import '../elements/names.dart' show Name;
14 import '../elements/types.dart'; 14 import '../elements/types.dart';
15 import '../kernel/element_map.dart'; 15 import '../kernel/element_map.dart';
16 import '../kernel/env.dart'; 16 import '../kernel/env.dart';
17 import '../world.dart'; 17 import '../world.dart';
18 import 'elements.dart'; 18 import 'elements.dart';
19 import 'closure_visitors.dart'; 19 import 'closure_visitors.dart';
20 import 'locals.dart'; 20 import 'locals.dart';
21 import 'js_strategy.dart' show JsClosedWorld; 21 import 'js_strategy.dart' show JsClosedWorld;
22 22
23 class KernelClosureAnalysis { 23 class KernelClosureAnalysis {
24 /// Inspect members and mark if those members capture any state that needs to 24 /// Inspect members and mark if those members capture any state that needs to
25 /// be marked as free variables. 25 /// be marked as free variables.
26 static ClosureModel computeClosureModel(MemberEntity entity, ir.Member node) { 26 static ScopeModel computeScopeModel(MemberEntity entity, ir.Member node) {
27 if (entity.isAbstract) return null; 27 if (entity.isAbstract) return null;
28 if (entity.isField && !entity.isInstanceMember) { 28 if (entity.isField && !entity.isInstanceMember) {
29 ir.Field field = node; 29 ir.Field field = node;
30 // Skip top-level/static fields without an initializer. 30 // Skip top-level/static fields without an initializer.
31 if (field.initializer == null) return null; 31 if (field.initializer == null) return null;
32 } 32 }
33 33
34 ClosureModel model = new ClosureModel(); 34 ScopeModel model = new ScopeModel();
35 CapturedScopeBuilder translator = new CapturedScopeBuilder(model, 35 CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
36 hasThisLocal: entity.isInstanceMember || entity.isConstructor); 36 hasThisLocal: entity.isInstanceMember || entity.isConstructor);
37 if (entity.isField) { 37 if (entity.isField) {
38 if (node is ir.Field && node.initializer != null) { 38 if (node is ir.Field && node.initializer != null) {
39 translator.translateLazyInitializer(node); 39 translator.translateLazyInitializer(node);
40 } else {
41 assert(entity.isInstanceMember);
42 model.scopeInfo = new KernelScopeInfo(true);
40 } 43 }
41 } else { 44 } else {
42 assert(node is ir.Procedure || node is ir.Constructor); 45 assert(node is ir.Procedure || node is ir.Constructor);
43 translator.translateConstructorOrProcedure(node); 46 translator.translateConstructorOrProcedure(node);
44 } 47 }
45 return model; 48 return model;
46 } 49 }
47 } 50 }
48 51
49 /// Closure conversion code using our new Entity model. Closure conversion is 52 /// Closure conversion code using our new Entity model. Closure conversion is
50 /// necessary because the semantics of closures are slightly different in Dart 53 /// necessary because the semantics of closures are slightly different in Dart
51 /// than JavaScript. Closure conversion is separated out into two phases: 54 /// than JavaScript. Closure conversion is separated out into two phases:
52 /// generation of a new (temporary) representation to store where variables need 55 /// generation of a new (temporary) representation to store where variables need
53 /// to be hoisted/captured up at another level to re-write the closure, and then 56 /// to be hoisted/captured up at another level to re-write the closure, and then
54 /// the code generation phase where we generate elements and/or instructions to 57 /// the code generation phase where we generate elements and/or instructions to
55 /// represent this new code path. 58 /// represent this new code path.
56 /// 59 ///
57 /// For a general explanation of how closure conversion works at a high level, 60 /// For a general explanation of how closure conversion works at a high level,
58 /// check out: 61 /// check out:
59 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or 62 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or
60 /// http://matt.might.net/articles/closure-conversion/. 63 /// http://matt.might.net/articles/closure-conversion/.
61 // TODO(efortuna): Change inheritance hierarchy so that the 64 // TODO(efortuna): Change inheritance hierarchy so that the
62 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a 65 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a
63 // glorified timer. 66 // glorified timer.
64 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { 67 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
65 final KernelToElementMapForBuilding _elementMap; 68 final KernelToElementMapForBuilding _elementMap;
66 final GlobalLocalsMap _globalLocalsMap; 69 final GlobalLocalsMap _globalLocalsMap;
67 final Map<MemberEntity, ClosureModel> _closureModels; 70 final Map<MemberEntity, ScopeModel> _closureModels;
68 71
69 /// Map of the scoping information that corresponds to a particular entity. 72 /// Map of the scoping information that corresponds to a particular entity.
70 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{}; 73 Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{};
71 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{}; 74 Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{};
72 75
73 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap = 76 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap =
74 <Entity, ClosureRepresentationInfo>{}; 77 <Entity, ClosureRepresentationInfo>{};
75 78
76 KernelClosureConversionTask(Measurer measurer, this._elementMap, 79 KernelClosureConversionTask(Measurer measurer, this._elementMap,
77 this._globalLocalsMap, this._closureModels) 80 this._globalLocalsMap, this._closureModels)
78 : super(measurer); 81 : super(measurer);
79 82
80 /// The combined steps of generating our intermediate representation of 83 /// The combined steps of generating our intermediate representation of
81 /// closures that need to be rewritten and generating the element model. 84 /// closures that need to be rewritten and generating the element model.
82 /// Ultimately these two steps will be split apart with the second step 85 /// Ultimately these two steps will be split apart with the second step
83 /// happening later in compilation just before codegen. These steps are 86 /// happening later in compilation just before codegen. These steps are
84 /// combined here currently to provide a consistent interface to the rest of 87 /// combined here currently to provide a consistent interface to the rest of
85 /// the compiler until we are ready to separate these phases. 88 /// the compiler until we are ready to separate these phases.
86 @override 89 @override
87 void convertClosures(Iterable<MemberEntity> processedEntities, 90 void convertClosures(Iterable<MemberEntity> processedEntities,
88 ClosedWorldRefiner closedWorldRefiner) { 91 ClosedWorldRefiner closedWorldRefiner) {
89 _createClosureEntities(_closureModels, closedWorldRefiner); 92 _createClosureEntities(_closureModels, closedWorldRefiner);
90 } 93 }
91 94
92 void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels, 95 void _createClosureEntities(Map<MemberEntity, ScopeModel> closureModels,
93 JsClosedWorld closedWorldRefiner) { 96 JsClosedWorld closedWorldRefiner) {
94 closureModels.forEach((MemberEntity member, ClosureModel model) { 97 closureModels.forEach((MemberEntity member, ScopeModel model) {
95 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 98 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
96 if (model.scopeInfo != null) { 99 if (model.scopeInfo != null) {
97 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); 100 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap);
98 } 101 }
99 102
100 model.capturedScopesMap 103 model.capturedScopesMap
101 .forEach((ir.Node node, KernelCapturedScope scope) { 104 .forEach((ir.Node node, KernelCapturedScope scope) {
102 if (scope is KernelCapturedLoopScope) { 105 if (scope is KernelCapturedLoopScope) {
103 _capturedScopesMap[node] = 106 _capturedScopesMap[node] =
104 new JsCapturedLoopScope.from(scope, localsMap); 107 new JsCapturedLoopScope.from(scope, localsMap);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 } 173 }
171 } 174 }
172 175
173 @override 176 @override
174 // TODO(efortuna): Eventually capturedScopesMap[node] should always 177 // TODO(efortuna): Eventually capturedScopesMap[node] should always
175 // be non-null, and we should just test that with an assert. 178 // be non-null, and we should just test that with an assert.
176 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => 179 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) =>
177 _capturedScopesMap[loopNode] ?? const CapturedLoopScope(); 180 _capturedScopesMap[loopNode] ?? const CapturedLoopScope();
178 181
179 @override 182 @override
180 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be
181 // non-null, and we should just test that with an assert.
182 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { 183 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) {
183 return _closureRepresentationMap[entity] ?? 184 var closure = _closureRepresentationMap[entity];
184 const ClosureRepresentationInfo(); 185 assert(closure != null,
186 "Corresponding closure class not found for $entity. Closures found for $ {_closureRepresentationMap.keys}");
187 return closure;
185 } 188 }
186 } 189 }
187 190
188 class KernelScopeInfo { 191 class KernelScopeInfo {
189 final Set<ir.VariableDeclaration> localsUsedInTryOrSync; 192 final Set<ir.VariableDeclaration> localsUsedInTryOrSync;
190 final bool hasThisLocal; 193 final bool hasThisLocal;
191 final Set<ir.VariableDeclaration> boxedVariables; 194 final Set<ir.VariableDeclaration> boxedVariables;
192 // If boxedVariables is empty, this will be null, because no variables will 195 // If boxedVariables is empty, this will be null, because no variables will
193 // need to be boxed. 196 // need to be boxed.
194 final NodeBox capturedVariablesAccessor; 197 final NodeBox capturedVariablesAccessor;
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 324 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
322 } 325 }
323 326
324 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 327 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
325 class KernelClosureClass extends JsScopeInfo 328 class KernelClosureClass extends JsScopeInfo
326 implements ClosureRepresentationInfo, JClass { 329 implements ClosureRepresentationInfo, JClass {
327 final String name; 330 final String name;
328 final JLibrary library; 331 final JLibrary library;
329 JFunction callMethod; 332 JFunction callMethod;
330 final Local closureEntity; 333 final Local closureEntity;
334 final Local thisLocal;
331 335
332 /// Index into the classData, classList and classEnvironment lists where this 336 /// Index into the classData, classList and classEnvironment lists where this
333 /// entity is stored in [JsToFrontendMapImpl]. 337 /// entity is stored in [JsToFrontendMapImpl].
334 final int classIndex; 338 final int classIndex;
335 339
336 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 340 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
337 341
338 KernelClosureClass.fromScopeInfo( 342 KernelClosureClass.fromScopeInfo(
339 ir.FunctionNode closureSourceNode, 343 ir.FunctionNode closureSourceNode,
340 this.name, 344 this.name,
341 this.classIndex, 345 this.classIndex,
342 this.library, 346 this.library,
343 KernelScopeInfo info, 347 KernelScopeInfo info,
344 KernelToLocalsMap localsMap) 348 KernelToLocalsMap localsMap)
345 : closureEntity = closureSourceNode.parent is ir.Member 349 : closureEntity = closureSourceNode.parent is ir.Member
346 ? null 350 ? null
347 : localsMap.getLocalFunction(closureSourceNode.parent), 351 : localsMap.getLocalFunction(closureSourceNode.parent),
352 thisLocal =
353 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
348 super.from(info, localsMap); 354 super.from(info, localsMap);
349 355
350 ClassEntity get closureClassEntity => this; 356 ClassEntity get closureClassEntity => this;
351 357
352 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 358 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
353 359
354 // TODO(efortuna): Implement. 360 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
355 FieldEntity get thisFieldEntity => null;
356 361
357 void forEachCapturedVariable(f(Local from, JField to)) { 362 void forEachCapturedVariable(f(Local from, JField to)) {
358 localToFieldMap.forEach(f); 363 localToFieldMap.forEach(f);
359 } 364 }
360 365
361 @override 366 @override
362 void forEachBoxedVariable(f(Local local, JField field)) { 367 void forEachBoxedVariable(f(Local local, JField field)) {
363 for (Local l in localToFieldMap.keys) { 368 for (Local l in localToFieldMap.keys) {
364 if (localToFieldMap[l] is JBoxedField) f(l, localToFieldMap[l]); 369 if (localToFieldMap[l] is JBoxedField) f(l, localToFieldMap[l]);
365 } 370 }
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 final SourceSpan location; 502 final SourceSpan location;
498 final MemberKind kind; 503 final MemberKind kind;
499 final ir.Node node; 504 final ir.Node node;
500 505
501 ClosureMemberDefinition(this.member, this.location, this.kind, this.node); 506 ClosureMemberDefinition(this.member, this.location, this.kind, this.node);
502 507
503 String toString() => 508 String toString() =>
504 'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)'; 509 'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)';
505 } 510 }
506 511
507 /// Collection of closure data collected for a single member. 512 /// Collection of scope data collected for a single member.
508 class ClosureModel { 513 class ScopeModel {
509 /// Collection [ScopeInfo] data for the member, if any. 514 /// Collection [ScopeInfo] data for the member.
510 // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields
511 // without initializers; we shouldn't even create a [ClosureModel] in these
512 // cases.
513 KernelScopeInfo scopeInfo; 515 KernelScopeInfo scopeInfo;
514 516
515 /// Collected [CapturedScope] data for nodes. 517 /// Collected [CapturedScope] data for nodes.
516 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 518 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
517 <ir.Node, KernelCapturedScope>{}; 519 <ir.Node, KernelCapturedScope>{};
518 520
519 /// Collected [ScopeInfo] data for nodes. 521 /// Collected [ScopeInfo] data for nodes.
520 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = 522 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate =
521 <ir.FunctionNode, KernelScopeInfo>{}; 523 <ir.FunctionNode, KernelScopeInfo>{};
522 } 524 }
OLDNEW
« 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