Chromium Code Reviews| Index: runtime/observatory/lib/src/elements/object_common.dart |
| diff --git a/runtime/observatory/lib/src/elements/object_common.dart b/runtime/observatory/lib/src/elements/object_common.dart |
| index 1deb5d6023134dfe25a27f581e479c44a61ee9b0..540a8acf13916ea07494deb073de70b470751626 100644 |
| --- a/runtime/observatory/lib/src/elements/object_common.dart |
| +++ b/runtime/observatory/lib/src/elements/object_common.dart |
| @@ -2,52 +2,217 @@ |
| // 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 object_common_element; |
| - |
| +import 'dart:html'; |
| import 'dart:async'; |
| -import 'observatory_element.dart'; |
| -import 'package:observatory/service.dart'; |
| -import 'package:polymer/polymer.dart'; |
| - |
| -@CustomTag('object-common') |
| -class ObjectCommonElement extends ObservatoryElement { |
| - @published ServiceObject object; |
| - @published ServiceMap path; |
| - @published ServiceMap inboundReferences; |
| - @observable int retainedBytes = null; |
| - @observable int reachableBytes = null; |
| +import 'package:observatory/models.dart' as M; |
| +import 'package:observatory/src/elements/class_ref.dart'; |
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| +import 'package:observatory/src/elements/helpers/tag.dart'; |
| +import 'package:observatory/src/elements/inbound_references.dart'; |
| +import 'package:observatory/src/elements/retaining_path.dart'; |
| +import 'package:observatory/src/elements/sentinel_value.dart'; |
| +import 'package:observatory/utils.dart'; |
| + |
| +class ObjectCommonElement extends HtmlElement implements Renderable { |
| + static const tag = const Tag<ObjectCommonElement>('object-common-wrapped', |
| + dependencies: const [ |
| + ClassRefElement.tag, |
| + InboundReferencesElement.tag, |
| + RetainingPathElement.tag, |
| + SentinelValueElement.tag |
| + ]); |
| + |
| + RenderingScheduler<ObjectCommonElement> _r; |
| + |
| + Stream<RenderedEvent<ObjectCommonElement>> get onRendered => _r.onRendered; |
| + |
| + M.IsolateRef _isolate; |
| + M.Object _object; |
| + M.RetainedSizeRepository _retainedSizes; |
| + M.ReachableSizeRepository _reachableSizes; |
| + M.InboundReferencesRepository _references; |
| + M.RetainingPathRepository _retainingPaths; |
| + M.InstanceRepository _instances; |
| + M.Guarded<M.Instance> _retainedSize = null; |
| + bool _loadingRetainedBytes = false; |
| + M.Guarded<M.Instance> _reachableSize = null; |
| + bool _loadingReachableBytes = false; |
| + |
| + M.IsolateRef get isolate => _isolate; |
| + M.Object get object => _object; |
| + |
| + factory ObjectCommonElement(M.IsolateRef isolate, M.Object object, |
| + M.RetainedSizeRepository retainedSizes, |
| + M.ReachableSizeRepository reachableSizes, |
| + M.InboundReferencesRepository references, |
| + M.RetainingPathRepository retainingPaths, |
| + M.InstanceRepository instances, |
| + {RenderingQueue queue}) { |
| + assert(isolate != null); |
| + assert(object != null); |
| + assert(retainedSizes != null); |
| + assert(reachableSizes != null); |
| + assert(references != null); |
| + assert(retainingPaths != null); |
| + assert(instances != null); |
| + ObjectCommonElement e = document.createElement(tag.name); |
| + e._r = new RenderingScheduler(e, queue: queue); |
| + e._isolate = isolate; |
| + e._object = object; |
| + e._retainedSizes = retainedSizes; |
| + e._reachableSizes = reachableSizes; |
| + e._references = references; |
| + e._instances = instances; |
| + e._retainingPaths = retainingPaths; |
| + return e; |
| + } |
| ObjectCommonElement.created() : super.created(); |
| - // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link". |
| - Future<ServiceObject> reachableSize(var dummy) { |
| - return object.isolate.getReachableSize(object).then((Instance obj) { |
| - // TODO(turnidge): Handle collected/expired objects gracefully. |
| - reachableBytes = int.parse(obj.valueAsString); |
| - }); |
| + @override |
| + void attached() { |
| + super.attached(); |
| + _r.enable(); |
| } |
| - Future<ServiceObject> retainedSize(var dummy) { |
| - return object.isolate.getRetainedSize(object).then((Instance obj) { |
| - // TODO(turnidge): Handle collected/expired objects gracefully. |
| - retainedBytes = int.parse(obj.valueAsString); |
| - }); |
| + @override |
| + void detached() { |
| + super.detached(); |
| + _r.disable(notify: true); |
| + children = []; |
| } |
| - Future<ServiceObject> retainingPath(var limit) { |
| - return object.isolate.getRetainingPath(object, limit).then((ServiceObject obj) { |
| - path = obj; |
| - }); |
| + RetainingPathElement _path; |
| + InboundReferencesElement _inbounds; |
| + |
| + void render() { |
|
Cutch
2016/08/19 22:11:19
long line?
cbernaschina
2016/08/19 22:17:40
The long line was in the old file
Cutch
2016/08/19 22:21:38
It was a bug then :)
|
| + _path = _path ?? new RetainingPathElement(_isolate, _object, |
| + _retainingPaths, _instances, |
| + queue: _r.queue); |
| + _inbounds = _inbounds ?? new InboundReferencesElement(_isolate, _object, |
| + _references, |
| + _instances, |
| + queue: _r.queue); |
| + children = [ |
| + new DivElement()..classes = const ['memberList'] |
| + ..children = [ |
| + new DivElement()..classes = const ['memberItem'] |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Class ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..children = [ |
| + new ClassRefElement(_isolate, _object.clazz, queue: _r.queue) |
| + ] |
| + ], |
| + new DivElement()..classes = const ['memberItem'] |
| + ..title = 'Space for this object in memory' |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Shallow size ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..text = Utils.formatSize(_object.size) |
| + ], |
| + new DivElement()..classes = const ['memberItem'] |
| + ..title = 'Space reachable from this object, ' |
| + 'excluding class references' |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Reachable size ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..children = _createReachableSizeValue() |
| + ], |
| + new DivElement()..classes = const ['memberItem'] |
| + ..title = 'Space that would be reclaimed if references to this ' |
| + 'object were replaced with null' |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Retained size ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..children = _createRetainedSizeValue() |
| + ], |
| + new DivElement()..classes = const ['memberItem'] |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Retaining path ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..children = [_path] |
| + ], |
| + new DivElement()..classes = const ['memberItem'] |
| + ..title = 'Objects which directly reference this object' |
| + ..children = [ |
| + new DivElement()..classes = const ['memberName'] |
| + ..text = 'Inbound references ', |
| + new DivElement()..classes = const ['memberValue'] |
| + ..children = [_inbounds] |
| + ] |
| + ] |
| + ]; |
| } |
| - Future<ServiceObject> fetchInboundReferences(var limit) { |
| - return object.isolate.getInboundReferences(object, limit) |
| - .then((ServiceObject obj) { |
| - inboundReferences = obj; |
| - }); |
| + List<Element> _createReachableSizeValue() { |
| + final content = <Element>[]; |
| + if (_reachableSize != null) { |
| + if (_reachableSize.isSentinel) { |
| + content.add( |
| + new SentinelValueElement(_reachableSize.asSentinel, queue: _r.queue) |
| + ); |
| + } else { |
| + content.add( |
| + new SpanElement()..text = Utils.formatSize(int.parse( |
| + _reachableSize.asValue.valueAsString)) |
| + ); |
| + } |
| + } else { |
| + content.add( |
| + new SpanElement()..text = '...' |
| + ); |
| + } |
| + var button; |
| + content.add( |
|
Cutch
2016/08/19 22:11:19
don't assign inside a function call
cbernaschina
2016/08/19 22:17:40
Done.
|
| + button = new ButtonElement()..classes = ['reachable_size'] |
| + ..disabled = _loadingReachableBytes |
| + ..text = '↺' |
| + ..onClick.listen((_) async { |
| + button.disabled = true; |
| + _loadingReachableBytes = true; |
| + _reachableSize = await _reachableSizes.get(_isolate, _object.id); |
| + _r.dirty(); |
| + }) |
| + ); |
| + return content; |
| } |
| - Future refresh() { |
| - return object.reload(); |
| + List<Element> _createRetainedSizeValue() { |
| + final content = <Element>[]; |
| + if (_retainedSize != null) { |
| + if (_retainedSize.isSentinel) { |
| + content.add( |
| + new SentinelValueElement(_retainedSize.asSentinel, queue: _r.queue) |
| + ); |
| + } else { |
| + content.add( |
| + new SpanElement()..text = Utils.formatSize(int.parse( |
| + _retainedSize.asValue.valueAsString)) |
| + ); |
| + } |
| + } else { |
| + content.add( |
| + new SpanElement()..text = '...' |
| + ); |
| + } |
| + var button; |
| + content.add( |
| + button = new ButtonElement()..classes = ['retained_size'] |
|
Cutch
2016/08/19 22:11:19
don't assign inside a function call
cbernaschina
2016/08/19 22:17:40
Done.
|
| + ..disabled = _loadingRetainedBytes |
| + ..text = '↺' |
| + ..onClick.listen((_) async { |
| + button.disabled = true; |
| + _loadingRetainedBytes = true; |
| + _retainedSize = await _retainedSizes.get(_isolate, _object.id); |
| + _r.dirty(); |
| + }) |
| + ); |
| + return content; |
| } |
| } |