[kernel] Debugging of switch statement

BUG=
R=ahe@google.com, kmillikin@google.com

Review-Url: https://codereview.chromium.org/2750013002 .
This commit is contained in:
Jens Johansen 2017-03-21 11:36:48 +01:00
parent 4d208e2ffb
commit a1a34a1c84
11 changed files with 81 additions and 53 deletions

View file

@ -1115,12 +1115,13 @@ class StatementBuilder extends GeneralizingAstVisitor<ast.Statement> {
return scope.emitCompileTimeError(error);
}
if (currentCase == null) {
currentCase = new ast.SwitchCase(<ast.Expression>[], null);
currentCase = new ast.SwitchCase(<ast.Expression>[], <int>[], null);
cases.add(currentCase);
}
if (member is SwitchCase) {
var expression = scope.buildExpression(member.expression);
currentCase.expressions.add(expression..parent = currentCase);
currentCase.expressionOffsets.add(expression.fileOffset);
} else {
currentCase.isDefault = true;
}

View file

@ -1011,10 +1011,13 @@ class KernelVisitor extends Object
@override
ir.SwitchCase visitSwitchCase(SwitchCase node) {
List<ir.Expression> expressions = <ir.Expression>[];
List<int> expressionOffsets = <int>[];
for (var labelOrCase in node.labelsAndCases.nodes) {
CaseMatch match = labelOrCase.asCaseMatch();
if (match != null) {
expressions.add(visitForValue(match.expression));
ir.TreeNode expression = visitForValue(match.expression);
expressions.add(expression);
expressionOffsets.add(expression.fileOffset);
} else {
// Assert that labelOrCase is one of two known types: [CaseMatch] or
// [Label]. We ignore cases, as any users have been resolved to use the
@ -1025,7 +1028,8 @@ class KernelVisitor extends Object
// We ignore the node's statements here, they're generated below in
// [visitSwitchStatement] once we've set up all the jump targets.
return associateNode(
new ir.SwitchCase(expressions, null, isDefault: node.isDefaultCase),
new ir.SwitchCase(expressions, expressionOffsets, null,
isDefault: node.isDefaultCase),
node);
}

View file

@ -811,7 +811,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
debugEvent("endLiteralString");
if (interpolationCount == 0) {
Token token = pop();
push(new StringLiteral(unescapeString(token.lexeme)));
push(new StringLiteral(unescapeString(token.lexeme))
..fileOffset = token.charOffset);
} else {
List parts = popList(1 + interpolationCount * 2);
Token first = parts.first;
@ -873,7 +874,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
@override
void handleLiteralInt(Token token) {
debugEvent("LiteralInt");
push(new IntLiteral(int.parse(token.lexeme)));
push(
new IntLiteral(int.parse(token.lexeme))..fileOffset = token.charOffset);
}
@override
@ -1113,19 +1115,19 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
debugEvent("LiteralBool");
bool value = optional("true", token);
assert(value || optional("false", token));
push(new BoolLiteral(value));
push(new BoolLiteral(value)..fileOffset = token.charOffset);
}
@override
void handleLiteralDouble(Token token) {
debugEvent("LiteralDouble");
push(new DoubleLiteral(double.parse(token.lexeme)));
push(new DoubleLiteral(double.parse(token.lexeme))..fileOffset = token.charOffset);
}
@override
void handleLiteralNull(Token token) {
debugEvent("LiteralNull");
push(new NullLiteral());
push(new NullLiteral()..fileOffset = token.charOffset);
}
@override
@ -2080,8 +2082,12 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
exitLocalScope();
List<Label> labels = pop();
List<Expression> expressions = pop();
push(new SwitchCase(expressions, block, isDefault: defaultKeyword != null)
..fileOffset = firstToken.charOffset);
List<int> expressionOffsets = <int>[];
for (Expression expression in expressions) {
expressionOffsets.add(expression.fileOffset);
}
push(new SwitchCase(expressions, expressionOffsets, block,
isDefault: defaultKeyword != null)..fileOffset = firstToken.charOffset);
push(labels);
}

View file

@ -745,6 +745,7 @@ type SwitchStatement extends Statement {
type SwitchCase {
// Note: there is no tag on SwitchCase
List<Expression> expressions;
FileOffset[expressions.length] expressionOffsets; // 1-to-1 with expressions.
Byte isDefault; // 1 if default, 0 is not default.
Statement body;
}

View file

@ -3080,22 +3080,26 @@ class SwitchStatement extends Statement {
/// This is a potential target of [ContinueSwitchStatement].
class SwitchCase extends TreeNode {
final List<Expression> expressions;
final List<int> expressionOffsets;
Statement body;
bool isDefault;
SwitchCase(this.expressions, this.body, {this.isDefault: false}) {
SwitchCase(this.expressions, this.expressionOffsets, this.body,
{this.isDefault: false}) {
setParents(expressions, this);
body?.parent = this;
}
SwitchCase.defaultCase(this.body)
: isDefault = true,
expressions = <Expression>[] {
expressions = <Expression>[],
expressionOffsets = <int>[] {
body?.parent = this;
}
SwitchCase.empty()
: expressions = <Expression>[],
expressionOffsets = <int>[],
body = null,
isDefault = false;

View file

@ -910,6 +910,10 @@ class BinaryBuilder {
for (int i = 0; i < cases.length; ++i) {
var caseNode = cases[i];
_fillTreeNodeList(caseNode.expressions, readExpression, caseNode);
caseNode.expressionOffsets.length = caseNode.expressions.length;
for (int i = 0; i < caseNode.expressionOffsets.length; ++i) {
caseNode.expressionOffsets[i] = readOffset();
}
caseNode.isDefault = readByte() == 1;
caseNode.body = readStatement()..parent = caseNode;
}

View file

@ -221,7 +221,7 @@ class BinaryPrinter extends Visitor {
writeCanonicalNameReference(node.canonicalName);
}
writeOffset(TreeNode node, int offset) {
writeOffset(int offset) {
// TODO(jensj): Delta-encoding.
// File offset ranges from -1 and up,
// but is here saved as unsigned (thus the +1)
@ -305,7 +305,7 @@ class BinaryPrinter extends Visitor {
}
writeByte(Tag.Class);
writeCanonicalNameReference(getCanonicalNameOfClass(node));
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeByte(flags);
writeStringReference(node.name ?? '');
writeUriReference(node.fileUri ?? '');
@ -330,8 +330,8 @@ class BinaryPrinter extends Visitor {
_variableIndexer = new VariableIndexer();
writeByte(Tag.Constructor);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
writeOffset(node, node.fileOffset);
writeOffset(node, node.fileEndOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.flags);
writeName(node.name ?? _emptyName);
writeAnnotationList(node.annotations);
@ -351,8 +351,8 @@ class BinaryPrinter extends Visitor {
_variableIndexer = new VariableIndexer();
writeByte(Tag.Procedure);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
writeOffset(node, node.fileOffset);
writeOffset(node, node.fileEndOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.kind.index);
writeByte(node.flags);
writeName(node.name ?? '');
@ -369,8 +369,8 @@ class BinaryPrinter extends Visitor {
_variableIndexer = new VariableIndexer();
writeByte(Tag.Field);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
writeOffset(node, node.fileOffset);
writeOffset(node, node.fileEndOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.flags);
writeName(node.name);
writeUriReference(node.fileUri ?? '');
@ -417,8 +417,8 @@ class BinaryPrinter extends Visitor {
_switchCaseIndexer = new SwitchCaseIndexer();
// Note: FunctionNode has no tag.
_typeParameterIndexer.enter(node.typeParameters);
writeOffset(node, node.fileOffset);
writeOffset(node, node.fileEndOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.asyncMarker.index);
writeByte(node.dartAsyncMarker.index);
writeNodeList(node.typeParameters);
@ -445,10 +445,10 @@ class BinaryPrinter extends Visitor {
if (index & Tag.SpecializedPayloadMask == index &&
node.promotedType == null) {
writeByte(Tag.SpecializedVariableGet + index);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
} else {
writeByte(Tag.VariableGet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeUInt30(_variableIndexer[node.variable]);
writeOptionalNode(node.promotedType);
}
@ -459,11 +459,11 @@ class BinaryPrinter extends Visitor {
int index = _variableIndexer[node.variable];
if (index & Tag.SpecializedPayloadMask == index) {
writeByte(Tag.SpecializedVariableSet + index);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.value);
} else {
writeByte(Tag.VariableSet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeUInt30(_variableIndexer[node.variable]);
writeNode(node.value);
}
@ -471,7 +471,7 @@ class BinaryPrinter extends Visitor {
visitPropertyGet(PropertyGet node) {
writeByte(Tag.PropertyGet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.receiver);
writeName(node.name);
writeReference(node.interfaceTargetReference);
@ -479,7 +479,7 @@ class BinaryPrinter extends Visitor {
visitPropertySet(PropertySet node) {
writeByte(Tag.PropertySet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.receiver);
writeName(node.name);
writeNode(node.value);
@ -514,20 +514,20 @@ class BinaryPrinter extends Visitor {
visitStaticGet(StaticGet node) {
writeByte(Tag.StaticGet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeReference(node.targetReference);
}
visitStaticSet(StaticSet node) {
writeByte(Tag.StaticSet);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeReference(node.targetReference);
writeNode(node.value);
}
visitMethodInvocation(MethodInvocation node) {
writeByte(Tag.MethodInvocation);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.receiver);
writeName(node.name);
writeNode(node.arguments);
@ -536,7 +536,7 @@ class BinaryPrinter extends Visitor {
visitSuperMethodInvocation(SuperMethodInvocation node) {
writeByte(Tag.SuperMethodInvocation);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeName(node.name);
writeNode(node.arguments);
writeReference(node.interfaceTargetReference);
@ -551,7 +551,7 @@ class BinaryPrinter extends Visitor {
visitStaticInvocation(StaticInvocation node) {
writeByte(node.isConst ? Tag.ConstStaticInvocation : Tag.StaticInvocation);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeReference(node.targetReference);
writeNode(node.arguments);
}
@ -560,7 +560,7 @@ class BinaryPrinter extends Visitor {
writeByte(node.isConst
? Tag.ConstConstructorInvocation
: Tag.ConstructorInvocation);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeReference(node.targetReference);
writeNode(node.arguments);
}
@ -608,20 +608,20 @@ class BinaryPrinter extends Visitor {
visitStringConcatenation(StringConcatenation node) {
writeByte(Tag.StringConcatenation);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNodeList(node.expressions);
}
visitIsExpression(IsExpression node) {
writeByte(Tag.IsExpression);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.operand);
writeNode(node.type);
}
visitAsExpression(AsExpression node) {
writeByte(Tag.AsExpression);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.operand);
writeNode(node.type);
}
@ -682,25 +682,25 @@ class BinaryPrinter extends Visitor {
visitRethrow(Rethrow node) {
writeByte(Tag.Rethrow);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
}
visitThrow(Throw node) {
writeByte(Tag.Throw);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.expression);
}
visitListLiteral(ListLiteral node) {
writeByte(node.isConst ? Tag.ConstListLiteral : Tag.ListLiteral);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.typeArgument);
writeNodeList(node.expressions);
}
visitMapLiteral(MapLiteral node) {
writeByte(node.isConst ? Tag.ConstMapLiteral : Tag.MapLiteral);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeNode(node.keyType);
writeNode(node.valueType);
writeNodeList(node.entries);
@ -782,7 +782,7 @@ class BinaryPrinter extends Visitor {
visitBreakStatement(BreakStatement node) {
writeByte(Tag.BreakStatement);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeUInt30(_labelIndexer[node.target]);
}
@ -811,7 +811,7 @@ class BinaryPrinter extends Visitor {
visitForInStatement(ForInStatement node) {
_variableIndexer.pushScope();
writeByte(node.isAsync ? Tag.AsyncForInStatement : Tag.ForInStatement);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeVariableDeclaration(node.variable);
writeNode(node.iterable);
writeNode(node.body);
@ -829,6 +829,7 @@ class BinaryPrinter extends Visitor {
visitSwitchCase(SwitchCase node) {
// Note: there is no tag on SwitchCase.
writeNodeList(node.expressions);
node.expressionOffsets.forEach(writeOffset);
writeByte(node.isDefault ? 1 : 0);
writeNode(node.body);
}
@ -847,7 +848,7 @@ class BinaryPrinter extends Visitor {
visitReturnStatement(ReturnStatement node) {
writeByte(Tag.ReturnStatement);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeOptionalNode(node.expression);
}
@ -875,7 +876,7 @@ class BinaryPrinter extends Visitor {
visitYieldStatement(YieldStatement node) {
writeByte(Tag.YieldStatement);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeByte(node.flags);
writeNode(node.expression);
}
@ -886,8 +887,8 @@ class BinaryPrinter extends Visitor {
}
void writeVariableDeclaration(VariableDeclaration node) {
writeOffset(node, node.fileOffset);
writeOffset(node, node.fileEqualsOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEqualsOffset);
writeByte(node.flags);
writeStringReference(node.name ?? '');
writeNode(node.type);
@ -913,7 +914,7 @@ class BinaryPrinter extends Visitor {
visitFunctionDeclaration(FunctionDeclaration node) {
writeByte(Tag.FunctionDeclaration);
writeOffset(node, node.fileOffset);
writeOffset(node.fileOffset);
writeVariableDeclaration(node.variable);
writeNode(node.function);
}

View file

@ -282,8 +282,10 @@ class CloneVisitor extends TreeVisitor {
visitSwitchStatement(SwitchStatement node) {
for (SwitchCase switchCase in node.cases) {
switchCases[switchCase] =
new SwitchCase(switchCase.expressions.map(clone).toList(), null);
switchCases[switchCase] = new SwitchCase(
switchCase.expressions.map(clone).toList(),
new List<int>.from(switchCase.expressionOffsets),
null);
}
return new SwitchStatement(
clone(node.expression), node.cases.map(clone).toList());

View file

@ -1006,6 +1006,7 @@ class Expression : public TreeNode {
virtual void AcceptTreeVisitor(TreeVisitor* visitor);
virtual void AcceptExpressionVisitor(ExpressionVisitor* visitor) = 0;
TokenPosition position() { return position_; }
void set_position(TokenPosition position) { position_ = position; }
protected:
Expression() : position_(TokenPosition::kNoSource) {}

View file

@ -1599,6 +1599,9 @@ SwitchStatement* SwitchStatement::ReadFrom(Reader* reader) {
SwitchCase* SwitchCase::ReadFrom(Reader* reader) {
TRACE_READ_OFFSET();
expressions_.ReadFromStatic<Expression>(reader);
for (intptr_t i = 0; i < expressions_.length(); ++i) {
expressions_[i]->set_position(reader->ReadPosition());
}
is_default_ = reader->ReadBool();
body_ = Statement::ReadFrom(reader);
return this;

View file

@ -5810,13 +5810,14 @@ void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) {
TargetEntryInstr* then;
TargetEntryInstr* otherwise;
current_instructions += Constant(constant_evaluator_.EvaluateExpression(
switch_case->expressions()[j]));
Expression* expression = switch_case->expressions()[j];
current_instructions +=
Constant(constant_evaluator_.EvaluateExpression(expression));
current_instructions += PushArgument();
current_instructions += LoadLocal(scopes_->switch_variable);
current_instructions += PushArgument();
current_instructions += InstanceCall(
TokenPosition::kNoSource, Symbols::EqualOperator(), Token::kEQ,
expression->position(), Symbols::EqualOperator(), Token::kEQ,
/*argument_count=*/2,
/*num_args_checked=*/2);
current_instructions += BranchIfTrue(&then, &otherwise);