| 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 '../constants/expressions.dart'; | 10 import '../constants/expressions.dart'; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 _capturedScopesMap[node] = | 106 _capturedScopesMap[node] = |
| 107 new JsCapturedLoopScope.from(scope, localsMap); | 107 new JsCapturedLoopScope.from(scope, localsMap); |
| 108 } else { | 108 } else { |
| 109 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); | 109 _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap); |
| 110 } | 110 } |
| 111 }); | 111 }); |
| 112 | 112 |
| 113 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = | 113 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = |
| 114 model.closuresToGenerate; | 114 model.closuresToGenerate; |
| 115 for (ir.FunctionNode node in closuresToGenerate.keys) { | 115 for (ir.FunctionNode node in closuresToGenerate.keys) { |
| 116 _produceSyntheticElements( | 116 KernelClosureClass closureClass = _produceSyntheticElements( |
| 117 member, node, closuresToGenerate[node], closedWorldRefiner); | 117 member, node, closuresToGenerate[node], closedWorldRefiner); |
| 118 // Add also for the call method. |
| 119 _scopeMap[closureClass.callMethod] = closureClass; |
| 118 } | 120 } |
| 119 }); | 121 }); |
| 120 } | 122 } |
| 121 | 123 |
| 122 /// Given what variables are captured at each point, construct closure classes | 124 /// Given what variables are captured at each point, construct closure classes |
| 123 /// with fields containing the captured variables to replicate the Dart | 125 /// with fields containing the captured variables to replicate the Dart |
| 124 /// closure semantics in JS. If this closure captures any variables (meaning | 126 /// closure semantics in JS. If this closure captures any variables (meaning |
| 125 /// the closure accesses a variable that gets accessed at some point), then | 127 /// the closure accesses a variable that gets accessed at some point), then |
| 126 /// boxForCapturedVariables stores the local context for those variables. | 128 /// boxForCapturedVariables stores the local context for those variables. |
| 127 /// If no variables are captured, this parameter is null. | 129 /// If no variables are captured, this parameter is null. |
| 128 void _produceSyntheticElements(MemberEntity member, ir.FunctionNode node, | 130 KernelClosureClass _produceSyntheticElements( |
| 129 KernelScopeInfo info, JsClosedWorld closedWorldRefiner) { | 131 MemberEntity member, |
| 132 ir.FunctionNode node, |
| 133 KernelScopeInfo info, |
| 134 JsClosedWorld closedWorldRefiner) { |
| 130 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); | 135 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
| 131 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( | 136 KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass( |
| 132 member, node, member.library, info, node.location, localsMap); | 137 member, node, member.library, info, node.location, localsMap); |
| 133 | 138 |
| 134 // We want the original declaration where that function is used to point | 139 // We want the original declaration where that function is used to point |
| 135 // to the correct closure class. | 140 // to the correct closure class. |
| 136 _closureRepresentationMap[closureClass.callMethod] = closureClass; | 141 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 137 Entity entity; | 142 Entity entity; |
| 138 if (node.parent is ir.Member) { | 143 if (node.parent is ir.Member) { |
| 139 entity = _elementMap.getMember(node.parent); | 144 entity = _elementMap.getMember(node.parent); |
| 140 } else { | 145 } else { |
| 141 entity = localsMap.getLocalFunction(node.parent); | 146 entity = localsMap.getLocalFunction(node.parent); |
| 142 } | 147 } |
| 143 assert(entity != null); | 148 assert(entity != null); |
| 144 _closureRepresentationMap[entity] = closureClass; | 149 _closureRepresentationMap[entity] = closureClass; |
| 150 return closureClass; |
| 145 } | 151 } |
| 146 | 152 |
| 147 @override | 153 @override |
| 148 ScopeInfo getScopeInfo(Entity entity) { | 154 ScopeInfo getScopeInfo(Entity entity) { |
| 149 // TODO(johnniwinther): Remove this check when constructor bodies a created | 155 // TODO(johnniwinther): Remove this check when constructor bodies a created |
| 150 // eagerly with the J-model; a constructor body should have it's own | 156 // eagerly with the J-model; a constructor body should have it's own |
| 151 // [ClosureRepresentationInfo]. | 157 // [ClosureRepresentationInfo]. |
| 152 if (entity is ConstructorBodyEntity) { | 158 if (entity is ConstructorBodyEntity) { |
| 153 ConstructorBodyEntity constructorBody = entity; | 159 ConstructorBodyEntity constructorBody = entity; |
| 154 entity = constructorBody.constructor; | 160 entity = constructorBody.constructor; |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 : this.boxedLoopVariables = capturedScope.boxedLoopVariables | 333 : this.boxedLoopVariables = capturedScope.boxedLoopVariables |
| 328 .map(localsMap.getLocalVariable) | 334 .map(localsMap.getLocalVariable) |
| 329 .toList(), | 335 .toList(), |
| 330 super.from(capturedScope, localsMap); | 336 super.from(capturedScope, localsMap); |
| 331 | 337 |
| 332 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 338 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 333 } | 339 } |
| 334 | 340 |
| 335 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 341 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
| 336 class KernelClosureClass extends JsScopeInfo | 342 class KernelClosureClass extends JsScopeInfo |
| 337 implements ClosureRepresentationInfo, JClass { | 343 implements ClosureRepresentationInfo { |
| 338 final String name; | |
| 339 final JLibrary library; | |
| 340 JFunction callMethod; | 344 JFunction callMethod; |
| 341 final Local closureEntity; | 345 final Local closureEntity; |
| 342 final Local thisLocal; | 346 final Local thisLocal; |
| 343 | 347 final JClass closureClassEntity; |
| 344 /// Index into the classData, classList and classEnvironment lists where this | |
| 345 /// entity is stored in [JsToFrontendMapImpl]. | |
| 346 final int classIndex; | |
| 347 | 348 |
| 348 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 349 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
| 349 | 350 |
| 350 KernelClosureClass.fromScopeInfo( | 351 KernelClosureClass.fromScopeInfo( |
| 352 this.closureClassEntity, |
| 351 ir.FunctionNode closureSourceNode, | 353 ir.FunctionNode closureSourceNode, |
| 352 this.name, | |
| 353 this.classIndex, | |
| 354 this.library, | |
| 355 KernelScopeInfo info, | 354 KernelScopeInfo info, |
| 356 KernelToLocalsMap localsMap) | 355 KernelToLocalsMap localsMap) |
| 357 : closureEntity = closureSourceNode.parent is ir.Member | 356 : closureEntity = closureSourceNode.parent is ir.Member |
| 358 ? null | 357 ? null |
| 359 : localsMap.getLocalFunction(closureSourceNode.parent), | 358 : localsMap.getLocalFunction(closureSourceNode.parent), |
| 360 thisLocal = | 359 thisLocal = |
| 361 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, | 360 info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null, |
| 362 super.from(info, localsMap); | 361 super.from(info, localsMap); |
| 363 | 362 |
| 364 ClassEntity get closureClassEntity => this; | |
| 365 | |
| 366 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); | 363 List<Local> get createdFieldEntities => localToFieldMap.keys.toList(); |
| 367 | 364 |
| 368 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; | 365 FieldEntity get thisFieldEntity => localToFieldMap[thisLocal]; |
| 369 | 366 |
| 370 void forEachCapturedVariable(f(Local from, JField to)) { | 367 void forEachCapturedVariable(f(Local from, JField to)) { |
| 371 localToFieldMap.forEach(f); | 368 localToFieldMap.forEach(f); |
| 372 } | 369 } |
| 373 | 370 |
| 374 @override | 371 @override |
| 375 void forEachBoxedVariable(f(Local local, JField field)) { | 372 void forEachBoxedVariable(f(Local local, JField field)) { |
| 376 for (Local l in localToFieldMap.keys) { | 373 for (Local l in localToFieldMap.keys) { |
| 377 if (localToFieldMap[l] is JBoxedField) f(l, localToFieldMap[l]); | 374 if (localToFieldMap[l] is JBoxedField) f(l, localToFieldMap[l]); |
| 378 } | 375 } |
| 379 } | 376 } |
| 380 | 377 |
| 381 void forEachFreeVariable(f(Local variable, JField field)) { | 378 void forEachFreeVariable(f(Local variable, JField field)) { |
| 382 for (Local l in localToFieldMap.keys) { | 379 for (Local l in localToFieldMap.keys) { |
| 383 var jField = localToFieldMap[l]; | 380 var jField = localToFieldMap[l]; |
| 384 if (jField is! JBoxedField && jField is! BoxLocal) f(l, jField); | 381 if (jField is! JBoxedField && jField is! BoxLocal) f(l, jField); |
| 385 } | 382 } |
| 386 } | 383 } |
| 387 | 384 |
| 388 bool isVariableBoxed(Local variable) => | 385 bool isVariableBoxed(Local variable) => |
| 389 localToFieldMap.keys.contains(variable); | 386 localToFieldMap.keys.contains(variable); |
| 390 | 387 |
| 391 bool get isClosure => true; | 388 bool get isClosure => true; |
| 392 | |
| 393 bool get isAbstract => false; | |
| 394 | |
| 395 String toString() => '${jsElementPrefix}class($name)'; | |
| 396 } | 389 } |
| 397 | 390 |
| 398 /// A local variable to disambiguate between a variable that has been captured | 391 /// A local variable to disambiguate between a variable that has been captured |
| 399 /// from one scope to another. This is the ir.Node version that corresponds to | 392 /// from one scope to another. This is the ir.Node version that corresponds to |
| 400 /// [BoxLocal]. | 393 /// [BoxLocal]. |
| 401 class NodeBox { | 394 class NodeBox { |
| 402 final String name; | 395 final String name; |
| 403 final ir.TreeNode executableContext; | 396 final ir.TreeNode executableContext; |
| 404 NodeBox(this.name, this.executableContext); | 397 NodeBox(this.name, this.executableContext); |
| 405 } | 398 } |
| 406 | 399 |
| 400 class JClosureClass extends JClass { |
| 401 // TODO(efortuna): Storing this map here is so horrible. Instead store this on |
| 402 // the ScopeModel (because all of the closures share that localsMap) and then |
| 403 // set populate the getLocalVariable lookup with this localsMap for all the |
| 404 // closures. |
| 405 final KernelToLocalsMap localsMap; |
| 406 |
| 407 JClosureClass(this.localsMap, JLibrary library, int classIndex, String name) |
| 408 : super(library, classIndex, name, isAbstract: false); |
| 409 |
| 410 @override |
| 411 bool get isClosure => true; |
| 412 |
| 413 String toString() => '${jsElementPrefix}closure_class($name)'; |
| 414 } |
| 415 |
| 407 class JClosureField extends JField { | 416 class JClosureField extends JField { |
| 408 JClosureField(String name, int memberIndex, | 417 JClosureField(String name, int memberIndex, |
| 409 KernelClosureClass containingClass, bool isConst, bool isAssignable) | 418 KernelClosureClass containingClass, bool isConst, bool isAssignable) |
| 410 : super(memberIndex, containingClass.library, containingClass, | 419 : super( |
| 411 new Name(name, containingClass.library), | 420 memberIndex, |
| 412 isAssignable: isAssignable, isConst: isConst, isStatic: false); | 421 containingClass.closureClassEntity.library, |
| 422 containingClass.closureClassEntity, |
| 423 new Name(name, containingClass.closureClassEntity.library), |
| 424 isAssignable: isAssignable, |
| 425 isConst: isConst, |
| 426 isStatic: false); |
| 413 } | 427 } |
| 414 | 428 |
| 415 /// A ClosureField that has been "boxed" to prevent name shadowing with the | 429 /// A ClosureField that has been "boxed" to prevent name shadowing with the |
| 416 /// original variable and ensure that this variable is updated/read with the | 430 /// original variable and ensure that this variable is updated/read with the |
| 417 /// most recent value. | 431 /// most recent value. |
| 418 /// This corresponds to BoxFieldElement; we reuse BoxLocal from the original | 432 /// This corresponds to BoxFieldElement; we reuse BoxLocal from the original |
| 419 /// algorithm to correspond to the actual name of the variable. | 433 /// algorithm to correspond to the actual name of the variable. |
| 420 class JBoxedField extends JField { | 434 class JBoxedField extends JField { |
| 421 final BoxLocal box; | 435 final BoxLocal box; |
| 422 JBoxedField(String name, int memberIndex, this.box, | 436 JBoxedField(String name, int memberIndex, this.box, JClass containingClass, |
| 423 KernelClosureClass containingClass, bool isConst, bool isAssignable) | 437 bool isConst, bool isAssignable) |
| 424 : super(memberIndex, containingClass.library, containingClass, | 438 : super(memberIndex, containingClass.library, containingClass, |
| 425 new Name(name, containingClass.library), | 439 new Name(name, containingClass.library), |
| 426 isAssignable: isAssignable, isConst: isConst); | 440 isAssignable: isAssignable, isConst: isConst); |
| 427 } | 441 } |
| 428 | 442 |
| 429 class ClosureClassDefinition implements ClassDefinition { | 443 class ClosureClassDefinition implements ClassDefinition { |
| 430 final ClassEntity cls; | 444 final ClassEntity cls; |
| 431 final SourceSpan location; | 445 final SourceSpan location; |
| 432 | 446 |
| 433 ClosureClassDefinition(this.cls, this.location); | 447 ClosureClassDefinition(this.cls, this.location); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 KernelScopeInfo scopeInfo; | 537 KernelScopeInfo scopeInfo; |
| 524 | 538 |
| 525 /// Collected [CapturedScope] data for nodes. | 539 /// Collected [CapturedScope] data for nodes. |
| 526 Map<ir.Node, KernelCapturedScope> capturedScopesMap = | 540 Map<ir.Node, KernelCapturedScope> capturedScopesMap = |
| 527 <ir.Node, KernelCapturedScope>{}; | 541 <ir.Node, KernelCapturedScope>{}; |
| 528 | 542 |
| 529 /// Collected [ScopeInfo] data for nodes. | 543 /// Collected [ScopeInfo] data for nodes. |
| 530 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = | 544 Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate = |
| 531 <ir.FunctionNode, KernelScopeInfo>{}; | 545 <ir.FunctionNode, KernelScopeInfo>{}; |
| 532 } | 546 } |
| OLD | NEW |