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

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

Issue 382063002: Redo "Information about which functions require other functions is gathered in the enqueuer." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase Created 6 years, 5 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 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
index 06195fea2c0f15403eb33925c9f10ef69d144abf..5e6e39342904ad297a512e11994ba285ef57fb05 100644
--- a/sdk/lib/_internal/compiler/implementation/dump_info.dart
+++ b/sdk/lib/_internal/compiler/implementation/dump_info.dart
@@ -22,37 +22,14 @@ import 'util/util.dart' show modifiersToString;
import 'deferred_load.dart' show OutputUnit;
import 'js_backend/js_backend.dart' show JavaScriptBackend;
import 'js/js.dart' as jsAst;
-
-// 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.
-// TODO (sigurdm): Include javascript names of entities in the output.
-
-const List<String> COLORS = const [
- "#fff",
- "#8dd3c7",
- "#ffffb3",
- "#bebada",
- "#fb8072",
- "#80b1d3",
- "#fdb462",
- "#b3de69",
- "#fccde5",
- "#d9d9d9",
- "#bc80bd",
- "#ccebc5",
- "#ffed6f"];
+import 'compilation_info.dart' show CompilationInformation;
class CodeSizeCounter {
final Map<Element, int> generatedSize = new Map<Element, int>();
int getGeneratedSizeOf(Element element) {
int result = generatedSize[element];
- return result == null ? 0 : result;
+ return result == null ? 0: result;
}
void countCode(Element element, int added) {
@@ -61,709 +38,402 @@ class CodeSizeCounter {
}
}
-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');
+/// Maps elements to an id. Supports lookups in
+/// both directions.
+class ElementMapper {
+ Map<int, Element> _idToElement = {};
+ Map<Element, int> _elementToId = {};
+ int _idCounter = 0;
+ String name;
-var esc = const HtmlEscape().convert;
-
-String sizeDescription(int size, ProgramInfo programInfo) {
- if (size == null) {
- return '';
- }
- return span(span(size.toString(), cls: 'value') +
- ' bytes (${size * 100 ~/ programInfo.size}%)', cls: 'size');
-}
-
-String sizePercent(int size, ProgramInfo programInfo) {
- if (size == null) {
- return "0.000%";
- } else {
- return (100 * size / programInfo.size).toStringAsFixed(3) + "%";
- }
-}
+ ElementMapper(this.name);
-/// An [InfoNode] holds information about a part the program.
-abstract class InfoNode {
- String get name;
-
- int get size;
-
- void emitHtml(ProgramInfo programInfo, StringSink buffer,
- [String indentation = '']);
-
- Map<String, dynamic> toJson(ProgramInfo programInfo);
-}
-
-/// An [ElementNode] holds information about an [Element]
-class ElementInfoNode implements InfoNode {
- /// The name of the represented [Element].
- final String name;
-
- /// The kind of the [Element] represented. This is presented to the
- /// user, so it might be more specific than [element.kind].
- final String kind;
-
- /// The static type of the represented [Element].
- /// [:null:] if this kind of element has no type.
- final String type;
-
- /// Any extra information to display about the represented [Element].
- final String extra;
-
- /// A textual description of the modifiers (such as "static", "abstract") of
- /// the represented [Element].
- final String modifiers;
-
- /// Describes how many bytes the code for the represented [Element] takes up
- /// in the output.
- final int size;
-
- /// Subnodes containing more detailed information about the represented
- /// [Element], and its members.
- List<InfoNode> contents;
-
- /// Subnodes containing more detailed information about the represented
- /// [Element], and its members.
- int outputUnitId;
-
- ElementInfoNode({this.name: "",
- this.kind: "",
- this.type,
- this.modifiers: "",
- this.size,
- this.contents,
- this.extra: "",
- this.outputUnitId});
-
- Map<String, dynamic> toJson(ProgramInfo programInfo) {
- Map<String, dynamic> json = <String, dynamic>{
- 'kind': this.kind,
- 'modifiers': this.modifiers,
- 'name': this.name,
- 'type': this.type,
- 'size': this.size,
- 'sizePercent': sizePercent(this.size, programInfo),
- 'extra': this.extra
- };
-
- if (this.contents != null) {
- json['children'] =
- this.contents.map((c) => c.toJson(programInfo)).toList();
+ String add(Element e) {
+ if (_elementToId.containsKey(e)) {
+ return name + "/${_elementToId[e]}";
}
- return json;
+ _idToElement[_idCounter] = e;
+ _elementToId[e] = _idCounter;
+ _idCounter += 1;
+ return name + "/${_idCounter - 1}";
}
+}
- void emitHtml(ProgramInfo programInfo, StringSink buffer,
- [String indentation = '']) {
- String kindString = span(esc(kind), cls: 'kind');
- String modifiersString = span(esc(modifiers), cls: "modifiers");
-
- String nameString = span(esc(name), cls: 'name');
- String typeString = type == null
- ? ''
- : span('/* ' + esc(type) + ' */', cls: 'type');
- String extraString = span(esc(extra), cls: 'type');
- String describe = [
- kindString,
- typeString,
- modifiersString,
- nameString,
- sizeDescription(size, programInfo),
- extraString].join(' ');
-
- if (contents != null) {
- String outputUnitClass = outputUnitId == null
- ? ""
- : " outputUnit${outputUnitId % COLORS.length}";
- buffer.write(indentation);
- buffer.write('<div class="container$outputUnitClass">\n');
- buffer.write('$indentation ');
- buffer.write(div('+$describe', cls: "details"));
- buffer.write('\n');
- buffer.write('$indentation <div class="contents">');
- if (contents.isEmpty) {
- buffer.write('No members</div>');
- } else {
- buffer.write('\n');
- for (InfoNode subElementDescription in contents) {
- subElementDescription.emitHtml(programInfo, buffer,
- indentation + ' ');
+class DividedElementMapper {
+ // Mappers for specific kinds of elements.
+ ElementMapper _library = new ElementMapper('library');
+ ElementMapper _typedef = new ElementMapper('typedef');
+ ElementMapper _field = new ElementMapper('field');
+ ElementMapper _class = new ElementMapper('class');
+ ElementMapper _function = new ElementMapper('function');
+
+ // Convert this database of elements into JSON for rendering
+ Map<String, dynamic> _toJson(ElementToJsonVisitor elementToJson) {
+ Map<String, dynamic> json = {};
+ var m = [_library, _typedef, _field, _class, _function];
+ for (ElementMapper mapper in m) {
+ Map<String, dynamic> innerMapper = {};
+ mapper._idToElement.forEach((k, v) {
+ // All these elements are already cached in the
+ // jsonCache, so this is just an access.
+ var elementJson = elementToJson.process(v);
+ if (elementJson != null) {
+ innerMapper["$k"] = elementJson;
}
- buffer.write("\n$indentation </div>");
- }
- buffer.write("\n$indentation</div>\n");
- } else {
- buffer.writeln(div('$describe', cls: "element"));
+ });
+ json[mapper.name] = innerMapper;
}
+ return json;
}
}
-/// A [CodeInfoNode] holds information about a piece of code.
-class CodeInfoNode implements InfoNode {
- /// A short description of the code.
- final String description;
-
- final String generatedCode;
-
- get size => generatedCode.length;
-
- get name => "";
-
- CodeInfoNode({this.description: "", this.generatedCode});
+class ElementToJsonVisitor extends ElementVisitor<Map<String, dynamic>> {
+ DividedElementMapper mapper = new DividedElementMapper();
+ Compiler compiler;
- void emitHtml(ProgramInfo programInfo, StringBuffer buffer,
- [String indentation = '']) {
- buffer.write(indentation);
- buffer.write(div(description + ' ' +
- sizeDescription(generatedCode.length, programInfo),
- cls: 'kind') +
- code(esc(generatedCode)));
- buffer.write('\n');
- }
-
- Map<String, dynamic> toJson(ProgramInfo programInfo) {
- return <String, dynamic>{
- 'kind': 'code',
- 'description': description,
- 'code': generatedCode,
- 'size': generatedCode.length,
- 'sizePercent': sizePercent(generatedCode.length, programInfo)
- };
- }
-}
+ CompilationInformation compilationInfo;
-/// Instances represent information inferred about the program such as
-/// inferred type information or inferred side effects.
-class InferredInfoNode implements InfoNode {
- /// Text describing the represented information.
- final String description;
+ Map<Element, Map<String, dynamic>> jsonCache = {};
+ Map<Element, jsAst.Expression> codeCache;
- /// The name of the entity this information is inferred about (for example the
- /// name of a parameter).
- final String name;
+ int programSize;
+ DateTime compilationMoment;
+ String dart2jsVersion;
+ Duration compilationDuration;
+ Duration dumpInfoDuration;
- /// The inferred type/side effect.
- final String type;
+ ElementToJsonVisitor(Compiler compiler) {
+ this.compiler = compiler;
ahe 2014/08/18 15:31:14 Please use Dart constructor syntax. For example:
Ty Overby (Google) 2014/08/19 19:44:13 Done.
+ this.compilationInfo = compiler.enqueuer.codegen.compilationInfo;
- get size => 0;
+ programSize = compiler.assembledCode.length;
+ compilationMoment = new DateTime.now();
+ dart2jsVersion = compiler.hasBuildId ? compiler.buildId : null;
+ compilationDuration = compiler.totalCompileTime.elapsed;
- InferredInfoNode({this.name: "", this.description, this.type});
+ for (var library in compiler.libraryLoader.libraries.toList()) {
+ library.accept(this);
+ }
- Map<String, dynamic> toJson(ProgramInfo programInfo) {
- return <String, dynamic>{
- 'kind': 'inferred',
- 'name': name,
- 'type': type,
- 'desc': description
- };
+ dumpInfoDuration = new DateTime.now().difference(compilationMoment);
ahe 2014/08/18 15:31:14 We have CompilerTask to measure timing.
Ty Overby (Google) 2014/08/19 19:44:13 I can't seem to find out how to extract time measu
ahe 2014/08/20 08:33:19 Create a subclass of CompilerTask and add it to co
}
- void emitHtml(ProgramInfo programInfo, StringBuffer buffer,
- [String indentation = '']) {
- buffer.write(indentation);
- buffer.write(
- div('${span("Inferred " + description, cls: "kind")} '
- '${span(esc(name), cls: "name")} '
- '${span(esc(type), cls: "type")} ',
- cls: "attr"));
- buffer.write('\n');
+ // If keeping the element is in question (like if a function has a size
+ // of zero), only keep it if it holds dependencies to elsewhere.
+ bool shouldKeep(Element element) {
+ return compilationInfo.relations['addsToWorklist'].containsKey(element) ||
+ compilationInfo.relations['enqueues'].containsKey(element);
}
-}
-
-/// Instances represent information about a program.
-class ProgramInfo {
- /// A list of all the libraries in the program to show information about.
- final List<InfoNode> libraries;
-
- /// The size of the whole program in bytes.
- final int size;
-
- /// The time the compilation took place.
- final DateTime compilationMoment;
-
- /// The time the compilation took to complete.
- final Duration compilationDuration;
-
- /// The version of dart2js used to compile the program.
- final String dart2jsVersion;
-
- final Map<OutputUnit, int> outputUnitNumbering;
-
- ProgramInfo({this.libraries,
- this.size,
- this.compilationMoment,
- this.compilationDuration,
- this.dart2jsVersion,
- this.outputUnitNumbering: null});
Map<String, dynamic> toJson() {
- return <String, dynamic>{
- 'program_size': size,
- 'compile_time': compilationMoment.toString(),
- 'compile_duration': compilationDuration.toString(),
- 'dart2js_version': dart2jsVersion
- };
+ return mapper._toJson(this);
}
-}
-class InfoDumpVisitor extends ElementVisitor<InfoNode> {
- final Compiler compiler;
-
- /// Contains the elements visited on the path from the library to here.
- final List<Element> stack = new List<Element>();
+ // Memoization of the JSON creating process.
+ Map<String, dynamic> process(Element element) {
+ return jsonCache.putIfAbsent(element, () => element.accept(this));
+ }
- final Map<OutputUnit, int> outputUnitNumbering = new Map<OutputUnit, int>();
+ Map<String, dynamic> visitElement(Element element) {
+ return null;
+ }
- Element get currentElement => stack.last;
+ Map<String, dynamic> visitConstructorBodyElement(ConstructorBodyElement e) {
+ return visitFunctionElement(e.constructor);
+ }
- InfoDumpVisitor(Compiler this.compiler);
+ Map<String, dynamic> visitLibraryElement(LibraryElement element) {
+ var id = mapper._library.add(element);
+ List<String> children = <String>[];
- ProgramInfo collectDumpInfo() {
- JavaScriptBackend backend = compiler.backend;
+ String libname = element.getLibraryName();
+ libname = libname == "" ? "<unnamed>" : libname;
- int counter = 0;
- for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) {
- outputUnitNumbering[outputUnit] = counter;
- counter += 1;
- }
+ int size =
+ compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
- List<LibraryElement> sortedLibraries =
- compiler.libraryLoader.libraries.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());
+ LibraryElement contentsOfLibrary = element.isPatched
+ ? element.patch : element;
+ contentsOfLibrary.forEachLocalMember((Element member) {
+ Map<String, dynamic> childJson = this.process(member);
+ if (childJson == null) return;
+ children.add(childJson['id']);
});
- List<InfoNode> libraryInfos = new List<InfoNode>();
- libraryInfos.addAll(sortedLibraries
- .map((library) => visit(library))
- .where((info) => info != null));
-
- return new ProgramInfo(
- compilationDuration: compiler.totalCompileTime.elapsed,
- // 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,
- outputUnitNumbering: outputUnitNumbering);
- }
-
- InfoNode visitElement(Element element) {
- compiler.internalError(element,
- "This element of kind ${element.kind} "
- "does not support --dump-info");
- return null;
- }
+ if (children.length == 0 && !shouldKeep(element)) {
+ return null;
+ }
- InfoNode visitLibraryElement(LibraryElement element) {
- List<InfoNode> contents = new List<InfoNode>();
- int size = compiler.dumpInfoTask.codeSizeCounter
- .getGeneratedSizeOf(element);
- if (size == 0) return null;
- stack.add(element);
- // For some reason the patch library contains the origin libraries members,
- // but the origin library does not contain the patch members.
- LibraryElement contentsLibrary = element.isPatched
- ? element.patch
- : element;
- contentsLibrary.forEachLocalMember((Element member) {
- InfoNode info = member.accept(this);
- if (info != null) {
- contents.add(info);
- }
- });
- stack.removeLast();
- String nameString = element.getLibraryName() == ""
- ? "<unnamed>"
- : element.getLibraryName();
- contents.sort((InfoNode e1, InfoNode e2) {
- return e1.name.compareTo(e2.name);
- });
- return new ElementInfoNode(
- extra: "${element.canonicalUri}",
- kind: "library",
- name: nameString,
- size: size,
- modifiers: "",
- contents: contents);
+ return {
+ 'kind': 'library',
+ 'name': libname,
+ 'size': size,
+ 'id': id,
+ 'children': children
+ };
}
- InfoNode visitTypedefElement(TypedefElement element) {
+ Map<String, dynamic> visitTypedefElement(TypedefElement element) {
+ String id = mapper._typedef.add(element);
return element.alias == null
- ? null
- : new ElementInfoNode(
- type: element.alias.toString(),
- kind: "typedef",
- name: element.name);
+ ? null
+ : {
+ 'id': id,
+ 'type': element.alias.toString(),
+ 'kind': 'typedef',
+ 'name': element.name
+ };
}
- InfoNode visitFieldElement(FieldElement element) {
+ Map<String, dynamic> visitFieldElement(FieldElement element) {
+ String id = mapper._field.add(element);
+ List<String> children = [];
CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
- TypeMask inferredType = compiler.typesTask
- .getGuaranteedTypeOfElement(element);
+
// If a field has an empty inferred type it is never used.
- // Also constant fields do not get output as fields.
+ TypeMask inferredType =
+ compiler.typesTask.getGuaranteedTypeOfElement(element);
if (inferredType == null || inferredType.isEmpty || element.isConst) {
return null;
}
+
int size = 0;
- DartType type = element.type;
- List<InfoNode> contents = new List<InfoNode>();
+ String code;
+
if (emittedCode != null) {
- contents.add(new CodeInfoNode(
- description: "Generated initializer",
- generatedCode: emittedCode.getText()));
- size = emittedCode.length;
- }
- if (inferredType != null) {
- contents.add(new InferredInfoNode(
- description: "type",
- type: inferredType.toString()));
- stack.add(element);
+ size += emittedCode.length;
+ code = emittedCode.getText();
}
+
for (Element closure in element.nestedClosures) {
- InfoNode info = closure.accept(this);
- if (info != null) {
- contents.add(info);
- size += info.size;
+ var childJson = this.process(closure);
+ if (childJson != null) {
+ children.add(childJson['id']);
+ if (childJson.containsKey('size')) {
+ size += childJson['size'];
+ }
}
}
- stack.removeLast();
-
- return new ElementInfoNode(
- kind: "field",
- type: "$type",
- name: element.name,
- size: size,
- modifiers: modifiersToString(isStatic: element.isStatic,
- isFinal: element.isFinal,
- isConst: element.isConst),
- contents: contents,
- outputUnitId: outputUnitId(element));
- }
- int outputUnitId(Element element) {
- OutputUnit outputUnit =
- compiler.deferredLoadTask.outputUnitForElement(element);
- return outputUnitNumbering[outputUnit];
+ return {
+ 'id': id,
+ 'kind': 'field',
+ 'name': element.name,
+ 'children': children,
+ 'size': size,
+ 'code': code
+ };
}
- InfoNode visitClassElement(ClassElement element) {
- // If the element is not emitted in the program, we omit it from the output.
+ Map<String, dynamic> visitClassElement(ClassElement element) {
+ String id = mapper._class.add(element);
+ List<String> children = [];
+
+ int size = compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
+
+ // Omit element if it is not needed.
JavaScriptBackend backend = compiler.backend;
if (!backend.emitter.neededClasses.contains(element)) return null;
- String modifiersString = modifiersToString(isAbstract: element.isAbstract);
- String supersString = element.allSupertypes == null ? "" :
- "implements ${element.allSupertypes}";
- List contents = [];
- stack.add(element);
+ Map<String, dynamic> modifiers = { 'abstract': element.isAbstract };
+
element.forEachLocalMember((Element member) {
- InfoNode info = member.accept(this);
- if (info != null) {
- contents.add(info);
+ Map<String, dynamic> childJson = this.process(member);
+ if (childJson != null) {
+ children.add(childJson['id']);
}
});
- stack.removeLast();
- contents.sort((InfoNode n1, InfoNode n2) {
- return n1.name.compareTo(n2.name);
- });
- return new ElementInfoNode(
- kind: "class",
- name: element.name,
- extra: supersString,
- modifiers: modifiersString,
- contents: contents,
- outputUnitId: outputUnitId(element));
+
+ return {
+ 'name': element.name,
+ 'size': size,
+ 'kind': 'class',
+ 'modifiers': modifiers,
+ 'children': children,
+ 'id': id
+ };
}
- InfoNode visitFunctionElement(FunctionElement element) {
+ Map<String, dynamic> visitFunctionElement(FunctionElement element) {
+ String id = mapper._function.add(element);
+ String name = element.name;
+ String kind = "function";
+ List<String> children = [];
+ List<Map<String, dynamic>> parameters = [];
+ String returnType = null;
+ String sideEffects = null;
+ String code = "";
+
CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
int size = 0;
- String nameString = element.name;
- String modifiersString = modifiersToString(
- isStatic: element.isStatic,
- isConst: element.isConst,
- isFactory: element.isFactoryConstructor,
- isExternal: element.isPatched);
- String kindString = "function";
- if (currentElement.isClass) {
- kindString = "method";
- } else if (currentElement.isField ||
- currentElement.isFunction ||
- currentElement.isConstructor) {
- kindString = "closure";
- nameString = "<unnamed>";
+
+ Map<String, dynamic> modifiers = {
+ 'static': element.isStatic,
+ 'const': element.isConst,
+ 'factory': element.isFactoryConstructor,
+ 'external': element.isPatched
+ };
+
+ var enclosingElement = element.enclosingElement;
+ if (enclosingElement.isField ||
+ enclosingElement.isFunction ||
+ element.isClosure ||
+ enclosingElement.isConstructor) {
+ kind = "closure";
+ name = "<unnamed>";
+ } else if (enclosingElement.isClass) {
+ kind = 'method';
}
+
if (element.isConstructor) {
- nameString = element.name == ""
- ? "${element.enclosingClass.name}"
- : "${element.enclosingClass.name}.${element.name}";
- kindString = "constructor";
+ name == ""
+ ? "${element.enclosingElement.name}"
+ : "${element.enclosingElement.name}.${element.name}";
+ kind = "constructor";
}
- List contents = [];
+
if (emittedCode != null) {
FunctionSignature signature = element.functionSignature;
signature.forEachParameter((parameter) {
- contents.add(new InferredInfoNode(
- description: "parameter",
- name: parameter.name,
- type: compiler.typesTask
- .getGuaranteedTypeOfElement(parameter).toString()));
+ parameters.add({
+ 'name': parameter.name,
+ 'type': compiler.typesTask
+ .getGuaranteedTypeOfElement(parameter).toString()
+ });
});
- contents.add(new InferredInfoNode(
- description: "return type",
- type: compiler.typesTask
- .getGuaranteedReturnTypeOfElement(element).toString()));
- contents.add(new InferredInfoNode(
- description: "side effects",
- type: compiler.world
- .getSideEffectsOfElement(element).toString()));
- contents.add(new CodeInfoNode(
- description: "Generated code",
- generatedCode: emittedCode.getText()));
- size += emittedCode.length;
+ returnType = compiler.typesTask
+ .getGuaranteedReturnTypeOfElement(element).toString();
+ sideEffects = compiler.world.getSideEffectsOfElement(element).toString();
+ code = emittedCode.getText();
+ size += code.length;
}
- stack.add(element);
+
for (Element closure in element.nestedClosures) {
- InfoNode info = closure.accept(this);
- if (info != null) {
- contents.add(info);
- size += info.size;
+ Map<String, dynamic> child = this.process(closure);
+ if (child != null) {
+ children.add(child['id']);
+ size += child['size'];
}
}
- stack.removeLast();
- if (size == 0) {
+
+ if (size == 0 && !shouldKeep(element)) {
return null;
}
- return new ElementInfoNode(
- type: element.computeType(compiler).toString(),
- kind: kindString,
- name: nameString,
- size: size,
- modifiers: modifiersString,
- contents: contents,
- outputUnitId: outputUnitId(element));
+ return {
+ 'kind': kind,
+ 'name': name,
+ 'id': id,
+ 'modifiers': modifiers,
+ 'children': children,
+ 'size': size,
+ 'returnType': returnType,
+ 'parameters': parameters,
+ 'sideEffects': sideEffects,
+ 'code': code,
+ 'type': element.computeType(compiler).toString()
+ };
}
}
+
class DumpInfoTask extends CompilerTask {
DumpInfoTask(Compiler compiler)
- : infoDumpVisitor = new InfoDumpVisitor(compiler),
- super(compiler);
+ : super(compiler);
String name = "Dump Info";
final CodeSizeCounter codeSizeCounter = new CodeSizeCounter();
- final InfoDumpVisitor infoDumpVisitor;
+ ElementToJsonVisitor infoCollector;
- final Map<Element, jsAst.Expression>_generatedCode =
- new Map<Element, jsAst.Expression>();
+ final Map<Element, jsAst.Expression> _generatedCode = {};
- /// Registers that [code] has been generated for [element] so that it can be
- /// emitted in the info.html.
void registerGeneratedCode(Element element, jsAst.Expression code) {
if (compiler.dumpInfo) {
_generatedCode[element] = code;
}
}
- CodeBuffer codeOf(Element element) {
- jsAst.Expression code = _generatedCode[element];
- return code != null
- ? jsAst.prettyPrint(code, compiler)
- : compiler.backend.codeOf(element);
+
+ void collectInfo() {
+ infoCollector = new ElementToJsonVisitor(compiler);
}
void dumpInfo() {
measure(() {
- ProgramInfo info = infoDumpVisitor.collectDumpInfo();
-
- StringBuffer htmlBuffer = new StringBuffer();
- dumpInfoHtml(info, htmlBuffer);
- compiler.outputProvider('', 'info.html')
- ..add(htmlBuffer.toString())
- ..close();
+ if (infoCollector == null) {
+ collectInfo();
+ }
StringBuffer jsonBuffer = new StringBuffer();
- dumpInfoJson(info, jsonBuffer);
+ dumpInfoJson(jsonBuffer);
compiler.outputProvider('', 'info.json')
..add(jsonBuffer.toString())
..close();
});
}
- void dumpInfoJson(ProgramInfo info, StringSink buffer) {
- Map<String, dynamic> entire = <String, dynamic>{
- 'program': info.toJson(),
- 'libs': info.libraries.map((lib) => lib.toJson(info)).toList()
- };
+ CodeBuffer codeOf(Element element) {
+ jsAst.Expression code = _generatedCode[element];
+ return code != null
+ ? jsAst.prettyPrint(code, compiler)
+ : compiler.backend.codeOf(element);
+ }
+ void dumpInfoJson(StringSink buffer) {
JsonEncoder encoder = const JsonEncoder();
- ChunkedConversionSink<Object> sink =
- encoder.startChunkedConversion(
- new StringConversionSink.fromStringSink(buffer));
- sink.add(entire);
- }
- void dumpInfoHtml(ProgramInfo info, StringSink buffer) {
- int totalSize = info.size;
-
- buffer.writeln("""
-<html>
- <head>
- <title>Dart2JS compilation information</title>
- <style>
- code {margin-left: 20px; display: block; white-space: pre; }
- div.container, div.contained, div.element, div.attr {
- margin-top:0px;
- margin-bottom: 0px;
- }
- div.container, div.element, div.attr {
- white-space: nowrap;
- }
- .contents {
- margin-left: 20px;
+ // `A` uses and depends on the functions `Bs`.
+ // A Bs
+ Map<String, List<String>> holding = <String, List<String>>{};
+
+ DateTime startToJsonTime = new DateTime.now();
+
+ CompilationInformation compilationInfo =
+ infoCollector.compiler.enqueuer.codegen.compilationInfo;
+ var relations = compilationInfo.relations;
+ relations['addsToWorklist'].forEach((func, deps) {
+ if (func != null) {
+ var funcJson = infoCollector.process(func);
+ if (funcJson != null) {
+ var funcId = funcJson['id'];
+
+ List<String> heldList = <String>[];
+
+ for (var held in deps) {
+ // "process" to get the ids of the elements.
+ var heldJson = infoCollector.process(held);
+ if (heldJson != null) {
+ var heldId = heldJson['id'];
+ heldList.add(heldId);
+ }
+ }
+ holding[funcId] = heldList;
}
- div.contained {margin-left: 20px;}
- div {/*border: 1px solid;*/}
- span.kind {}
- span.modifiers {font-weight:bold;}
- span.name {font-weight:bold; font-family: monospace;}
- span.type {font-family: monospace; color:blue;}
-""");
- for (int i = 0; i < COLORS.length; i++) {
- buffer.writeln(" .outputUnit$i "
- "{border-left: 4px solid ${COLORS[i]}}");
- }
- buffer.writeln("""
- </style>
- </head>
- <body>
- <h1>Dart2js compilation information</h1>""");
- if (info.outputUnitNumbering.length > 1) {
- for (OutputUnit outputUnit in info.outputUnitNumbering.keys) {
- String color = COLORS[info.outputUnitNumbering[outputUnit]
- % COLORS.length];
- JavaScriptBackend backend = compiler.backend;
- int size = backend.emitter.outputBuffers[outputUnit].length;
- buffer.writeln('<div style='
- '"background:$color;">'
- '${outputUnit.partFileName(compiler)} $size bytes</div>');
}
- }
- buffer.writeln(h2('Compilation took place: '
- '${info.compilationMoment}'));
- buffer.writeln(h2('Compilation took: '
- '${info.compilationDuration.inSeconds} seconds'));
- buffer.writeln(h2('Output size: ${info.size} bytes'));
- if (info.dart2jsVersion != null) {
- buffer.writeln(h2('Dart2js version: ${info.dart2jsVersion}'));
- }
+ });
- buffer.writeln('<a href="#" class="sort_by_size">Sort by size</a>\n');
+ Map<String, dynamic> outJson = {};
+ outJson['elements'] = infoCollector.toJson();
+ outJson['holding'] = holding;
+ outJson['dump_version'] = 1;
- buffer.writeln('<div class="contents">');
- info.libraries.forEach((InfoNode node) {
- node.emitHtml(info, buffer);
- });
- buffer.writeln('</div>');
-
- // 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.querySelector('.details').addEventListener('click',
- toggler(container.querySelector('.contents')), false);
- container.querySelector('.contents').hidden = true;
- }
+ Duration toJsonDuration = new DateTime.now().difference(startToJsonTime);
- function sortBySize() {
- var toSort = document.querySelectorAll('.contents');
- for (var i = 0; i < toSort.length; ++i) {
- sortNodes(toSort[i], function(a, b) {
- if (a[1] !== b[1]) {
- return a[1] > b[1] ? -1 : 1;
- }
- return a[2] === b[2] ? 0 : a[2] > b[2] ? 1 : -1;
- });
- }
- }
+ Map<String, dynamic> generalProgramInfo = <String, dynamic>{};
+ generalProgramInfo['size'] = infoCollector.programSize;
+ generalProgramInfo['dart2jsVersion'] = infoCollector.dart2jsVersion;
+ generalProgramInfo['compilationMoment'] = infoCollector.compilationMoment.toString();
+ generalProgramInfo['compilationDuration'] = infoCollector.compilationDuration.toString();
+ generalProgramInfo['toJsonDuration'] = toJsonDuration.toString();
+ generalProgramInfo['dumpInfoDuration'] = infoCollector.dumpInfoDuration.toString();
- function findSize(node) {
- var size = 0;
- var details = node.querySelector('.details');
- if (details) {
- var sizeElement = details.querySelector('.size');
- if (sizeElement) {
- size = parseInt(sizeElement.textContent);
- } else {
- // For classes, sum up the contents for sorting purposes.
- var kind = details.querySelector('.kind');
- if (kind && kind.textContent === 'class') {
- var contents = node.querySelector('.contents');
- if (contents) {
- var child = contents.firstElementChild;
- while (child) {
- size += findSize(child);
- child = child.nextElementSibling;
- }
- }
- }
- }
- }
- return size;
- }
+ outJson['program'] = generalProgramInfo;
- function findName(node) {
- var name = '';
- var nameNode = node.querySelector('.name');
- if (nameNode) {
- return nameNode.textContent;
- }
- return node.textContent;
- }
- function sortNodes(node, fn) {
- var items = [];
- var child = node.firstElementChild;
- while (child) {
- items.push([child, findSize(child), findName(child)]);
- child = child.nextElementSibling;
- }
- items.sort(fn);
- for (var i = 0; i < items.length; ++i) {
- node.appendChild(items[i][0]);
- }
- }
- document.querySelector('.sort_by_size').addEventListener('click',
- function() {
- sortBySize();
- }, false);
- </script>
- </body>
-</html>""");
+ ChunkedConversionSink<Object> sink =
+ encoder.startChunkedConversion(
+ new StringConversionSink.fromStringSink(buffer));
+ sink.add(outJson);
}
}

Powered by Google App Engine
This is Rietveld 408576698