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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart

Issue 1409483002: dart2js cps: Speed up CPS IR integrity checker. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/insert_refinements.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 }
14
13 /// Performs integrity checks on the CPS IR. 15 /// Performs integrity checks on the CPS IR.
14 /// 16 ///
15 /// To be run for debugging purposes, not for use in production. 17 /// To be run for debugging purposes, not for use in production.
16 /// 18 ///
17 /// The following integrity checks are performed: 19 /// The following integrity checks are performed:
18 /// 20 ///
19 /// - References are in scope of their definitions. 21 /// - References are in scope of their definitions.
20 /// - Recursive Continuations and InvokeContinuations are marked as recursive. 22 /// - Recursive Continuations and InvokeContinuations are marked as recursive.
21 /// - InvokeContinuations have the same arity as their target. 23 /// - InvokeContinuations have the same arity as their target.
22 /// - Reference chains are valid doubly-linked lists. 24 /// - Reference chains are valid doubly-linked lists.
23 /// - Reference chains contain exactly the references that are in the IR. 25 /// - Reference chains contain exactly the references that are in the IR.
24 /// - Each definition object occurs only once in the IR (no redeclaring). 26 /// - Each definition object occurs only once in the IR (no redeclaring).
25 /// - Each reference object occurs only once in the IR (no sharing). 27 /// - Each reference object occurs only once in the IR (no sharing).
26 /// 28 ///
27 class CheckCpsIntegrity extends TrampolineRecursiveVisitor { 29 class CheckCpsIntegrity extends TrampolineRecursiveVisitor {
28 30
29 FunctionDefinition topLevelNode; 31 FunctionDefinition topLevelNode;
32 final Map<Definition, ScopeType> inScope = <Definition, ScopeType>{};
33 final List<Definition> definitions = [];
30 String previousPass; 34 String previousPass;
31 35
32 Set<Definition> seenDefinitions = new Set<Definition>(); 36 void setScope(Iterable<Definition> defs, ScopeType scope) {
33 Map<Definition, Set<Reference>> seenReferences = 37 for (Definition def in defs) {
34 <Definition, Set<Reference>>{}; 38 inScope[def] = scope;
39 }
40 }
35 41
36 Set<Definition> inScope = new Set<Definition>(); 42 void handleDeclaration(Definition def) {
37 Set<Continuation> insideContinuations = new Set<Continuation>(); 43 definitions.add(def);
38 44 // Check the reference chain for cycles broken links.
39 void markAsSeen(Definition def) { 45 Reference anchor = null;
40 if (!seenDefinitions.add(def)) { 46 int i = 0;
41 error('Redeclared $def', def); 47 for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
48 if (ref.definition != def) {
49 error('Reference to ${ref.definition} found in '
50 'reference chain for $def', def);
51 }
52 if (ref == anchor) {
53 error('Cyclic reference chain for $def', def);
54 }
55 if (i & ++i == 0) { // Move the anchor every 2^Nth step.
56 anchor = ref;
57 }
42 } 58 }
43 seenReferences[def] = new Set<Reference>();
44 } 59 }
45 60
46 void enterScope(Iterable<Definition> definitions) { 61 void enterScope(Iterable<Definition> definitions) {
47 inScope.addAll(definitions); 62 for (Definition def in definitions) {
48 pushAction(() => inScope.removeAll(definitions)); 63 inScope[def] = ScopeType.InScope;
64 }
65 pushAction(() {
66 for (Definition def in definitions) {
67 inScope[def] = ScopeType.NotInScope;
68 }
69 });
49 } 70 }
50 71
51 void enterContinuation(Continuation cont) { 72 void enterContinuation(Continuation cont) {
52 insideContinuations.add(cont); 73 inScope[cont] = ScopeType.InDefinition;
53 pushAction(() => insideContinuations.remove(cont)); 74 pushAction(() {
75 inScope[cont] = ScopeType.NotInScope;
76 });
54 } 77 }
55 78
56 void check(FunctionDefinition node, String previousPass) { 79 void check(FunctionDefinition node, String previousPass) {
57 topLevelNode = node; 80 topLevelNode = node;
58 this.previousPass = previousPass; 81 this.previousPass = previousPass;
59 ParentChecker.checkParents(node, this); 82 ParentChecker.checkParents(node, this);
60 visit(node); 83 visit(node);
61 // Check for broken reference chains. We check this last, so out-of-scope 84 // Check for broken reference chains. We check this last, so out-of-scope
62 // references are not classified as a broken reference chain. 85 // references are not classified as a broken reference chain.
63 seenDefinitions.forEach(checkReferenceChain); 86 definitions.forEach(checkReferenceChain);
64 } 87 }
65 88
66 @override 89 @override
67 Expression traverseLetCont(LetCont node) { 90 Expression traverseLetCont(LetCont node) {
68 node.continuations.forEach(markAsSeen); 91 node.continuations.forEach(handleDeclaration);
69 node.continuations.forEach(push); 92 node.continuations.forEach(push);
70 93
71 // Put all continuations in scope when visiting the body. 94 // Put all continuations in scope when visiting the body.
72 enterScope(node.continuations); 95 enterScope(node.continuations);
73 96
74 return node.body; 97 return node.body;
75 } 98 }
76 99
77 @override 100 @override
78 Expression traverseLetPrim(LetPrim node) { 101 Expression traverseLetPrim(LetPrim node) {
79 markAsSeen(node.primitive); 102 handleDeclaration(node.primitive);
80 103
81 // Process references in the primitive. 104 // Process references in the primitive.
82 visit(node.primitive); 105 visit(node.primitive);
83 106
84 // Put the primitive in scope when visiting the body. 107 // Put the primitive in scope when visiting the body.
85 enterScope([node.primitive]); 108 enterScope([node.primitive]);
86 109
87 return node.body; 110 return node.body;
88 } 111 }
89 112
90 @override 113 @override
91 Expression traverseLetMutable(LetMutable node) { 114 Expression traverseLetMutable(LetMutable node) {
92 markAsSeen(node.variable); 115 handleDeclaration(node.variable);
93 processReference(node.value); 116 processReference(node.value);
94 117
95 // Put the primitive in scope when visiting the body. 118 // Put the primitive in scope when visiting the body.
96 enterScope([node.variable]); 119 enterScope([node.variable]);
97 120
98 return node.body; 121 return node.body;
99 } 122 }
100 123
101 @override 124 @override
102 Expression traverseContinuation(Continuation cont) { 125 Expression traverseContinuation(Continuation cont) {
103 if (cont.isReturnContinuation) { 126 if (cont.isReturnContinuation) {
104 error('Non-return continuation missing body', cont); 127 error('Non-return continuation missing body', cont);
105 } 128 }
106 cont.parameters.forEach(markAsSeen); 129 cont.parameters.forEach(handleDeclaration);
107 enterScope(cont.parameters); 130 enterScope(cont.parameters);
108 // Put every continuation in scope at its own body. The isRecursive 131 // Put every continuation in scope at its own body. The isRecursive
109 // flag is checked explicitly using [insideContinuations]. 132 // flag is checked explicitly using [insideContinuations].
110 enterScope([cont]); 133 enterScope([cont]);
111 enterContinuation(cont); 134 enterContinuation(cont);
112 return cont.body; 135 return cont.body;
113 } 136 }
114 137
115 @override 138 @override
116 visitFunctionDefinition(FunctionDefinition node) { 139 visitFunctionDefinition(FunctionDefinition node) {
117 if (node.thisParameter != null) { 140 if (node.thisParameter != null) {
118 markAsSeen(node.thisParameter); 141 handleDeclaration(node.thisParameter);
119 enterScope([node.thisParameter]); 142 enterScope([node.thisParameter]);
120 } 143 }
121 node.parameters.forEach(markAsSeen); 144 node.parameters.forEach(handleDeclaration);
122 enterScope(node.parameters); 145 enterScope(node.parameters);
123 markAsSeen(node.returnContinuation); 146 handleDeclaration(node.returnContinuation);
124 enterScope([node.returnContinuation]); 147 enterScope([node.returnContinuation]);
125 if (!node.returnContinuation.isReturnContinuation) { 148 if (!node.returnContinuation.isReturnContinuation) {
126 error('Return continuation with a body', node); 149 error('Return continuation with a body', node);
127 } 150 }
128 visit(node.body); 151 visit(node.body);
129 } 152 }
130 153
131 @override 154 @override
132 processReference(Reference reference) { 155 processReference(Reference ref) {
133 if (!inScope.contains(reference.definition)) { 156 Definition def = ref.definition;
134 error('Referenced out of scope: ${reference.definition}', reference); 157 if (inScope[def] == ScopeType.NotInScope) {
158 error('Referenced out of scope: $def', ref);
135 } 159 }
136 if (!seenReferences[reference.definition].add(reference)) { 160 if (ref.previous == null && def.firstRef != ref ||
137 error('Duplicate use of Reference to ${reference.definition}', reference); 161 ref.previous != null && ref.previous.next != ref) {
162 error('Broken .previous link in reference to $def', def);
138 } 163 }
164 ref.previous = ref; // Mark reference as "seen". We will repair it later.
139 } 165 }
140 166
141 @override 167 @override
142 processInvokeContinuation(InvokeContinuation node) { 168 processInvokeContinuation(InvokeContinuation node) {
143 Continuation target = node.continuation.definition; 169 Continuation target = node.continuation.definition;
144 if (node.isRecursive && !insideContinuations.contains(target)) { 170 if (node.isRecursive && inScope[target] == ScopeType.InScope) {
145 error('Non-recursive InvokeContinuation marked as recursive', node); 171 error('Non-recursive InvokeContinuation marked as recursive', node);
146 } 172 }
147 if (!node.isRecursive && insideContinuations.contains(target)) { 173 if (!node.isRecursive && inScope[target] == ScopeType.InDefinition) {
148 error('Recursive InvokeContinuation marked as non-recursive', node); 174 error('Recursive InvokeContinuation marked as non-recursive', node);
149 } 175 }
150 if (node.isRecursive && !target.isRecursive) { 176 if (node.isRecursive && !target.isRecursive) {
151 error('Recursive Continuation was not marked as recursive', node); 177 error('Recursive Continuation was not marked as recursive', node);
152 } 178 }
153 if (node.arguments.length != target.parameters.length) { 179 if (node.arguments.length != target.parameters.length) {
154 error('Arity mismatch in InvokeContinuation', node); 180 error('Arity mismatch in InvokeContinuation', node);
155 } 181 }
156 } 182 }
157 183
158 void checkReferenceChain(Definition def) { 184 void checkReferenceChain(Definition def) {
159 Set<Reference> chainedReferences = new Set<Reference>(); 185 Reference previous = null;
160 Reference prev = null;
161 for (Reference ref = def.firstRef; ref != null; ref = ref.next) { 186 for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
162 if (ref.definition != def) { 187 if (ref.previous != ref) {
163 error('Reference in chain for $def points to ${ref.definition}', def); 188 // Reference was not seen during IR traversal, so it is orphaned.
189 error('Orphaned reference in reference chain for $def', def);
164 } 190 }
165 if (ref.previous != prev) { 191 // Repair the .previous link that was used for marking.
166 error('Broken .previous link in reference to $def', def); 192 ref.previous = previous;
167 } 193 previous = ref;
168 prev = ref;
169 if (!chainedReferences.add(ref)) {
170 error('Cyclic reference chain for $def', def);
171 }
172 }
173 if (!chainedReferences.containsAll(seenReferences[def])) {
174 error('Seen reference to $def not in reference chain', def);
175 }
176 if (!seenReferences[def].containsAll(chainedReferences)) {
177 error('Reference chain for $def contains orphaned references', def);
178 } 194 }
179 } 195 }
180 196
181 error(String message, node) { 197 error(String message, node) {
182 String sexpr; 198 String sexpr;
183 if (ENABLE_DUMP) { 199 if (ENABLE_DUMP) {
184 try { 200 try {
185 Decorator decorator = (n, String s) => n == node ? '**$s**' : s; 201 Decorator decorator = (n, String s) => n == node ? '**$s**' : s;
186 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode); 202 sexpr = new SExpressionStringifier(decorator).visit(topLevelNode);
187 sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr'; 203 sexpr = 'SExpr dump (offending node marked with **):\n\n$sexpr';
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 } 248 }
233 249
234 @override 250 @override
235 processReference(Reference node) { 251 processReference(Reference node) {
236 if (node.parent != _parent) { 252 if (node.parent != _parent) {
237 error('Parent pointer on $node is ${node.parent} but should be $_parent', 253 error('Parent pointer on $node is ${node.parent} but should be $_parent',
238 node); 254 node);
239 } 255 }
240 } 256 }
241 } 257 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/insert_refinements.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698