Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: pkg/compiler/lib/src/dump_info.dart

Issue 3008793002: Use the entity model for dump_info. (Closed)
Patch Set: respond to comments Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/deferred_load.dart ('k') | pkg/compiler/lib/src/elements/elements.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/deferred_load.dart ('k') | pkg/compiler/lib/src/elements/elements.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698