| 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 RecursiveVisitor { | 27 class CheckCpsIntegrity extends RecursiveVisitor { |
| 28 | 28 |
| 29 ExecutableDefinition topLevelNode; | 29 RootNode topLevelNode; |
| 30 | 30 |
| 31 Set<Definition> seenDefinitions = new Set<Definition>(); | 31 Set<Definition> seenDefinitions = new Set<Definition>(); |
| 32 Map<Definition, Set<Reference>> seenReferences = | 32 Map<Definition, Set<Reference>> seenReferences = |
| 33 <Definition, Set<Reference>>{}; | 33 <Definition, Set<Reference>>{}; |
| 34 | 34 |
| 35 Map<Definition, Node> bindings = <Definition, Node>{}; | 35 Map<Definition, Node> bindings = <Definition, Node>{}; |
| 36 Set<Continuation> insideContinuations = new Set<Continuation>(); | 36 Set<Continuation> insideContinuations = new Set<Continuation>(); |
| 37 | 37 |
| 38 doInScope(Iterable<Definition> defs, Node binding, action()) { | 38 doInScope(Iterable<Definition> defs, Node binding, action()) { |
| 39 for (Definition def in defs) { | 39 for (Definition def in defs) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 if (node.isReturnContinuation) { | 71 if (node.isReturnContinuation) { |
| 72 error('Non-return continuation missing body', node); | 72 error('Non-return continuation missing body', node); |
| 73 } | 73 } |
| 74 node.parameters.forEach(markAsSeen); | 74 node.parameters.forEach(markAsSeen); |
| 75 insideContinuations.add(node); | 75 insideContinuations.add(node); |
| 76 doInScope(node.parameters, node, () => visit(node.body)); | 76 doInScope(node.parameters, node, () => visit(node.body)); |
| 77 insideContinuations.remove(node); | 77 insideContinuations.remove(node); |
| 78 } | 78 } |
| 79 | 79 |
| 80 @override | 80 @override |
| 81 visitRunnableBody(RunnableBody node) { | 81 visitBody(Body node) { |
| 82 markAsSeen(node.returnContinuation); | 82 markAsSeen(node.returnContinuation); |
| 83 if (!node.returnContinuation.isReturnContinuation) { | 83 if (!node.returnContinuation.isReturnContinuation) { |
| 84 error('Return continuation with a body', node); | 84 error('Return continuation with a body', node); |
| 85 } | 85 } |
| 86 doInScope([node.returnContinuation], node, () => visit(node.body)); | 86 doInScope([node.returnContinuation], node, () => visit(node.body)); |
| 87 } | 87 } |
| 88 | 88 |
| 89 @override | 89 @override |
| 90 visitLetPrim(LetPrim node) { | 90 visitLetPrim(LetPrim node) { |
| 91 markAsSeen(node.primitive); | 91 markAsSeen(node.primitive); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 } | 202 } |
| 203 } else { | 203 } else { |
| 204 sexpr = '(Set DUMP_IR flag to enable)'; | 204 sexpr = '(Set DUMP_IR flag to enable)'; |
| 205 } | 205 } |
| 206 throw 'CPS integrity violation in ${topLevelNode.element}:\n' | 206 throw 'CPS integrity violation in ${topLevelNode.element}:\n' |
| 207 '$message\n\n' | 207 '$message\n\n' |
| 208 'SExpr dump (offending node marked with **):\n\n' | 208 'SExpr dump (offending node marked with **):\n\n' |
| 209 '$sexpr\n'; | 209 '$sexpr\n'; |
| 210 } | 210 } |
| 211 | 211 |
| 212 void check(ExecutableDefinition node) { | 212 void check(RootNode node) { |
| 213 topLevelNode = node; | 213 topLevelNode = node; |
| 214 visit(node); | 214 visit(node); |
| 215 | 215 |
| 216 // Check this last, so out-of-scope references are not classified as | 216 // Check this last, so out-of-scope references are not classified as |
| 217 // a broken reference chain. | 217 // a broken reference chain. |
| 218 seenDefinitions.forEach(checkReferenceChain); | 218 seenDefinitions.forEach(checkReferenceChain); |
| 219 } | 219 } |
| 220 | 220 |
| 221 } | 221 } |
| OLD | NEW |