| 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 computeEntityValue(element); | 99 return computeObjectValue(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 computeEntityValue(element); | 113 return computeObjectValue(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 } |
| 150 Local local = _localsMap.getLocalVariable(node); | 153 Local local = _localsMap.getLocalVariable(node); |
| 151 return computeLocalValue(local); | 154 return computeLocalValue(local); |
| 155 } else if (node is ir.FunctionExpression) { |
| 156 return computeObjectValue(node); |
| 152 } | 157 } |
| 153 // TODO(johnniwinther,efortuna): Collect data for other nodes? | |
| 154 return null; | 158 return null; |
| 155 } | 159 } |
| 156 | 160 |
| 157 @override | 161 @override |
| 158 String computeMemberValue(ir.Member node) { | 162 String computeMemberValue(ir.Member node) { |
| 159 // TODO(johnniwinther,efortuna): Collect data for the member | 163 return computeObjectValue(member); |
| 160 // (has thisLocal, has box, etc.). | |
| 161 return computeEntityValue(member); | |
| 162 } | 164 } |
| 163 } | 165 } |
| 164 | 166 |
| 165 abstract class ComputeValueMixin<T> { | 167 abstract class ComputeValueMixin<T> { |
| 166 bool get verbose; | 168 bool get verbose; |
| 167 ClosureDataLookup<T> get closureDataLookup; | 169 ClosureDataLookup<T> get closureDataLookup; |
| 168 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); | 170 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>(); |
| 169 ScopeInfo get scopeInfo => scopeInfoStack.head; | 171 ScopeInfo get scopeInfo => scopeInfoStack.head; |
| 170 CapturedScope capturedScope; | 172 CapturedScope capturedScope; |
| 171 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = | 173 Link<ClosureRepresentationInfo> closureRepresentationInfoStack = |
| 172 const Link<ClosureRepresentationInfo>(); | 174 const Link<ClosureRepresentationInfo>(); |
| 173 ClosureRepresentationInfo get closureRepresentationInfo => | 175 ClosureRepresentationInfo get closureRepresentationInfo => |
| 174 closureRepresentationInfoStack.head; | 176 closureRepresentationInfoStack.isNotEmpty |
| 177 ? closureRepresentationInfoStack.head |
| 178 : null; |
| 175 | 179 |
| 176 void pushMember(MemberEntity member) { | 180 void pushMember(MemberEntity member) { |
| 177 scopeInfoStack = | 181 scopeInfoStack = |
| 178 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); | 182 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(member)); |
| 179 capturedScope = closureDataLookup.getCapturedScope(member); | 183 capturedScope = closureDataLookup.getCapturedScope(member); |
| 180 closureRepresentationInfoStack = closureRepresentationInfoStack | |
| 181 .prepend(closureDataLookup.getClosureInfoForMemberTesting(member)); | |
| 182 dump(member); | 184 dump(member); |
| 183 } | 185 } |
| 184 | 186 |
| 185 void popMember() { | 187 void popMember() { |
| 186 scopeInfoStack = scopeInfoStack.tail; | 188 scopeInfoStack = scopeInfoStack.tail; |
| 187 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | |
| 188 } | 189 } |
| 189 | 190 |
| 190 void pushLocalFunction(T node) { | 191 void pushLocalFunction(T node) { |
| 191 closureRepresentationInfoStack = closureRepresentationInfoStack | 192 closureRepresentationInfoStack = closureRepresentationInfoStack |
| 192 .prepend(closureDataLookup.getClosureInfoForTesting(node)); | 193 .prepend(closureDataLookup.getClosureInfo(node)); |
| 193 dump(node); | 194 dump(node); |
| 194 } | 195 } |
| 195 | 196 |
| 196 void popLocalFunction() { | 197 void popLocalFunction() { |
| 197 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; | 198 closureRepresentationInfoStack = closureRepresentationInfoStack.tail; |
| 198 } | 199 } |
| 199 | 200 |
| 200 void dump(Object object) { | 201 void dump(Object object) { |
| 201 if (!verbose) return; | 202 if (!verbose) return; |
| 202 | 203 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 features.add('field'); | 248 features.add('field'); |
| 248 } | 249 } |
| 249 if (closureRepresentationInfo.isVariableBoxed(local)) { | 250 if (closureRepresentationInfo.isVariableBoxed(local)) { |
| 250 features.add('variable-boxed'); | 251 features.add('variable-boxed'); |
| 251 } | 252 } |
| 252 } | 253 } |
| 253 // TODO(johnniwinther,efortuna): Add more info? | 254 // TODO(johnniwinther,efortuna): Add more info? |
| 254 return (features.toList()..sort()).join(','); | 255 return (features.toList()..sort()).join(','); |
| 255 } | 256 } |
| 256 | 257 |
| 257 String computeEntityValue(Entity entity) { | 258 String computeObjectValue(Object object) { |
| 258 Map<String, String> features = <String, String>{}; | 259 Map<String, String> features = <String, String>{}; |
| 259 | 260 |
| 260 void addLocals(String name, forEach(f(Local local, _))) { | 261 void addLocals(String name, forEach(f(Local local, _))) { |
| 261 List<String> names = <String>[]; | 262 List<String> names = <String>[]; |
| 262 forEach((Local local, _) { | 263 forEach((Local local, _) { |
| 263 if (local is BoxLocal) { | 264 if (local is BoxLocal) { |
| 264 names.add('box'); | 265 names.add('box'); |
| 265 } else { | 266 } else { |
| 266 names.add(local.name); | 267 names.add(local.name); |
| 267 } | 268 } |
| 268 }); | 269 }); |
| 269 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; | 270 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]'; |
| 270 if (features.containsKey(name)) { | 271 if (features.containsKey(name)) { |
| 271 Expect.equals( | 272 Expect.equals( |
| 272 features[name], value, "Inconsistent values for $name on $entity."); | 273 features[name], value, "Inconsistent values for $name on $object."); |
| 273 } | 274 } |
| 274 features[name] = value; | 275 features[name] = value; |
| 275 } | 276 } |
| 276 | 277 |
| 277 if (scopeInfo.thisLocal != null) { | 278 if (object is MemberEntity) { |
| 278 features['hasThis'] = ''; | 279 if (scopeInfo.thisLocal != null) { |
| 279 } | 280 features['hasThis'] = ''; |
| 280 addLocals('boxed', scopeInfo.forEachBoxedVariable); | 281 } |
| 282 addLocals('boxed', scopeInfo.forEachBoxedVariable); |
| 281 | 283 |
| 282 if (entity is MemberEntity) { | |
| 283 if (capturedScope.requiresContextBox) { | 284 if (capturedScope.requiresContextBox) { |
| 284 features['requiresBox'] = ''; | 285 features['requiresBox'] = ''; |
| 285 } | 286 } |
| 286 addLocals('boxed', capturedScope.forEachBoxedVariable); | 287 addLocals('boxed', capturedScope.forEachBoxedVariable); |
| 287 } | 288 } |
| 288 | 289 |
| 289 if (closureRepresentationInfo != null) { | 290 if (closureRepresentationInfo != null) { |
| 290 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); | 291 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable); |
| 291 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); | 292 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable); |
| 292 addLocals('free', closureRepresentationInfo.forEachFreeVariable); | 293 addLocals('free', closureRepresentationInfo.forEachFreeVariable); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 304 if (value != '') { | 305 if (value != '') { |
| 305 sb.write('='); | 306 sb.write('='); |
| 306 sb.write(value); | 307 sb.write(value); |
| 307 } | 308 } |
| 308 needsComma = true; | 309 needsComma = true; |
| 309 } | 310 } |
| 310 } | 311 } |
| 311 return sb.toString(); | 312 return sb.toString(); |
| 312 } | 313 } |
| 313 } | 314 } |
| OLD | NEW |