mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 15:21:31 +00:00
[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:
parent
4d208e2ffb
commit
a1a34a1c84
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue