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 'closure.dart'; |
12 import 'common/tasks.dart' show CompilerTask; | 13 import 'common/tasks.dart' show CompilerTask; |
13 import 'common.dart'; | 14 import 'common.dart'; |
14 import 'compiler.dart' show Compiler; | 15 import 'compiler.dart' show Compiler; |
15 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; | 16 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue; |
16 import 'deferred_load.dart' show OutputUnit; | 17 import 'deferred_load.dart' show OutputUnit; |
17 import 'elements/elements.dart'; | 18 import 'elements/elements.dart'; |
18 import 'elements/visitor.dart'; | 19 import 'elements/visitor.dart'; |
19 import 'js/js.dart' as jsAst; | 20 import 'js/js.dart' as jsAst; |
20 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 21 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
21 import 'js_emitter/full_emitter/emitter.dart' as full show Emitter; | 22 import 'js_emitter/full_emitter/emitter.dart' as full show Emitter; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 String code = compiler.dumpInfoTask.codeOf(element); | 124 String code = compiler.dumpInfoTask.codeOf(element); |
124 if (code != null) size += code.length; | 125 if (code != null) size += code.length; |
125 | 126 |
126 FieldInfo info = new FieldInfo( | 127 FieldInfo info = new FieldInfo( |
127 name: element.name, | 128 name: element.name, |
128 // We use element.hashCode because it is globally unique and it is | 129 // We use element.hashCode because it is globally unique and it is |
129 // available while we are doing codegen. | 130 // available while we are doing codegen. |
130 coverageId: '${element.hashCode}', | 131 coverageId: '${element.hashCode}', |
131 type: '${element.type}', | 132 type: '${element.type}', |
132 inferredType: '$inferredType', | 133 inferredType: '$inferredType', |
133 size: size, | |
134 code: code, | 134 code: code, |
135 outputUnit: _unitInfoForElement(element), | 135 outputUnit: _unitInfoForElement(element), |
136 isConst: element.isConst); | 136 isConst: element.isConst); |
137 _elementToInfo[element] = info; | 137 _elementToInfo[element] = info; |
138 if (element.isConst) { | 138 if (element.isConst) { |
139 var value = compiler.backend.constantCompilerTask | 139 var value = compiler.backend.constantCompilerTask |
140 .getConstantValue(element.constant); | 140 .getConstantValue(element.constant); |
141 if (value != null) { | 141 if (value != null) { |
142 info.initializer = _constantToInfo[value]; | 142 info.initializer = _constantToInfo[value]; |
143 } | 143 } |
144 } | 144 } |
145 | 145 |
146 List<FunctionInfo> nestedClosures = <FunctionInfo>[]; | 146 int closureSize = _addClosureInfo(info, element); |
147 for (Element closure in element.nestedClosures) { | 147 info.size = size + closureSize; |
148 Info child = this.process(closure); | 148 |
149 if (child != null) { | |
150 ClassInfo parent = this.process(closure.enclosingElement); | |
151 if (parent != null) { | |
152 child.name = "${parent.name}.${child.name}"; | |
153 } | |
154 nestedClosures.add(child); | |
155 size += child.size; | |
156 } | |
157 } | |
158 info.closures = nestedClosures; | |
159 result.fields.add(info); | 149 result.fields.add(info); |
160 return info; | 150 return info; |
161 } | 151 } |
162 | 152 |
163 ClassInfo visitClassElement(ClassElement element, _) { | 153 ClassInfo visitClassElement(ClassElement element, _) { |
164 ClassInfo classInfo = new ClassInfo( | 154 ClassInfo classInfo = new ClassInfo( |
165 name: element.name, | 155 name: element.name, |
166 isAbstract: element.isAbstract, | 156 isAbstract: element.isAbstract, |
167 outputUnit: _unitInfoForElement(element)); | 157 outputUnit: _unitInfoForElement(element)); |
168 _elementToInfo[element] = classInfo; | 158 _elementToInfo[element] = classInfo; |
169 | 159 |
170 int size = compiler.dumpInfoTask.sizeOf(element); | 160 int size = compiler.dumpInfoTask.sizeOf(element); |
171 element.forEachLocalMember((Element member) { | 161 element.forEachLocalMember((Element member) { |
172 Info info = this.process(member); | 162 Info info = this.process(member); |
173 if (info == null) return; | 163 if (info == null) return; |
174 if (info is FieldInfo) { | 164 if (info is FieldInfo) { |
175 classInfo.fields.add(info); | 165 classInfo.fields.add(info); |
176 info.parent = classInfo; | 166 info.parent = classInfo; |
| 167 for (ClosureInfo closureInfo in info.closures) { |
| 168 size += closureInfo.size; |
| 169 } |
177 } else { | 170 } else { |
178 assert(info is FunctionInfo); | 171 assert(info is FunctionInfo); |
179 classInfo.functions.add(info); | 172 classInfo.functions.add(info); |
180 info.parent = classInfo; | 173 info.parent = classInfo; |
181 } | 174 for (ClosureInfo closureInfo in (info as FunctionInfo).closures) { |
182 | |
183 // Closures are placed in the library namespace, but we want to attribute | |
184 // them to a function, and by extension, this class. Process and add the | |
185 // sizes here. | |
186 if (member is MemberElement) { | |
187 for (Element closure in member.nestedClosures) { | |
188 FunctionInfo closureInfo = this.process(closure); | |
189 if (closureInfo == null) continue; | |
190 | |
191 // TODO(sigmund): remove this legacy update on the name, represent the | |
192 // information explicitly in the info format. | |
193 // Look for the parent element of this closure might be the enclosing | |
194 // class or an enclosing function. | |
195 Element parent = closure.enclosingElement; | |
196 ClassInfo parentInfo = this.process(parent); | |
197 if (parentInfo != null) { | |
198 closureInfo.name = "${parentInfo.name}.${closureInfo.name}"; | |
199 } | |
200 size += closureInfo.size; | 175 size += closureInfo.size; |
201 } | 176 } |
202 } | 177 } |
203 }); | 178 }); |
204 | 179 |
205 classInfo.size = size; | 180 classInfo.size = size; |
206 | 181 |
207 // Omit element if it is not needed. | 182 // Omit element if it is not needed. |
208 JavaScriptBackend backend = compiler.backend; | 183 JavaScriptBackend backend = compiler.backend; |
209 if (!backend.emitter.neededClasses.contains(element) && | 184 if (!backend.emitter.neededClasses.contains(element) && |
210 classInfo.fields.isEmpty && | 185 classInfo.fields.isEmpty && |
211 classInfo.functions.isEmpty) { | 186 classInfo.functions.isEmpty) { |
212 return null; | 187 return null; |
213 } | 188 } |
214 result.classes.add(classInfo); | 189 result.classes.add(classInfo); |
215 return classInfo; | 190 return classInfo; |
216 } | 191 } |
217 | 192 |
| 193 ClosureInfo visitClosureClassElement(ClosureClassElement element, _) { |
| 194 ClosureInfo closureInfo = new ClosureInfo( |
| 195 name: element.name, |
| 196 outputUnit: _unitInfoForElement(element), |
| 197 size: compiler.dumpInfoTask.sizeOf(element)); |
| 198 _elementToInfo[element] = closureInfo; |
| 199 |
| 200 ClosureClassMap closureMap = |
| 201 compiler.closureToClassMapper.closureMappingCache[element.node]; |
| 202 assert(closureMap != null && closureMap.closureClassElement == element); |
| 203 |
| 204 FunctionInfo functionInfo = this.process(closureMap.callElement); |
| 205 if (functionInfo == null) return null; |
| 206 closureInfo.function = functionInfo; |
| 207 functionInfo.parent = closureInfo; |
| 208 |
| 209 result.closures.add(closureInfo); |
| 210 return closureInfo; |
| 211 } |
| 212 |
218 FunctionInfo visitFunctionElement(FunctionElement element, _) { | 213 FunctionInfo visitFunctionElement(FunctionElement element, _) { |
219 int size = compiler.dumpInfoTask.sizeOf(element); | 214 int size = compiler.dumpInfoTask.sizeOf(element); |
220 // TODO(sigmund): consider adding a small info to represent unreachable | 215 // TODO(sigmund): consider adding a small info to represent unreachable |
221 // code here. | 216 // code here. |
222 if (size == 0 && !shouldKeep(element)) return null; | 217 if (size == 0 && !shouldKeep(element)) return null; |
223 | 218 |
224 String name = element.name; | 219 String name = element.name; |
225 int kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND; | 220 int kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND; |
226 var enclosingElement = element.enclosingElement; | 221 var enclosingElement = element.enclosingElement; |
227 if (enclosingElement.isField || | 222 if (enclosingElement.isField || |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 returnType: returnType, | 282 returnType: returnType, |
288 inferredReturnType: inferredReturnType, | 283 inferredReturnType: inferredReturnType, |
289 parameters: parameters, | 284 parameters: parameters, |
290 sideEffects: sideEffects, | 285 sideEffects: sideEffects, |
291 inlinedCount: inlinedCount, | 286 inlinedCount: inlinedCount, |
292 code: code, | 287 code: code, |
293 type: element.type.toString(), | 288 type: element.type.toString(), |
294 outputUnit: _unitInfoForElement(element)); | 289 outputUnit: _unitInfoForElement(element)); |
295 _elementToInfo[element] = info; | 290 _elementToInfo[element] = info; |
296 | 291 |
297 List<FunctionInfo> nestedClosures = <FunctionInfo>[]; | |
298 if (element is MemberElement) { | 292 if (element is MemberElement) { |
299 MemberElement member = element as MemberElement; | 293 int closureSize = _addClosureInfo(info, element as MemberElement); |
300 for (Element closure in member.nestedClosures) { | 294 size += closureSize; |
301 Info child = this.process(closure); | 295 } else { |
302 if (child != null) { | 296 info.closures = <ClosureInfo>[]; |
303 BasicInfo parent = this.process(closure.enclosingElement); | 297 } |
304 if (parent != null) { | 298 |
305 child.name = "${parent.name}.${child.name}"; | 299 result.functions.add(info); |
306 } | 300 return info; |
307 nestedClosures.add(child); | 301 } |
308 child.parent = parent; | 302 |
309 size += child.size; | 303 /// Adds closure information to [info], using all nested closures in [member]. |
310 } | 304 /// |
| 305 /// Returns the total size of the nested closures, to add to the info size. |
| 306 int _addClosureInfo(Info info, MemberElement member) { |
| 307 assert(info is FunctionInfo || info is FieldInfo); |
| 308 int size = 0; |
| 309 List<ClosureInfo> nestedClosures = <ClosureInfo>[]; |
| 310 for (Element function in member.nestedClosures) { |
| 311 assert(function is SynthesizedCallMethodElementX); |
| 312 SynthesizedCallMethodElementX callMethod = function; |
| 313 ClosureInfo closure = this.process(callMethod.closureClass); |
| 314 if (closure != null) { |
| 315 closure.parent = info; |
| 316 nestedClosures.add(closure); |
| 317 size += closure.size; |
311 } | 318 } |
312 } | 319 } |
313 info.closures = nestedClosures; | 320 if (info is FunctionInfo) info.closures = nestedClosures; |
314 result.functions.add(info); | 321 if (info is FieldInfo) info.closures = nestedClosures; |
315 return info; | 322 |
| 323 return size; |
316 } | 324 } |
317 | 325 |
318 OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) { | 326 OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) { |
319 return _outputToInfo.putIfAbsent(outputUnit, () { | 327 return _outputToInfo.putIfAbsent(outputUnit, () { |
320 // Dump-info currently only works with the full emitter. If another | 328 // Dump-info currently only works with the full emitter. If another |
321 // emitter is used it will fail here. | 329 // emitter is used it will fail here. |
322 JavaScriptBackend backend = compiler.backend; | 330 JavaScriptBackend backend = compiler.backend; |
323 full.Emitter emitter = backend.emitter.emitter; | 331 full.Emitter emitter = backend.emitter.emitter; |
324 assert(outputUnit.name != null || outputUnit.isMainOutput); | 332 assert(outputUnit.name != null || outputUnit.isMainOutput); |
325 OutputUnitInfo info = new OutputUnitInfo( | 333 OutputUnitInfo info = new OutputUnitInfo( |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 | 596 |
589 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( | 597 ChunkedConversionSink<Object> sink = encoder.startChunkedConversion( |
590 new StringConversionSink.fromStringSink(buffer)); | 598 new StringConversionSink.fromStringSink(buffer)); |
591 sink.add(new AllInfoJsonCodec().encode(result)); | 599 sink.add(new AllInfoJsonCodec().encode(result)); |
592 compiler.reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { | 600 compiler.reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, { |
593 'text': "View the dumped .info.json file at " | 601 'text': "View the dumped .info.json file at " |
594 "https://dart-lang.github.io/dump-info-visualizer" | 602 "https://dart-lang.github.io/dump-info-visualizer" |
595 }); | 603 }); |
596 } | 604 } |
597 } | 605 } |
OLD | NEW |