OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:io' hide Link; | 5 import 'dart:io' hide Link; |
6 import 'package:async_helper/async_helper.dart'; | 6 import 'package:async_helper/async_helper.dart'; |
7 import 'package:compiler/src/closure.dart'; | 7 import 'package:compiler/src/closure.dart'; |
8 import 'package:compiler/src/common.dart'; | 8 import 'package:compiler/src/common.dart'; |
9 import 'package:compiler/src/compiler.dart'; | 9 import 'package:compiler/src/compiler.dart'; |
10 import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; | 10 import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 ClosureAstComputer(DiagnosticReporter reporter, Map<Id, ActualData> actualMap, | 88 ClosureAstComputer(DiagnosticReporter reporter, Map<Id, ActualData> actualMap, |
89 ResolvedAst resolvedAst, this.closureDataLookup, | 89 ResolvedAst resolvedAst, this.closureDataLookup, |
90 {this.verbose: false}) | 90 {this.verbose: false}) |
91 : super(reporter, actualMap, resolvedAst) { | 91 : super(reporter, actualMap, resolvedAst) { |
92 pushMember(resolvedAst.element as MemberElement); | 92 pushMember(resolvedAst.element as MemberElement); |
93 } | 93 } |
94 | 94 |
95 visitFunctionExpression(ast.FunctionExpression node) { | 95 visitFunctionExpression(ast.FunctionExpression node) { |
96 Entity localFunction = resolvedAst.elements.getFunctionDefinition(node); | 96 Entity localFunction = resolvedAst.elements.getFunctionDefinition(node); |
97 if (localFunction is LocalFunctionElement) { | 97 if (localFunction is LocalFunctionElement) { |
98 pushMember(localFunction.callMethod); | |
98 pushLocalFunction(node); | 99 pushLocalFunction(node); |
99 super.visitFunctionExpression(node); | 100 super.visitFunctionExpression(node); |
100 popLocalFunction(); | 101 popLocalFunction(); |
102 popMember(); | |
101 } else { | 103 } else { |
102 super.visitFunctionExpression(node); | 104 super.visitFunctionExpression(node); |
103 } | 105 } |
104 } | 106 } |
105 | 107 |
106 @override | 108 @override |
107 String computeNodeValue(ast.Node node, [AstElement element]) { | 109 String computeNodeValue(ast.Node node, [AstElement element]) { |
108 if (element != null && element.isLocal) { | 110 if (element != null && element.isLocal) { |
109 if (element.isFunction) { | 111 if (element.isFunction) { |
110 return computeObjectValue(element); | 112 LocalFunctionElement localFunction = element; |
113 return computeObjectValue(localFunction.callMethod); | |
111 } else { | 114 } else { |
112 LocalElement local = element; | 115 LocalElement local = element; |
113 return computeLocalValue(local); | 116 return computeLocalValue(local); |
114 } | 117 } |
115 } | 118 } |
116 // TODO(johnniwinther,efortuna): Collect data for other nodes? | 119 // TODO(johnniwinther,efortuna): Collect data for other nodes? |
117 return null; | 120 return null; |
118 } | 121 } |
119 | 122 |
120 @override | 123 @override |
121 String computeElementValue(AstElement element) { | 124 String computeElementValue(covariant MemberElement element) { |
122 // TODO(johnniwinther,efortuna): Collect data for the member | 125 // TODO(johnniwinther,efortuna): Collect data for the member |
123 // (has thisLocal, has box, etc.). | 126 // (has thisLocal, has box, etc.). |
124 return computeObjectValue(element); | 127 return computeObjectValue(element); |
125 } | 128 } |
126 } | 129 } |
127 | 130 |
128 /// Kernel IR visitor for computing closure data. | 131 /// Kernel IR visitor for computing closure data. |
129 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { | 132 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { |
130 final MemberEntity member; | 133 final MemberEntity member; |
131 final ClosureDataLookup<ir.Node> closureDataLookup; | 134 final ClosureDataLookup<ir.Node> closureDataLookup; |
132 final KernelToLocalsMap _localsMap; | 135 final KernelToLocalsMap _localsMap; |
133 final bool verbose; | 136 final bool verbose; |
134 | 137 |
135 ClosureIrChecker( | 138 ClosureIrChecker( |
136 Map<Id, ActualData> actualMap, | 139 Map<Id, ActualData> actualMap, |
137 KernelToElementMapForBuilding elementMap, | 140 KernelToElementMapForBuilding elementMap, |
138 this.member, | 141 this.member, |
139 this._localsMap, | 142 this._localsMap, |
140 this.closureDataLookup, | 143 this.closureDataLookup, |
141 {this.verbose: false}) | 144 {this.verbose: false}) |
142 : super(actualMap) { | 145 : super(actualMap) { |
143 pushMember(member); | 146 pushMember(member); |
144 } | 147 } |
145 | 148 |
146 visitFunctionExpression(ir.FunctionExpression node) { | 149 visitFunctionExpression(ir.FunctionExpression node) { |
150 ClosureRepresentationInfo info = closureDataLookup.getClosureInfo(node); | |
151 pushMember(info.callMethod); | |
147 pushLocalFunction(node); | 152 pushLocalFunction(node); |
148 super.visitFunctionExpression(node); | 153 super.visitFunctionExpression(node); |
149 popLocalFunction(); | 154 popLocalFunction(); |
155 popMember(); | |
150 } | 156 } |
151 | 157 |
152 visitFunctionDeclaration(ir.FunctionDeclaration node) { | 158 visitFunctionDeclaration(ir.FunctionDeclaration node) { |
159 ClosureRepresentationInfo info = closureDataLookup.getClosureInfo(node); | |
160 pushMember(info.callMethod); | |
153 pushLocalFunction(node); | 161 pushLocalFunction(node); |
154 super.visitFunctionDeclaration(node); | 162 super.visitFunctionDeclaration(node); |
155 popLocalFunction(); | 163 popLocalFunction(); |
164 popMember(); | |
156 } | 165 } |
157 | 166 |
158 @override | 167 @override |
159 String computeNodeValue(ir.Node node) { | 168 String computeNodeValue(ir.Node node) { |
160 if (node is ir.VariableDeclaration) { | 169 if (node is ir.VariableDeclaration) { |
161 if (node.parent is ir.FunctionDeclaration) { | 170 if (node.parent is ir.FunctionDeclaration) { |
162 return computeObjectValue(node.parent); | 171 ClosureRepresentationInfo info = |
172 closureDataLookup.getClosureInfo(node.parent); | |
173 return computeObjectValue(info.callMethod); | |
163 } | 174 } |
164 Local local = _localsMap.getLocalVariable(node); | 175 Local local = _localsMap.getLocalVariable(node); |
165 return computeLocalValue(local); | 176 return computeLocalValue(local); |
166 } else if (node is ir.FunctionExpression) { | 177 } else if (node is ir.FunctionExpression) { |
167 return computeObjectValue(node); | 178 ClosureRepresentationInfo info = closureDataLookup.getClosureInfo(node); |
179 return computeObjectValue(info.callMethod); | |
168 } | 180 } |
169 return null; | 181 return null; |
170 } | 182 } |
171 | 183 |
172 @override | 184 @override |
173 String computeMemberValue(ir.Member node) { | 185 String computeMemberValue(ir.Member node) { |
174 return computeObjectValue(member); | 186 return computeObjectValue(member); |
175 } | 187 } |
176 } | 188 } |
177 | 189 |
178 abstract class ComputeValueMixin<T> { | 190 abstract class ComputeValueMixin<T> { |
179 bool get verbose; | 191 bool get verbose; |
192 Map<BoxLocal, String> boxNames = <BoxLocal, String>{}; | |
180 ClosureDataLookup<T> get closureDataLookup; | 193 ClosureDataLookup<T> get closureDataLookup; |
181 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); | 194 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); |
182 ScopeInfo get scopeInfo => scopeInfoStack.head; | 195 ScopeInfo get scopeInfo => scopeInfoStack.head; |
183 CapturedScope capturedScope; | 196 CapturedScope get capturedScope => capturedScopeStack.head; |
197 Link<CapturedScope> capturedScopeStack = const Link<CapturedScope>(); | |
184 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = | 198 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = |
185 const Link<ClosureRepresentationInfo>(); | 199 const Link<ClosureRepresentationInfo>(); |
186 ClosureRepresentationInfo get closureRepresentationInfo => | 200 ClosureRepresentationInfo get closureRepresentationInfo => |
187 closureRepresentationInfoStack.isNotEmpty | 201 closureRepresentationInfoStack.isNotEmpty |
188 ? closureRepresentationInfoStack.head | 202 ? closureRepresentationInfoStack.head |
189 : null; | 203 : null; |
190 | 204 |
191 void pushMember(MemberEntity member) { | 205 void pushMember(MemberEntity member) { |
192 scopeInfoStack = | 206 scopeInfoStack = |
193 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); | 207 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); |
194 capturedScope = closureDataLookup.getCapturedScope(member); | 208 capturedScopeStack = |
209 capturedScopeStack.prepend(closureDataLookup.getCapturedScope(member)); | |
210 if (capturedScope.hasBox) { | |
211 boxNames[capturedScope.box] = 'box${boxNames.length}'; | |
212 } | |
195 dump(member); | 213 dump(member); |
196 } | 214 } |
197 | 215 |
198 void popMember() { | 216 void popMember() { |
199 scopeInfoStack = scopeInfoStack.tail; | 217 scopeInfoStack = scopeInfoStack.tail; |
218 capturedScopeStack = capturedScopeStack.tail; | |
200 } | 219 } |
201 | 220 |
202 void pushLocalFunction(T node) { | 221 void pushLocalFunction(T node) { |
203 closureRepresentationInfoStack = closureRepresentationInfoStack | 222 closureRepresentationInfoStack = closureRepresentationInfoStack |
204 .prepend(closureDataLookup.getClosureInfo(node)); | 223 .prepend(closureDataLookup.getClosureInfo(node)); |
205 dump(node); | 224 dump(node); |
206 } | 225 } |
207 | 226 |
208 void popLocalFunction() { | 227 void popLocalFunction() { |
209 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | 228 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; |
(...skipping 23 matching lines...) Expand all Loading... | |
233 if (scopeInfo.localIsUsedInTryOrSync(local)) { | 252 if (scopeInfo.localIsUsedInTryOrSync(local)) { |
234 features.add('inTry'); | 253 features.add('inTry'); |
235 // TODO(johnniwinther,efortuna): Should this be enabled and checked? | 254 // TODO(johnniwinther,efortuna): Should this be enabled and checked? |
236 //Expect.isTrue(capturedScope.localIsUsedInTryOrSync(local)); | 255 //Expect.isTrue(capturedScope.localIsUsedInTryOrSync(local)); |
237 } else { | 256 } else { |
238 //Expect.isFalse(capturedScope.localIsUsedInTryOrSync(local)); | 257 //Expect.isFalse(capturedScope.localIsUsedInTryOrSync(local)); |
239 } | 258 } |
240 if (capturedScope.isBoxed(local)) { | 259 if (capturedScope.isBoxed(local)) { |
241 features.add('boxed'); | 260 features.add('boxed'); |
242 } | 261 } |
243 if (capturedScope.context == local) { | 262 if (capturedScope.box == local) { |
244 features.add('local'); | 263 // TODO(johnniwinther): This can't happen! |
Emily Fortuna
2017/08/22 23:47:37
but this is happening?
if not... throw?
Johnni Winther
2017/08/23 07:47:18
I'm still in the process of making this accurate.
| |
264 features.add('box'); | |
245 } | 265 } |
246 if (capturedScope is CapturedLoopScope) { | 266 if (capturedScope is CapturedLoopScope) { |
247 CapturedLoopScope loopScope = capturedScope; | 267 CapturedLoopScope loopScope = capturedScope; |
248 if (loopScope.boxedLoopVariables.contains(local)) { | 268 if (loopScope.boxedLoopVariables.contains(local)) { |
249 features.add('loop'); | 269 features.add('loop'); |
250 } | 270 } |
251 } | 271 } |
252 if (closureRepresentationInfo != null) { | 272 if (closureRepresentationInfo != null) { |
253 if (closureRepresentationInfo.createdFieldEntities.contains(local)) { | 273 if (closureRepresentationInfo.createdFieldEntities.contains(local)) { |
254 features.add('field'); | 274 features.add('field'); |
255 } | 275 } |
256 if (closureRepresentationInfo.isVariableBoxed(local)) { | |
257 features.add('variable-boxed'); | |
258 } | |
259 } | 276 } |
260 // TODO(johnniwinther,efortuna): Add more info? | 277 // TODO(johnniwinther,efortuna): Add more info? |
261 return (features.toList()..sort()).join(','); | 278 return (features.toList()..sort()).join(','); |
262 } | 279 } |
263 | 280 |
264 String computeObjectValue(Object object) { | 281 String computeObjectValue(MemberEntity member) { |
265 Map<String, String> features = <String, String>{}; | 282 Map<String, String> features = <String, String>{}; |
266 | 283 |
267 void addLocals(String name, forEach(f(Local local, _))) { | 284 void addLocals(String name, forEach(f(Local local, _))) { |
268 List<String> names = <String>[]; | 285 List<String> names = <String>[]; |
269 forEach((Local local, _) { | 286 forEach((Local local, _) { |
270 if (local is BoxLocal) { | 287 if (local is BoxLocal) { |
271 names.add('box'); | 288 names.add(boxNames[local]); |
272 } else { | 289 } else { |
273 names.add(local.name); | 290 names.add(local.name); |
274 } | 291 } |
275 }); | 292 }); |
276 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; | 293 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; |
277 if (features.containsKey(name)) { | 294 if (features.containsKey(name)) { |
278 Expect.equals( | 295 Expect.equals( |
279 features[name], value, "Inconsistent values for $name on $object."); | 296 features[name], value, "Inconsistent values for $name on $member."); |
280 } | 297 } |
281 features[name] = value; | 298 features[name] = value; |
282 } | 299 } |
283 | 300 |
284 if (object is MemberEntity) { | 301 if (scopeInfo.thisLocal != null) { |
285 if (scopeInfo.thisLocal != null) { | 302 features['hasThis'] = ''; |
286 features['hasThis'] = ''; | |
287 } | |
288 | |
289 if (capturedScope.requiresContextBox) { | |
290 features['requiresBox'] = ''; | |
291 } | |
292 addLocals('boxed', capturedScope.forEachBoxedVariable); | |
293 } | 303 } |
304 if (capturedScope.hasBox) { | |
305 //print('------------- $object from $capturedScope'); | |
Emily Fortuna
2017/08/22 23:47:37
remove commented out line?
| |
306 features['box'] = boxNames[capturedScope.box]; | |
307 } | |
308 addLocals('boxed', capturedScope.forEachBoxedVariable); | |
294 | 309 |
295 if (closureRepresentationInfo != null) { | 310 if (closureRepresentationInfo != null) { |
296 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); | |
297 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); | |
298 addLocals('free', closureRepresentationInfo.forEachFreeVariable); | 311 addLocals('free', closureRepresentationInfo.forEachFreeVariable); |
299 } | 312 } |
300 | 313 |
301 StringBuffer sb = new StringBuffer(); | 314 StringBuffer sb = new StringBuffer(); |
302 bool needsComma = false; | 315 bool needsComma = false; |
303 for (String name in features.keys.toList()..sort()) { | 316 for (String name in features.keys.toList()..sort()) { |
304 String value = features[name]; | 317 String value = features[name]; |
305 if (value != null) { | 318 if (value != null) { |
306 if (needsComma) { | 319 if (needsComma) { |
307 sb.write(','); | 320 sb.write(','); |
308 } | 321 } |
309 sb.write(name); | 322 sb.write(name); |
310 if (value != '') { | 323 if (value != '') { |
311 sb.write('='); | 324 sb.write('='); |
312 sb.write(value); | 325 sb.write(value); |
313 } | 326 } |
314 needsComma = true; | 327 needsComma = true; |
315 } | 328 } |
316 } | 329 } |
317 return sb.toString(); | 330 return sb.toString(); |
318 } | 331 } |
319 } | 332 } |
OLD | NEW |