Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart

Issue 981523002: Integrity checker for CPS and Tree IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Stronger checks on Tree IR and update status file Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 library tree_ir.integrity;
2
3 import 'tree_ir_nodes.dart';
4
5 /// Performs integrity checks on the tree_ir.
6 ///
7 /// Should only be run for debugging purposes, not in production.
8 ///
9 /// - Reference counts on must match the actual number of references.
10 /// - Labels must be in scope when referenced.
11 /// - Breaks must target a [LabeledStatement].
12 /// - Continues must target a [Loop].
13 /// - Variables must only be used after their first assignment
14 /// (checked on a best-effort basis).
15 /// - Variables with a declaration must only be referenced in scope.
16 /// - Variables must not have more than one declaration.
17 ///
18 class CheckTreeIntegrity extends RecursiveVisitor {
19 ExecutableDefinition topLevelNode;
20
21 Map<Variable, int> varReads = <Variable, int>{};
22 Map<Variable, int> varWrites = <Variable, int>{};
23 Map<Label, int> labelUses = <Label, int>{};
24 Map<Label, JumpTarget> label2declaration = <Label, JumpTarget>{};
25
26 /// Variables that are currently in scope.
27 Set<Variable> scope = new Set<Variable>();
28
29 /// Variables for which we have seen a declaration.
30 Set<Variable> seenDeclaration = new Set<Variable>();
31
32 void write(Variable variable) {
33 if (!seenDeclaration.contains(variable)) {
34 // Implicitly-declared variables are in scope after the first assignment.
35 scope.add(variable);
36 } else if (!scope.contains(variable)) {
37 // There is a declaration for variable but it is no longer in scope.
38 error('$variable assigned out of scope');
39 }
40 varWrites.putIfAbsent(variable, () => 0);
41 varWrites[variable]++;
42 }
43
44 void read(Variable variable) {
45 if (!scope.contains(variable)) {
46 error('$variable used out of scope');
47 }
48 varReads.putIfAbsent(variable, () => 0);
49 varReads[variable]++;
50 }
51
52 void declare(Variable variable) {
53 if (!scope.add(variable) || !seenDeclaration.add(variable)) {
54 error('Redeclared $variable');
55 }
56 varWrites.putIfAbsent(variable, () => 0);
57 varWrites[variable]++;
58 }
59
60 void undeclare(Variable variable) {
61 scope.remove(variable);
62 }
63
64 visitVariableUse(VariableUse node) {
65 read(node.variable);
66 }
67
68 visitAssign(Assign node) {
69 visitExpression(node.definition);
70 if (node.isDeclaration) {
71 declare(node.variable);
72 } else {
73 write(node.variable);
74 }
75 visitStatement(node.next);
76 if (node.isDeclaration) {
77 undeclare(node.variable);
78 }
79 }
80
81 visitTry(Try node) {
82 visitStatement(node.tryBody);
83 node.catchParameters.forEach(declare);
84 visitStatement(node.catchBody);
85 node.catchParameters.forEach(undeclare);
86 }
87
88 visitFunctionDefinition(FunctionDefinition node) {
89 node.parameters.forEach(declare);
90 if (node.body != null) visitStatement(node.body);
91 node.parameters.forEach(undeclare);
92 }
93
94 visitConstructorDefinition(ConstructorDefinition node) {
95 node.parameters.forEach(declare);
96 if (node.initializers != null) node.initializers.forEach(visitInitializer);
97 if (node.body != null) visitStatement(node.body);
98 node.parameters.forEach(undeclare);
99 }
100
101 visitFunctionDeclaration(FunctionDeclaration node) {
102 declare(node.variable);
103 visitFunctionDefinition(node.definition);
104 visitStatement(node.next);
105 undeclare(node.variable);
106 if (varWrites[node.variable] > 1) {
107 error('Assignment to function declaration ${node.variable}');
108 }
109 }
110
111 visitJumpTargetBody(JumpTarget target) {
112 Label label = target.label;
113 if (label2declaration.containsKey(label)) {
114 error('Duplicate declaration of label $label');
115 }
116 label2declaration[label] = target;
117 labelUses[label] = 0;
118 visitStatement(target.body);
119 label2declaration.remove(target);
120
121 if (labelUses[label] != label.useCount) {
122 error('Label $label has ${labelUses[label]} uses '
123 'but its reference count is ${label.useCount}');
124 }
125 }
126
127 visitLabeledStatement(LabeledStatement node) {
128 visitJumpTargetBody(node);
129 visitStatement(node.next);
130 }
131
132 visitWhileTrue(WhileTrue node) {
133 visitJumpTargetBody(node);
134 }
135
136 visitWhileCondition(WhileCondition node) {
137 visitExpression(node.condition);
138 visitJumpTargetBody(node);
139 visitStatement(node.next);
140 }
141
142 visitBreak(Break node) {
143 if (!label2declaration.containsKey(node.target)) {
144 error('Break to label that is not in scope');
145 }
146 if (label2declaration[node.target] is! LabeledStatement) {
147 error('Break to non-labeled statement ${label2declaration[node.target]}');
148 }
149 labelUses[node.target]++;
150 }
151
152 visitContinue(Continue node) {
153 if (!label2declaration.containsKey(node.target)) {
154 error('Continue to label that is not in scope');
155 }
156 if (label2declaration[node.target] is! Loop) {
157 error('Continue to non-loop statement ${label2declaration[node.target]}');
158 }
159 labelUses[node.target]++;
160 }
161
162 dynamic error(String message) {
163 throw 'Tree IR integrity violation in ${topLevelNode.element}:\n$message';
164 }
165
166 void check(ExecutableDefinition node) {
167 topLevelNode = node;
168 visitExecutableDefinition(node);
169
170 // Verify reference counters for all variables.
171 List<Variable> seenVariables = new List<Variable>();
172 seenVariables.addAll(varReads.keys);
173 seenVariables.addAll(varWrites.keys);
174 for (Variable variable in seenVariables) {
175 int reads = varReads.putIfAbsent(variable, () => 0);
176 int writes = varWrites.putIfAbsent(variable, () => 0);
177 if (reads != variable.readCount || writes != variable.writeCount) {
178 error('Invalid reference count for $variable:\n'
179 '- Variable has $reads reads and $writes writes\n'
180 '- Reference count is ${variable.readCount} reads and '
181 '${variable.writeCount} writes');
182 }
183 }
184 }
185
186 }
187
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698