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

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

Issue 3007743002: Add boxing for modified variables (Closed)
Patch Set: merged with master 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
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | 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';
(...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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 StringBuffer sb = new StringBuffer(); 274 StringBuffer sb = new StringBuffer();
259 sb.write('this=$hasThisLocal,'); 275 sb.write('this=$hasThisLocal,');
260 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 276 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
261 return sb.toString(); 277 return sb.toString();
262 } 278 }
263 } 279 }
264 280
265 class JsScopeInfo extends ScopeInfo { 281 class JsScopeInfo extends ScopeInfo {
266 final Set<Local> localsUsedInTryOrSync; 282 final Set<Local> localsUsedInTryOrSync;
267 final Local thisLocal; 283 final Local thisLocal;
268 final Set<Local> boxedVariables; 284 final Map<Local, JRecordField> boxedVariables;
269 285
270 /// The set of variables that were defined in another scope, but are used in 286 /// The set of variables that were defined in another scope, but are used in
271 /// this scope. 287 /// this scope.
272 final Set<Local> freeVariables; 288 final Set<Local> freeVariables;
273 289
274 JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables, 290 JsScopeInfo.from(
275 this.freeVariables); 291 this.boxedVariables, KernelScopeInfo info, KernelToLocalsMap localsMap)
276
277 JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
278 : this.thisLocal = 292 : this.thisLocal =
279 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, 293 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
280 this.localsUsedInTryOrSync = 294 this.localsUsedInTryOrSync =
281 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(), 295 info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
282 this.boxedVariables =
283 info.boxedVariables.map(localsMap.getLocalVariable).toSet(),
284 this.freeVariables = 296 this.freeVariables =
285 info.freeVariables.map(localsMap.getLocalVariable).toSet(); 297 info.freeVariables.map(localsMap.getLocalVariable).toSet();
286 298
287 void forEachBoxedVariable(f(Local local, FieldEntity field)) { 299 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
288 boxedVariables.forEach((Local l) { 300 boxedVariables.forEach((Local l, JRecordField box) {
289 // TODO(efortuna): add FieldEntities as created. 301 f(l, box);
290 f(l, null);
291 }); 302 });
292 } 303 }
293 304
294 bool localIsUsedInTryOrSync(Local variable) => 305 bool localIsUsedInTryOrSync(Local variable) =>
295 localsUsedInTryOrSync.contains(variable); 306 localsUsedInTryOrSync.contains(variable);
296 307
297 String toString() { 308 String toString() {
298 StringBuffer sb = new StringBuffer(); 309 StringBuffer sb = new StringBuffer();
299 sb.write('this=$thisLocal,'); 310 sb.write('this=$thisLocal,');
300 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 311 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
301 return sb.toString(); 312 return sb.toString();
302 } 313 }
303 314
304 bool isBoxed(Local variable) => boxedVariables.contains(variable); 315 bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
305 } 316 }
306 317
307 class KernelCapturedScope extends KernelScopeInfo { 318 class KernelCapturedScope extends KernelScopeInfo {
308 final ir.TreeNode context;
309
310 KernelCapturedScope( 319 KernelCapturedScope(
311 Set<ir.VariableDeclaration> boxedVariables, 320 Set<ir.VariableDeclaration> boxedVariables,
312 NodeBox capturedVariablesAccessor, 321 NodeBox capturedVariablesAccessor,
313 this.context,
314 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 322 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
315 Set<ir.VariableDeclaration> freeVariables, 323 Set<ir.VariableDeclaration> freeVariables,
316 bool hasThisLocal) 324 bool hasThisLocal)
317 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor, 325 : super.withBoxedVariables(boxedVariables, capturedVariablesAccessor,
318 localsUsedInTryOrSync, freeVariables, hasThisLocal); 326 localsUsedInTryOrSync, freeVariables, hasThisLocal);
319 327
320 bool get requiresContextBox => boxedVariables.isNotEmpty; 328 bool get requiresContextBox => boxedVariables.isNotEmpty;
321 } 329 }
322 330
323 class JsCapturedScope extends JsScopeInfo implements CapturedScope { 331 class JsCapturedScope extends JsScopeInfo implements CapturedScope {
324 final Local context; 332 final Local context;
325 333
326 JsCapturedScope.from( 334 JsCapturedScope.from(Map<Local, JRecordField> boxedVariables,
327 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap) 335 KernelCapturedScope capturedScope, KernelToLocalsMap localsMap)
328 : this.context = localsMap.getLocalVariable(capturedScope.context), 336 : this.context =
329 super.from(capturedScope, localsMap); 337 boxedVariables.isNotEmpty ? boxedVariables.values.first.box : null,
338 super.from(boxedVariables, capturedScope, localsMap);
330 339
331 bool get requiresContextBox => boxedVariables.isNotEmpty; 340 bool get requiresContextBox => boxedVariables.isNotEmpty;
332 } 341 }
333 342
334 class KernelCapturedLoopScope extends KernelCapturedScope { 343 class KernelCapturedLoopScope extends KernelCapturedScope {
335 final List<ir.VariableDeclaration> boxedLoopVariables; 344 final List<ir.VariableDeclaration> boxedLoopVariables;
336 345
337 KernelCapturedLoopScope( 346 KernelCapturedLoopScope(
338 Set<ir.VariableDeclaration> boxedVariables, 347 Set<ir.VariableDeclaration> boxedVariables,
339 NodeBox capturedVariablesAccessor, 348 NodeBox capturedVariablesAccessor,
340 this.boxedLoopVariables, 349 this.boxedLoopVariables,
341 ir.TreeNode context,
342 Set<ir.VariableDeclaration> localsUsedInTryOrSync, 350 Set<ir.VariableDeclaration> localsUsedInTryOrSync,
343 Set<ir.VariableDeclaration> freeVariables, 351 Set<ir.VariableDeclaration> freeVariables,
344 bool hasThisLocal) 352 bool hasThisLocal)
345 : super(boxedVariables, capturedVariablesAccessor, context, 353 : super(boxedVariables, capturedVariablesAccessor, localsUsedInTryOrSync,
346 localsUsedInTryOrSync, freeVariables, hasThisLocal); 354 freeVariables, hasThisLocal);
347 355
348 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 356 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
349 } 357 }
350 358
351 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope { 359 class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
352 final List<Local> boxedLoopVariables; 360 final List<Local> boxedLoopVariables;
353 361
354 JsCapturedLoopScope.from( 362 JsCapturedLoopScope.from(Map<Local, JRecordField> boxedVariables,
355 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap) 363 KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap)
356 : this.boxedLoopVariables = capturedScope.boxedLoopVariables 364 : this.boxedLoopVariables = capturedScope.boxedLoopVariables
357 .map(localsMap.getLocalVariable) 365 .map(localsMap.getLocalVariable)
358 .toList(), 366 .toList(),
359 super.from(capturedScope, localsMap); 367 super.from(boxedVariables, capturedScope, localsMap);
360 368
361 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; 369 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
362 } 370 }
363 371
364 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. 372 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
365 class KernelClosureClass extends JsScopeInfo 373 class KernelClosureClass extends JsScopeInfo
366 implements ClosureRepresentationInfo { 374 implements ClosureRepresentationInfo {
367 JFunction callMethod; 375 JFunction callMethod;
368 final Local closureEntity; 376 final Local closureEntity;
369 final Local thisLocal; 377 final Local thisLocal;
370 final JClass closureClassEntity; 378 final JClass closureClassEntity;
371 379
372 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); 380 final Map<Local, JField> localToFieldMap = new Map<Local, JField>();
373 381
374 KernelClosureClass.fromScopeInfo( 382 KernelClosureClass.fromScopeInfo(
375 this.closureClassEntity, 383 this.closureClassEntity,
376 ir.FunctionNode closureSourceNode, 384 ir.FunctionNode closureSourceNode,
385 Map<Local, JRecordField> boxedVariables,
377 KernelScopeInfo info, 386 KernelScopeInfo info,
378 KernelToLocalsMap localsMap, 387 KernelToLocalsMap localsMap,
379 this.closureEntity, 388 this.closureEntity,
380 this.thisLocal) 389 this.thisLocal)
381 : super.from(info, localsMap); 390 : super.from(boxedVariables, info, localsMap);
382 391
383 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); 392 List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
384 393
385 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; 394 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
386 395
387 void forEachCapturedVariable(f(Local from, JField to)) { 396 void forEachCapturedVariable(f(Local from, JField to)) {
388 localToFieldMap.forEach(f); 397 for (Local l in localToFieldMap.keys) {
398 var jField = localToFieldMap[l];
399 if (l is! BoxLocal) f(l, jField);
400 }
389 } 401 }
390 402
391 @override 403 @override
392 void forEachBoxedVariable(f(Local local, JField field)) { 404 void forEachBoxedVariable(f(Local local, JField field)) {
393 for (Local l in localToFieldMap.keys) { 405 boxedVariables.forEach(f);
394 if (localToFieldMap[l] is JRecordField) f(l, localToFieldMap[l]);
395 }
396 } 406 }
397 407
398 void forEachFreeVariable(f(Local variable, JField field)) { 408 void forEachFreeVariable(f(Local variable, JField field)) {
399 for (Local l in localToFieldMap.keys) { 409 localToFieldMap.forEach(f);
400 var jField = localToFieldMap[l]; 410 boxedVariables.forEach(f);
401 if (jField is! JRecordField && jField is! BoxLocal) f(l, jField);
402 }
403 } 411 }
404 412
405 bool isVariableBoxed(Local variable) => 413 bool isVariableBoxed(Local variable) =>
406 localToFieldMap.keys.contains(variable); 414 localToFieldMap.keys.contains(variable);
407 415
408 bool get isClosure => true; 416 bool get isClosure => true;
409 } 417 }
410 418
411 /// A local variable to disambiguate between a variable that has been captured 419 /// A local variable to disambiguate between a variable that has been captured
412 /// from one scope to another. This is the ir.Node version that corresponds to 420 /// from one scope to another. This is the ir.Node version that corresponds to
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 KernelScopeInfo scopeInfo; 619 KernelScopeInfo scopeInfo;
612 620
613 /// Collected [CapturedScope] data for nodes. 621 /// Collected [CapturedScope] data for nodes.
614 Map<ir.Node, KernelCapturedScope> capturedScopesMap = 622 Map<ir.Node, KernelCapturedScope> capturedScopesMap =
615 <ir.Node, KernelCapturedScope>{}; 623 <ir.Node, KernelCapturedScope>{};
616 624
617 /// Collected [ScopeInfo] data for nodes. 625 /// Collected [ScopeInfo] data for nodes.
618 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = 626 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate =
619 <ir.TreeNode, KernelScopeInfo>{}; 627 <ir.TreeNode, KernelScopeInfo>{};
620 } 628 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698