| 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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 popLocalFunction(); | 100 popLocalFunction(); |
| 101 } else { | 101 } else { |
| 102 super.visitFunctionExpression(node); | 102 super.visitFunctionExpression(node); |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 | 105 |
| 106 @override | 106 @override |
| 107 String computeNodeValue(ast.Node node, [AstElement element]) { | 107 String computeNodeValue(ast.Node node, [AstElement element]) { |
| 108 if (element != null && element.isLocal) { | 108 if (element != null && element.isLocal) { |
| 109 if (element.isFunction) { | 109 if (element.isFunction) { |
| 110 return computeEntityValue(element); | 110 return computeObjectValue(element); |
| 111 } else { | 111 } else { |
| 112 LocalElement local = element; | 112 LocalElement local = element; |
| 113 return computeLocalValue(local); | 113 return computeLocalValue(local); |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 // TODO(johnniwinther,efortuna): Collect data for other nodes? | 116 // TODO(johnniwinther,efortuna): Collect data for other nodes? |
| 117 return null; | 117 return null; |
| 118 } | 118 } |
| 119 | 119 |
| 120 @override | 120 @override |
| 121 String computeElementValue(AstElement element) { | 121 String computeElementValue(AstElement element) { |
| 122 // TODO(johnniwinther,efortuna): Collect data for the member | 122 // TODO(johnniwinther,efortuna): Collect data for the member |
| 123 // (has thisLocal, has box, etc.). | 123 // (has thisLocal, has box, etc.). |
| 124 return computeEntityValue(element); | 124 return computeObjectValue(element); |
| 125 } | 125 } |
| 126 } | 126 } |
| 127 | 127 |
| 128 /// Kernel IR visitor for computing closure data. | 128 /// Kernel IR visitor for computing closure data. |
| 129 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { | 129 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { |
| 130 final MemberEntity member; | 130 final MemberEntity member; |
| 131 final ClosureDataLookup<ir.Node> closureDataLookup; | 131 final ClosureDataLookup<ir.Node> closureDataLookup; |
| 132 final KernelToLocalsMap _localsMap; | 132 final KernelToLocalsMap _localsMap; |
| 133 final bool verbose; | 133 final bool verbose; |
| 134 | 134 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 151 | 151 |
| 152 visitFunctionDeclaration(ir.FunctionDeclaration node) { | 152 visitFunctionDeclaration(ir.FunctionDeclaration node) { |
| 153 pushLocalFunction(node); | 153 pushLocalFunction(node); |
| 154 super.visitFunctionDeclaration(node); | 154 super.visitFunctionDeclaration(node); |
| 155 popLocalFunction(); | 155 popLocalFunction(); |
| 156 } | 156 } |
| 157 | 157 |
| 158 @override | 158 @override |
| 159 String computeNodeValue(ir.Node node) { | 159 String computeNodeValue(ir.Node node) { |
| 160 if (node is ir.VariableDeclaration) { | 160 if (node is ir.VariableDeclaration) { |
| 161 if (node.parent is ir.FunctionDeclaration) { |
| 162 return computeObjectValue(node.parent); |
| 163 } |
| 161 Local local = _localsMap.getLocalVariable(node); | 164 Local local = _localsMap.getLocalVariable(node); |
| 162 return computeLocalValue(local); | 165 return computeLocalValue(local); |
| 166 } else if (node is ir.FunctionExpression) { |
| 167 return computeObjectValue(node); |
| 163 } | 168 } |
| 164 // TODO(johnniwinther,efortuna): Collect data for other nodes? | |
| 165 return null; | 169 return null; |
| 166 } | 170 } |
| 167 | 171 |
| 168 @override | 172 @override |
| 169 String computeMemberValue(ir.Member node) { | 173 String computeMemberValue(ir.Member node) { |
| 170 // TODO(johnniwinther,efortuna): Collect data for the member | 174 return computeObjectValue(member); |
| 171 // (has thisLocal, has box, etc.). | |
| 172 return computeEntityValue(member); | |
| 173 } | 175 } |
| 174 } | 176 } |
| 175 | 177 |
| 176 abstract class ComputeValueMixin<T> { | 178 abstract class ComputeValueMixin<T> { |
| 177 bool get verbose; | 179 bool get verbose; |
| 178 ClosureDataLookup<T> get closureDataLookup; | 180 ClosureDataLookup<T> get closureDataLookup; |
| 179 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); | 181 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); |
| 180 ScopeInfo get scopeInfo => scopeInfoStack.head; | 182 ScopeInfo get scopeInfo => scopeInfoStack.head; |
| 181 CapturedScope capturedScope; | 183 CapturedScope capturedScope; |
| 182 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = | 184 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = |
| 183 const Link<ClosureRepresentationInfo>(); | 185 const Link<ClosureRepresentationInfo>(); |
| 184 ClosureRepresentationInfo get closureRepresentationInfo => | 186 ClosureRepresentationInfo get closureRepresentationInfo => |
| 185 closureRepresentationInfoStack.head; | 187 closureRepresentationInfoStack.isNotEmpty |
| 188 ? closureRepresentationInfoStack.head |
| 189 : null; |
| 186 | 190 |
| 187 void pushMember(MemberEntity member) { | 191 void pushMember(MemberEntity member) { |
| 188 scopeInfoStack = | 192 scopeInfoStack = |
| 189 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); | 193 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); |
| 190 capturedScope = closureDataLookup.getCapturedScope(member); | 194 capturedScope = closureDataLookup.getCapturedScope(member); |
| 191 closureRepresentationInfoStack = closureRepresentationInfoStack | |
| 192 .prepend(closureDataLookup.getClosureInfoForMemberTesting(member)); | |
| 193 dump(member); | 195 dump(member); |
| 194 } | 196 } |
| 195 | 197 |
| 196 void popMember() { | 198 void popMember() { |
| 197 scopeInfoStack = scopeInfoStack.tail; | 199 scopeInfoStack = scopeInfoStack.tail; |
| 198 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | |
| 199 } | 200 } |
| 200 | 201 |
| 201 void pushLocalFunction(T node) { | 202 void pushLocalFunction(T node) { |
| 202 closureRepresentationInfoStack = closureRepresentationInfoStack | 203 closureRepresentationInfoStack = closureRepresentationInfoStack |
| 203 .prepend(closureDataLookup.getClosureInfoForTesting(node)); | 204 .prepend(closureDataLookup.getClosureInfo(node)); |
| 204 dump(node); | 205 dump(node); |
| 205 } | 206 } |
| 206 | 207 |
| 207 void popLocalFunction() { | 208 void popLocalFunction() { |
| 208 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | 209 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; |
| 209 } | 210 } |
| 210 | 211 |
| 211 void dump(Object object) { | 212 void dump(Object object) { |
| 212 if (!verbose) return; | 213 if (!verbose) return; |
| 213 | 214 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 features.add('field'); | 259 features.add('field'); |
| 259 } | 260 } |
| 260 if (closureRepresentationInfo.isVariableBoxed(local)) { | 261 if (closureRepresentationInfo.isVariableBoxed(local)) { |
| 261 features.add('variable-boxed'); | 262 features.add('variable-boxed'); |
| 262 } | 263 } |
| 263 } | 264 } |
| 264 // TODO(johnniwinther,efortuna): Add more info? | 265 // TODO(johnniwinther,efortuna): Add more info? |
| 265 return (features.toList()..sort()).join(','); | 266 return (features.toList()..sort()).join(','); |
| 266 } | 267 } |
| 267 | 268 |
| 268 String computeEntityValue(Entity entity) { | 269 String computeObjectValue(Object object) { |
| 269 Map<String, String> features = <String, String>{}; | 270 Map<String, String> features = <String, String>{}; |
| 270 | 271 |
| 271 void addLocals(String name, forEach(f(Local local, _))) { | 272 void addLocals(String name, forEach(f(Local local, _))) { |
| 272 List<String> names = <String>[]; | 273 List<String> names = <String>[]; |
| 273 forEach((Local local, _) { | 274 forEach((Local local, _) { |
| 274 if (local is BoxLocal) { | 275 if (local is BoxLocal) { |
| 275 names.add('box'); | 276 names.add('box'); |
| 276 } else { | 277 } else { |
| 277 names.add(local.name); | 278 names.add(local.name); |
| 278 } | 279 } |
| 279 }); | 280 }); |
| 280 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; | 281 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; |
| 281 if (features.containsKey(name)) { | 282 if (features.containsKey(name)) { |
| 282 Expect.equals( | 283 Expect.equals( |
| 283 features[name], value, "Inconsistent values for $name on $entity."); | 284 features[name], value, "Inconsistent values for $name on $object."); |
| 284 } | 285 } |
| 285 features[name] = value; | 286 features[name] = value; |
| 286 } | 287 } |
| 287 | 288 |
| 288 if (scopeInfo.thisLocal != null) { | 289 if (object is MemberEntity) { |
| 289 features['hasThis'] = ''; | 290 if (scopeInfo.thisLocal != null) { |
| 290 } | 291 features['hasThis'] = ''; |
| 291 addLocals('boxed', scopeInfo.forEachBoxedVariable); | 292 } |
| 293 addLocals('boxed', scopeInfo.forEachBoxedVariable); |
| 292 | 294 |
| 293 if (entity is MemberEntity) { | |
| 294 if (capturedScope.requiresContextBox) { | 295 if (capturedScope.requiresContextBox) { |
| 295 features['requiresBox'] = ''; | 296 features['requiresBox'] = ''; |
| 296 } | 297 } |
| 297 addLocals('boxed', capturedScope.forEachBoxedVariable); | 298 addLocals('boxed', capturedScope.forEachBoxedVariable); |
| 298 } | 299 } |
| 299 | 300 |
| 300 if (closureRepresentationInfo != null) { | 301 if (closureRepresentationInfo != null) { |
| 301 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); | 302 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); |
| 302 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); | 303 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); |
| 303 addLocals('free', closureRepresentationInfo.forEachFreeVariable); | 304 addLocals('free', closureRepresentationInfo.forEachFreeVariable); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 315 if (value != '') { | 316 if (value != '') { |
| 316 sb.write('='); | 317 sb.write('='); |
| 317 sb.write(value); | 318 sb.write(value); |
| 318 } | 319 } |
| 319 needsComma = true; | 320 needsComma = true; |
| 320 } | 321 } |
| 321 } | 322 } |
| 322 return sb.toString(); | 323 return sb.toString(); |
| 323 } | 324 } |
| 324 } | 325 } |
| OLD | NEW |