Index: pkg/compiler/lib/src/kernel/closure.dart |
diff --git a/pkg/compiler/lib/src/kernel/closure.dart b/pkg/compiler/lib/src/kernel/closure.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f441d7fbc02cae60edeeb2deb4d3a6833ba96c02 |
--- /dev/null |
+++ b/pkg/compiler/lib/src/kernel/closure.dart |
@@ -0,0 +1,134 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import 'package:kernel/ast.dart' as ir; |
+ |
+import '../closure.dart'; |
+import '../common/tasks.dart'; |
+import '../elements/entities.dart'; |
+import '../world.dart'; |
+import 'element_map.dart'; |
+import 'kernel_backend_strategy.dart'; |
+ |
+class KernelClosureDataBuilder extends ir.Visitor { |
+ final KernelToLocalsMap _localsMap; |
+ final KernelClosureRepresentationInfo info; |
+ |
+ bool _inTry = false; |
+ |
+ KernelClosureDataBuilder(this._localsMap, ThisLocal thisLocal) |
+ : info = new KernelClosureRepresentationInfo(thisLocal); |
+ |
+ @override |
+ defaultNode(ir.Node node) { |
+ node.visitChildren(this); |
+ } |
+ |
+ @override |
+ visitTryCatch(ir.TryCatch node) { |
+ bool oldInTry = _inTry; |
+ _inTry = true; |
+ node.visitChildren(this); |
+ _inTry = oldInTry; |
+ } |
+ |
+ @override |
+ visitTryFinally(ir.TryFinally node) { |
+ bool oldInTry = _inTry; |
+ _inTry = true; |
+ node.visitChildren(this); |
+ _inTry = oldInTry; |
+ } |
+ |
+ @override |
+ visitVariableGet(ir.VariableGet node) { |
+ if (_inTry) { |
+ info.registerUsedInTryOrSync(_localsMap.getLocal(node.variable)); |
+ } |
+ } |
+} |
+ |
+/// Closure conversion code using our new Entity model. Closure conversion is |
+/// necessary because the semantics of closures are slightly different in Dart |
+/// than JavaScript. Closure conversion is separated out into two phases: |
+/// generation of a new (temporary) representation to store where variables need |
+/// to be hoisted/captured up at another level to re-write the closure, and then |
+/// the code generation phase where we generate elements and/or instructions to |
+/// represent this new code path. |
+/// |
+/// For a general explanation of how closure conversion works at a high level, |
+/// check out: |
+/// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or |
+/// http://matt.might.net/articles/closure-conversion/. |
+class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { |
+ final KernelToElementMap _elementMap; |
+ final GlobalLocalsMap _globalLocalsMap; |
+ Map<Entity, ClosureRepresentationInfo> _infoMap = |
+ <Entity, ClosureRepresentationInfo>{}; |
+ |
+ KernelClosureConversionTask( |
+ Measurer measurer, this._elementMap, this._globalLocalsMap) |
+ : super(measurer); |
+ |
+ /// The combined steps of generating our intermediate representation of |
+ /// closures that need to be rewritten and generating the element model. |
+ /// Ultimately these two steps will be split apart with the second step |
+ /// happening later in compilation just before codegen. These steps are |
+ /// combined here currently to provide a consistent interface to the rest of |
+ /// the compiler until we are ready to separate these phases. |
+ @override |
+ void convertClosures(Iterable<MemberEntity> processedEntities, |
+ ClosedWorldRefiner closedWorldRefiner) { |
+ // TODO(efortuna): implement. |
+ } |
+ |
+ /// TODO(johnniwinther,efortuna): Implement this. |
+ @override |
+ ClosureAnalysisInfo getClosureAnalysisInfo(ir.Node node) { |
+ return const ClosureAnalysisInfo(); |
+ } |
+ |
+ /// TODO(johnniwinther,efortuna): Implement this. |
+ @override |
+ LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( |
+ ir.Node loopNode) { |
+ return const LoopClosureRepresentationInfo(); |
+ } |
+ |
+ @override |
+ ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) { |
+ return _infoMap.putIfAbsent(entity, () { |
+ if (entity is MemberEntity) { |
+ ir.Member node = _elementMap.getMemberNode(entity); |
+ ThisLocal thisLocal; |
+ if (entity.isInstanceMember) { |
+ thisLocal = new ThisLocal(entity); |
+ } |
+ KernelClosureDataBuilder builder = new KernelClosureDataBuilder( |
+ _globalLocalsMap.getLocalsMap(entity), thisLocal); |
+ node.accept(builder); |
+ return builder.info; |
+ } |
+ |
+ /// TODO(johnniwinther,efortuna): Implement this. |
+ return const ClosureRepresentationInfo(); |
+ }); |
+ } |
+} |
+ |
+// TODO(johnniwinther): Add unittest for the computed |
+// [ClosureRepresentationInfo]. |
+class KernelClosureRepresentationInfo extends ClosureRepresentationInfo { |
+ final ThisLocal thisLocal; |
+ final Set<Local> _localsUsedInTryOrSync = new Set<Local>(); |
+ |
+ KernelClosureRepresentationInfo(this.thisLocal); |
+ |
+ void registerUsedInTryOrSync(Local local) { |
+ _localsUsedInTryOrSync.add(local); |
+ } |
+ |
+ bool variableIsUsedInTryOrSync(Local variable) => |
+ _localsUsedInTryOrSync.contains(variable); |
+} |