blob: 3268808c514a6286d7770947c4a9fca9f136ce17 [file] [log] [blame]
// 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));
}
}
@override
visitVariableSet(ir.VariableSet node) {
if (_inTry) {
info.registerUsedInTryOrSync(_localsMap.getLocal(node.variable));
}
node.visitChildren(this);
}
}
/// 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 KernelToElementMapForBuilding _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
ClosureScope getClosureScope(ir.Node node) {
return const ClosureScope();
}
@override
ScopeInfo getScopeInfo(Entity entity) {
// TODO(efortuna): Specialize this function from the one below.
return getClosureRepresentationInfo(entity);
}
/// TODO(johnniwinther,efortuna): Implement this.
@override
LoopClosureScope getLoopClosureScope(ir.Node loopNode) {
return const LoopClosureScope();
}
@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);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('this=$thisLocal,');
sb.write('localsUsedInTryOrSync={${_localsUsedInTryOrSync.join(', ')}}');
return sb.toString();
}
}