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

Unified Diff: sdk/lib/_internal/compiler/implementation/dump_info.dart

Issue 90713003: Dart2js option to dump info about compilation (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/dump_info.dart
diff --git a/sdk/lib/_internal/compiler/implementation/dump_info.dart b/sdk/lib/_internal/compiler/implementation/dump_info.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c59699136f1fcda17e5a8e9c53ccc690ad3c48d3
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/dump_info.dart
@@ -0,0 +1,361 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dump_types;
+
+import 'elements/elements.dart';
+import 'elements/visitor.dart';
+import 'dart:convert' show HtmlEscape;
+import 'dart2jslib.dart'
+ show Compiler,
ahe 2013/12/02 15:20:26 Put show on previous line and indent by four.
sigurdm 2013/12/05 09:19:44 Done.
+ CompilerTask,
+ CodeBuffer;
+import 'dart_types.dart' show DartType;
+
+// TODO (sigurdm): A search function.
+// TODO (sigurdm): Output size of classes.
+// TODO (sigurdm): Print that we dumped the HTML-file.
+// TODO (sigurdm): Include why a given element was included in the output.
+// TODO (sigurdm): Include how much output grew because of mirror support.
+// TODO (sigurdm): Write each function with parameter names.
+// TODO (sigurdm): Write how much space the boilerplate takes.
+
+class CodeSizeCounter {
+ final Map<Element, int> generatedSize = new Map<Element, int>();
+
+ int getGeneratedSizeOf(Element element) {
+ int result = generatedSize[element];
+ return result == null ? 0 : result;
+ }
+
+ void countCode(Element element, int added) {
+ int before = generatedSize.putIfAbsent(element, () => 0);
+ generatedSize[element] = before + added;
+ }
+}
+
+class ElementInfo {
ahe 2013/12/02 15:20:26 I'd put a line between each member.
sigurdm 2013/12/05 09:19:44 Done.
+ final String name;
+ final String kind;
+ final String type;
+ final String modifiers;
+ final String generatedCode;
+ // How to present this piece of information
ahe 2013/12/02 15:20:26 What does this comment apply to? Is it a TODO?
sigurdm 2013/12/05 09:19:44 Done.
+ // As "element" or "code"
ahe 2013/12/02 15:20:26 Is this a sentence by itself or a continuation of
+ final String presentation;
+ final int size; // How many bytes does this take in the output
ahe 2013/12/02 15:20:26 Is this supposed to be a documentation comment?
sigurdm 2013/12/05 09:19:44 yes
+ List<ElementInfo> contents;
+ ElementInfo({this.name: "",
+ this.kind: "",
+ this.type: "",
+ this.modifiers: "",
+ this.size,
+ this.generatedCode,
+ this.presentation: "element",
+ this.contents});
+}
+
+class ProgramInfo {
ahe 2013/12/02 15:20:26 I'd put a line between each member.
sigurdm 2013/12/05 09:19:44 Done.
+ final String name;
+ final String presentation;
+ final List<ElementInfo> libraries;
+ final int size; // How many bytes is the output
ahe 2013/12/02 15:20:26 Documentation comment?
sigurdm 2013/12/05 09:19:44 Done.
+ final DateTime compilationMoment;
+ final int compilationDuration;
+ final String dart2jsVersion;
+
+ ProgramInfo({String this.name,
+ this.presentation,
+ this.libraries,
+ this.size, DateTime this.compilationMoment,
+ this.compilationDuration, String this.dart2jsVersion});
+}
+
+class InfoDumpVisitor extends ElementVisitor<ElementInfo> {
+
ahe 2013/12/02 15:20:26 Extra line.
sigurdm 2013/12/05 09:19:44 Done.
+ Compiler compiler;
+
+ InfoDumpVisitor(Compiler this.compiler);
+
+ ElementInfo visitElement(Element element) {
+ compiler.internalError("This element of kind ${element.kind} "
+ "does not support dumping of types",
+ token: element.position());
+ }
+
+ ElementInfo visitLibraryElement(LibraryElement element) {
+ List<ElementInfo> contents = new List<ElementInfo>();
+ int size = compiler.dumpInfoTask.codeSizeCounter
+ .getGeneratedSizeOf(element);
+ if (size == 0) return null;
+ element.forEachLocalMember((Element member) {
+ ElementInfo info = member.accept(this);
+ if (info != null) {
+ contents.add(info);
+ }
+ });
+
+ String nameString = element.getLibraryName() == ""
+ ? "<unnamed>"
+ : element.getLibraryName();
+ contents.sort((ElementInfo e1, ElementInfo e2) {
+ return e1.name.compareTo(e2.name);
+ });
+ return new ElementInfo(
+ type: element.canonicalUri.toString(),
+ kind: "library",
+ name: nameString,
+ size: size,
+ modifiers: "",
+ contents: contents);
+ }
+
+ ElementInfo visitTypedefElement(TypedefElement element) {
+ return element.thisType == null
+ ? null
+ : new ElementInfo(
+ type: element.thisType.toString(),
+ kind: "typedef",
+ name: element.name);
+ }
+
+ ElementInfo visitVariableElement(VariableElement element) {
+ DartType type = element.computeType(compiler);
+ if (type == null) return null;
+ String modifiersString = element.modifiers.toString() == ""
+ ? ""
+ : element.modifiers.toString()+" ";
+ List inferredType = [new ElementInfo(
ahe 2013/12/02 15:20:26 I don't understand why an inferredType is a list.
sigurdm 2013/12/05 09:19:44 Done.
+ kind: "inferred type",
+ name: "",
+ type: compiler.typesTask.getGuaranteedTypeOfElement(element).toString(),
+ modifiers: "")];
+ return new ElementInfo(
+ kind: "field",
+ type: type.toString(),
+ name: element.name,
+ modifiers: modifiersString,
+ contents: inferredType);
+ }
+
+ ElementInfo visitClassElement(ClassElement element) {
+ String modifiersString = element.modifiers.toString() == ""
+ ? ""
+ : element.modifiers.toString()+" ";
+ if (!element.isResolved) return null;
+ String supersString = element.allSupertypes == null ? "" :
+ "implements ${element.allSupertypes}";
+ List contents = [];
+ element.forEachLocalMember((Element member) {
+ ElementInfo info = member.accept(this);
+ if (info != null) {
+ contents.add(info);
+ }
+ });
+ if (contents.isEmpty) {
+ return null;
+ }
+ contents.sort((ElementInfo m1, ElementInfo m2) {
+ return m1.name.compareTo(m2.name);
+ });
+ return new ElementInfo(
+ kind: "class",
+ name: element.name,
+ type: supersString,
+ modifiers: modifiersString,
+ contents: contents);
+ }
+
+ ElementInfo visitFunctionElement(FunctionElement element) {
+ CodeBuffer emittedCode = compiler.backend.codeOf(element);
+ if (emittedCode == null) {
+ return null;
+ }
+ String modifiersString = element.modifiers.toString() == ""
+ ? ""
+ : element.modifiers.toString()+" ";
+ String kindString = "function";
+ String nameString = element.name;
+ if (element.isConstructor()) {
+ nameString = element.name == "" ? "${element.enclosingElement.name}()" :
+ "${element.enclosingElement.name}.${element.name}";
+ kindString = "constructor";
+ }
+ List contents = [];
+ FunctionSignature signature = element.computeSignature(compiler);
+ signature.forEachParameter((parameter) {
+ contents.add(new ElementInfo(
+ kind: "inferred",
+ name: parameter.name,
+ modifiers: "parameter type",
+ type: compiler.typesTask
+ .getGuaranteedTypeOfElement(parameter).toString()));
+ });
+ contents.add(new ElementInfo(
+ kind: "inferred",
+ modifiers: "return type",
+ type: compiler.typesTask
+ .getGuaranteedReturnTypeOfElement(element).toString()));
+ contents.add(new ElementInfo(
+ kind: "inferred",
+ modifiers: "side effects",
+ type: compiler.world.getSideEffectsOfElement(element).toString()));
+ contents.add(new ElementInfo(
+ name: "Generated code",
+ presentation: "code",
+ generatedCode: emittedCode.getText()));
+ return new ElementInfo(
+ type: element.type.toString(),
+ kind: kindString,
+ name: nameString,
+ size: emittedCode.length,
+ modifiers: modifiersString,
+ contents: contents);
+ }
+}
+
+class DumpInfoTask extends CompilerTask {
+ DumpInfoTask(Compiler compiler) :
+ super(compiler),
+ infoDumpVisitor = new InfoDumpVisitor(compiler);
+
+ String name = "Dump Info";
+
+ final CodeSizeCounter codeSizeCounter = new CodeSizeCounter();
+
+ final InfoDumpVisitor infoDumpVisitor;
+
+ void dumpInfo() {
+ measure(() {
+ ProgramInfo info = collectDumpInfo();
+ StringBuffer buffer = new StringBuffer();
+ dumpInfoHtml(info, buffer);
+ compiler.outputProvider('', 'info.html')
+ ..add(buffer.toString())
+ ..close();
+ });
+ }
+
+ ProgramInfo collectDumpInfo() {
+ List<LibraryElement> sortedLibraries = compiler.libraries.values.toList();
+ sortedLibraries.sort((LibraryElement l1, LibraryElement l2) {
+ if (l1.isPlatformLibrary && !l2.isPlatformLibrary) {
+ return 1;
+ } else if (!l1.isPlatformLibrary && l2.isPlatformLibrary) {
+ return -1;
+ }
+ return l1.getLibraryName().compareTo(l2.getLibraryName());
+ });
+
+ List<ElementInfo> libraryInfos = new List<ElementInfo>();
+ libraryInfos.addAll(sortedLibraries
+ .map((library) => infoDumpVisitor.visit(library))
+ .where((library) => library != null));
+
+ return new ProgramInfo(
+ compilationDuration: compiler.totalCompileTime.elapsedTicks,
+ // TODO (sigurdm): Also count the size of deferred code
+ size: compiler.assembledCode.length,
+ libraries: libraryInfos,
+ compilationMoment: new DateTime.now(),
+ dart2jsVersion: compiler.hasBuildId ? compiler.buildId : null);
+ }
+
+ void dumpInfoHtml(ProgramInfo info, StringSink buffer) {
+ tag(String element) {
+ return (String content, {String cls}) {
+ String classString = cls == null ? '' : ' class="$cls"';
+ return '<$element$classString>$content</$element>';
+ };
+ }
+ var div = tag('div');
+ var span = tag('span');
+ var code = tag('code');
+ var h2 = tag('h2');
+ int totalSize = info.size;
+ void dumpElement(ElementInfo description) {
+ var esc = const HtmlEscape().convert;
+ if (description.presentation == 'code') {
+ buffer.write(div(description.name, cls: 'kind') +
+ code(esc(description.generatedCode)));
+ } else {
+ String kind = span(esc(description.kind), cls: 'kind');
+ String modifiers = span(esc(description.modifiers), cls: "modifiers");
+ String size = '';
+ if (description.size != null) {
+ size = 'Size: ' +
+ span('${description.size} bytes '
+ '(${description.size * 100 ~/ totalSize})%',
+ cls: "size");
+ }
+ String name = span(esc(description.name), cls: 'name');
+ String type = span(esc(description.type), cls: 'type');
+ String describe = [kind, modifiers, name, size, type].join(' ');
+
+ if (description.contents != null) {
+ buffer.write(div("+$describe", cls: "container"));
+ String contents = "No Members";
+ buffer.write('<div class="contained">');
+ if (description.contents.isEmpty) {
+ buffer.writeln("No members");
+ }
+ for (Object subElementDescription in description.contents) {
+ dumpElement(subElementDescription);
+ }
+ buffer.write("</div>");
+ } else {
+ buffer.writeln(describe);
+ }
+ }
+ }
+ buffer.writeln("""
+ <html>
+ <head>
+ <title>Dart2JS compilation information</title>
+ <style>
+ div.show {display:block;}
+ code {margin-left: 20px; display: block;}
+ div.contained {margin-left: 20px;}
+ div {margin-top:0px;
+ margin-bottom: 0px;
+ white-space: pre; /*border: 1px solid;*/}
+ span.kind {font-weight:bold;}
+ span.modifiers {font-weight:bold;}
+ span.name {font-style:italic}
+ span.type {color:blue;}
+ </style>
+ </head>
+ <body>
+ <h1>Dart2js compilation information</h1>""");
+ buffer.writeln(h2('Compilation took place: '
+ '${info.compilationMoment}'));
+ buffer.writeln(h2('Compilation took: '
+ '${info.compilationDuration/1000000} seconds'));
+ buffer.writeln(h2('Output size: ${info.size} bytes'));
+ if (info.dart2jsVersion != null) {
+ buffer.writeln(h2('Dart2js version: ${info.dart2jsVersion}'));
+ }
+
+ info.libraries.forEach(dumpElement);
+
+ // TODO (sigurdm): This script should be written in dart
+ buffer.writeln(r"""
+ <script type="text/javascript">
+ function toggler(element) {
+ return function(e) {
+ element.hidden = !element.hidden;
+ };
+ }
+ var containers = document.getElementsByClassName('container');
+ for (var i = 0; i < containers.length; i++) {
+ var container = containers[i];
+ container.addEventListener('click',
+ toggler(container.nextElementSibling), false);
+ container.nextElementSibling.hidden = true;
+ };
+ </script>
+ </body>
+ </html>""");
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698