| Index: runtime/observatory/lib/src/elements/script_inset.dart
|
| diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
|
| index 3aeaf67619f19ba9b79c790a47f3b2965a05860a..1c9d97b8e6cbde28d26da64761fbfc20f52aa6b4 100644
|
| --- a/runtime/observatory/lib/src/elements/script_inset.dart
|
| +++ b/runtime/observatory/lib/src/elements/script_inset.dart
|
| @@ -43,6 +43,16 @@ void addInfoBox(Element content, Function infoBoxGenerator) {
|
| content.style.cursor = 'pointer';
|
| }
|
|
|
| +
|
| +void addLink(Element content, String target) {
|
| + // Ick, destructive but still compatible with also adding an info box.
|
| + var a = new AnchorElement(href: target);
|
| + a.text = content.text;
|
| + content.text = '';
|
| + content.append(a);
|
| +}
|
| +
|
| +
|
| abstract class Annotation implements Comparable<Annotation> {
|
| int line;
|
| int columnStart;
|
| @@ -101,47 +111,29 @@ class CurrentExecutionAnnotation extends Annotation {
|
|
|
| class LibraryAnnotation extends Annotation {
|
| Library target;
|
| - LibraryAnnotation(this.target);
|
| + String url;
|
| + LibraryAnnotation(this.target, this.url);
|
|
|
| void applyStyleTo(element) {
|
| if (element == null) {
|
| return; // TODO(rmacnak): Handling overlapping annotations.
|
| }
|
| - element.style.fontWeight = "bold";
|
| element.title = "library ${target.uri}";
|
| -
|
| - addInfoBox(element, () {
|
| - var details = table();
|
| - var r = row();
|
| - r.append(cell("Library"));
|
| - r.append(cell(serviceRef(target)));
|
| - details.append(r);
|
| -
|
| - return details;
|
| - });
|
| + addLink(element, url);
|
| }
|
| }
|
|
|
| class PartAnnotation extends Annotation {
|
| Script part;
|
| - PartAnnotation(this.part);
|
| + String url;
|
| + PartAnnotation(this.part, this.url);
|
|
|
| void applyStyleTo(element) {
|
| if (element == null) {
|
| return; // TODO(rmacnak): Handling overlapping annotations.
|
| }
|
| - element.style.fontWeight = "bold";
|
| element.title = "script ${part.uri}";
|
| -
|
| - addInfoBox(element, () {
|
| - var details = table();
|
| - var r = row();
|
| - r.append(cell("Script"));
|
| - r.append(cell(serviceRef(part)));
|
| - details.append(r);
|
| -
|
| - return details;
|
| - });
|
| + addLink(element, url);
|
| }
|
| }
|
|
|
| @@ -207,7 +199,8 @@ class CallSiteAnnotation extends Annotation {
|
| }
|
|
|
| abstract class DeclarationAnnotation extends Annotation {
|
| - DeclarationAnnotation(decl) {
|
| + String url;
|
| + DeclarationAnnotation(decl, this.url) {
|
| assert(decl.loaded);
|
| SourceLocation location = decl.location;
|
| if (location == null) {
|
| @@ -244,89 +237,58 @@ abstract class DeclarationAnnotation extends Annotation {
|
| class ClassDeclarationAnnotation extends DeclarationAnnotation {
|
| Class klass;
|
|
|
| - ClassDeclarationAnnotation(Class cls) : klass = cls, super(cls);
|
| + ClassDeclarationAnnotation(Class cls, String url)
|
| + : klass = cls,
|
| + super(cls, url);
|
|
|
| void applyStyleTo(element) {
|
| if (element == null) {
|
| return; // TODO(rmacnak): Handling overlapping annotations.
|
| }
|
| - element.style.fontWeight = "bold";
|
| element.title = "class ${klass.name}";
|
| -
|
| - addInfoBox(element, () {
|
| - var details = table();
|
| - var r = row();
|
| - r.append(cell("Class"));
|
| - r.append(cell(serviceRef(klass)));
|
| - details.append(r);
|
| -
|
| - return details;
|
| - });
|
| + addLink(element, url);
|
| }
|
| }
|
|
|
| class FieldDeclarationAnnotation extends DeclarationAnnotation {
|
| Field field;
|
|
|
| - FieldDeclarationAnnotation(Field fld) : field = fld, super(fld);
|
| + FieldDeclarationAnnotation(Field fld, String url)
|
| + : field = fld,
|
| + super(fld, url);
|
|
|
| void applyStyleTo(element) {
|
| if (element == null) {
|
| return; // TODO(rmacnak): Handling overlapping annotations.
|
| }
|
| - element.style.fontWeight = "bold";
|
| - element.title = "field ${field.name}";
|
| -
|
| - addInfoBox(element, () {
|
| - var details = table();
|
| - var r = row();
|
| - r.append(cell("Field"));
|
| - r.append(cell(serviceRef(field)));
|
| - details.append(r);
|
| -
|
| - if (field.isStatic) {
|
| - if (field.loaded) {
|
| - r = row();
|
| - r.append(cell("Value"));
|
| - r.append(cell(serviceRef(field.staticValue)));
|
| - details.append(r);
|
| - }
|
| - } else {
|
| - r = row();
|
| - r.append(cell("Nullable"));
|
| - r.append(cell(field.guardNullable ? "null observed"
|
| - : "null not observed"));
|
| - details.append(r);
|
| -
|
| - r = row();
|
| - r.append(cell("Types"));
|
| - if (field.guardClass == "dynamic") {
|
| - r.append(cell("various"));
|
| - } else if (field.guardClass == "unknown") {
|
| - r.append(cell("none"));
|
| - } else {
|
| - r.append(cell(serviceRef(field.guardClass)));
|
| - }
|
| - details.append(r);
|
| - }
|
| -
|
| - return details;
|
| - });
|
| + var tooltip = "field ${field.name}";
|
| + element.title = tooltip;
|
| + addLink(element, url);
|
| }
|
| }
|
|
|
| class FunctionDeclarationAnnotation extends DeclarationAnnotation {
|
| ServiceFunction function;
|
|
|
| - FunctionDeclarationAnnotation(ServiceFunction func)
|
| - : function = func, super(func);
|
| + FunctionDeclarationAnnotation(ServiceFunction func, String url)
|
| + : function = func,
|
| + super(func, url);
|
|
|
| void applyStyleTo(element) {
|
| if (element == null) {
|
| return; // TODO(rmacnak): Handling overlapping annotations.
|
| }
|
| - element.style.fontWeight = "bold";
|
| - element.title = "method ${function.name}";
|
| + var tooltip = "method ${function.name}";
|
| + if (function.isOptimizable == false) {
|
| + tooltip += "\nUnoptimizable!";
|
| + }
|
| + if (function.isInlinable == false) {
|
| + tooltip += "\nNot inlinable!";
|
| + }
|
| + if (function.deoptimizations > 0) {
|
| + tooltip += "\nDeoptimized ${function.deoptimizations} times!";
|
| + }
|
| + element.title = tooltip;
|
|
|
| if (function.isOptimizable == false ||
|
| function.isInlinable == false ||
|
| @@ -334,29 +296,7 @@ class FunctionDeclarationAnnotation extends DeclarationAnnotation {
|
| element.style.backgroundColor = "red";
|
| }
|
|
|
| - addInfoBox(element, () {
|
| - var details = table();
|
| - var r = row();
|
| - r.append(cell("Function"));
|
| - r.append(cell(serviceRef(function)));
|
| - details.append(r);
|
| -
|
| - r = row();
|
| - r.append(cell("Usage Count"));
|
| - r.append(cell("${function.usageCounter}"));
|
| - details.append(r);
|
| -
|
| - if (function.isOptimizable == false) {
|
| - details.append(row(cell("Unoptimizable!")));
|
| - }
|
| - if (function.isInlinable == false) {
|
| - details.append(row(cell("Not inlinable!")));
|
| - }
|
| - if (function.deoptimizations > 0) {
|
| - details.append(row("Deoptimized ${function.deoptimizations} times!"));
|
| - }
|
| - return details;
|
| - });
|
| + addLink(element, url);
|
| }
|
| }
|
|
|
| @@ -385,6 +325,8 @@ class ScriptInsetElement extends ObservatoryElement {
|
|
|
| StreamSubscription scriptChangeSubscription;
|
|
|
| + bool hasLoadedLibraryDeclarations = false;
|
| +
|
| String makeLineId(int line) {
|
| return 'line-$line';
|
| }
|
| @@ -502,14 +444,20 @@ class ScriptInsetElement extends ObservatoryElement {
|
| addCurrentExecutionAnnotation();
|
|
|
| if (!inDebuggerContext && script.library != null) {
|
| - loadDeclarationsOfLibrary(script.library);
|
| - addLibraryAnnotations();
|
| - addDependencyAnnotations();
|
| - addPartAnnotations();
|
| - addClassAnnotations();
|
| - addFieldAnnotations();
|
| - addFunctionAnnotations();
|
| - addCallSiteAnnotations();
|
| + if (hasLoadedLibraryDeclarations) {
|
| + addLibraryAnnotations();
|
| + addDependencyAnnotations();
|
| + addPartAnnotations();
|
| + addClassAnnotations();
|
| + addFieldAnnotations();
|
| + addFunctionAnnotations();
|
| + addCallSiteAnnotations();
|
| + } else {
|
| + loadDeclarationsOfLibrary(script.library).then((_) {
|
| + hasLoadedLibraryDeclarations = true;
|
| + update();
|
| + });
|
| + }
|
| }
|
|
|
| addLocalVariableAnnotations();
|
| @@ -527,34 +475,47 @@ class ScriptInsetElement extends ObservatoryElement {
|
| }
|
| }
|
|
|
| - void loadDeclarationsOfLibrary(Library lib) {
|
| - lib.load().then((lib) {
|
| + Future loadDeclarationsOfLibrary(Library lib) {
|
| + return lib.load().then((lib) {
|
| + var loads = [];
|
| for (var func in lib.functions) {
|
| - func.load();
|
| + loads.add(func.load());
|
| }
|
| for (var field in lib.variables) {
|
| - field.load();
|
| + loads.add(field.load());
|
| }
|
| for (var cls in lib.classes) {
|
| - cls.load().then((cls) {
|
| - for (var func in cls.functions) {
|
| - func.load();
|
| - }
|
| - for (var field in cls.fields) {
|
| - field.load();
|
| - }
|
| - });
|
| + loads.add(loadDeclarationsOfClass(cls));
|
| }
|
| + return Future.wait(loads);
|
| });
|
| }
|
|
|
| + Future loadDeclarationsOfClass(Class cls) {
|
| + return cls.load().then((cls) {
|
| + var loads = [];
|
| + for (var func in cls.functions) {
|
| + loads.add(func.load());
|
| + }
|
| + for (var field in cls.fields) {
|
| + loads.add(field.load());
|
| + }
|
| + return Future.wait(loads);
|
| + });
|
| + }
|
| +
|
| + String inspectLink(ServiceObject ref) {
|
| + return gotoLink('/inspect', ref);
|
| + }
|
| +
|
| void addLibraryAnnotations() {
|
| for (ScriptLine line in script.lines) {
|
| // TODO(rmacnak): Use a real scanner.
|
| var pattern = new RegExp("library ${script.library.name}");
|
| var match = pattern.firstMatch(line.text);
|
| if (match != null) {
|
| - var anno = new LibraryAnnotation(script.library);
|
| + var anno = new LibraryAnnotation(script.library,
|
| + inspectLink(script.library));
|
| anno.line = line.line;
|
| anno.columnStart = match.start + 8;
|
| anno.columnStop = match.end;
|
| @@ -564,7 +525,8 @@ class ScriptInsetElement extends ObservatoryElement {
|
| pattern = new RegExp("part of ${script.library.name}");
|
| match = pattern.firstMatch(line.text);
|
| if (match != null) {
|
| - var anno = new LibraryAnnotation(script.library);
|
| + var anno = new LibraryAnnotation(script.library,
|
| + inspectLink(script.library));
|
| anno.line = line.line;
|
| anno.columnStart = match.start + 8;
|
| anno.columnStop = match.end;
|
| @@ -598,7 +560,7 @@ class ScriptInsetElement extends ObservatoryElement {
|
| if (match != null) {
|
| Library target = resolveDependency(match[1]);
|
| if (target != null) {
|
| - var anno = new LibraryAnnotation(target);
|
| + var anno = new LibraryAnnotation(target, inspectLink(target));
|
| anno.line = line.line;
|
| anno.columnStart = match.start + 8;
|
| anno.columnStop = match.end - 1;
|
| @@ -637,7 +599,7 @@ class ScriptInsetElement extends ObservatoryElement {
|
| if (match != null) {
|
| Script part = resolvePart(match[1]);
|
| if (part != null) {
|
| - var anno = new PartAnnotation(part);
|
| + var anno = new PartAnnotation(part, inspectLink(part));
|
| anno.line = line.line;
|
| anno.columnStart = match.start + 6;
|
| anno.columnStop = match.end - 1;
|
| @@ -651,7 +613,8 @@ class ScriptInsetElement extends ObservatoryElement {
|
| void addClassAnnotations() {
|
| for (var cls in script.library.classes) {
|
| if ((cls.location != null) && (cls.location.script == script)) {
|
| - annotations.add(new ClassDeclarationAnnotation(cls));
|
| + var a = new ClassDeclarationAnnotation(cls, inspectLink(cls));
|
| + annotations.add(a);
|
| }
|
| }
|
| }
|
| @@ -659,13 +622,15 @@ class ScriptInsetElement extends ObservatoryElement {
|
| void addFieldAnnotations() {
|
| for (var field in script.library.variables) {
|
| if ((field.location != null) && (field.location.script == script)) {
|
| - annotations.add(new FieldDeclarationAnnotation(field));
|
| + var a = new FieldDeclarationAnnotation(field, inspectLink(field));
|
| + annotations.add(a);
|
| }
|
| }
|
| for (var cls in script.library.classes) {
|
| for (var field in cls.fields) {
|
| if ((field.location != null) && (field.location.script == script)) {
|
| - annotations.add(new FieldDeclarationAnnotation(field));
|
| + var a = new FieldDeclarationAnnotation(field, inspectLink(field));
|
| + annotations.add(a);
|
| }
|
| }
|
| }
|
| @@ -679,7 +644,8 @@ class ScriptInsetElement extends ObservatoryElement {
|
| (func.kind != FunctionKind.kImplicitSetterFunction)) {
|
| // We annotate a field declaration with the field instead of the
|
| // implicit getter or setter.
|
| - annotations.add(new FunctionDeclarationAnnotation(func));
|
| + var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
|
| + annotations.add(a);
|
| }
|
| }
|
| for (var cls in script.library.classes) {
|
| @@ -690,7 +656,8 @@ class ScriptInsetElement extends ObservatoryElement {
|
| (func.kind != FunctionKind.kImplicitSetterFunction)) {
|
| // We annotate a field declaration with the field instead of the
|
| // implicit getter or setter.
|
| - annotations.add(new FunctionDeclarationAnnotation(func));
|
| + var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
|
| + annotations.add(a);
|
| }
|
| }
|
| }
|
|
|