| Index: runtime/observatory/lib/src/elements/persistent_handles.dart
|
| diff --git a/runtime/observatory/lib/src/elements/persistent_handles.dart b/runtime/observatory/lib/src/elements/persistent_handles.dart
|
| index f6ccfaf433baedd8f1f0d31dd3d2b180b2700c09..7a7b3333a93a7591660984f3af050a1579f16360 100644
|
| --- a/runtime/observatory/lib/src/elements/persistent_handles.dart
|
| +++ b/runtime/observatory/lib/src/elements/persistent_handles.dart
|
| @@ -6,173 +6,269 @@ library persitent_handles_page;
|
|
|
| import 'dart:async';
|
| import 'dart:html';
|
| -import 'observatory_element.dart';
|
| -import 'package:observatory/app.dart';
|
| -import 'package:observatory/elements.dart';
|
| -import 'package:observatory/service.dart';
|
| -import 'package:polymer/polymer.dart';
|
| -
|
| -class WeakPersistentHandlesSortedTable extends SortedTable {
|
| - factory WeakPersistentHandlesSortedTable() {
|
| - var columns = [
|
| - new SortedTableColumn.withFormatter('External Size',
|
| - Utils.formatSize),
|
| - new SortedTableColumn('Peer'),
|
| - new SortedTableColumn('Finalizer Callback'),
|
| - new SortedTableColumn(''), // Spacer column.
|
| - new SortedTableColumn('Object'),
|
| - ];
|
| - WeakPersistentHandlesSortedTable result =
|
| - new WeakPersistentHandlesSortedTable._(columns);
|
| - // Sort by external size.
|
| - result.sortColumnIndex = 0;
|
| - return result;
|
| - }
|
| +import 'package:observatory/models.dart' as M;
|
| +import 'package:observatory/src/elements/containers/virtual_collection.dart';
|
| +import 'package:observatory/src/elements/helpers/any_ref.dart';
|
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
|
| +import 'package:observatory/src/elements/helpers/tag.dart';
|
| +import 'package:observatory/src/elements/helpers/uris.dart';
|
| +import 'package:observatory/src/elements/instance_ref.dart';
|
| +import 'package:observatory/src/elements/nav/bar.dart';
|
| +import 'package:observatory/src/elements/nav/isolate_menu.dart';
|
| +import 'package:observatory/src/elements/nav/menu.dart';
|
| +import 'package:observatory/src/elements/nav/notify.dart';
|
| +import 'package:observatory/src/elements/nav/refresh.dart';
|
| +import 'package:observatory/src/elements/nav/top_menu.dart';
|
| +import 'package:observatory/src/elements/nav/vm_menu.dart';
|
| +import 'package:observatory/utils.dart';
|
|
|
| - WeakPersistentHandlesSortedTable._(columns) : super(columns);
|
| +enum _SortingField {
|
| + externalSize,
|
| + peer,
|
| + finalizerCallback
|
| +}
|
|
|
| - @override
|
| - dynamic getSortKeyFor(int row, int col) {
|
| - return super.getSortKeyFor(row, col);
|
| - }
|
| +enum _SortingDirection {
|
| + ascending,
|
| + descending
|
| +}
|
|
|
| - void update(List<ServiceMap> handles, HtmlElement tableBody) {
|
| - clearRows();
|
| - for (ServiceMap handle in handles) {
|
| - var row = [int.parse(handle['externalSize'], onError: (_) => 0),
|
| - handle['peer'],
|
| - handle['callbackSymbolName'] +
|
| - '( ${handle['callbackAddress']} )',
|
| - '', // Spacer column.
|
| - handle['object']];
|
| - addRow(new SortedTableRow(row));
|
| - print(row);
|
| - }
|
| - sort();
|
| - _updateTableInDom(tableBody);
|
| - }
|
| +class PersistentHandlesPageElement extends HtmlElement implements Renderable {
|
| + static const tag =
|
| + const Tag<PersistentHandlesPageElement>('persistent-handles-page',
|
| + dependencies: const [
|
| + InstanceRefElement.tag,
|
| + NavBarElement.tag,
|
| + NavTopMenuElement.tag,
|
| + NavVMMenuElement.tag,
|
| + NavIsolateMenuElement.tag,
|
| + NavMenuElement.tag,
|
| + NavRefreshElement.tag,
|
| + NavNotifyElement.tag,
|
| + VirtualCollectionElement.tag
|
| + ]);
|
|
|
| - void sortAndDisplay(HtmlElement tableBody) {
|
| - sort();
|
| - _updateTableInDom(tableBody);
|
| - }
|
| + RenderingScheduler<PersistentHandlesPageElement> _r;
|
|
|
| + Stream<RenderedEvent<PersistentHandlesPageElement>> get onRendered =>
|
| + _r.onRendered;
|
|
|
| - void _updateTableInDom(HtmlElement tableBody) {
|
| - assert(tableBody != null);
|
| - // Resize DOM table.
|
| - if (tableBody.children.length > sortedRows.length) {
|
| - // Shrink the table.
|
| - var deadRows =
|
| - tableBody.children.length - sortedRows.length;
|
| - for (var i = 0; i < deadRows; i++) {
|
| - tableBody.children.removeLast();
|
| - }
|
| - } else if (tableBody.children.length < sortedRows.length) {
|
| - // Grow table.
|
| - var newRows = sortedRows.length - tableBody.children.length;
|
| - for (var i = 0; i < newRows; i++) {
|
| - _addDomRow(tableBody);
|
| - }
|
| - }
|
| - assert(tableBody.children.length == sortedRows.length);
|
| - // Fill table.
|
| - for (var i = 0; i < sortedRows.length; i++) {
|
| - var rowIndex = sortedRows[i];
|
| - var tr = tableBody.children[i];
|
| - _fillDomRow(tr, rowIndex);
|
| - }
|
| - }
|
| + M.VM _vm;
|
| + M.IsolateRef _isolate;
|
| + M.EventRepository _events;
|
| + M.NotificationRepository _notifications;
|
| + M.PersistentHandlesRepository _repository;
|
| + M.InstanceRepository _instances;
|
| + M.PersistentHandles _handles;
|
| + _SortingField _sortingField =
|
| + _SortingField.externalSize;
|
| + _SortingDirection _sortingDirection =
|
| + _SortingDirection.descending;
|
|
|
| - void _addDomRow(HtmlElement tableBody) {
|
| - // Add empty dom row.
|
| - var tr = new TableRowElement();
|
| + M.VMRef get vm => _vm;
|
| + M.IsolateRef get isolate => _isolate;
|
| + M.NotificationRepository get notifications => _notifications;
|
|
|
| - var cell;
|
| + factory PersistentHandlesPageElement(M.VM vm, M.IsolateRef isolate,
|
| + M.EventRepository events,
|
| + M.NotificationRepository notifications,
|
| + M.PersistentHandlesRepository repository,
|
| + M.InstanceRepository instances,
|
| + {RenderingQueue queue}) {
|
| + assert(vm != null);
|
| + assert(isolate != null);
|
| + assert(events != null);
|
| + assert(notifications != null);
|
| + assert(repository != null);
|
| + assert(instances != null);
|
| + PersistentHandlesPageElement e = document.createElement(tag.name);
|
| + e._r = new RenderingScheduler(e, queue: queue);
|
| + e._vm = vm;
|
| + e._isolate = isolate;
|
| + e._events = events;
|
| + e._notifications = notifications;
|
| + e._repository = repository;
|
| + e._instances = instances;
|
| + return e;
|
| + }
|
|
|
| - cell = tr.insertCell(-1);
|
| - cell = tr.insertCell(-1);
|
| - cell = tr.insertCell(-1);
|
| + PersistentHandlesPageElement.created() : super.created();
|
|
|
| - // Add spacer.
|
| - cell = tr.insertCell(-1);
|
| - cell.classes.add('left-border-spacer');
|
| + @override
|
| + attached() {
|
| + super.attached();
|
| + _r.enable();
|
| + _refresh();
|
| + }
|
|
|
| - // Add class ref.
|
| - cell = tr.insertCell(-1);
|
| - AnyServiceRefElement objectRef = new Element.tag('any-service-ref');
|
| - cell.children.add(objectRef);
|
| + @override
|
| + detached() {
|
| + super.detached();
|
| + _r.disable(notify: true);
|
| + children = [];
|
| + }
|
|
|
| - // Add row to table.
|
| - tableBody.children.add(tr);
|
| + void render() {
|
| + children = [
|
| + new NavBarElement(queue: _r.queue)
|
| + ..children = [
|
| + new NavTopMenuElement(queue: _r.queue),
|
| + new NavVMMenuElement(_vm, _events, queue: _r.queue),
|
| + new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
|
| + new NavMenuElement('persistent handles', last: true,
|
| + link: Uris.persistentHandles(_isolate), queue: _r.queue),
|
| + new NavRefreshElement(queue: _r.queue)
|
| + ..onRefresh.listen((_) => _refresh()),
|
| + new NavNotifyElement(_notifications, queue: _r.queue)
|
| + ]
|
| + ]..addAll(_createHandlers('Persistent Handles',
|
| + _handles?.elements?.toList(),
|
| + _createLine,
|
| + _updateLine))
|
| + ..add(new BRElement())
|
| + ..addAll(_createHandlers('Weak Persistent Handles',
|
| + _handles == null
|
| + ? null
|
| + : (_handles.weakElements.toList()
|
| + ..sort(_createSorter())),
|
| + _createWeakLine,
|
| + _updateWeakLine,
|
| + createHeader: _createWeakHeader));
|
| }
|
|
|
| - void _fillDomRow(TableRowElement tr, int rowIndex) {
|
| - var row = rows[rowIndex];
|
| + List<Element> _createHandlers(String name, List items, create, update,
|
| + {createHeader}) {
|
| + return [
|
| + new DivElement()..classes = const ['content-centered-big']
|
| + ..children = [
|
| + new HeadingElement.h1()
|
| + ..text = items == null ? '$name'
|
| + : '$name (${items.length})',
|
| + new HRElement(),
|
| + ],
|
| + new DivElement()..classes = const ['persistent-handles']
|
| + ..children = [
|
| + items == null
|
| + ? (new HeadingElement.h2()..classes = const ['content-centered-big']
|
| + ..text = 'Loading...')
|
| + : new VirtualCollectionElement(create, update, items: items,
|
| + createHeader: createHeader,
|
| + queue: _r.queue)
|
| + ]
|
| + ];
|
| + }
|
|
|
| - for (var i = 0; i < row.values.length - 2; i++) {
|
| - var cell = tr.children[i];
|
| - cell.title = row.values[i].toString();
|
| - cell.text = getFormattedValue(rowIndex, i);
|
| - cell.style.paddingLeft = '1em';
|
| - cell.style.paddingRight = '1em';
|
| + _createSorter() {
|
| + var getter;
|
| + switch (_sortingField) {
|
| + case _SortingField.externalSize:
|
| + getter = _getExternalSize;
|
| + break;
|
| + case _SortingField.peer:
|
| + getter = _getPeer;
|
| + break;
|
| + case _SortingField.finalizerCallback:
|
| + getter = _getFinalizerCallback;
|
| + break;
|
| + }
|
| + switch (_sortingDirection) {
|
| + case _SortingDirection.ascending:
|
| + return (a, b) => getter(a).compareTo(getter(b));
|
| + case _SortingDirection.descending:
|
| + return (a, b) => getter(b).compareTo(getter(a));
|
| }
|
| -
|
| - final int objectIndex = row.values.length - 1;
|
| - AnyServiceRefElement objectRef = tr.children[objectIndex].children[0];
|
| - objectRef.ref = row.values[objectIndex];
|
| }
|
| -}
|
|
|
| + static Element _createLine() =>
|
| + new DivElement()..classes = const ['collection-item']
|
| + ..text = 'object';
|
|
|
| -@CustomTag('persistent-handles-page')
|
| -class PersistentHandlesPageElement extends ObservatoryElement {
|
| - PersistentHandlesPageElement.created() : super.created();
|
| + static Element _createWeakLine() =>
|
| + new DivElement()
|
| + ..classes = const ['weak-item']
|
| + ..children = [
|
| + new SpanElement()..classes = const ['external-size']
|
| + ..text = '0B',
|
| + new SpanElement()..classes = const ['peer']
|
| + ..text = '0x00000',
|
| + new SpanElement()..classes = const ['object'],
|
| + new SpanElement()..classes = const ['finalizer']
|
| + ..text = 'dart::Class::Method()'
|
| + ];
|
|
|
| - @observable Isolate isolate;
|
| - @observable var /*ObservableList | ServiceObject*/ persistentHandles;
|
| - @observable var /*ObservableList | ServiceObject*/ weakPersistentHandles;
|
| - @observable WeakPersistentHandlesSortedTable weakPersistentHandlesTable;
|
| - var _weakPersistentHandlesTableBody;
|
| + Element _createWeakHeader() =>
|
| + new DivElement()
|
| + ..classes = const ['weak-item']
|
| + ..children = [
|
| + _createHeaderButton(const ['external-size'], 'External Size',
|
| + _SortingField.externalSize,
|
| + _SortingDirection.descending),
|
| + _createHeaderButton(const ['peer'], 'Peer',
|
| + _SortingField.peer,
|
| + _SortingDirection.descending),
|
| + new SpanElement()..classes = const ['object']
|
| + ..text = 'Object',
|
| + _createHeaderButton(const ['finalizer'], 'Finalizer Callback',
|
| + _SortingField.finalizerCallback,
|
| + _SortingDirection.ascending)
|
| + ];
|
|
|
| - void isolateChanged(oldValue) {
|
| - if (isolate != null) {
|
| - refresh();
|
| + ButtonElement _createHeaderButton(List<String> classes,
|
| + String text,
|
| + _SortingField field,
|
| + _SortingDirection direction) =>
|
| + new ButtonElement()..classes = classes
|
| + ..text = _sortingField != field ? text :
|
| + _sortingDirection == _SortingDirection.ascending
|
| + ? '$textâ–¼' : '$textâ–²'
|
| + ..onClick.listen((_) => _setSorting(field, direction));
|
| +
|
| +
|
| + void _setSorting(_SortingField field,
|
| + _SortingDirection defaultDirection) {
|
| + if (_sortingField == field) {
|
| + switch (_sortingDirection) {
|
| + case _SortingDirection.descending:
|
| + _sortingDirection = _SortingDirection.ascending;
|
| + break;
|
| + case _SortingDirection.ascending:
|
| + _sortingDirection = _SortingDirection.descending;
|
| + break;
|
| + }
|
| + } else {
|
| + _sortingDirection = defaultDirection;
|
| + _sortingField = field;
|
| }
|
| + _r.dirty();
|
| }
|
|
|
| - @override
|
| - void attached() {
|
| - super.attached();
|
| - _weakPersistentHandlesTableBody =
|
| - shadowRoot.querySelector('#weakPersistentHandlesTableBody');
|
| - weakPersistentHandlesTable =
|
| - new WeakPersistentHandlesSortedTable();
|
| + void _updateWeakLine(Element e, M.WeakPersistentHandle item,
|
| + index) {
|
| + e.children[0].text = Utils.formatSize(_getExternalSize(item));
|
| + e.children[1].text = '${_getPeer(item)}';
|
| + e.children[2] = anyRef(_isolate, item.object, _instances, queue: _r.queue)
|
| + ..classes = const ['object'];
|
| + e.children[3]..text = '${_getFinalizerCallback(item)}'
|
| + ..title = '${_getFinalizerCallback(item)}';
|
| }
|
|
|
| - Future refresh() {
|
| - return isolate.getPersistentHandles().then(_refreshView);
|
| + void _updateLine(Element e, M.PersistentHandle item,
|
| + index) {
|
| + e.children = [
|
| + anyRef(_isolate, item.object, _instances, queue: _r.queue)
|
| + ..classes = const ['object']
|
| + ];
|
| }
|
|
|
| - _refreshView(/*ObservableList | ServiceObject*/ object) {
|
| - persistentHandles = object['persistentHandles'];
|
| - weakPersistentHandles = object['weakPersistentHandles'];
|
| - weakPersistentHandlesTable.update(
|
| - weakPersistentHandles,
|
| - _weakPersistentHandlesTableBody);
|
| + Future _refresh({bool gc: false, bool reset: false}) async {
|
| + _handles = null;
|
| + _r.dirty();
|
| + _handles = await _repository.get(_isolate);
|
| + _r.dirty();
|
| }
|
|
|
| - @observable void changeSort(Event e, var detail, Element target) {
|
| - if (target is TableCellElement) {
|
| - if (weakPersistentHandlesTable.sortColumnIndex != target.cellIndex) {
|
| - weakPersistentHandlesTable.sortColumnIndex = target.cellIndex;
|
| - weakPersistentHandlesTable.sortDescending = true;
|
| - } else {
|
| - weakPersistentHandlesTable.sortDescending =
|
| - !weakPersistentHandlesTable.sortDescending;
|
| - }
|
| - weakPersistentHandlesTable.sortAndDisplay(
|
| - _weakPersistentHandlesTableBody);
|
| - }
|
| - }
|
| + static int _getExternalSize(M.WeakPersistentHandle h) => h.externalSize;
|
| + static String _getPeer(M.WeakPersistentHandle h) => h.peer;
|
| + static String _getFinalizerCallback(M.WeakPersistentHandle h) =>
|
| + '${h.callbackSymbolName} (${h.callbackAddress})';
|
| }
|
|
|