Handle for-loop with simple break in compile_from_dill_test

R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2950303002 .
This commit is contained in:
Johnni Winther 2017-06-26 11:10:28 +02:00
parent f7f4d6133b
commit 14dda16482
4 changed files with 102 additions and 20 deletions

View file

@ -12,7 +12,8 @@ abstract class LabelDefinition<T> extends Entity {
String get labelName;
JumpTarget<T> get target;
bool get isTarget;
bool get isTarget => isBreakTarget || isContinueTarget;
bool get isBreakTarget;
bool get isContinueTarget;
}
@ -20,11 +21,14 @@ abstract class LabelDefinition<T> extends Entity {
/// A jump target is the reference point of a statement or switch-case,
/// either by label or as the default target of a break or continue.
abstract class JumpTarget<T> extends Local {
String get name => 'target';
bool get isTarget => isBreakTarget || isContinueTarget;
T get statement;
int get nestingLevel;
List<LabelDefinition<T>> get labels;
bool get isTarget;
bool get isBreakTarget;
bool get isContinueTarget;
bool get isSwitch;

View file

@ -3337,7 +3337,7 @@ class UnnamedMixinApplicationElementX extends MixinApplicationElementX {
bool get isAbstract => true;
}
class LabelDefinitionX implements LabelDefinition<Node> {
class LabelDefinitionX extends LabelDefinition<Node> {
final Label label;
final String labelName;
final JumpTargetX target;
@ -3362,12 +3362,10 @@ class LabelDefinitionX implements LabelDefinition<Node> {
target.isContinueTarget = true;
}
bool get isTarget => isBreakTarget || isContinueTarget;
String toString() => 'Label:${name}';
}
class JumpTargetX implements JumpTarget<Node> {
class JumpTargetX extends JumpTarget<Node> {
final ExecutableElement executableContext;
final Node statement;
final int nestingLevel;
@ -3382,10 +3380,6 @@ class JumpTargetX implements JumpTarget<Node> {
@override
MemberElement get memberContext => executableContext.memberContext;
String get name => "target";
bool get isTarget => isBreakTarget || isContinueTarget;
LabelDefinition<Node> addLabel(Label label, String labelName,
{bool isBreakTarget: false}) {
LabelDefinitionX result = new LabelDefinitionX(label, labelName, this);

View file

@ -8,6 +8,7 @@ import 'package:kernel/ast.dart' as ir;
import '../backend_strategy.dart';
import '../closure.dart';
import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
import '../common/tasks.dart';
import '../compiler.dart';
@ -279,9 +280,25 @@ class GlobalLocalsMap {
class KernelToLocalsMapImpl implements KernelToLocalsMap {
final List<MemberEntity> _members = <MemberEntity>[];
Map<ir.VariableDeclaration, KLocal> _map = <ir.VariableDeclaration, KLocal>{};
Map<ir.LabeledStatement, KJumpTarget> _jumpTargetMap;
MemberEntity get currentMember => _members.last;
// TODO(johnniwinther): Compute this eagerly from the root of the member.
void _ensureJumpMap(ir.TreeNode node) {
if (_jumpTargetMap == null) {
JumpVisitor visitor = new JumpVisitor(currentMember);
// Find the root node for the current member.
while (node is! ir.Member) {
node = node.parent;
}
node.accept(visitor);
_jumpTargetMap = visitor.jumpTargetMap;
}
}
KernelToLocalsMapImpl(MemberEntity member) {
_members.add(member);
}
@ -299,54 +316,63 @@ class KernelToLocalsMapImpl implements KernelToLocalsMap {
@override
JumpTarget getJumpTargetForBreak(ir.BreakStatement node) {
throw new UnimplementedError('KernelToLocalsMapImpl.getJumpTargetForBreak');
_ensureJumpMap(node.target);
JumpTarget target = _jumpTargetMap[node.target];
assert(target != null, failedAt(currentMember, 'No target for $node.'));
return target;
}
@override
JumpTarget getJumpTargetForContinueSwitch(ir.ContinueSwitchStatement node) {
_ensureJumpMap(node.target);
throw new UnimplementedError(
'KernelToLocalsMapImpl.getJumpTargetForContinueSwitch');
}
@override
JumpTarget getJumpTargetForSwitchCase(ir.SwitchCase node) {
_ensureJumpMap(node);
throw new UnimplementedError(
'KernelToLocalsMapImpl.getJumpTargetForSwitchCase');
}
@override
JumpTarget getJumpTargetForDo(ir.DoStatement node) {
// TODO(redemption): Support do statement as jump target.
return null;
_ensureJumpMap(node);
return _jumpTargetMap[node.parent];
}
@override
JumpTarget getJumpTargetForLabel(ir.LabeledStatement node) {
throw new UnimplementedError('KernelToLocalsMapImpl.getJumpTargetForLabel');
_ensureJumpMap(node);
JumpTarget target = _jumpTargetMap[node];
assert(target != null, failedAt(currentMember, 'No target for $node.'));
return target;
}
@override
JumpTarget getJumpTargetForSwitch(ir.SwitchStatement node) {
_ensureJumpMap(node);
throw new UnimplementedError(
'KernelToLocalsMapImpl.getJumpTargetForSwitch');
}
@override
JumpTarget getJumpTargetForFor(ir.ForStatement node) {
// TODO(redemption): Support for statement as jump target.
return null;
_ensureJumpMap(node);
return _jumpTargetMap[node.parent];
}
@override
JumpTarget getJumpTargetForForIn(ir.ForInStatement node) {
// TODO(redemption): Support for-in statement as jump target.
return null;
_ensureJumpMap(node);
return _jumpTargetMap[node.parent];
}
@override
JumpTarget getJumpTargetForWhile(ir.WhileStatement node) {
// TODO(redemption): Support while statement as jump target.
return null;
_ensureJumpMap(node);
return _jumpTargetMap[node.parent];
}
@override
@ -363,6 +389,60 @@ class KernelToLocalsMapImpl implements KernelToLocalsMap {
}
}
class JumpVisitor extends ir.Visitor {
final MemberEntity member;
final Map<ir.LabeledStatement, KJumpTarget> jumpTargetMap =
<ir.LabeledStatement, KJumpTarget>{};
JumpVisitor(this.member);
KJumpTarget _getJumpTarget(ir.LabeledStatement node) {
return jumpTargetMap.putIfAbsent(node, () {
return new KJumpTarget(member, jumpTargetMap.length);
});
}
@override
defaultNode(ir.Node node) => node.visitChildren(this);
@override
visitBreakStatement(ir.BreakStatement node) {
KJumpTarget target = _getJumpTarget(node.target);
target.isBreakTarget = true;
super.visitBreakStatement(node);
}
}
class KJumpTarget extends JumpTarget<ir.Node> {
final MemberEntity memberContext;
final int nestingLevel;
KJumpTarget(this.memberContext, this.nestingLevel);
bool isBreakTarget = false;
bool isContinueTarget = false;
bool isSwitch = false;
@override
Entity get executableContext => memberContext;
@override
LabelDefinition<ir.Node> addLabel(ir.Node label, String labelName,
{bool isBreakTarget: false}) {
throw new UnimplementedError('KJumpTarget.addLabel');
}
@override
List<LabelDefinition<ir.Node>> get labels {
return const <LabelDefinition<ir.Node>>[];
}
@override
ir.Node get statement {
throw new UnimplementedError('KJumpTarget.statement');
}
}
class KLocal implements Local {
final String name;
final MemberEntity memberContext;

View file

@ -48,6 +48,10 @@ main() {
new Class('');
Class.staticField;
var x = null;
for (int i = 0; i < 10; i++) {
x = i;
if (i == 5) break;
}
return x;
}
'''