Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library dump_info; | 5 library dump_info; |
| 6 | 6 |
| 7 import 'dart:convert' | 7 import 'dart:convert' |
| 8 show ChunkedConversionSink, JsonEncoder, StringConversionSink; | 8 show ChunkedConversionSink, JsonEncoder, StringConversionSink; |
| 9 | 9 |
| 10 import 'package:dart2js_info/info.dart'; | 10 import 'package:dart2js_info/info.dart'; |
| 11 | 11 |
| 12 import '../compiler_new.dart'; | 12 import '../compiler_new.dart'; |
| 13 import 'closure.dart'; | 13 import 'closure.dart'; |
| 14 import 'common/tasks.dart' show CompilerTask; | 14 import 'common/tasks.dart' show CompilerTask; |
| 15 import 'common.dart'; | 15 import 'common.dart'; |
| 16 import 'common_elements.dart'; | |
| 16 import 'compiler.dart' show Compiler; | 17 import 'compiler.dart' show Compiler; |
| 17 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; | 18 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; |
| 18 import 'deferred_load.dart' show OutputUnit; | 19 import 'deferred_load.dart' show OutputUnit; |
| 19 import 'elements/elements.dart'; | 20 import 'elements/elements.dart'; |
| 20 import 'elements/entities.dart'; | 21 import 'elements/entities.dart'; |
| 21 import 'elements/visitor.dart'; | |
| 22 import 'js/js.dart' as jsAst; | 22 import 'js/js.dart' as jsAst; |
| 23 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 23 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
| 24 import 'types/types.dart' show TypeMask; | 24 import 'types/types.dart' |
| 25 import 'universe/world_builder.dart' show ReceiverConstraint; | 25 show |
| 26 GlobalTypeInferenceElementResult, | |
| 27 GlobalTypeInferenceMemberResult, | |
| 28 TypeMask; | |
| 29 import 'universe/world_builder.dart' | |
| 30 show CodegenWorldBuilder, ReceiverConstraint; | |
| 26 import 'universe/world_impact.dart' | 31 import 'universe/world_impact.dart' |
| 27 show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl; | 32 show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl; |
| 28 import 'world.dart' show ClosedWorld; | 33 import 'world.dart' show ClosedWorld; |
| 29 | 34 |
| 30 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> { | 35 class ElementInfoCollector { |
| 31 final Compiler compiler; | 36 final Compiler compiler; |
| 32 final ClosedWorld closedWorld; | 37 final ClosedWorld closedWorld; |
| 33 | 38 |
| 39 ElementEnvironment get environment => closedWorld.elementEnvironment; | |
| 40 CodegenWorldBuilder get codegenWorldBuilder => compiler.codegenWorldBuilder; | |
| 41 | |
| 34 final AllInfo result = new AllInfo(); | 42 final AllInfo result = new AllInfo(); |
| 35 final Map<Entity, Info> _elementToInfo = <Entity, Info>{}; | 43 final Map<Entity, Info> _entityToInfo = <Entity, Info>{}; |
| 36 final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{}; | 44 final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{}; |
| 37 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; | 45 final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {}; |
| 38 | 46 |
| 39 ElementInfoCollector(this.compiler, this.closedWorld); | 47 ElementInfoCollector(this.compiler, this.closedWorld); |
| 40 | 48 |
| 41 void run() { | 49 void run() { |
| 42 compiler.dumpInfoTask._constantToNode.forEach((constant, node) { | 50 compiler.dumpInfoTask._constantToNode.forEach((constant, node) { |
| 43 // TODO(sigmund): add dependencies on other constants | 51 // TODO(sigmund): add dependencies on other constants |
| 44 var size = compiler.dumpInfoTask._nodeToSize[node]; | 52 var size = compiler.dumpInfoTask._nodeToSize[node]; |
| 45 var code = jsAst.prettyPrint(node, compiler.options); | 53 var code = jsAst.prettyPrint(node, compiler.options); |
| 46 var info = new ConstantInfo( | 54 var info = new ConstantInfo( |
| 47 size: size, code: code, outputUnit: _unitInfoForConstant(constant)); | 55 size: size, code: code, outputUnit: _unitInfoForConstant(constant)); |
| 48 _constantToInfo[constant] = info; | 56 _constantToInfo[constant] = info; |
| 49 result.constants.add(info); | 57 result.constants.add(info); |
| 50 }); | 58 }); |
| 51 (compiler.libraryLoader.libraries as Iterable<LibraryElement>) | 59 environment.libraries.forEach(visitLibrary); |
| 52 .forEach(visit); | 60 closedWorld.allTypedefs.forEach(visitTypedef); |
| 53 } | 61 } |
| 54 | 62 |
| 55 Info visit(Element e, [_]) => e.accept(this, null); | 63 /// Whether to emit information about [entity]. |
| 56 | |
| 57 /// Whether to emit information about [element]. | |
| 58 /// | 64 /// |
| 59 /// By default we emit information for any element that contributes to the | 65 /// By default we emit information for any entity that contributes to the |
| 60 /// output size. Either because the it is a function being emitted or inlined, | 66 /// output size. Either because it is a function being emitted or inlined, |
| 61 /// or because it is an element that holds dependencies to other elements. | 67 /// or because it is an entity that holds dependencies to other entities. |
| 62 bool shouldKeep(Element element) { | 68 bool shouldKeep(Entity entity) { |
| 63 return compiler.dumpInfoTask.impacts.containsKey(element) || | 69 return compiler.dumpInfoTask.impacts.containsKey(entity) || |
| 64 compiler.dumpInfoTask.inlineCount.containsKey(element); | 70 compiler.dumpInfoTask.inlineCount.containsKey(entity); |
| 65 } | 71 } |
| 66 | 72 |
| 67 /// Visits [element] and produces it's corresponding info. | 73 LibraryInfo visitLibrary(LibraryEntity lib) { |
| 68 Info process(Entity element) { | 74 String libname = environment.getLibraryName(lib); |
| 69 // TODO(sigmund): change the visit order to eliminate the need to check | 75 if (libname.isEmpty) { |
| 70 // whether or not an element has been processed. | 76 libname = '<unnamed>'; |
| 71 return _elementToInfo.putIfAbsent(element, () => visit(element)); | 77 } |
| 72 } | 78 int size = compiler.dumpInfoTask.sizeOf(lib); |
| 79 LibraryInfo info = new LibraryInfo(libname, lib.canonicalUri, null, size); | |
| 80 _entityToInfo[lib] = info; | |
| 73 | 81 |
| 74 Info visitElement(Element element, _) => null; | 82 environment.forEachLibraryMember(lib, (MemberEntity member) { |
| 75 | 83 if (member.isFunction || member.isGetter || member.isSetter) { |
| 76 FunctionInfo visitConstructorBodyElement(ConstructorBodyElement e, _) { | 84 FunctionInfo functionInfo = visitFunction(member); |
| 77 return visitFunctionElement(e.constructor, _); | 85 if (functionInfo != null) { |
| 78 } | 86 info.topLevelFunctions.add(functionInfo); |
| 79 | 87 functionInfo.parent = info; |
| 80 LibraryInfo visitLibraryElement(LibraryElement element, _) { | 88 } |
| 81 String libname = element.hasLibraryName ? element.libraryName : "<unnamed>"; | 89 } else if (member.isField) { |
| 82 int size = compiler.dumpInfoTask.sizeOf(element); | 90 FieldInfo fieldInfo = visitField(member); |
| 83 LibraryInfo info = | 91 if (fieldInfo != null) { |
| 84 new LibraryInfo(libname, element.canonicalUri, null, size); | 92 info.topLevelVariables.add(fieldInfo); |
| 85 _elementToInfo[element] = info; | 93 fieldInfo.parent = info; |
| 86 | 94 } |
| 87 LibraryElement realElement = element.isPatched ? element.patch : element; | |
| 88 realElement.forEachLocalMember((Element member) { | |
| 89 Info child = this.process(member); | |
| 90 if (child is ClassInfo) { | |
| 91 info.classes.add(child); | |
| 92 child.parent = info; | |
| 93 } else if (child is FunctionInfo) { | |
| 94 info.topLevelFunctions.add(child); | |
| 95 child.parent = info; | |
| 96 } else if (child is FieldInfo) { | |
| 97 info.topLevelVariables.add(child); | |
| 98 child.parent = info; | |
| 99 } else if (child is TypedefInfo) { | |
| 100 info.typedefs.add(child); | |
| 101 child.parent = info; | |
| 102 } else if (child != null) { | |
| 103 print('unexpected child of $info: $child ==> ${child.runtimeType}'); | |
| 104 assert(false); | |
| 105 } | 95 } |
| 106 }); | 96 }); |
| 107 | 97 |
| 108 if (info.isEmpty && !shouldKeep(element)) return null; | 98 environment.forEachClass(lib, (ClassEntity clazz) { |
| 99 ClassInfo classInfo = visitClass(clazz); | |
| 100 if (classInfo != null) { | |
| 101 info.classes.add(classInfo); | |
| 102 classInfo.parent = info; | |
| 103 } | |
| 104 }); | |
| 105 | |
| 106 if (info.isEmpty && !shouldKeep(lib)) return null; | |
| 109 result.libraries.add(info); | 107 result.libraries.add(info); |
| 110 return info; | 108 return info; |
| 111 } | 109 } |
| 112 | 110 |
| 113 TypedefInfo visitTypedefElement(TypedefElement element, _) { | 111 TypedefInfo visitTypedef(TypedefEntity typdef) { |
| 114 if (!element.isResolved) return null; | 112 var type = environment.getFunctionTypeOfTypedef(typdef); |
| 115 TypedefInfo info = new TypedefInfo( | 113 TypedefInfo info = |
| 116 element.name, '${element.alias}', _unitInfoForElement(element)); | 114 new TypedefInfo(typdef.name, '$type', _unitInfoForEntity(typdef)); |
| 117 _elementToInfo[element] = info; | 115 _entityToInfo[typdef] = info; |
| 116 LibraryInfo lib = _entityToInfo[typdef.library]; | |
| 117 lib.typedefs.add(info); | |
| 118 info.parent = lib; | |
| 118 result.typedefs.add(info); | 119 result.typedefs.add(info); |
| 119 return info; | 120 return info; |
| 120 } | 121 } |
| 121 | 122 |
| 122 _resultOfMember(MemberElement e) => | 123 GlobalTypeInferenceMemberResult _resultOfMember(MemberEntity e) => |
| 123 compiler.globalInference.results.resultOfMember(e); | 124 compiler.globalInference.results.resultOfMember(e); |
| 124 | 125 |
| 125 _resultOfParameter(ParameterElement e) => | 126 GlobalTypeInferenceElementResult _resultOfParameter(Local e) => |
| 126 compiler.globalInference.results.resultOfParameter(e); | 127 compiler.globalInference.results.resultOfParameter(e); |
| 127 | 128 |
| 128 FieldInfo visitFieldElement(FieldElement element, _) { | 129 FieldInfo visitField(FieldEntity field) { |
| 129 if (!compiler.resolution.hasBeenResolved(element)) return null; | 130 if (!_hasBeenResolved(field)) return null; |
| 130 TypeMask inferredType = _resultOfMember(element).type; | 131 TypeMask inferredType = _resultOfMember(field).type; |
| 131 // If a field has an empty inferred type it is never used. | 132 // If a field has an empty inferred type it is never used. |
| 132 if (inferredType == null || inferredType.isEmpty) return null; | 133 if (inferredType == null || inferredType.isEmpty) return null; |
| 133 | 134 |
| 134 int size = compiler.dumpInfoTask.sizeOf(element); | 135 int size = compiler.dumpInfoTask.sizeOf(field); |
| 135 String code = compiler.dumpInfoTask.codeOf(element); | 136 String code = compiler.dumpInfoTask.codeOf(field); |
| 136 if (code != null) size += code.length; | 137 if (code != null) size += code.length; |
| 137 | 138 |
| 138 FieldInfo info = new FieldInfo( | 139 FieldInfo info = new FieldInfo( |
| 139 name: element.name, | 140 name: field.name, |
| 140 type: '${element.type}', | 141 type: '${environment.getFieldType(field)}', |
| 141 inferredType: '$inferredType', | 142 inferredType: '$inferredType', |
| 142 code: code, | 143 code: code, |
| 143 outputUnit: _unitInfoForElement(element), | 144 outputUnit: _unitInfoForEntity(field), |
| 144 isConst: element.isConst); | 145 isConst: field.isConst); |
| 145 _elementToInfo[element] = info; | 146 _entityToInfo[field] = info; |
| 146 if (element.isConst) { | 147 if (codegenWorldBuilder.hasConstantFieldInitializer(field)) { |
| 147 var value = compiler.backend.constantCompilerTask | 148 info.initializer = _constantToInfo[ |
| 148 .getConstantValue(element.constant); | 149 codegenWorldBuilder.getConstantFieldInitializer(field)]; |
| 149 if (value != null) { | |
| 150 info.initializer = _constantToInfo[value]; | |
| 151 } | |
| 152 } | 150 } |
| 153 | 151 |
| 154 if (JavaScriptBackend.TRACE_METHOD == 'post') { | 152 if (JavaScriptBackend.TRACE_METHOD == 'post') { |
| 155 // We use element.hashCode because it is globally unique and it is | 153 // We use field.hashCode because it is globally unique and it is |
| 156 // available while we are doing codegen. | 154 // available while we are doing codegen. |
| 157 info.coverageId = '${element.hashCode}'; | 155 info.coverageId = '${field.hashCode}'; |
| 158 } | 156 } |
| 159 | 157 |
| 160 int closureSize = _addClosureInfo(info, element); | 158 int closureSize = _addClosureInfo(info, field); |
| 161 info.size = size + closureSize; | 159 info.size = size + closureSize; |
| 162 | 160 |
| 163 result.fields.add(info); | 161 result.fields.add(info); |
| 164 return info; | 162 return info; |
| 165 } | 163 } |
| 166 | 164 |
| 167 ClassInfo visitClassElement(ClassElement element, _) { | 165 ClassInfo visitClass(ClassEntity clazz) { |
| 166 // Omit class if it is not needed. | |
| 167 if (!_hasClassBeenResolved(clazz)) return null; | |
| 168 | |
| 168 ClassInfo classInfo = new ClassInfo( | 169 ClassInfo classInfo = new ClassInfo( |
| 169 name: element.name, | 170 name: clazz.name, |
| 170 isAbstract: element.isAbstract, | 171 isAbstract: clazz.isAbstract, |
| 171 outputUnit: _unitInfoForElement(element)); | 172 outputUnit: _unitInfoForEntity(clazz)); |
| 172 _elementToInfo[element] = classInfo; | 173 _entityToInfo[clazz] = classInfo; |
| 173 | 174 |
| 174 int size = compiler.dumpInfoTask.sizeOf(element); | 175 int size = compiler.dumpInfoTask.sizeOf(clazz); |
| 175 element.forEachLocalMember((Element member) { | 176 environment.forEachClassMember(clazz, (declarer, member) { |
| 176 Info info = this.process(member); | 177 // We only care about local members. |
| 177 if (info == null) return; | 178 if (declarer != clazz) return; |
| 178 if (info is FieldInfo) { | 179 |
| 179 classInfo.fields.add(info); | 180 if (member.isFunction || member.isGetter || member.isSetter) { |
| 180 info.parent = classInfo; | 181 FunctionInfo functionInfo = visitFunction(member); |
| 181 for (ClosureInfo closureInfo in info.closures) { | 182 if (functionInfo != null) { |
| 182 size += closureInfo.size; | 183 classInfo.functions.add(functionInfo); |
| 184 functionInfo.parent = classInfo; | |
| 185 for (var closureInfo in functionInfo.closures) { | |
| 186 size += closureInfo.size; | |
| 187 } | |
| 188 } | |
| 189 } else if (member.isField) { | |
| 190 FieldInfo fieldInfo = visitField(member); | |
| 191 if (fieldInfo != null) { | |
| 192 classInfo.fields.add(fieldInfo); | |
| 193 fieldInfo.parent = classInfo; | |
| 194 for (var closureInfo in fieldInfo.closures) { | |
| 195 size += closureInfo.size; | |
| 196 } | |
| 183 } | 197 } |
| 184 } else { | 198 } else { |
| 185 assert(info is FunctionInfo); | 199 throw new StateError('Class member not a function or field'); |
| 186 classInfo.functions.add(info); | 200 } |
| 187 info.parent = classInfo; | 201 }); |
| 188 for (ClosureInfo closureInfo in (info as FunctionInfo).closures) { | 202 environment.forEachConstructor(clazz, (constructor) { |
| 203 FunctionInfo functionInfo = visitFunction(constructor); | |
| 204 if (functionInfo != null) { | |
| 205 classInfo.functions.add(functionInfo); | |
| 206 functionInfo.parent = classInfo; | |
| 207 for (var closureInfo in functionInfo.closures) { | |
| 189 size += closureInfo.size; | 208 size += closureInfo.size; |
| 190 } | 209 } |
| 191 } | 210 } |
| 192 }); | 211 }, ensureResolved: false); |
| 193 | 212 |
| 194 classInfo.size = size; | 213 classInfo.size = size; |
| 195 | 214 |
| 196 // Omit element if it is not needed. | 215 if (!compiler.backend.emitter.neededClasses.contains(clazz) && |
| 197 JavaScriptBackend backend = compiler.backend; | |
| 198 if (!backend.emitter.neededClasses.contains(element) && | |
| 199 classInfo.fields.isEmpty && | 216 classInfo.fields.isEmpty && |
| 200 classInfo.functions.isEmpty) { | 217 classInfo.functions.isEmpty) { |
| 201 return null; | 218 return null; |
| 202 } | 219 } |
| 220 | |
| 203 result.classes.add(classInfo); | 221 result.classes.add(classInfo); |
| 204 return classInfo; | 222 return classInfo; |
| 205 } | 223 } |
| 206 | 224 |
| 207 ClosureInfo visitClosureClassElement(ClosureClassElement element, _) { | 225 ClosureInfo visitClosureClass(ClosureClassElement element) { |
| 208 ClosureInfo closureInfo = new ClosureInfo( | 226 ClosureInfo closureInfo = new ClosureInfo( |
| 209 name: element.name, | 227 name: element.name, |
| 210 outputUnit: _unitInfoForElement(element), | 228 outputUnit: _unitInfoForEntity(element), |
| 211 size: compiler.dumpInfoTask.sizeOf(element)); | 229 size: compiler.dumpInfoTask.sizeOf(element)); |
| 212 _elementToInfo[element] = closureInfo; | 230 _entityToInfo[element] = closureInfo; |
| 213 | 231 |
| 214 ClosureRepresentationInfo closureRepresentation = | 232 ClosureRepresentationInfo closureRepresentation = |
| 215 compiler.backendStrategy.closureDataLookup.getClosureInfo(element.node); | 233 compiler.backendStrategy.closureDataLookup.getClosureInfo(element.node); |
| 216 assert(closureRepresentation.closureClassEntity == element); | 234 assert(closureRepresentation.closureClassEntity == element); |
| 217 | 235 |
| 218 FunctionInfo functionInfo = this.process(closureRepresentation.callMethod); | 236 FunctionInfo functionInfo = visitFunction(closureRepresentation.callMethod); |
| 219 if (functionInfo == null) return null; | 237 if (functionInfo == null) return null; |
| 220 closureInfo.function = functionInfo; | 238 closureInfo.function = functionInfo; |
| 221 functionInfo.parent = closureInfo; | 239 functionInfo.parent = closureInfo; |
| 222 | 240 |
| 223 result.closures.add(closureInfo); | 241 result.closures.add(closureInfo); |
| 224 return closureInfo; | 242 return closureInfo; |
| 225 } | 243 } |
| 226 | 244 |
| 227 FunctionInfo visitFunctionElement(FunctionElement element, _) { | 245 FunctionInfo visitFunction(FunctionEntity function) { |
| 228 int size = compiler.dumpInfoTask.sizeOf(element); | 246 int size = compiler.dumpInfoTask.sizeOf(function); |
| 229 // TODO(sigmund): consider adding a small info to represent unreachable | 247 // TODO(sigmund): consider adding a small info to represent unreachable |
| 230 // code here. | 248 // code here. |
| 231 if (size == 0 && !shouldKeep(element)) return null; | 249 if (size == 0 && !shouldKeep(function)) return null; |
| 232 | 250 |
| 233 String name = element.name; | 251 // TODO(het): use 'toString' instead of 'text'? It will add '=' for setters |
| 234 int kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND; | 252 String name = function.memberName.text; |
| 235 var enclosingElement = element.enclosingElement; | 253 int kind; |
| 236 if (enclosingElement.isField || | 254 if (function.isStatic || function.isTopLevel) { |
| 237 enclosingElement.isFunction || | |
| 238 element.isClosure || | |
| 239 enclosingElement.isConstructor) { | |
| 240 kind = FunctionInfo.CLOSURE_FUNCTION_KIND; | |
| 241 name = "<unnamed>"; | |
| 242 } else if (element.isStatic) { | |
| 243 kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND; | 255 kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND; |
| 244 } else if (enclosingElement.isClass) { | 256 } else if (function.enclosingClass != null) { |
| 245 kind = FunctionInfo.METHOD_FUNCTION_KIND; | 257 kind = FunctionInfo.METHOD_FUNCTION_KIND; |
| 246 } | 258 } |
| 247 | 259 |
| 248 if (element.isConstructor) { | 260 if (function.isConstructor) { |
| 249 name = name == "" | 261 name = name == "" |
| 250 ? "${element.enclosingElement.name}" | 262 ? "${function.enclosingClass.name}" |
| 251 : "${element.enclosingElement.name}.${element.name}"; | 263 : "${function.enclosingClass.name}.${function.name}"; |
| 252 kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND; | 264 kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND; |
| 253 } | 265 } |
| 254 | 266 |
| 267 assert(kind != null); | |
| 268 | |
| 255 FunctionModifiers modifiers = new FunctionModifiers( | 269 FunctionModifiers modifiers = new FunctionModifiers( |
| 256 isStatic: element.isStatic, | 270 isStatic: function.isStatic, |
| 257 isConst: element.isConst, | 271 isConst: function.isConst, |
| 258 isFactory: element.isFactoryConstructor, | 272 isFactory: function.isConstructor |
| 259 isExternal: element.isPatched); | 273 ? (function as ConstructorEntity).isFactoryConstructor |
| 260 String code = compiler.dumpInfoTask.codeOf(element); | 274 : false, |
| 275 isExternal: function.isExternal, | |
| 276 ); | |
| 277 String code = compiler.dumpInfoTask.codeOf(function); | |
| 261 | 278 |
| 262 String returnType = null; | |
| 263 List<ParameterInfo> parameters = <ParameterInfo>[]; | 279 List<ParameterInfo> parameters = <ParameterInfo>[]; |
| 264 if (element.hasFunctionSignature) { | 280 List<String> inferredParameterTypes = <String>[]; |
| 265 FunctionElement implementation = element.implementation; | 281 codegenWorldBuilder.forEachParameterAsLocal(function, (parameter) { |
| 266 FunctionSignature signature = implementation.functionSignature; | 282 inferredParameterTypes.add('${_resultOfParameter(parameter).type}'); |
| 267 signature.forEachParameter((parameter) { | 283 }); |
| 268 parameters.add(new ParameterInfo(parameter.name, | 284 int parameterIndex = 0; |
| 269 '${_resultOfParameter(parameter).type}', '${parameter.node.type}')); | 285 codegenWorldBuilder.forEachParameter(function, (type, name, _) { |
| 270 }); | 286 parameters.add(new ParameterInfo( |
| 271 returnType = '${element.type.returnType}'; | 287 name, inferredParameterTypes[parameterIndex++], '$type')); |
| 272 } | 288 }); |
| 273 | 289 |
| 274 MethodElement method; | 290 var functionType = environment.getFunctionType(function); |
| 275 if (element is LocalFunctionElement) { | 291 String returnType = '${functionType.returnType}'; |
| 276 method = element.callMethod; | |
| 277 } else { | |
| 278 method = element; | |
| 279 } | |
| 280 | 292 |
| 281 String inferredReturnType = '${_resultOfMember(method).returnType}'; | 293 String inferredReturnType = '${_resultOfMember(function).returnType}'; |
| 282 String sideEffects = '${closedWorld.getSideEffectsOfElement(method)}'; | 294 String sideEffects = '${closedWorld.getSideEffectsOfElement(function)}'; |
| 283 | 295 |
| 284 int inlinedCount = compiler.dumpInfoTask.inlineCount[element]; | 296 int inlinedCount = compiler.dumpInfoTask.inlineCount[function]; |
| 285 if (inlinedCount == null) inlinedCount = 0; | 297 if (inlinedCount == null) inlinedCount = 0; |
| 286 | 298 |
| 287 FunctionInfo info = new FunctionInfo( | 299 FunctionInfo info = new FunctionInfo( |
| 288 name: name, | 300 name: name, |
| 289 functionKind: kind, | 301 functionKind: kind, |
| 290 modifiers: modifiers, | 302 modifiers: modifiers, |
| 291 returnType: returnType, | 303 returnType: returnType, |
| 292 inferredReturnType: inferredReturnType, | 304 inferredReturnType: inferredReturnType, |
| 293 parameters: parameters, | 305 parameters: parameters, |
| 294 sideEffects: sideEffects, | 306 sideEffects: sideEffects, |
| 295 inlinedCount: inlinedCount, | 307 inlinedCount: inlinedCount, |
| 296 code: code, | 308 code: code, |
| 297 type: element.type.toString(), | 309 type: functionType.toString(), |
| 298 outputUnit: _unitInfoForElement(element)); | 310 outputUnit: _unitInfoForEntity(function)); |
| 299 _elementToInfo[element] = info; | 311 _entityToInfo[function] = info; |
| 300 | 312 |
| 301 if (element is MemberElement) { | 313 int closureSize = _addClosureInfo(info, function); |
| 302 int closureSize = _addClosureInfo(info, element as MemberElement); | 314 size += closureSize; |
| 303 size += closureSize; | |
| 304 } else { | |
| 305 info.closures = <ClosureInfo>[]; | |
| 306 } | |
| 307 | 315 |
| 308 if (JavaScriptBackend.TRACE_METHOD == 'post') { | 316 if (JavaScriptBackend.TRACE_METHOD == 'post') { |
| 309 // We use element.hashCode because it is globally unique and it is | 317 // We use function.hashCode because it is globally unique and it is |
| 310 // available while we are doing codegen. | 318 // available while we are doing codegen. |
| 311 info.coverageId = '${element.hashCode}'; | 319 info.coverageId = '${function.hashCode}'; |
| 312 } | 320 } |
| 313 | 321 |
| 314 info.size = size; | 322 info.size = size; |
| 315 | 323 |
| 316 result.functions.add(info); | 324 result.functions.add(info); |
| 317 return info; | 325 return info; |
| 318 } | 326 } |
| 319 | 327 |
| 320 /// Adds closure information to [info], using all nested closures in [member]. | 328 /// Adds closure information to [info], using all nested closures in [member]. |
| 321 /// | 329 /// |
| 322 /// Returns the total size of the nested closures, to add to the info size. | 330 /// Returns the total size of the nested closures, to add to the info size. |
| 323 int _addClosureInfo(Info info, MemberElement member) { | 331 int _addClosureInfo(Info info, MemberEntity member) { |
| 324 assert(info is FunctionInfo || info is FieldInfo); | 332 assert(info is FunctionInfo || info is FieldInfo); |
| 325 int size = 0; | 333 int size = 0; |
| 326 List<ClosureInfo> nestedClosures = <ClosureInfo>[]; | 334 List<ClosureInfo> nestedClosures = <ClosureInfo>[]; |
| 327 for (Element function in member.nestedClosures) { | 335 environment.forEachNestedClosure(member, (closure) { |
| 328 assert(function is SynthesizedCallMethodElementX); | 336 ClosureInfo closureInfo = visitClosureClass(closure.enclosingClass); |
| 329 SynthesizedCallMethodElementX callMethod = function; | 337 if (closureInfo != null) { |
| 330 ClosureInfo closure = this.process(callMethod.closureClass); | 338 closureInfo.parent = info; |
| 331 if (closure != null) { | 339 nestedClosures.add(closureInfo); |
| 332 closure.parent = info; | 340 size += closureInfo.size; |
| 333 nestedClosures.add(closure); | |
| 334 size += closure.size; | |
| 335 } | 341 } |
| 336 } | 342 }); |
| 337 if (info is FunctionInfo) info.closures = nestedClosures; | 343 if (info is FunctionInfo) info.closures = nestedClosures; |
| 338 if (info is FieldInfo) info.closures = nestedClosures; | 344 if (info is FieldInfo) info.closures = nestedClosures; |
| 339 | 345 |
| 340 return size; | 346 return size; |
| 341 } | 347 } |
| 342 | 348 |
| 343 OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) { | 349 OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) { |
| 344 return _outputToInfo.putIfAbsent(outputUnit, () { | 350 return _outputToInfo.putIfAbsent(outputUnit, () { |
| 345 // Dump-info currently only works with the full emitter. If another | 351 // Dump-info currently only works with the full emitter. If another |
| 346 // emitter is used it will fail here. | 352 // emitter is used it will fail here. |
| 347 JavaScriptBackend backend = compiler.backend; | 353 JavaScriptBackend backend = compiler.backend; |
| 348 assert(outputUnit.name != null || outputUnit.isMainOutput); | 354 assert(outputUnit.name != null || outputUnit.isMainOutput); |
| 349 OutputUnitInfo info = new OutputUnitInfo( | 355 OutputUnitInfo info = new OutputUnitInfo( |
| 350 outputUnit.name, backend.emitter.emitter.generatedSize(outputUnit)); | 356 outputUnit.name, backend.emitter.emitter.generatedSize(outputUnit)); |
| 351 info.imports.addAll(compiler.deferredLoadTask.getImportNames(outputUnit)); | 357 info.imports.addAll(compiler.deferredLoadTask.getImportNames(outputUnit)); |
| 352 result.outputUnits.add(info); | 358 result.outputUnits.add(info); |
| 353 return info; | 359 return info; |
| 354 }); | 360 }); |
| 355 } | 361 } |
| 356 | 362 |
| 357 OutputUnitInfo _unitInfoForElement(Element element) { | 363 OutputUnitInfo _unitInfoForEntity(Entity entity) { |
| 358 return _infoFromOutputUnit( | 364 return _infoFromOutputUnit( |
| 359 compiler.deferredLoadTask.outputUnitForElement(element)); | 365 compiler.deferredLoadTask.outputUnitForEntity(entity)); |
| 360 } | 366 } |
| 361 | 367 |
| 362 OutputUnitInfo _unitInfoForConstant(ConstantValue constant) { | 368 OutputUnitInfo _unitInfoForConstant(ConstantValue constant) { |
| 363 OutputUnit outputUnit = | 369 OutputUnit outputUnit = |
| 364 compiler.deferredLoadTask.outputUnitForConstant(constant); | 370 compiler.deferredLoadTask.outputUnitForConstant(constant); |
| 365 if (outputUnit == null) { | 371 if (outputUnit == null) { |
| 366 assert(constant is InterceptorConstantValue); | 372 assert(constant is InterceptorConstantValue); |
| 367 return null; | 373 return null; |
| 368 } | 374 } |
| 369 return _infoFromOutputUnit(outputUnit); | 375 return _infoFromOutputUnit(outputUnit); |
| 370 } | 376 } |
| 377 | |
| 378 bool _hasBeenResolved(Entity entity) { | |
| 379 return compiler.enqueuer.resolution.processedEntities.contains(entity); | |
|
Siggi Cherem (dart-lang)
2017/08/30 21:51:48
I believe using the `resolution` processedEntities
Harry Terkelsen
2017/08/30 22:14:46
Done.
| |
| 380 } | |
| 381 | |
| 382 bool _hasClassBeenResolved(ClassEntity cls) { | |
| 383 return compiler.backend.mirrorsData.isClassResolved(cls); | |
| 384 } | |
| 371 } | 385 } |
| 372 | 386 |
| 373 class Selection { | 387 class Selection { |
| 374 final Entity selectedElement; | 388 final Entity selectedEntity; |
| 375 final ReceiverConstraint mask; | 389 final ReceiverConstraint mask; |
| 376 Selection(this.selectedElement, this.mask); | 390 Selection(this.selectedEntity, this.mask); |
| 377 } | 391 } |
| 378 | 392 |
| 379 /// Interface used to record information from different parts of the compiler so | 393 /// Interface used to record information from different parts of the compiler so |
| 380 /// we can emit them in the dump-info task. | 394 /// we can emit them in the dump-info task. |
| 381 // TODO(sigmund,het): move more features here. Ideally the dump-info task | 395 // TODO(sigmund,het): move more features here. Ideally the dump-info task |
| 382 // shouldn't reach into internals of other parts of the compiler. For example, | 396 // shouldn't reach into internals of other parts of the compiler. For example, |
| 383 // we currently reach into the full emitter and as a result we don't support | 397 // we currently reach into the full emitter and as a result we don't support |
| 384 // dump-info when using the startup-emitter (issue #24190). | 398 // dump-info when using the startup-emitter (issue #24190). |
| 385 abstract class InfoReporter { | 399 abstract class InfoReporter { |
| 386 void reportInlined(Element element, Element inlinedFrom); | 400 void reportInlined(Element element, Element inlinedFrom); |
| 387 } | 401 } |
| 388 | 402 |
| 389 class DumpInfoTask extends CompilerTask implements InfoReporter { | 403 class DumpInfoTask extends CompilerTask implements InfoReporter { |
| 390 static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Dump info'); | 404 static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Dump info'); |
| 391 final Compiler compiler; | 405 final Compiler compiler; |
| 392 | 406 |
| 393 DumpInfoTask(Compiler compiler) | 407 DumpInfoTask(Compiler compiler) |
| 394 : compiler = compiler, | 408 : compiler = compiler, |
| 395 super(compiler.measurer); | 409 super(compiler.measurer); |
| 396 | 410 |
| 397 String get name => "Dump Info"; | 411 String get name => "Dump Info"; |
| 398 | 412 |
| 399 ElementInfoCollector infoCollector; | 413 ElementInfoCollector infoCollector; |
| 400 | 414 |
| 401 /// The size of the generated output. | 415 /// The size of the generated output. |
| 402 int _programSize; | 416 int _programSize; |
| 403 | 417 |
| 404 // A set of javascript AST nodes that we care about the size of. | 418 // A set of javascript AST nodes that we care about the size of. |
| 405 // This set is automatically populated when registerElementAst() | 419 // This set is automatically populated when registerEntityAst() |
| 406 // is called. | 420 // is called. |
| 407 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); | 421 final Set<jsAst.Node> _tracking = new Set<jsAst.Node>(); |
| 408 // A mapping from Dart Elements to Javascript AST Nodes. | 422 |
| 409 final Map<Entity, List<jsAst.Node>> _elementToNodes = | 423 // A mapping from Dart Entities to Javascript AST Nodes. |
| 424 final Map<Entity, List<jsAst.Node>> _entityToNodes = | |
| 410 <Entity, List<jsAst.Node>>{}; | 425 <Entity, List<jsAst.Node>>{}; |
| 411 final Map<ConstantValue, jsAst.Node> _constantToNode = | 426 final Map<ConstantValue, jsAst.Node> _constantToNode = |
| 412 <ConstantValue, jsAst.Node>{}; | 427 <ConstantValue, jsAst.Node>{}; |
| 428 | |
| 413 // A mapping from Javascript AST Nodes to the size of their | 429 // A mapping from Javascript AST Nodes to the size of their |
| 414 // pretty-printed contents. | 430 // pretty-printed contents. |
| 415 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; | 431 final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{}; |
| 416 | 432 |
| 417 final Map<Element, int> inlineCount = <Element, int>{}; | 433 final Map<Entity, int> inlineCount = <Entity, int>{}; |
| 418 // A mapping from an element to a list of elements that are | 434 |
| 435 // A mapping from an entity to a list of entities that are | |
| 419 // inlined inside of it. | 436 // inlined inside of it. |
| 420 final Map<Element, List<Element>> inlineMap = <Element, List<Element>>{}; | 437 final Map<Entity, List<Entity>> inlineMap = <Entity, List<Entity>>{}; |
| 421 | 438 |
| 422 final Map<MemberEntity, WorldImpact> impacts = <MemberEntity, WorldImpact>{}; | 439 final Map<MemberEntity, WorldImpact> impacts = <MemberEntity, WorldImpact>{}; |
| 423 | 440 |
| 424 /// Register the size of the generated output. | 441 /// Register the size of the generated output. |
| 425 void reportSize(int programSize) { | 442 void reportSize(int programSize) { |
| 426 _programSize = programSize; | 443 _programSize = programSize; |
| 427 } | 444 } |
| 428 | 445 |
| 429 void reportInlined(Element element, Element inlinedFrom) { | 446 void reportInlined(Element element, Element inlinedFrom) { |
| 430 element = element.declaration; | 447 element = element.declaration; |
| 431 inlinedFrom = inlinedFrom.declaration; | 448 inlinedFrom = inlinedFrom.declaration; |
| 432 | 449 |
| 433 inlineCount.putIfAbsent(element, () => 0); | 450 inlineCount.putIfAbsent(element, () => 0); |
| 434 inlineCount[element] += 1; | 451 inlineCount[element] += 1; |
| 435 inlineMap.putIfAbsent(inlinedFrom, () => new List<Element>()); | 452 inlineMap.putIfAbsent(inlinedFrom, () => new List<Element>()); |
| 436 inlineMap[inlinedFrom].add(element); | 453 inlineMap[inlinedFrom].add(element); |
| 437 } | 454 } |
| 438 | 455 |
| 439 void registerImpact(MemberEntity element, WorldImpact impact) { | 456 void registerImpact(MemberEntity member, WorldImpact impact) { |
| 440 if (compiler.options.dumpInfo) { | 457 if (compiler.options.dumpInfo) { |
| 441 impacts[element] = impact; | 458 impacts[member] = impact; |
| 442 } | 459 } |
| 443 } | 460 } |
| 444 | 461 |
| 445 void unregisterImpact(var impactSource) { | 462 void unregisterImpact(var impactSource) { |
| 446 impacts.remove(impactSource); | 463 impacts.remove(impactSource); |
| 447 } | 464 } |
| 448 | 465 |
| 449 /** | 466 /// Returns an iterable of [Selection]s that are used by [entity]. Each |
| 450 * Returns an iterable of [Selection]s that are used by | 467 /// [Selection] contains an entity that is used and the selector that |
| 451 * [element]. Each [Selection] contains an element that is | 468 /// selected the entity. |
| 452 * used and the selector that selected the element. | 469 Iterable<Selection> getRetaining(Entity entity, ClosedWorld closedWorld) { |
| 453 */ | 470 WorldImpact impact = impacts[entity]; |
| 454 Iterable<Selection> getRetaining(Element element, ClosedWorld closedWorld) { | |
| 455 WorldImpact impact = impacts[element]; | |
| 456 if (impact == null) return const <Selection>[]; | 471 if (impact == null) return const <Selection>[]; |
| 457 | 472 |
| 458 var selections = <Selection>[]; | 473 var selections = <Selection>[]; |
| 459 compiler.impactStrategy.visitImpact( | 474 compiler.impactStrategy.visitImpact( |
| 460 element, | 475 entity, |
| 461 impact, | 476 impact, |
| 462 new WorldImpactVisitorImpl(visitDynamicUse: (dynamicUse) { | 477 new WorldImpactVisitorImpl(visitDynamicUse: (dynamicUse) { |
| 463 selections.addAll(closedWorld | 478 selections.addAll(closedWorld |
| 464 .locateMembers(dynamicUse.selector, dynamicUse.mask) | 479 .locateMembers(dynamicUse.selector, dynamicUse.mask) |
| 465 .map((MemberEntity e) => new Selection(e, dynamicUse.mask))); | 480 .map((MemberEntity e) => new Selection(e, dynamicUse.mask))); |
| 466 }, visitStaticUse: (staticUse) { | 481 }, visitStaticUse: (staticUse) { |
| 467 selections.add(new Selection(staticUse.element, null)); | 482 selections.add(new Selection(staticUse.element, null)); |
| 468 }), | 483 }), |
| 469 IMPACT_USE); | 484 IMPACT_USE); |
| 470 return selections; | 485 return selections; |
| 471 } | 486 } |
| 472 | 487 |
| 473 // Returns true if we care about tracking the size of | 488 // Returns true if we care about tracking the size of |
| 474 // this node. | 489 // this node. |
| 475 bool isTracking(jsAst.Node code) { | 490 bool isTracking(jsAst.Node code) { |
| 476 if (compiler.options.dumpInfo) { | 491 if (compiler.options.dumpInfo) { |
| 477 return _tracking.contains(code); | 492 return _tracking.contains(code); |
| 478 } else { | 493 } else { |
| 479 return false; | 494 return false; |
| 480 } | 495 } |
| 481 } | 496 } |
| 482 | 497 |
| 483 // Registers that a javascript AST node `code` was produced by the | 498 /// Registers that a javascript AST node [code] was produced by the dart |
| 484 // dart Element `element`. | 499 /// Entity [entity]. |
| 485 void registerElementAst(Entity element, jsAst.Node code) { | 500 void registerEntityAst(Entity entity, jsAst.Node code) { |
| 486 if (compiler.options.dumpInfo) { | 501 if (compiler.options.dumpInfo) { |
| 487 _elementToNodes | 502 _entityToNodes |
| 488 .putIfAbsent(element, () => new List<jsAst.Node>()) | 503 .putIfAbsent(entity, () => new List<jsAst.Node>()) |
| 489 .add(code); | 504 .add(code); |
| 490 _tracking.add(code); | 505 _tracking.add(code); |
| 491 } | 506 } |
| 492 } | 507 } |
| 493 | 508 |
| 494 void registerConstantAst(ConstantValue constant, jsAst.Node code) { | 509 void registerConstantAst(ConstantValue constant, jsAst.Node code) { |
| 495 if (compiler.options.dumpInfo) { | 510 if (compiler.options.dumpInfo) { |
| 496 assert(_constantToNode[constant] == null || | 511 assert(_constantToNode[constant] == null || |
| 497 _constantToNode[constant] == code); | 512 _constantToNode[constant] == code); |
| 498 _constantToNode[constant] = code; | 513 _constantToNode[constant] = code; |
| 499 _tracking.add(code); | 514 _tracking.add(code); |
| 500 } | 515 } |
| 501 } | 516 } |
| 502 | 517 |
| 503 // Records the size of a dart AST node after it has been | 518 /// Records the size of a dart AST node after it has been pretty-printed into |
| 504 // pretty-printed into the output buffer. | 519 /// the output buffer. |
| 505 void recordAstSize(jsAst.Node node, int size) { | 520 void recordAstSize(jsAst.Node node, int size) { |
| 506 if (isTracking(node)) { | 521 if (isTracking(node)) { |
| 507 //TODO: should I be incrementing here instead? | 522 //TODO: should I be incrementing here instead? |
| 508 _nodeToSize[node] = size; | 523 _nodeToSize[node] = size; |
| 509 } | 524 } |
| 510 } | 525 } |
| 511 | 526 |
| 512 // Returns the size of the source code that | 527 /// Returns the size of the source code that was generated for an entity. |
| 513 // was generated for an element. If no source | 528 /// If no source code was produced, return 0. |
| 514 // code was produced, return 0. | 529 int sizeOf(Entity entity) { |
| 515 int sizeOf(Element element) { | 530 if (_entityToNodes.containsKey(entity)) { |
| 516 if (_elementToNodes.containsKey(element)) { | 531 return _entityToNodes[entity].map(sizeOfNode).fold(0, (a, b) => a + b); |
| 517 return _elementToNodes[element].map(sizeOfNode).fold(0, (a, b) => a + b); | |
| 518 } else { | 532 } else { |
| 519 return 0; | 533 return 0; |
| 520 } | 534 } |
| 521 } | 535 } |
| 522 | 536 |
| 523 int sizeOfNode(jsAst.Node node) { | 537 int sizeOfNode(jsAst.Node node) { |
| 524 // TODO(sigmund): switch back to null aware operators (issue #24136) | 538 // TODO(sigmund): switch back to null aware operators (issue #24136) |
| 525 var size = _nodeToSize[node]; | 539 var size = _nodeToSize[node]; |
| 526 return size == null ? 0 : size; | 540 return size == null ? 0 : size; |
| 527 } | 541 } |
| 528 | 542 |
| 529 String codeOf(Element element) { | 543 String codeOf(Entity entity) { |
| 530 List<jsAst.Node> code = _elementToNodes[element]; | 544 List<jsAst.Node> code = _entityToNodes[entity]; |
| 531 if (code == null) return null; | 545 if (code == null) return null; |
| 532 // Concatenate rendered ASTs. | 546 // Concatenate rendered ASTs. |
| 533 StringBuffer sb = new StringBuffer(); | 547 StringBuffer sb = new StringBuffer(); |
| 534 for (jsAst.Node ast in code) { | 548 for (jsAst.Node ast in code) { |
| 535 sb.writeln(jsAst.prettyPrint(ast, compiler.options)); | 549 sb.writeln(jsAst.prettyPrint(ast, compiler.options)); |
| 536 } | 550 } |
| 537 return sb.toString(); | 551 return sb.toString(); |
| 538 } | 552 } |
| 539 | 553 |
| 540 void dumpInfo(ClosedWorld closedWorld) { | 554 void dumpInfo(ClosedWorld closedWorld) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 552 } | 566 } |
| 553 | 567 |
| 554 void dumpInfoJson(StringSink buffer, ClosedWorld closedWorld) { | 568 void dumpInfoJson(StringSink buffer, ClosedWorld closedWorld) { |
| 555 JsonEncoder encoder = const JsonEncoder.withIndent(' '); | 569 JsonEncoder encoder = const JsonEncoder.withIndent(' '); |
| 556 Stopwatch stopwatch = new Stopwatch(); | 570 Stopwatch stopwatch = new Stopwatch(); |
| 557 stopwatch.start(); | 571 stopwatch.start(); |
| 558 | 572 |
| 559 AllInfo result = infoCollector.result; | 573 AllInfo result = infoCollector.result; |
| 560 | 574 |
| 561 // Recursively build links to function uses | 575 // Recursively build links to function uses |
| 562 Iterable<Entity> functionElements = | 576 Iterable<Entity> functionEntities = |
| 563 infoCollector._elementToInfo.keys.where((k) => k is FunctionElement); | 577 infoCollector._entityToInfo.keys.where((k) => k is FunctionEntity); |
| 564 for (FunctionElement element in functionElements) { | 578 for (FunctionEntity entity in functionEntities) { |
| 565 FunctionInfo info = infoCollector._elementToInfo[element]; | 579 FunctionInfo info = infoCollector._entityToInfo[entity]; |
| 566 Iterable<Selection> uses = getRetaining(element, closedWorld); | 580 Iterable<Selection> uses = getRetaining(entity, closedWorld); |
| 567 // Don't bother recording an empty list of dependencies. | 581 // Don't bother recording an empty list of dependencies. |
| 568 for (Selection selection in uses) { | 582 for (Selection selection in uses) { |
| 569 // Don't register dart2js builtin functions that are not recorded. | 583 // Don't register dart2js builtin functions that are not recorded. |
| 570 Info useInfo = infoCollector._elementToInfo[selection.selectedElement]; | 584 Info useInfo = infoCollector._entityToInfo[selection.selectedEntity]; |
| 571 if (useInfo == null) continue; | 585 if (useInfo == null) continue; |
| 572 info.uses.add(new DependencyInfo(useInfo, '${selection.mask}')); | 586 info.uses.add(new DependencyInfo(useInfo, '${selection.mask}')); |
| 573 } | 587 } |
| 574 } | 588 } |
| 575 | 589 |
| 576 // Recursively build links to field uses | 590 // Recursively build links to field uses |
| 577 Iterable<Entity> fieldElements = | 591 Iterable<Entity> fieldEntity = |
| 578 infoCollector._elementToInfo.keys.where((k) => k is FieldElement); | 592 infoCollector._entityToInfo.keys.where((k) => k is FieldEntity); |
| 579 for (FieldElement element in fieldElements) { | 593 for (FieldEntity entity in fieldEntity) { |
| 580 FieldInfo info = infoCollector._elementToInfo[element]; | 594 FieldInfo info = infoCollector._entityToInfo[entity]; |
| 581 Iterable<Selection> uses = getRetaining(element, closedWorld); | 595 Iterable<Selection> uses = getRetaining(entity, closedWorld); |
| 582 // Don't bother recording an empty list of dependencies. | 596 // Don't bother recording an empty list of dependencies. |
| 583 for (Selection selection in uses) { | 597 for (Selection selection in uses) { |
| 584 Info useInfo = infoCollector._elementToInfo[selection.selectedElement]; | 598 Info useInfo = infoCollector._entityToInfo[selection.selectedEntity]; |
| 585 if (useInfo == null) continue; | 599 if (useInfo == null) continue; |
| 586 info.uses.add(new DependencyInfo(useInfo, '${selection.mask}')); | 600 info.uses.add(new DependencyInfo(useInfo, '${selection.mask}')); |
| 587 } | 601 } |
| 588 } | 602 } |
| 589 | 603 |
| 590 // Notify the impact strategy impacts are no longer needed for dump info. | 604 // Notify the impact strategy impacts are no longer needed for dump info. |
| 591 compiler.impactStrategy.onImpactUsed(IMPACT_USE); | 605 compiler.impactStrategy.onImpactUsed(IMPACT_USE); |
| 592 | 606 |
| 593 // Track dependencies that come from inlining. | 607 // Track dependencies that come from inlining. |
| 594 for (Element element in inlineMap.keys) { | 608 for (Entity entity in inlineMap.keys) { |
| 595 CodeInfo outerInfo = infoCollector._elementToInfo[element]; | 609 CodeInfo outerInfo = infoCollector._entityToInfo[entity]; |
| 596 if (outerInfo == null) continue; | 610 if (outerInfo == null) continue; |
| 597 for (Element inlined in inlineMap[element]) { | 611 for (Entity inlined in inlineMap[entity]) { |
| 598 Info inlinedInfo = infoCollector._elementToInfo[inlined]; | 612 Info inlinedInfo = infoCollector._entityToInfo[inlined]; |
| 599 if (inlinedInfo == null) continue; | 613 if (inlinedInfo == null) continue; |
| 600 outerInfo.uses.add(new DependencyInfo(inlinedInfo, 'inlined')); | 614 outerInfo.uses.add(new DependencyInfo(inlinedInfo, 'inlined')); |
| 601 } | 615 } |
| 602 } | 616 } |
| 603 | 617 |
| 604 result.deferredFiles = compiler.deferredLoadTask.computeDeferredMap(); | 618 result.deferredFiles = compiler.deferredLoadTask.computeDeferredMap(); |
| 605 stopwatch.stop(); | 619 stopwatch.stop(); |
| 606 result.program = new ProgramInfo( | 620 result.program = new ProgramInfo( |
| 607 entrypoint: infoCollector | 621 entrypoint: infoCollector |
| 608 ._elementToInfo[closedWorld.elementEnvironment.mainFunction], | 622 ._entityToInfo[closedWorld.elementEnvironment.mainFunction], |
| 609 size: _programSize, | 623 size: _programSize, |
| 610 dart2jsVersion: | 624 dart2jsVersion: |
| 611 compiler.options.hasBuildId ? compiler.options.buildId : null, | 625 compiler.options.hasBuildId ? compiler.options.buildId : null, |
| 612 compilationMoment: new DateTime.now(), | 626 compilationMoment: new DateTime.now(), |
| 613 compilationDuration: compiler.measurer.wallClock.elapsed, | 627 compilationDuration: compiler.measurer.wallClock.elapsed, |
| 614 toJsonDuration: | 628 toJsonDuration: |
| 615 new Duration(milliseconds: stopwatch.elapsedMilliseconds), | 629 new Duration(milliseconds: stopwatch.elapsedMilliseconds), |
| 616 dumpInfoDuration: new Duration(milliseconds: this.timing), | 630 dumpInfoDuration: new Duration(milliseconds: this.timing), |
| 617 noSuchMethodEnabled: closedWorld.backendUsage.isNoSuchMethodUsed, | 631 noSuchMethodEnabled: closedWorld.backendUsage.isNoSuchMethodUsed, |
| 618 minified: compiler.options.enableMinification); | 632 minified: compiler.options.enableMinification); |
| 619 | 633 |
| 620 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( | 634 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( |
| 621 new StringConversionSink.fromStringSink(buffer)); | 635 new StringConversionSink.fromStringSink(buffer)); |
| 622 sink.add(new AllInfoJsonCodec().encode(result)); | 636 sink.add(new AllInfoJsonCodec().encode(result)); |
| 623 compiler.reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { | 637 compiler.reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { |
| 624 'text': "View the dumped .info.json file at " | 638 'text': "View the dumped .info.json file at " |
| 625 "https://dart-lang.github.io/dump-info-visualizer" | 639 "https://dart-lang.github.io/dump-info-visualizer" |
| 626 }); | 640 }); |
| 627 } | 641 } |
| 628 } | 642 } |
| OLD | NEW |