OLD | NEW |
1 library dart2js.cps_ir_integrity; | 1 library dart2js.cps_ir_integrity; |
2 | 2 |
3 import 'cps_ir_nodes.dart'; | 3 import 'cps_ir_nodes.dart'; |
4 import 'cps_ir_nodes_sexpr.dart'; | 4 import 'cps_ir_nodes_sexpr.dart'; |
5 import '../tracer.dart' as tracer; | 5 import '../tracer.dart' as tracer; |
6 | 6 |
7 /// Dump S-expressions on error if the tracer is enabled. | 7 /// Dump S-expressions on error if the tracer is enabled. |
8 /// | 8 /// |
9 /// Technically this has nothing to do with the tracer, but if you want one | 9 /// Technically this has nothing to do with the tracer, but if you want one |
10 /// enabled, you typically want the other as well, so we use the same flag. | 10 /// enabled, you typically want the other as well, so we use the same flag. |
11 const bool ENABLE_DUMP = tracer.TRACE_FILTER_PATTERN != null; | 11 const bool ENABLE_DUMP = tracer.TRACE_FILTER_PATTERN != null; |
12 | 12 |
13 enum ScopeType { InScope, InDefinition, NotInScope } | 13 enum ScopeType { InScope, InDefinition, NotInScope } |
14 | 14 |
15 /// Performs integrity checks on the CPS IR. | 15 /// Performs integrity checks on the CPS IR. |
16 /// | 16 /// |
17 /// To be run for debugging purposes, not for use in production. | 17 /// To be run for debugging purposes, not for use in production. |
18 /// | 18 /// |
19 /// The following integrity checks are performed: | 19 /// The following integrity checks are performed: |
20 /// | 20 /// |
21 /// - References are in scope of their definitions. | 21 /// - References are in scope of their definitions. |
22 /// - Recursive Continuations and InvokeContinuations are marked as recursive. | 22 /// - Recursive Continuations and InvokeContinuations are marked as recursive. |
23 /// - InvokeContinuations have the same arity as their target. | 23 /// - InvokeContinuations have the same arity as their target. |
24 /// - Reference chains are valid doubly-linked lists. | 24 /// - Reference chains are valid doubly-linked lists. |
25 /// - Reference chains contain exactly the references that are in the IR. | 25 /// - Reference chains contain exactly the references that are in the IR. |
26 /// - Each definition object occurs only once in the IR (no redeclaring). | 26 /// - Each definition object occurs only once in the IR (no redeclaring). |
27 /// - Each reference object occurs only once in the IR (no sharing). | 27 /// - Each reference object occurs only once in the IR (no sharing). |
28 /// | 28 /// |
29 class CheckCpsIntegrity extends TrampolineRecursiveVisitor { | 29 class CheckCpsIntegrity extends TrampolineRecursiveVisitor { |
30 | |
31 FunctionDefinition topLevelNode; | 30 FunctionDefinition topLevelNode; |
32 final Map<Definition, ScopeType> inScope = <Definition, ScopeType>{}; | 31 final Map<Definition, ScopeType> inScope = <Definition, ScopeType>{}; |
33 final List<Definition> definitions = []; | 32 final List<Definition> definitions = []; |
34 String previousPass; | 33 String previousPass; |
35 | 34 |
36 void handleDeclaration(Definition def) { | 35 void handleDeclaration(Definition def) { |
37 definitions.add(def); | 36 definitions.add(def); |
38 // Check the reference chain for cycles broken links. | 37 // Check the reference chain for cycles broken links. |
39 Reference anchor = null; | 38 Reference anchor = null; |
40 int i = 0; | 39 int i = 0; |
41 for (Reference ref = def.firstRef; ref != null; ref = ref.next) { | 40 for (Reference ref = def.firstRef; ref != null; ref = ref.next) { |
42 if (ref.definition != def) { | 41 if (ref.definition != def) { |
43 error('Reference to ${ref.definition} found in ' | 42 error( |
44 'reference chain for $def', def); | 43 'Reference to ${ref.definition} found in ' |
| 44 'reference chain for $def', |
| 45 def); |
45 } | 46 } |
46 if (ref == anchor) { | 47 if (ref == anchor) { |
47 error('Cyclic reference chain for $def', def); | 48 error('Cyclic reference chain for $def', def); |
48 } | 49 } |
49 if (i & ++i == 0) { // Move the anchor every 2^Nth step. | 50 if (i & ++i == 0) { |
| 51 // Move the anchor every 2^Nth step. |
50 anchor = ref; | 52 anchor = ref; |
51 } | 53 } |
52 } | 54 } |
53 } | 55 } |
54 | 56 |
55 void enterScope(Iterable<Definition> definitions) { | 57 void enterScope(Iterable<Definition> definitions) { |
56 for (Definition def in definitions) { | 58 for (Definition def in definitions) { |
57 inScope[def] = ScopeType.InScope; | 59 inScope[def] = ScopeType.InScope; |
58 } | 60 } |
59 pushAction(() { | 61 pushAction(() { |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 Decorator decorator = (n, String s) => n == node ? '**$s**' : s; | 220 Decorator decorator = (n, String s) => n == node ? '**$s**' : s; |
219 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode); | 221 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode); |
220 sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr'; | 222 sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr'; |
221 } catch (e) { | 223 } catch (e) { |
222 sexpr = '(Exception thrown by SExpressionStringifier: $e)'; | 224 sexpr = '(Exception thrown by SExpressionStringifier: $e)'; |
223 } | 225 } |
224 } else { | 226 } else { |
225 sexpr = '(Set DUMP_IR flag to enable SExpr dump)'; | 227 sexpr = '(Set DUMP_IR flag to enable SExpr dump)'; |
226 } | 228 } |
227 throw 'CPS integrity violation\n' | 229 throw 'CPS integrity violation\n' |
228 'After \'$previousPass\' on ${topLevelNode.element}\n' | 230 'After \'$previousPass\' on ${topLevelNode.element}\n' |
229 '$message\n\n' | 231 '$message\n\n' |
230 '$sexpr\n'; | 232 '$sexpr\n'; |
231 } | 233 } |
232 } | 234 } |
233 | 235 |
234 /// Traverses the CPS term and checks that node.parent is correctly set | 236 /// Traverses the CPS term and checks that node.parent is correctly set |
235 /// for each visited node. | 237 /// for each visited node. |
236 class ParentChecker extends DeepRecursiveVisitor { | 238 class ParentChecker extends DeepRecursiveVisitor { |
237 static void checkParents(Node node, CheckCpsIntegrity main) { | 239 static void checkParents(Node node, CheckCpsIntegrity main) { |
238 ParentChecker visitor = new ParentChecker._make(main); | 240 ParentChecker visitor = new ParentChecker._make(main); |
239 visitor._worklist.add(node); | 241 visitor._worklist.add(node); |
240 visitor.trampoline(); | 242 visitor.trampoline(); |
(...skipping 12 matching lines...) Expand all Loading... |
253 } | 255 } |
254 } | 256 } |
255 | 257 |
256 error(String message, node) => main.error(message, node); | 258 error(String message, node) => main.error(message, node); |
257 | 259 |
258 @override | 260 @override |
259 visit(Node node) { | 261 visit(Node node) { |
260 _worklist.add(node); | 262 _worklist.add(node); |
261 if (node.parent != _parent) { | 263 if (node.parent != _parent) { |
262 error('Parent pointer on $node is ${node.parent} but should be $_parent', | 264 error('Parent pointer on $node is ${node.parent} but should be $_parent', |
263 node); | 265 node); |
264 } | 266 } |
265 } | 267 } |
266 | 268 |
267 @override | 269 @override |
268 processReference(Reference node) { | 270 processReference(Reference node) { |
269 if (node.parent != _parent) { | 271 if (node.parent != _parent) { |
270 error('Parent pointer on $node is ${node.parent} but should be $_parent', | 272 error('Parent pointer on $node is ${node.parent} but should be $_parent', |
271 node); | 273 node); |
272 } | 274 } |
273 } | 275 } |
274 } | 276 } |
OLD | NEW |