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

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

Issue 3007743002: Add boxing for modified variables (Closed)
Patch Set: . Created 3 years, 3 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
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';
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 @override 93 @override
94 void convertClosures(Iterable<MemberEntity> processedEntities, 94 void convertClosures(Iterable<MemberEntity> processedEntities,
95 ClosedWorldRefiner closedWorldRefiner) { 95 ClosedWorldRefiner closedWorldRefiner) {
96 _createClosureEntities(_closureModels, closedWorldRefiner); 96 _createClosureEntities(_closureModels, closedWorldRefiner);
97 } 97 }
98 98
99 void _createClosureEntities(Map<MemberEntity, ScopeModel> closureModels, 99 void _createClosureEntities(Map<MemberEntity, ScopeModel> closureModels,
100 JsClosedWorld closedWorldRefiner) { 100 JsClosedWorld closedWorldRefiner) {
101 closureModels.forEach((MemberEntity member, ScopeModel model) { 101 closureModels.forEach((MemberEntity member, ScopeModel model) {
102 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 102 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
103 if (model.scopeInfo != null) { 103 Map<Local, JRecordField> allBoxedVariables =
104 _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap); 104 _elementMap.makeRecordContainer(model.scopeInfo, member, localsMap);
105 } 105 _scopeMap[member] =
106 new JsScopeInfo.from(allBoxedVariables, model.scopeInfo, localsMap);
106 107
107 model.capturedScopesMap 108 model.capturedScopesMap
108 .forEach((ir.Node node, KernelCapturedScope scope) { 109 .forEach((ir.Node node, KernelCapturedScope scope) {
110 Map<Local, JRecordField> boxedVariables =
111 _elementMap.makeRecordContainer(scope, member, localsMap);
109 if (scope is KernelCapturedLoopScope) { 112 if (scope is KernelCapturedLoopScope) {
110 _capturedScopesMap[node] = 113 _capturedScopesMap[node] =
111 new JsCapturedLoopScope.from(scope, localsMap); 114 new JsCapturedLoopScope.from(boxedVariables, scope, localsMap);
112 } else { 115 } else {
113 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); 116 _capturedScopesMap[node] =
117 new JsCapturedScope.from(boxedVariables, scope, localsMap);
114 } 118 }
119 allBoxedVariables.addAll(boxedVariables);
115 }); 120 });
116 121
117 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 122 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
118 model.closuresToGenerate; 123 model.closuresToGenerate;
119 for (ir.TreeNode node in closuresToGenerate.keys) { 124 for (ir.TreeNode node in closuresToGenerate.keys) {
120 ir.FunctionNode functionNode; 125 ir.FunctionNode functionNode;
121 if (node is ir.FunctionDeclaration) { 126 if (node is ir.FunctionDeclaration) {
122 functionNode = node.function; 127 functionNode = node.function;
123 } else if (node is ir.FunctionExpression) { 128 } else if (node is ir.FunctionExpression) {
124 functionNode = node.function; 129 functionNode = node.function;
125 } else { 130 } else {
126 failedAt(member, "Unexpected closure node ${node}"); 131 failedAt(member, "Unexpected closure node ${node}");
127 } 132 }
128 KernelClosureClass closureClass = _produceSyntheticElements( 133 KernelClosureClass closureClass = _produceSyntheticElements(
129 member, functionNode, closuresToGenerate[node], closedWorldRefiner); 134 member,
135 functionNode,
136 closuresToGenerate[node],
137 allBoxedVariables,
138 closedWorldRefiner);
130 // Add also for the call method. 139 // Add also for the call method.
131 _scopeMap[closureClass.callMethod] = closureClass; 140 _scopeMap[closureClass.callMethod] = closureClass;
132 } 141 }
133 }); 142 });
134 } 143 }
135 144
136 /// Given what variables are captured at each point, construct closure classes 145 /// Given what variables are captured at each point, construct closure classes
137 /// with fields containing the captured variables to replicate the Dart 146 /// with fields containing the captured variables to replicate the Dart
138 /// closure semantics in JS. If this closure captures any variables (meaning 147 /// closure semantics in JS. If this closure captures any variables (meaning
139 /// the closure accesses a variable that gets accessed at some point), then 148 /// the closure accesses a variable that gets accessed at some point), then
140 /// boxForCapturedVariables stores the local context for those variables. 149 /// boxForCapturedVariables stores the local context for those variables.
141 /// If no variables are captured, this parameter is null. 150 /// If no variables are captured, this parameter is null.
142 KernelClosureClass _produceSyntheticElements( 151 KernelClosureClass _produceSyntheticElements(
143 MemberEntity member, 152 MemberEntity member,
144 ir.FunctionNode node, 153 ir.FunctionNode node,
145 KernelScopeInfo info, 154 KernelScopeInfo info,
155 Map<Local, JRecordField> boxedVariables,
146 JsClosedWorld closedWorldRefiner) { 156 JsClosedWorld closedWorldRefiner) {
147 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); 157 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
148 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( 158 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass(
149 member, node, member.library, info, node.location, localsMap); 159 member,
160 node,
161 member.library,
162 boxedVariables,
163 info,
164 node.location,
165 localsMap);
150 166
151 // We want the original declaration where that function is used to point 167 // We want the original declaration where that function is used to point
152 // to the correct closure class. 168 // to the correct closure class.
153 _memberClosureRepresentationMap[closureClass.callMethod] = closureClass; 169 _memberClosureRepresentationMap[closureClass.callMethod] = closureClass;
154 _globalLocalsMap.setLocalsMap(closureClass.callMethod, localsMap); 170 _globalLocalsMap.setLocalsMap(closureClass.callMethod, localsMap);
155 if (node.parent is ir.Member) { 171 if (node.parent is ir.Member) {
156 assert(_elementMap.getMember(node.parent) == member); 172 assert(_elementMap.getMember(node.parent) == member);
157 _memberClosureRepresentationMap[member] = closureClass; 173 _memberClosureRepresentationMap[member] = closureClass;
158 } else { 174 } else {
159 assert(node.parent is ir.FunctionExpression || 175 assert(node.parent is ir.FunctionExpression ||
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 StringBuffer sb = new StringBuffer(); 272 StringBuffer sb = new StringBuffer();
257 sb.write('this=$hasThisLocal,'); 273 sb.write('this=$hasThisLocal,');
258 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 274 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
259 return sb.toString(); 275 return sb.toString();
260 } 276 }
261 } 277 }
262 278
263 class JsScopeInfo extends ScopeInfo { 279 class JsScopeInfo extends ScopeInfo {
264 final Set<Local> localsUsedInTryOrSync; 280 final Set<Local> localsUsedInTryOrSync;
265 final Local thisLocal; 281 final Local thisLocal;
266 final Set<Local> boxedVariables; 282 final Map<Local, JRecordField> boxedVariables;
267 283
268 /// The set of variables that were defined in another scope, but are used in 284 /// The set of variables that were defined in another scope, but are used in
269 /// this scope. 285 /// this scope.
270 final Set<Local> freeVariables; 286 final Set<Local> freeVariables;
271 287
272 JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables, 288 JsScopeInfo.from(
273 this.freeVariables); 289 this.boxedVariables, KernelScopeInfo info, KernelToLocalsMap localsMap)
274
275 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
276 : this.thisLocal = 290 : this.thisLocal =
277 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 291 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
278 this.localsUsedInTryOrSync = 292 this.localsUsedInTryOrSync =
279 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(), 293 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
280 this.boxedVariables =
281 info.boxedVariables.map(localsMap.getLocalVariable).toSet(),
282 this.freeVariables = 294 this.freeVariables =
283 info.freeVariables.map(localsMap.getLocalVariable).toSet(); 295 info.freeVariables.map(localsMap.getLocalVariable).toSet();
284 296
285 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 297 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
286 boxedVariables.forEach((Local l) { 298 boxedVariables.forEach((Local l, JRecordField box) {
287 // TODO(efortuna): add FieldEntities as created. 299 f(l, box);
288 f(l, null);
289 }); 300 });
290 } 301 }
291 302
292 bool localIsUsedInTryOrSync(Local variable) => 303 bool localIsUsedInTryOrSync(Local variable) =>
293 localsUsedInTryOrSync.contains(variable); 304 localsUsedInTryOrSync.contains(variable);
294 305
295 String toString() { 306 String toString() {
296 StringBuffer sb = new StringBuffer(); 307 StringBuffer sb = new StringBuffer();
297 sb.write('this=$thisLocal,'); 308 sb.write('this=$thisLocal,');
298 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 309 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
299 return sb.toString(); 310 return sb.toString();
300 } 311 }
301 312
302 bool isBoxed(Local variable) => boxedVariables.contains(variable); 313 bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
303 } 314 }
304 315
305 class KernelCapturedScope extends KernelScopeInfo { 316 class KernelCapturedScope extends KernelScopeInfo {
306 final ir.TreeNode context;
307
308 KernelCapturedScope( 317 KernelCapturedScope(
309 Set<ir.VariableDeclaration> boxedVariables, 318 Set<ir.VariableDeclaration> boxedVariables,
310 NodeBox capturedVariablesAccessor, 319 NodeBox capturedVariablesAccessor,
311 this.context,
312 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 320 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
313 Set<ir.VariableDeclaration> freeVariables, 321 Set<ir.VariableDeclaration> freeVariables,
314 bool hasThisLocal) 322 bool hasThisLocal)
315 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor, 323 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor,
316 localsUsedInTryOrSync, freeVariables, hasThisLocal); 324 localsUsedInTryOrSync, freeVariables, hasThisLocal);
317 325
318 bool get requiresContextBox => boxedVariables.isNotEmpty; 326 bool get requiresContextBox => boxedVariables.isNotEmpty;
319 } 327 }
320 328
321 class JsCapturedScope extends JsScopeInfo implements CapturedScope { 329 class JsCapturedScope extends JsScopeInfo implements CapturedScope {
322 final Local context; 330 final Local context;
323 331
324 JsCapturedScope.from( 332 JsCapturedScope.from(Map<Local, JRecordField> boxedVariables,
325 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap) 333 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap)
326 : this.context = localsMap.getLocalVariable(capturedScope.context), 334 : this.context =
327 super.from(capturedScope, localsMap); 335 boxedVariables.isNotEmpty ? boxedVariables.values.first.box : null,
336 super.from(boxedVariables, capturedScope, localsMap);
328 337
329 bool get requiresContextBox => boxedVariables.isNotEmpty; 338 bool get requiresContextBox => boxedVariables.isNotEmpty;
330 } 339 }
331 340
332 class KernelCapturedLoopScope extends KernelCapturedScope { 341 class KernelCapturedLoopScope extends KernelCapturedScope {
333 final List<ir.VariableDeclaration> boxedLoopVariables; 342 final List<ir.VariableDeclaration> boxedLoopVariables;
334 343
335 KernelCapturedLoopScope( 344 KernelCapturedLoopScope(
336 Set<ir.VariableDeclaration> boxedVariables, 345 Set<ir.VariableDeclaration> boxedVariables,
337 NodeBox capturedVariablesAccessor, 346 NodeBox capturedVariablesAccessor,
338 this.boxedLoopVariables, 347 this.boxedLoopVariables,
339 ir.TreeNode context,
340 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 348 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
341 Set<ir.VariableDeclaration> freeVariables, 349 Set<ir.VariableDeclaration> freeVariables,
342 bool hasThisLocal) 350 bool hasThisLocal)
343 : super(boxedVariables, capturedVariablesAccessor, context, 351 : super(boxedVariables, capturedVariablesAccessor, localsUsedInTryOrSync,
344 localsUsedInTryOrSync, freeVariables, hasThisLocal); 352 freeVariables, hasThisLocal);
345 353
346 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 354 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
347 } 355 }
348 356
349 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope { 357 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
350 final List<Local> boxedLoopVariables; 358 final List<Local> boxedLoopVariables;
351 359
352 JsCapturedLoopScope.from( 360 JsCapturedLoopScope.from(Map<Local, JRecordField> boxedVariables,
353 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap) 361 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap)
354 : this.boxedLoopVariables = capturedScope.boxedLoopVariables 362 : this.boxedLoopVariables = capturedScope.boxedLoopVariables
355 .map(localsMap.getLocalVariable) 363 .map(localsMap.getLocalVariable)
356 .toList(), 364 .toList(),
357 super.from(capturedScope, localsMap); 365 super.from(boxedVariables, capturedScope, localsMap);
358 366
359 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 367 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
360 } 368 }
361 369
362 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 370 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
363 class KernelClosureClass extends JsScopeInfo 371 class KernelClosureClass extends JsScopeInfo
364 implements ClosureRepresentationInfo { 372 implements ClosureRepresentationInfo {
365 JFunction callMethod; 373 JFunction callMethod;
366 final Local closureEntity; 374 final Local closureEntity;
367 final Local thisLocal; 375 final Local thisLocal;
368 final JClass closureClassEntity; 376 final JClass closureClassEntity;
369 377
370 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 378 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
371 379
372 KernelClosureClass.fromScopeInfo( 380 KernelClosureClass.fromScopeInfo(
373 this.closureClassEntity, 381 this.closureClassEntity,
374 ir.FunctionNode closureSourceNode, 382 ir.FunctionNode closureSourceNode,
383 Map<Local, JRecordField> boxedVariables,
375 KernelScopeInfo info, 384 KernelScopeInfo info,
376 KernelToLocalsMap localsMap, 385 KernelToLocalsMap localsMap,
377 this.closureEntity, 386 this.closureEntity,
378 this.thisLocal) 387 this.thisLocal)
379 : super.from(info, localsMap); 388 : super.from(boxedVariables, info, localsMap);
380 389
381 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 390 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
382 391
383 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; 392 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
384 393
385 void forEachCapturedVariable(f(Local from, JField to)) { 394 void forEachCapturedVariable(f(Local from, JField to)) {
386 localToFieldMap.forEach(f); 395 for (Local l in localToFieldMap.keys) {
396 var jField = localToFieldMap[l];
397 if (l is! BoxLocal) f(l, jField);
398 }
387 } 399 }
388 400
389 @override 401 @override
390 void forEachBoxedVariable(f(Local local, JField field)) { 402 void forEachBoxedVariable(f(Local local, JField field)) {
391 for (Local l in localToFieldMap.keys) { 403 boxedVariables.forEach(f);
392 if (localToFieldMap[l] is JRecordField) f(l, localToFieldMap[l]);
393 }
394 } 404 }
395 405
396 void forEachFreeVariable(f(Local variable, JField field)) { 406 void forEachFreeVariable(f(Local variable, JField field)) {
397 for (Local l in localToFieldMap.keys) { 407 localToFieldMap.forEach(f);
398 var jField = localToFieldMap[l]; 408 boxedVariables.forEach(f);
399 if (jField is! JRecordField && jField is! BoxLocal) f(l, jField);
400 }
401 } 409 }
402 410
403 bool isVariableBoxed(Local variable) => 411 bool isVariableBoxed(Local variable) =>
404 localToFieldMap.keys.contains(variable); 412 localToFieldMap.keys.contains(variable);
405 413
406 bool get isClosure => true; 414 bool get isClosure => true;
407 } 415 }
408 416
409 /// A local variable to disambiguate between a variable that has been captured 417 /// A local variable to disambiguate between a variable that has been captured
410 /// from one scope to another. This is the ir.Node version that corresponds to 418 /// from one scope to another. This is the ir.Node version that corresponds to
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 KernelScopeInfo scopeInfo; 599 KernelScopeInfo scopeInfo;
592 600
593 /// Collected [CapturedScope] data for nodes. 601 /// Collected [CapturedScope] data for nodes.
594 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 602 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
595 <ir.Node, KernelCapturedScope>{}; 603 <ir.Node, KernelCapturedScope>{};
596 604
597 /// Collected [ScopeInfo] data for nodes. 605 /// Collected [ScopeInfo] data for nodes.
598 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 606 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
599 <ir.TreeNode, KernelScopeInfo>{}; 607 <ir.TreeNode, KernelScopeInfo>{};
600 } 608 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698