| 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/commandline_options.dart'; | 8 import 'package:compiler/src/commandline_options.dart'; |
| 9 import 'package:compiler/src/common.dart'; | 9 import 'package:compiler/src/common.dart'; |
| 10 import 'package:compiler/src/compiler.dart'; | 10 import 'package:compiler/src/compiler.dart'; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 popLocalFunction(); | 89 popLocalFunction(); |
| 90 } else { | 90 } else { |
| 91 super.visitFunctionExpression(node); | 91 super.visitFunctionExpression(node); |
| 92 } | 92 } |
| 93 } | 93 } |
| 94 | 94 |
| 95 @override | 95 @override |
| 96 String computeNodeValue(ast.Node node, [AstElement element]) { | 96 String computeNodeValue(ast.Node node, [AstElement element]) { |
| 97 if (element != null && element.isLocal) { | 97 if (element != null && element.isLocal) { |
| 98 if (element.isFunction) { | 98 if (element.isFunction) { |
| 99 return computeObjectValue(element); | 99 return computeEntityValue(element); |
| 100 } else { | 100 } else { |
| 101 LocalElement local = element; | 101 LocalElement local = element; |
| 102 return computeLocalValue(local); | 102 return computeLocalValue(local); |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 // TODO(johnniwinther,efortuna): Collect data for other nodes? | 105 // TODO(johnniwinther,efortuna): Collect data for other nodes? |
| 106 return null; | 106 return null; |
| 107 } | 107 } |
| 108 | 108 |
| 109 @override | 109 @override |
| 110 String computeElementValue(AstElement element) { | 110 String computeElementValue(AstElement element) { |
| 111 // TODO(johnniwinther,efortuna): Collect data for the member | 111 // TODO(johnniwinther,efortuna): Collect data for the member |
| 112 // (has thisLocal, has box, etc.). | 112 // (has thisLocal, has box, etc.). |
| 113 return computeObjectValue(element); | 113 return computeEntityValue(element); |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 | 116 |
| 117 /// Kernel IR visitor for computing closure data. | 117 /// Kernel IR visitor for computing closure data. |
| 118 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { | 118 class ClosureIrChecker extends IrDataExtractor with ComputeValueMixin<ir.Node> { |
| 119 final MemberEntity member; | 119 final MemberEntity member; |
| 120 final ClosureDataLookup<ir.Node> closureDataLookup; | 120 final ClosureDataLookup<ir.Node> closureDataLookup; |
| 121 final KernelToLocalsMap _localsMap; | 121 final KernelToLocalsMap _localsMap; |
| 122 final bool verbose; | 122 final bool verbose; |
| 123 | 123 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 140 | 140 |
| 141 visitFunctionDeclaration(ir.FunctionDeclaration node) { | 141 visitFunctionDeclaration(ir.FunctionDeclaration node) { |
| 142 pushLocalFunction(node); | 142 pushLocalFunction(node); |
| 143 super.visitFunctionDeclaration(node); | 143 super.visitFunctionDeclaration(node); |
| 144 popLocalFunction(); | 144 popLocalFunction(); |
| 145 } | 145 } |
| 146 | 146 |
| 147 @override | 147 @override |
| 148 String computeNodeValue(ir.Node node) { | 148 String computeNodeValue(ir.Node node) { |
| 149 if (node is ir.VariableDeclaration) { | 149 if (node is ir.VariableDeclaration) { |
| 150 if (node.parent is ir.FunctionDeclaration) { | |
| 151 return computeObjectValue(node.parent); | |
| 152 } | |
| 153 Local local = _localsMap.getLocalVariable(node); | 150 Local local = _localsMap.getLocalVariable(node); |
| 154 return computeLocalValue(local); | 151 return computeLocalValue(local); |
| 155 } else if (node is ir.FunctionExpression) { | |
| 156 return computeObjectValue(node); | |
| 157 } | 152 } |
| 153 // TODO(johnniwinther,efortuna): Collect data for other nodes? |
| 158 return null; | 154 return null; |
| 159 } | 155 } |
| 160 | 156 |
| 161 @override | 157 @override |
| 162 String computeMemberValue(ir.Member node) { | 158 String computeMemberValue(ir.Member node) { |
| 163 return computeObjectValue(member); | 159 // TODO(johnniwinther,efortuna): Collect data for the member |
| 160 // (has thisLocal, has box, etc.). |
| 161 return computeEntityValue(member); |
| 164 } | 162 } |
| 165 } | 163 } |
| 166 | 164 |
| 167 abstract class ComputeValueMixin<T> { | 165 abstract class ComputeValueMixin<T> { |
| 168 bool get verbose; | 166 bool get verbose; |
| 169 ClosureDataLookup<T> get closureDataLookup; | 167 ClosureDataLookup<T> get closureDataLookup; |
| 170 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); | 168 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); |
| 171 ScopeInfo get scopeInfo => scopeInfoStack.head; | 169 ScopeInfo get scopeInfo => scopeInfoStack.head; |
| 172 CapturedScope capturedScope; | 170 CapturedScope capturedScope; |
| 173 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = | 171 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = |
| 174 const Link<ClosureRepresentationInfo>(); | 172 const Link<ClosureRepresentationInfo>(); |
| 175 ClosureRepresentationInfo get closureRepresentationInfo => | 173 ClosureRepresentationInfo get closureRepresentationInfo => |
| 176 closureRepresentationInfoStack.isNotEmpty | 174 closureRepresentationInfoStack.head; |
| 177 ? closureRepresentationInfoStack.head | |
| 178 : null; | |
| 179 | 175 |
| 180 void pushMember(MemberEntity member) { | 176 void pushMember(MemberEntity member) { |
| 181 scopeInfoStack = | 177 scopeInfoStack = |
| 182 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); | 178 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); |
| 183 capturedScope = closureDataLookup.getCapturedScope(member); | 179 capturedScope = closureDataLookup.getCapturedScope(member); |
| 180 closureRepresentationInfoStack = closureRepresentationInfoStack |
| 181 .prepend(closureDataLookup.getClosureInfoForMemberTesting(member)); |
| 184 dump(member); | 182 dump(member); |
| 185 } | 183 } |
| 186 | 184 |
| 187 void popMember() { | 185 void popMember() { |
| 188 scopeInfoStack = scopeInfoStack.tail; | 186 scopeInfoStack = scopeInfoStack.tail; |
| 187 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; |
| 189 } | 188 } |
| 190 | 189 |
| 191 void pushLocalFunction(T node) { | 190 void pushLocalFunction(T node) { |
| 192 closureRepresentationInfoStack = closureRepresentationInfoStack | 191 closureRepresentationInfoStack = closureRepresentationInfoStack |
| 193 .prepend(closureDataLookup.getClosureInfo(node)); | 192 .prepend(closureDataLookup.getClosureInfoForTesting(node)); |
| 194 dump(node); | 193 dump(node); |
| 195 } | 194 } |
| 196 | 195 |
| 197 void popLocalFunction() { | 196 void popLocalFunction() { |
| 198 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | 197 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; |
| 199 } | 198 } |
| 200 | 199 |
| 201 void dump(Object object) { | 200 void dump(Object object) { |
| 202 if (!verbose) return; | 201 if (!verbose) return; |
| 203 | 202 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 features.add('field'); | 247 features.add('field'); |
| 249 } | 248 } |
| 250 if (closureRepresentationInfo.isVariableBoxed(local)) { | 249 if (closureRepresentationInfo.isVariableBoxed(local)) { |
| 251 features.add('variable-boxed'); | 250 features.add('variable-boxed'); |
| 252 } | 251 } |
| 253 } | 252 } |
| 254 // TODO(johnniwinther,efortuna): Add more info? | 253 // TODO(johnniwinther,efortuna): Add more info? |
| 255 return (features.toList()..sort()).join(','); | 254 return (features.toList()..sort()).join(','); |
| 256 } | 255 } |
| 257 | 256 |
| 258 String computeObjectValue(Object object) { | 257 String computeEntityValue(Entity entity) { |
| 259 Map<String, String> features = <String, String>{}; | 258 Map<String, String> features = <String, String>{}; |
| 260 | 259 |
| 261 void addLocals(String name, forEach(f(Local local, _))) { | 260 void addLocals(String name, forEach(f(Local local, _))) { |
| 262 List<String> names = <String>[]; | 261 List<String> names = <String>[]; |
| 263 forEach((Local local, _) { | 262 forEach((Local local, _) { |
| 264 if (local is BoxLocal) { | 263 if (local is BoxLocal) { |
| 265 names.add('box'); | 264 names.add('box'); |
| 266 } else { | 265 } else { |
| 267 names.add(local.name); | 266 names.add(local.name); |
| 268 } | 267 } |
| 269 }); | 268 }); |
| 270 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; | 269 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; |
| 271 if (features.containsKey(name)) { | 270 if (features.containsKey(name)) { |
| 272 Expect.equals( | 271 Expect.equals( |
| 273 features[name], value, "Inconsistent values for $name on $object."); | 272 features[name], value, "Inconsistent values for $name on $entity."); |
| 274 } | 273 } |
| 275 features[name] = value; | 274 features[name] = value; |
| 276 } | 275 } |
| 277 | 276 |
| 278 if (object is MemberEntity) { | 277 if (scopeInfo.thisLocal != null) { |
| 279 if (scopeInfo.thisLocal != null) { | 278 features['hasThis'] = ''; |
| 280 features['hasThis'] = ''; | 279 } |
| 281 } | 280 addLocals('boxed', scopeInfo.forEachBoxedVariable); |
| 282 addLocals('boxed', scopeInfo.forEachBoxedVariable); | |
| 283 | 281 |
| 282 if (entity is MemberEntity) { |
| 284 if (capturedScope.requiresContextBox) { | 283 if (capturedScope.requiresContextBox) { |
| 285 features['requiresBox'] = ''; | 284 features['requiresBox'] = ''; |
| 286 } | 285 } |
| 287 addLocals('boxed', capturedScope.forEachBoxedVariable); | 286 addLocals('boxed', capturedScope.forEachBoxedVariable); |
| 288 } | 287 } |
| 289 | 288 |
| 290 if (closureRepresentationInfo != null) { | 289 if (closureRepresentationInfo != null) { |
| 291 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); | 290 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); |
| 292 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); | 291 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); |
| 293 addLocals('free', closureRepresentationInfo.forEachFreeVariable); | 292 addLocals('free', closureRepresentationInfo.forEachFreeVariable); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 305 if (value != '') { | 304 if (value != '') { |
| 306 sb.write('='); | 305 sb.write('='); |
| 307 sb.write(value); | 306 sb.write(value); |
| 308 } | 307 } |
| 309 needsComma = true; | 308 needsComma = true; |
| 310 } | 309 } |
| 311 } | 310 } |
| 312 return sb.toString(); | 311 return sb.toString(); |
| 313 } | 312 } |
| 314 } | 313 } |
| OLD | NEW |