Chromium Code Reviews| 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 |