Skip to content

Commit

Permalink
Handle for-loop with simple break in compile_from_dill_test
Browse files Browse the repository at this point in the history
R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2950303002 .
  • Loading branch information
johnniwinther committed Jun 26, 2017
1 parent f7f4d61 commit 14dda16
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 20 deletions.
8 changes: 6 additions & 2 deletions pkg/compiler/lib/src/elements/jumps.dart
Expand Up @@ -12,19 +12,23 @@ 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;
}

/// 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;
Expand Down
10 changes: 2 additions & 8 deletions pkg/compiler/lib/src/elements/modelx.dart
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down
100 changes: 90 additions & 10 deletions pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
}
Expand All @@ -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
Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions tests/compiler/dart2js/kernel/compile_from_dill_test.dart
Expand Up @@ -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;
}
'''
Expand Down

0 comments on commit 14dda16

Please sign in to comment.