| OLD | NEW |
| 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 '../elements/elements.dart'; | |
| 11 import '../elements/entities.dart'; | 10 import '../elements/entities.dart'; |
| 12 import '../elements/entity_utils.dart' as utils; | |
| 13 import '../elements/names.dart' show Name; | 11 import '../elements/names.dart' show Name; |
| 14 import '../kernel/element_map.dart'; | 12 import '../kernel/element_map.dart'; |
| 15 import '../world.dart'; | 13 import '../world.dart'; |
| 16 import 'elements.dart'; | 14 import 'elements.dart'; |
| 17 import 'closure_visitors.dart'; | 15 import 'closure_visitors.dart'; |
| 18 import 'locals.dart'; | 16 import 'locals.dart'; |
| 19 import 'js_strategy.dart' show JsClosedWorld; | 17 import 'js_strategy.dart' show JsClosedWorld; |
| 20 | 18 |
| 21 /// Closure conversion code using our new Entity model. Closure conversion is | 19 /// Closure conversion code using our new Entity model. Closure conversion is |
| 22 /// necessary because the semantics of closures are slightly different in Dart | 20 /// necessary because the semantics of closures are slightly different in Dart |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 model.capturedScopesMap | 99 model.capturedScopesMap |
| 102 .forEach((ir.Node node, KernelCapturedScope scope) { | 100 .forEach((ir.Node node, KernelCapturedScope scope) { |
| 103 if (scope is KernelCapturedLoopScope) { | 101 if (scope is KernelCapturedLoopScope) { |
| 104 _capturedScopesMap[node] = | 102 _capturedScopesMap[node] = |
| 105 new JsCapturedLoopScope.from(scope, localsMap); | 103 new JsCapturedLoopScope.from(scope, localsMap); |
| 106 } else { | 104 } else { |
| 107 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); | 105 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); |
| 108 } | 106 } |
| 109 }); | 107 }); |
| 110 | 108 |
| 111 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = | 109 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = |
| 112 model.closuresToGenerate; | 110 model.closuresToGenerate; |
| 113 for (ir.TreeNode node in closuresToGenerate.keys) { | 111 for (ir.FunctionNode node in closuresToGenerate.keys) { |
| 114 _produceSyntheticElements( | 112 _produceSyntheticElements( |
| 115 member, node, closuresToGenerate[node], closedWorldRefiner); | 113 member, node, closuresToGenerate[node], closedWorldRefiner); |
| 116 } | 114 } |
| 117 }); | 115 }); |
| 118 } | 116 } |
| 119 | 117 |
| 120 /// Inspect members and mark if those members capture any state that needs to | 118 /// Inspect members and mark if those members capture any state that needs to |
| 121 /// be marked as free variables. | 119 /// be marked as free variables. |
| 122 ClosureModel _buildClosureModel(MemberEntity entity) { | 120 ClosureModel _buildClosureModel(MemberEntity entity) { |
| 123 ClosureModel model = new ClosureModel(); | 121 ClosureModel model = new ClosureModel(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 142 } | 140 } |
| 143 return model; | 141 return model; |
| 144 } | 142 } |
| 145 | 143 |
| 146 /// Given what variables are captured at each point, construct closure classes | 144 /// Given what variables are captured at each point, construct closure classes |
| 147 /// with fields containing the captured variables to replicate the Dart | 145 /// with fields containing the captured variables to replicate the Dart |
| 148 /// closure semantics in JS. If this closure captures any variables (meaning | 146 /// closure semantics in JS. If this closure captures any variables (meaning |
| 149 /// the closure accesses a variable that gets accessed at some point), then | 147 /// the closure accesses a variable that gets accessed at some point), then |
| 150 /// boxForCapturedVariables stores the local context for those variables. | 148 /// boxForCapturedVariables stores the local context for those variables. |
| 151 /// If no variables are captured, this parameter is null. | 149 /// If no variables are captured, this parameter is null. |
| 152 void _produceSyntheticElements( | 150 void _produceSyntheticElements(MemberEntity member, ir.FunctionNode node, |
| 153 MemberEntity member, | 151 KernelScopeInfo info, JsClosedWorld closedWorldRefiner) { |
| 154 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, | |
| 155 KernelScopeInfo info, | |
| 156 JsClosedWorld closedWorldRefiner) { | |
| 157 String name = _computeClosureName(node); | |
| 158 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); | 152 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
| 159 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( | 153 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( |
| 160 name, member.library, info, node.location, localsMap); | 154 member, node, member.library, info, node.location, localsMap); |
| 161 | 155 |
| 162 Entity entity; | 156 // We want the original declaration where that function is used to point |
| 163 if (node is ir.Member) { | 157 // to the correct closure class. |
| 164 entity = member; | 158 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 165 } else { | 159 Entity entity = localsMap.getLocalFunction(node.parent); |
| 166 assert(node is ir.FunctionNode); | |
| 167 entity = localsMap.getLocalFunction(node.parent); | |
| 168 // We want the original declaration where that function is used to point | |
| 169 // to the correct closure class. | |
| 170 _closureRepresentationMap[closureClass.callMethod] = closureClass; | |
| 171 } | |
| 172 assert(entity != null); | 160 assert(entity != null); |
| 173 _closureRepresentationMap[entity] = closureClass; | 161 _closureRepresentationMap[entity] = closureClass; |
| 174 } | 162 } |
| 175 | 163 |
| 176 // Returns a non-unique name for the given closure element. | |
| 177 String _computeClosureName(ir.TreeNode treeNode) { | |
| 178 var parts = <String>[]; | |
| 179 if (treeNode is ir.Field && treeNode.name.name != "") { | |
| 180 parts.add(treeNode.name.name); | |
| 181 } else { | |
| 182 parts.add('closure'); | |
| 183 } | |
| 184 ir.TreeNode node = treeNode.parent; | |
| 185 while (node != null && | |
| 186 (node is ir.Constructor || | |
| 187 node is ir.Class || | |
| 188 node is ir.FunctionNode || | |
| 189 node is ir.Procedure)) { | |
| 190 // TODO(johnniwinther): Simplify computed names. | |
| 191 if (node is ir.Constructor || | |
| 192 node.parent is ir.Constructor || | |
| 193 (node is ir.Procedure && node.kind == ir.ProcedureKind.Factory)) { | |
| 194 FunctionEntity entity; | |
| 195 if (node.parent is ir.Constructor) { | |
| 196 entity = _elementMap.getConstructorBody(node); | |
| 197 } else { | |
| 198 entity = _elementMap.getMember(node); | |
| 199 } | |
| 200 parts.add(utils.reconstructConstructorName(entity)); | |
| 201 } else { | |
| 202 String surroundingName = ''; | |
| 203 if (node is ir.Class) { | |
| 204 surroundingName = Elements.operatorNameToIdentifier(node.name); | |
| 205 } else if (node is ir.Procedure) { | |
| 206 surroundingName = Elements.operatorNameToIdentifier(node.name.name); | |
| 207 } | |
| 208 parts.add(surroundingName); | |
| 209 } | |
| 210 // A generative constructors's parent is the class; the class name is | |
| 211 // already part of the generative constructor's name. | |
| 212 if (node is ir.Constructor) break; | |
| 213 node = node.parent; | |
| 214 } | |
| 215 return parts.reversed.join('_'); | |
| 216 } | |
| 217 | |
| 218 @override | 164 @override |
| 219 ScopeInfo getScopeInfo(Entity entity) { | 165 ScopeInfo getScopeInfo(Entity entity) { |
| 220 // TODO(johnniwinther): Remove this check when constructor bodies a created | 166 // TODO(johnniwinther): Remove this check when constructor bodies a created |
| 221 // eagerly with the J-model; a constructor body should have it's own | 167 // eagerly with the J-model; a constructor body should have it's own |
| 222 // [ClosureRepresentationInfo]. | 168 // [ClosureRepresentationInfo]. |
| 223 if (entity is ConstructorBodyEntity) { | 169 if (entity is ConstructorBodyEntity) { |
| 224 ConstructorBodyEntity constructorBody = entity; | 170 ConstructorBodyEntity constructorBody = entity; |
| 225 entity = constructorBody.constructor; | 171 entity = constructorBody.constructor; |
| 226 } | 172 } |
| 227 | 173 |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 329 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 384 } | 330 } |
| 385 | 331 |
| 386 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 332 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
| 387 class KernelClosureClass extends JsScopeInfo | 333 class KernelClosureClass extends JsScopeInfo |
| 388 implements ClosureRepresentationInfo, JClass { | 334 implements ClosureRepresentationInfo, JClass { |
| 389 final ir.Location location; | 335 final ir.Location location; |
| 390 | 336 |
| 391 final String name; | 337 final String name; |
| 392 final JLibrary library; | 338 final JLibrary library; |
| 339 JFunction callMethod; |
| 393 | 340 |
| 394 /// Index into the classData, classList and classEnvironment lists where this | 341 /// Index into the classData, classList and classEnvironment lists where this |
| 395 /// entity is stored in [JsToFrontendMapImpl]. | 342 /// entity is stored in [JsToFrontendMapImpl]. |
| 396 final int classIndex; | 343 final int classIndex; |
| 397 | 344 |
| 398 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 345 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
| 399 | 346 |
| 400 KernelClosureClass.fromScopeInfo(this.name, this.classIndex, this.library, | 347 KernelClosureClass.fromScopeInfo(this.name, this.classIndex, this.library, |
| 401 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) | 348 KernelScopeInfo info, this.location, KernelToLocalsMap localsMap) |
| 402 : super.from(info, localsMap); | 349 : super.from(info, localsMap); |
| 403 | 350 |
| 404 // TODO(efortuna): Implement. | 351 // TODO(efortuna): Implement. |
| 405 Local get closureEntity => null; | 352 Local get closureEntity => null; |
| 406 | 353 |
| 407 ClassEntity get closureClassEntity => this; | 354 ClassEntity get closureClassEntity => this; |
| 408 | 355 |
| 409 // TODO(efortuna): Implement. | |
| 410 FunctionEntity get callMethod => null; | |
| 411 | |
| 412 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); | 356 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); |
| 413 | 357 |
| 414 // TODO(efortuna): Implement. | 358 // TODO(efortuna): Implement. |
| 415 FieldEntity get thisFieldEntity => null; | 359 FieldEntity get thisFieldEntity => null; |
| 416 | 360 |
| 417 void forEachCapturedVariable(f(Local from, JField to)) { | 361 void forEachCapturedVariable(f(Local from, JField to)) { |
| 418 localToFieldMap.forEach(f); | 362 localToFieldMap.forEach(f); |
| 419 } | 363 } |
| 420 | 364 |
| 421 // TODO(efortuna): Implement. | 365 // TODO(efortuna): Implement. |
| 422 @override | 366 @override |
| 423 void forEachBoxedVariable(f(Local local, JField field)) {} | 367 void forEachBoxedVariable(f(Local local, JField field)) {} |
| 424 | 368 |
| 425 // TODO(efortuna): Implement. | 369 // TODO(efortuna): Implement. |
| 426 void forEachFreeVariable(f(Local variable, JField field)) {} | 370 void forEachFreeVariable(f(Local variable, JField field)) {} |
| 427 | 371 |
| 428 // TODO(efortuna): Implement. | 372 // TODO(efortuna): Implement. |
| 429 bool isVariableBoxed(Local variable) => false; | 373 bool isVariableBoxed(Local variable) => false; |
| 430 | 374 |
| 431 bool get isClosure => true; | 375 bool get isClosure => true; |
| 432 | 376 |
| 433 bool get isAbstract => false; | 377 bool get isAbstract => false; |
| 434 | 378 |
| 435 String toString() => '${jsElementPrefix}class($name)'; | 379 String toString() => '${jsElementPrefix}class($name)'; |
| 436 } | 380 } |
| 437 | 381 |
| 438 class ClosureField extends JField { | 382 class JClosureField extends JField { |
| 439 ClosureField(String name, int memberIndex, KernelClosureClass containingClass, | 383 JClosureField(String name, int memberIndex, |
| 440 bool isConst, bool isAssignable) | 384 KernelClosureClass containingClass, bool isConst, bool isAssignable) |
| 441 : super(memberIndex, containingClass.library, containingClass, | 385 : super(memberIndex, containingClass.library, containingClass, |
| 442 new Name(name, containingClass.library), | 386 new Name(name, containingClass.library), |
| 443 isAssignable: isAssignable, isConst: isConst); | 387 isAssignable: isAssignable, isConst: isConst); |
| 444 } | 388 } |
| 445 | 389 |
| 446 class ClosureClassDefinition implements ClassDefinition { | 390 class ClosureClassDefinition implements ClassDefinition { |
| 447 final ClassEntity cls; | 391 final ClassEntity cls; |
| 448 final ir.Location location; | 392 final ir.Location location; |
| 449 | 393 |
| 450 ClosureClassDefinition(this.cls, this.location); | 394 ClosureClassDefinition(this.cls, this.location); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 476 // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields | 420 // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields |
| 477 // without initializers; we shouldn't even create a [ClosureModel] in these | 421 // without initializers; we shouldn't even create a [ClosureModel] in these |
| 478 // cases. | 422 // cases. |
| 479 KernelScopeInfo scopeInfo; | 423 KernelScopeInfo scopeInfo; |
| 480 | 424 |
| 481 /// Collected [CapturedScope] data for nodes. | 425 /// Collected [CapturedScope] data for nodes. |
| 482 Map<ir.Node, KernelCapturedScope> capturedScopesMap = | 426 Map<ir.Node, KernelCapturedScope> capturedScopesMap = |
| 483 <ir.Node, KernelCapturedScope>{}; | 427 <ir.Node, KernelCapturedScope>{}; |
| 484 | 428 |
| 485 /// Collected [ScopeInfo] data for nodes. | 429 /// Collected [ScopeInfo] data for nodes. |
| 486 Map<ir.TreeNode, KernelScopeInfo> closuresToGenerate = | 430 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = |
| 487 <ir.TreeNode, KernelScopeInfo>{}; | 431 <ir.FunctionNode, KernelScopeInfo>{}; |
| 488 } | 432 } |
| OLD | NEW |