| 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 /// Performs integrity checks on the CPS IR. | 13 /// Performs integrity checks on the CPS IR. |
| 14 /// | 14 /// |
| 15 /// To be run for debugging purposes, not for use in production. | 15 /// To be run for debugging purposes, not for use in production. |
| 16 /// | 16 /// |
| 17 /// The following integrity checks are performed: | 17 /// The following integrity checks are performed: |
| 18 /// | 18 /// |
| 19 /// - References are in scope of their definitions. | 19 /// - References are in scope of their definitions. |
| 20 /// - Recursive Continuations and InvokeContinuations are marked as recursive. | 20 /// - Recursive Continuations and InvokeContinuations are marked as recursive. |
| 21 /// - InvokeContinuations have the same arity as their target. | 21 /// - InvokeContinuations have the same arity as their target. |
| 22 /// - Reference chains are valid doubly-linked lists. | 22 /// - Reference chains are valid doubly-linked lists. |
| 23 /// - Reference chains contain exactly the references that are in the IR. | 23 /// - Reference chains contain exactly the references that are in the IR. |
| 24 /// - Each definition object occurs only once in the IR (no redeclaring). | 24 /// - Each definition object occurs only once in the IR (no redeclaring). |
| 25 /// - Each reference object occurs only once in the IR (no sharing). | 25 /// - Each reference object occurs only once in the IR (no sharing). |
| 26 /// | 26 /// |
| 27 class CheckCpsIntegrity extends TrampolineRecursiveVisitor { | 27 class CheckCpsIntegrity extends RecursiveVisitor { |
| 28 | 28 |
| 29 FunctionDefinition topLevelNode; | 29 FunctionDefinition topLevelNode; |
| 30 String previousPass; | |
| 31 | 30 |
| 32 Set<Definition> seenDefinitions = new Set<Definition>(); | 31 Set<Definition> seenDefinitions = new Set<Definition>(); |
| 33 Map<Definition, Set<Reference>> seenReferences = | 32 Map<Definition, Set<Reference>> seenReferences = |
| 34 <Definition, Set<Reference>>{}; | 33 <Definition, Set<Reference>>{}; |
| 35 | 34 |
| 36 Set<Definition> inScope = new Set<Definition>(); | 35 Set<Definition> inScope = new Set<Definition>(); |
| 37 Set<Continuation> insideContinuations = new Set<Continuation>(); | 36 Set<Continuation> insideContinuations = new Set<Continuation>(); |
| 38 | 37 |
| 39 void markAsSeen(Definition def) { | 38 void markAsSeen(Definition def) { |
| 40 if (!seenDefinitions.add(def)) { | 39 if (!seenDefinitions.add(def)) { |
| 41 error('Redeclared $def', def); | 40 error('Redeclared $def', def); |
| 42 } | 41 } |
| 43 seenReferences[def] = new Set<Reference>(); | 42 seenReferences[def] = new Set<Reference>(); |
| 44 } | 43 } |
| 45 | 44 |
| 46 void enterScope(Iterable<Definition> definitions) { | 45 void enterScope(Iterable<Definition> definitions) { |
| 47 inScope.addAll(definitions); | 46 inScope.addAll(definitions); |
| 48 pushAction(() => inScope.removeAll(definitions)); | 47 pushAction(() => inScope.removeAll(definitions)); |
| 49 } | 48 } |
| 50 | 49 |
| 51 void enterContinuation(Continuation cont) { | 50 void enterContinuation(Continuation cont) { |
| 52 insideContinuations.add(cont); | 51 insideContinuations.add(cont); |
| 53 pushAction(() => insideContinuations.remove(cont)); | 52 pushAction(() => insideContinuations.remove(cont)); |
| 54 } | 53 } |
| 55 | 54 |
| 56 void check(FunctionDefinition node, String previousPass) { | 55 void check(FunctionDefinition node) { |
| 57 topLevelNode = node; | 56 topLevelNode = node; |
| 58 this.previousPass = previousPass; | |
| 59 ParentChecker.checkParents(node, this); | |
| 60 visit(node); | 57 visit(node); |
| 61 // Check for broken reference chains. We check this last, so out-of-scope | 58 // Check for broken reference chains. We check this last, so out-of-scope |
| 62 // references are not classified as a broken reference chain. | 59 // references are not classified as a broken reference chain. |
| 63 seenDefinitions.forEach(checkReferenceChain); | 60 seenDefinitions.forEach(checkReferenceChain); |
| 64 } | 61 } |
| 65 | 62 |
| 66 @override | 63 @override |
| 67 Expression traverseLetCont(LetCont node) { | 64 Expression traverseLetCont(LetCont node) { |
| 68 node.continuations.forEach(markAsSeen); | 65 node.continuations.forEach(markAsSeen); |
| 69 node.continuations.forEach(push); | 66 node.continuations.forEach(push); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 error('Reference chain for $def contains orphaned references', def); | 174 error('Reference chain for $def contains orphaned references', def); |
| 178 } | 175 } |
| 179 } | 176 } |
| 180 | 177 |
| 181 error(String message, node) { | 178 error(String message, node) { |
| 182 String sexpr; | 179 String sexpr; |
| 183 if (ENABLE_DUMP) { | 180 if (ENABLE_DUMP) { |
| 184 try { | 181 try { |
| 185 Decorator decorator = (n, String s) => n == node ? '**$s**' : s; | 182 Decorator decorator = (n, String s) => n == node ? '**$s**' : s; |
| 186 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode); | 183 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode); |
| 187 sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr'; | |
| 188 } catch (e) { | 184 } catch (e) { |
| 189 sexpr = '(Exception thrown by SExpressionStringifier: $e)'; | 185 sexpr = '(Exception thrown by SExpressionStringifier: $e)'; |
| 190 } | 186 } |
| 191 } else { | 187 } else { |
| 192 sexpr = '(Set DUMP_IR flag to enable SExpr dump)'; | 188 sexpr = '(Set DUMP_IR flag to enable)'; |
| 193 } | 189 } |
| 194 throw 'CPS integrity violation\n' | 190 throw 'CPS integrity violation in ${topLevelNode.element}:\n' |
| 195 'After $previousPass on ${topLevelNode.element}\n' | |
| 196 '$message\n\n' | 191 '$message\n\n' |
| 192 'SExpr dump (offending node marked with **):\n\n' |
| 197 '$sexpr\n'; | 193 '$sexpr\n'; |
| 198 } | 194 } |
| 195 |
| 199 } | 196 } |
| 200 | |
| 201 /// Traverses the CPS term and checks that node.parent is correctly set | |
| 202 /// for each visited node. | |
| 203 class ParentChecker extends DeepRecursiveVisitor { | |
| 204 static void checkParents(Node node, CheckCpsIntegrity main) { | |
| 205 ParentChecker visitor = new ParentChecker._make(main); | |
| 206 visitor._worklist.add(node); | |
| 207 visitor.trampoline(); | |
| 208 } | |
| 209 | |
| 210 ParentChecker._make(this.main); | |
| 211 | |
| 212 Node _parent; | |
| 213 final List<Node> _worklist = <Node>[]; | |
| 214 final CheckCpsIntegrity main; | |
| 215 | |
| 216 void trampoline() { | |
| 217 while (_worklist.isNotEmpty) { | |
| 218 _parent = _worklist.removeLast(); | |
| 219 _parent.accept(this); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 error(String message, node) => main.error(message, node); | |
| 224 | |
| 225 @override | |
| 226 visit(Node node) { | |
| 227 _worklist.add(node); | |
| 228 if (node.parent != _parent) { | |
| 229 error('Parent pointer on $node is ${node.parent} but should be $_parent', | |
| 230 node); | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 @override | |
| 235 processReference(Reference node) { | |
| 236 if (node.parent != _parent) { | |
| 237 error('Parent pointer on $node is ${node.parent} but should be $_parent', | |
| 238 node); | |
| 239 } | |
| 240 } | |
| 241 } | |
| OLD | NEW |