[ VM ] Remove dead fork of Observatory from runtime/

Observatory was moved to pkg/observatory in a previous CL.

TEST=N/A

Change-Id: Ie0e7cb71799408cefe30d2c72b4dfd7bd43747ce
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450221
Auto-Submit: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ben Konyi
2025-09-17 15:15:26 -07:00
committed by Commit Queue
parent d874ad2ed5
commit be2d42a11f
291 changed files with 1 additions and 53951 deletions
+1 -1
View File
@@ -317,4 +317,4 @@ dependency_overrides:
# observatory needs a migration to language version 3.6 before it can be
# included in the workspace. (If it is not deleted before)
observatory:
path: runtime/observatory
path: pkg/observatory
-6
View File
@@ -1,6 +0,0 @@
bootstrap_css
out
build
.pub
.idea
.dart_tool
-174
View File
@@ -1,174 +0,0 @@
# Hacking Observatory
These instructions will guide you through the Observatory development and
testing workflow.
## SDK Setup & Build
Getting ready to start.
Before you start to hack on Observatory, follow the [instructions][build_sdk] to
have a working environment in which you are able to build and test the Dart SDK.
## Run existing tests
Before hacking Observatory let's run the existing Observatory tests.
We suggest to run all the test in __debug__ mode.
First build the sdk in debug mode
```
$ ./tools/build.py --mode debug create_sdk
```
From the root of the sdk repository run:
```
$ ./tools/test.py -mdebug service
```
## Serve Observatory
Observatory is built as part of building the sdk. Previously, it was recommended
to run the Observatory using `pub serve` to avoid having to rebuild the sdk for
each change to Observatory. However, `pub serve` was deprecated as part of the
transition to Dart 2.0.
[Issue #35678](https://github.com/dart-lang/sdk/issues/35678)
tracks changes required to allow for `package:build_runner` to run Observatory
without having to rebuild the sdk after each change.
## Connect to a VM
Start a Dart VM with the ``--observe`` flag (as explained in the
[get started guide][observatory_get_started]) and connect your Observatory
instance to that VM.
Example script (file name ```clock.dart```):
```dart
import 'dart:async' show Timer, Duration;
main() {
bool tick = true;
new Timer.periodic(const Duration(seconds: 1), (Timer t) {
print(tick ? 'tick' : 'tock');
tick = !tick;
});
}
```
Start the script:
```
$ dart --disable-service-origin-check --observe clock.dart
```
## Code Reviews
The development workflow of Dart (and Observatory) is based on code reviews.
Follow the code review [instructions][code_review] to be able to successfully
submit your code.
The main reviewers for Observatory related CLs are:
- asiva
- bkonyi
- rmacnak
## Write a new service test
All the service tests are located in the ```tests/service``` folder.
Test file names follow the convention ```<description>_test.dart```
(e.g. ```a_brief_description_test.dart```).
The test is generally structured in the following way.
```dart
import 'package:test/test.dart';
main() {
// Some code that you need to test.
var a = 1 + 2;
// Some assertions to check the results.
expect(a, equal(3));
}
```
See the official [test library][test_library] instructions;
The ```test_helper.dart``` file expose some functions that allow to run a part
of the code into another __VM__.
To test synchronous operations:
```dart
import 'test_helper.dart';
code() {
// Write the code you want to be execute into another VM.
}
var tests = [
// A series of tests that you want to run against the above code.
(Isolate isolate) async {
await isolate.reload();
// Use the isolate to communicate to the VM.
}
];
main(args) => runIsolateTestsSynchronous(args,
tests,
testeeConcurrent: code);
```
In order to test asynchronous operations:
```dart
import 'test_helper.dart';
code() async {
// Write the asynchronous code you want to be execute into another VM.
}
var tests = [
// A series of tests that you want to run against the above code.
(Isolate isolate) async {
await isolate.reload();
// Use the isolate to communicate to the VM.
}
];
main(args) async => runIsolateTests(args,
tests,
testeeConcurrent: code);
```
Both ```runIsolateTests``` and ```runIsolateTestsSynchronous``` have the
following named parameters:
- __testeeBefore__ (void()) a function that is going to be executed before
the test
- __testeeConcurrent__ (void()) test that is going to be executed
- __pause_on_start__ (bool, default: false) pause the Isolate before the first
instruction
- __pause_on_exit__ (bool, default: false) pause the Isolate after the last
instruction
- __pause_on_unhandled_exceptions__ (bool, default: false) pause the Isolate at
an unhandled exception
- __trace_service__ (bool, default: false) trace VM service requests
- __trace_compiler__ (bool, default: false) trace compiler operations
- __verbose_vm__ (bool, default: false) verbose logging
Some common and reusable test are available from ```service_test_common.dart```:
- hasPausedFor
- hasStoppedAtBreakpoint
- hasStoppedWithUnhandledException
- hasStoppedAtExit
- hasPausedAtStartcode_review
and utility functions:
- subscribeToStream
- cancelStreamSubscription
- asyncStepOver
- setBreakpointAtLine
- resumeIsolate
- resumeAndAwaitEvent
- resumeIsolateAndAwaitEvent
- stepOver
- getClassFromRootLib
- rootLibraryFieldValue
## Run your tests
See: __Run existing tests__
[build_sdk]: https://github.com/dart-lang/sdk/wiki/Building "Building the Dart SDK"
[open_observatory]: http://localhost:8080/ "Open Observatory"
[observatory_get_started]: https://dart-lang.github.io/observatory/get-started.html "Observatory get started"
[code_review]: https://github.com/dart-lang/sdk/wiki/Code-review-workflow-with-GitHub-and-reitveld "Code Review"
[test_library]: https://pub.dartlang.org/packages/test "Test Library"
-22
View File
@@ -1,22 +0,0 @@
analyzer:
errors:
dead_code: info
getter_not_subtype_setter_types: info
missing_enum_constant_in_switch: info
unused_element: info
unused_field: info
unused_import: info
unused_local_variable: info
exclude:
- tests/service/bad_reload/v2/main.dart
- tests/service/complex_reload/v2/main.dart
- tests/service/developer_extension_test.dart
- tests/service/evaluate_activation_in_method_class_test.dart
- tests/service/get_user_level_retaining_path_rpc_test.dart
- tests/service/pause_on_unhandled_async_exceptions_test.dart
# linter:
# rules:
# - prefer_final_fields
# - prefer_final_locals
-421
View File
@@ -1,421 +0,0 @@
// Copyright (c) 2020, 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.
// A way to test heap snapshot loading and analysis outside of Observatory, and
// to handle snapshots that require more memory to analyze than is available in
// a web browser.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:observatory/object_graph.dart';
Future<SnapshotGraph> load(String uri) async {
final ws = await WebSocket.connect(uri,
compression: CompressionOptions.compressionOff);
final getVM = new Completer<String>();
final reader = new SnapshotReader();
reader.onProgress.listen(print);
ws.listen((dynamic dynResponse) {
if (dynResponse is String) {
final response = json.decode(dynResponse);
if (response['id'] == 1) {
getVM.complete(response['result']['isolates'][0]['id']);
}
} else if (dynResponse is List<int>) {
final response = new Uint8List.fromList(dynResponse);
final dataOffset =
new ByteData.view(response.buffer).getUint32(0, Endian.little);
dynamic metadata = new Uint8List.view(response.buffer, 4, dataOffset - 4);
final data = new Uint8List.view(
response.buffer, dataOffset, response.length - dataOffset);
metadata = utf8.decode(metadata);
metadata = json.decode(metadata);
var event = metadata['params']['event'];
if (event['kind'] == 'HeapSnapshot') {
bool last = event['last'] == true;
reader.add(data);
if (last) {
reader.close();
ws.close();
}
}
}
});
ws.add(json.encode({
'jsonrpc': '2.0',
'method': 'getVM',
'params': {},
'id': 1,
}));
final String isolateId = await getVM.future;
ws.add(json.encode({
'jsonrpc': '2.0',
'method': 'streamListen',
'params': {'streamId': 'HeapSnapshot'},
'id': 2,
}));
ws.add(json.encode({
'jsonrpc': '2.0',
'method': 'requestHeapSnapshot',
'params': {'isolateId': isolateId},
'id': 3,
}));
return reader.done;
}
String makeData(dynamic root) {
// 'root' can be arbitrarily deep, so we can't directly represent it as a
// JSON tree, which cause a stack overflow here encoding it and in the JS
// engine decoding it. Instead we flatten the tree into a list of tuples with
// a parent pointer and re-inflate it in JS.
final indices = <dynamic, int>{};
final preorder = <dynamic>[];
preorder.add(root);
for (var index = 0; index < preorder.length; index++) {
final object = preorder[index];
preorder.addAll(object.children);
}
final flattened = <dynamic>[];
for (var index = 0; index < preorder.length; index++) {
final object = preorder[index];
indices[object] = index;
flattened.add(object.description);
flattened.add(object.klass.name);
flattened.add(object.retainedSize);
if (index == 0) {
flattened.add(null);
} else {
flattened.add(indices[object.parent] as int);
}
}
return json.encode(flattened);
}
var css = '''
.treemapTile {
position: absolute;
box-sizing: border-box;
border: solid 1px;
font-size: 10;
text-align: center;
overflow: hidden;
white-space: nowrap;
cursor: default;
}
''';
var js = '''
function hash(string) {
// Jenkin's one_at_a_time.
let h = string.length;
for (let i = 0; i < string.length; i++) {
h += string.charCodeAt(i);
h += h << 10;
h ^= h >> 6;
}
h += h << 3;
h ^= h >> 11;
h += h << 15;
return h;
}
function color(string) {
let hue = hash(string) % 360;
return "hsl(" + hue + ",60%,60%)";
}
function prettySize(size) {
if (size < 1024) return size + "B";
size /= 1024;
if (size < 1024) return size.toFixed(1) + "KiB";
size /= 1024;
if (size < 1024) return size.toFixed(1) + "MiB";
size /= 1024;
return size.toFixed(1) + "GiB";
}
function prettyPercent(fraction) {
return (fraction * 100).toFixed(1);
}
function createTreemapTile(v, width, height, depth) {
let div = document.createElement("div");
div.className = "treemapTile";
div.style["background-color"] = color(v.type);
div.ondblclick = function(event) {
event.stopPropagation();
if (depth == 0) {
let dom = v.parent;
if (dom == undefined) {
// Already at root.
} else {
showDominatorTree(dom); // Zoom out.
}
} else {
showDominatorTree(v); // Zoom in.
}
};
let left = 0;
let top = 0;
const kPadding = 5;
const kBorder = 1;
left += kPadding - kBorder;
top += kPadding - kBorder;
width -= 2 * kPadding;
height -= 2 * kPadding;
let label = v.name + " [" + prettySize(v.size) + "]";
div.title = label;
if (width < 10 || height < 10) {
// Too small: don't render label or children.
return div;
}
div.appendChild(document.createTextNode(label));
const kLabelHeight = 9;
top += kLabelHeight;
height -= kLabelHeight;
if (depth > 2) {
// Too deep: don't render children.
return div;
}
if (width < 4 || height < 4) {
// Too small: don't render children.
return div;
}
let children = new Array();
v.children.forEach(function(c) {
// Size 0 children seem to confuse the layout algorithm (accumulating
// rounding errors?).
if (c.size > 0) {
children.push(c);
}
});
children.sort(function (a, b) {
return b.size - a.size;
});
const scale = width * height / v.size;
// Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
// Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
// Springer, Vienna.
for (let rowStart = 0; // Index of first child in the next row.
rowStart < children.length;) {
// Prefer wider rectangles, the better to fit text labels.
const GOLDEN_RATIO = 1.61803398875;
let verticalSplit = (width / height) > GOLDEN_RATIO;
let space;
if (verticalSplit) {
space = height;
} else {
space = width;
}
let rowMin = children[rowStart].size * scale;
let rowMax = rowMin;
let rowSum = 0;
let lastRatio = 0;
let rowEnd; // One after index of last child in the next row.
for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
let size = children[rowEnd].size * scale;
if (size < rowMin) rowMin = size;
if (size > rowMax) rowMax = size;
rowSum += size;
let ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
(rowSum * rowSum) / (space * space * rowMin));
if ((lastRatio != 0) && (ratio > lastRatio)) {
// Adding the next child makes the aspect ratios worse: remove it and
// add the row.
rowSum -= size;
break;
}
lastRatio = ratio;
}
let rowLeft = left;
let rowTop = top;
let rowSpace = rowSum / space;
for (let i = rowStart; i < rowEnd; i++) {
let child = children[i];
let size = child.size * scale;
let childWidth;
let childHeight;
if (verticalSplit) {
childWidth = rowSpace;
childHeight = size / childWidth;
} else {
childHeight = rowSpace;
childWidth = size / childHeight;
}
let childDiv = createTreemapTile(child, childWidth, childHeight, depth + 1);
childDiv.style.left = rowLeft + "px";
childDiv.style.top = rowTop + "px";
// Oversize the final div by kBorder to make the borders overlap.
childDiv.style.width = (childWidth + kBorder) + "px";
childDiv.style.height = (childHeight + kBorder) + "px";
div.appendChild(childDiv);
if (verticalSplit)
rowTop += childHeight;
else
rowLeft += childWidth;
}
if (verticalSplit) {
left += rowSpace;
width -= rowSpace;
} else {
top += rowSpace;
height -= rowSpace;
}
rowStart = rowEnd;
}
return div;
}
function setBody(div) {
let body = document.body;
while (body.firstChild) {
body.removeChild(body.firstChild);
}
body.appendChild(div);
}
function showDominatorTree(v) {
let header = document.createElement("div");
header.textContent = "Dominator Tree";
header.title =
"Double click a box to zoom in.\\n" +
"Double click the outermost box to zoom out.";
header.className = "headerRow";
header.style["flex-grow"] = 0;
header.style["padding"] = "5px";
header.style["border-bottom"] = "solid 1px";
let content = document.createElement("div");
content.style["flex-basis"] = 0;
content.style["flex-grow"] = 1;
let column = document.createElement("div");
column.style["width"] = "100%";
column.style["height"] = "100%";
column.style["border"] = "solid 2px";
column.style["display"] = "flex";
column.style["flex-direction"] = "column";
column.appendChild(header);
column.appendChild(content);
setBody(column);
// Add the content div to the document first so the browser will calculate
// the available width and height.
let w = content.offsetWidth;
let h = content.offsetHeight;
let topTile = createTreemapTile(v, w, h, 0);
topTile.style.width = w;
topTile.style.height = h;
topTile.style.border = "none";
content.appendChild(topTile);
}
function inflateData(flattened) {
// 'root' can be arbitrarily deep, so we need to use an explicit stack
// instead of the call stack.
let nodes = new Array();
let i = 0;
while (i < flattened.length) {
let node = {
"name": flattened[i++],
"type": flattened[i++],
"size": flattened[i++],
"children": [],
"parent": null
};
nodes.push(node);
let parentIndex = flattened[i++];
if (parentIndex != null) {
let parent = nodes[parentIndex];
parent.children.push(node);
node.parent = parent;
}
}
return nodes[0];
}
var root = __DATA__;
root = inflateData(root);
showDominatorTree(root);
''';
var html = '''
<html>
<head>
<title>Dart Heap Snapshot</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>$css</style>
</head>
<body>
<script>$js</script>
</body>
</html>
''';
main(List<String> args) async {
if (args.length < 1) {
print('Usage: heap_snapshot.dart <vm-service-uri>');
exitCode = 1;
return;
}
var uri = Uri.parse(args[0]);
if (uri.isScheme('http')) {
uri = uri.replace(scheme: 'ws');
} else if (uri.isScheme('https')) {
uri = uri.replace(scheme: 'wss');
}
if (!uri.path.endsWith('/ws')) {
uri = uri.resolve('ws');
}
final snapshot = await load(uri.toString());
final dir = await Directory.systemTemp.createTemp('heap-snapshot');
final path = dir.path + '/merged-dominator.html';
final file = await File(path).create();
final tree = makeData(snapshot.mergedRoot);
await file.writeAsString(html.replaceAll('__DATA__', tree));
print('Wrote file://' + path);
}
-37
View File
@@ -1,37 +0,0 @@
// Copyright (c) 2014, 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 shell;
import 'dart:io';
import 'package:observatory/service_io.dart';
// Simple demo for service_io library. Connects to localhost on the default
// port, picks the first isolate, reads requests from stdin, and prints
// results to stdout. Example session:
// <<< isolate isolates/1071334835
// >>> /classes/40
// <<< {"type":"Class","id":"classes\/40","name":"num","user_name":"num",...
// >>> /objects/0
// >>> {"type":"Array","class":{"type":"@Class","id":"classes\/62",...
void repl(VM vm, Isolate isolate, String lastResult) {
print(lastResult);
Map params = {
'objectId': stdin.readLineSync(),
};
isolate.invokeRpcNoUpgrade('getObject', params).then((Map result) {
repl(vm, isolate, result.toString());
});
}
void main() {
String addr = 'ws://localhost:8181/ws';
new WebSocketVM(new WebSocketVMTarget(addr)).load().then((serviceObject) {
VM vm = serviceObject as VM;
Isolate isolate = vm.isolates.first;
repl(vm, isolate, 'isolate ${isolate.id}');
});
}
@@ -1,10 +0,0 @@
// Copyright (c) 2015, 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 allocation_profiler;
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart' as S;
part 'src/allocation_profile/allocation_profile.dart';
-31
View File
@@ -1,31 +0,0 @@
// Copyright (c) 2014, 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 app;
import 'dart:async';
import 'dart:convert';
import 'dart:js_interop';
import 'package:logging/logging.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:web/web.dart' as web;
import 'package:observatory/elements.dart';
import 'package:observatory/event.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/repositories.dart';
import 'package:observatory/service_html.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/tracer.dart';
export 'package:observatory/utils.dart';
part 'src/app/application.dart';
part 'src/app/location_manager.dart';
part 'src/app/notification.dart';
part 'src/app/page.dart';
part 'src/app/settings.dart';
part 'src/app/view_model.dart';
-9
View File
@@ -1,9 +0,0 @@
// Copyright (c) 2015, 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 cli;
import 'dart:async';
part 'src/cli/command.dart';
-13
View File
@@ -1,13 +0,0 @@
// Copyright (c) 2015, 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 debugger;
import 'dart:async';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
part 'src/debugger/debugger.dart';
part 'src/debugger/debugger_location.dart';
-97
View File
@@ -1,97 +0,0 @@
library observatory_elements;
export 'package:observatory/src/elements/allocation_profile.dart';
export 'package:observatory/src/elements/class_allocation_profile.dart';
export 'package:observatory/src/elements/class_instances.dart';
export 'package:observatory/src/elements/class_ref.dart';
export 'package:observatory/src/elements/class_tree.dart';
export 'package:observatory/src/elements/class_view.dart';
export 'package:observatory/src/elements/code_ref.dart';
export 'package:observatory/src/elements/code_view.dart';
export 'package:observatory/src/elements/containers/search_bar.dart';
export 'package:observatory/src/elements/containers/virtual_collection.dart';
export 'package:observatory/src/elements/containers/virtual_tree.dart';
export 'package:observatory/src/elements/context_ref.dart';
export 'package:observatory/src/elements/context_view.dart';
export 'package:observatory/src/elements/cpu_profile.dart';
export 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
export 'package:observatory/src/elements/cpu_profile_table.dart';
export 'package:observatory/src/elements/curly_block.dart';
export 'package:observatory/src/elements/debugger.dart';
export 'package:observatory/src/elements/error_ref.dart';
export 'package:observatory/src/elements/error_view.dart';
export 'package:observatory/src/elements/eval_box.dart';
export 'package:observatory/src/elements/field_ref.dart';
export 'package:observatory/src/elements/field_view.dart';
export 'package:observatory/src/elements/flag_list.dart';
export 'package:observatory/src/elements/function_ref.dart';
export 'package:observatory/src/elements/function_view.dart';
export 'package:observatory/src/elements/general_error.dart';
export 'package:observatory/src/elements/heap_map.dart';
export 'package:observatory/src/elements/heap_snapshot.dart';
export 'package:observatory/src/elements/process_snapshot.dart';
export 'package:observatory/src/elements/helpers/rendering_queue.dart';
export 'package:observatory/src/elements/icdata_ref.dart';
export 'package:observatory/src/elements/icdata_view.dart';
export 'package:observatory/src/elements/instance_ref.dart';
export 'package:observatory/src/elements/instance_view.dart';
export 'package:observatory/src/elements/isolate/counter_chart.dart';
export 'package:observatory/src/elements/isolate/location.dart';
export 'package:observatory/src/elements/isolate/run_state.dart';
export 'package:observatory/src/elements/isolate/shared_summary.dart';
export 'package:observatory/src/elements/isolate/summary.dart';
export 'package:observatory/src/elements/isolate_reconnect.dart';
export 'package:observatory/src/elements/isolate_ref.dart';
export 'package:observatory/src/elements/isolate_view.dart';
export 'package:observatory/src/elements/json_view.dart';
export 'package:observatory/src/elements/library_ref.dart';
export 'package:observatory/src/elements/library_view.dart';
export 'package:observatory/src/elements/local_var_descriptors_ref.dart';
export 'package:observatory/src/elements/logging.dart';
export 'package:observatory/src/elements/megamorphiccache_ref.dart';
export 'package:observatory/src/elements/megamorphiccache_view.dart';
export 'package:observatory/src/elements/metric/details.dart';
export 'package:observatory/src/elements/metric/graph.dart';
export 'package:observatory/src/elements/metrics.dart';
export 'package:observatory/src/elements/native_memory_profiler.dart';
export 'package:observatory/src/elements/nav/class_menu.dart';
export 'package:observatory/src/elements/nav/isolate_menu.dart';
export 'package:observatory/src/elements/nav/library_menu.dart';
export 'package:observatory/src/elements/nav/menu_item.dart';
export 'package:observatory/src/elements/nav/notify.dart';
export 'package:observatory/src/elements/nav/notify_event.dart';
export 'package:observatory/src/elements/nav/notify_exception.dart';
export 'package:observatory/src/elements/nav/refresh.dart';
export 'package:observatory/src/elements/nav/top_menu.dart';
export 'package:observatory/src/elements/nav/vm_menu.dart';
export 'package:observatory/src/elements/object_common.dart';
export 'package:observatory/src/elements/object_view.dart';
export 'package:observatory/src/elements/objectpool_ref.dart';
export 'package:observatory/src/elements/objectpool_view.dart';
export 'package:observatory/src/elements/objectstore_view.dart';
export 'package:observatory/src/elements/observatory_application.dart';
export 'package:observatory/src/elements/pc_descriptors_ref.dart';
export 'package:observatory/src/elements/persistent_handles.dart';
export 'package:observatory/src/elements/ports.dart';
export 'package:observatory/src/elements/sample_buffer_control.dart';
export 'package:observatory/src/elements/script_inset.dart';
export 'package:observatory/src/elements/script_ref.dart';
export 'package:observatory/src/elements/script_view.dart';
export 'package:observatory/src/elements/sentinel_value.dart';
export 'package:observatory/src/elements/sentinel_view.dart';
export 'package:observatory/src/elements/singletargetcache_ref.dart';
export 'package:observatory/src/elements/singletargetcache_view.dart';
export 'package:observatory/src/elements/source_inset.dart';
export 'package:observatory/src/elements/source_link.dart';
export 'package:observatory/src/elements/stack_trace_tree_config.dart';
export 'package:observatory/src/elements/strongly_reachable_instances.dart';
export 'package:observatory/src/elements/subtypetestcache_ref.dart';
export 'package:observatory/src/elements/subtypetestcache_view.dart';
export 'package:observatory/src/elements/timeline_page.dart';
export 'package:observatory/src/elements/type_arguments_ref.dart';
export 'package:observatory/src/elements/unknown_ref.dart';
export 'package:observatory/src/elements/unlinkedcall_ref.dart';
export 'package:observatory/src/elements/unlinkedcall_view.dart';
export 'package:observatory/src/elements/vm_connect.dart';
export 'package:observatory/src/elements/vm_connect_target.dart';
export 'package:observatory/src/elements/vm_view.dart';
-281
View File
@@ -1,281 +0,0 @@
// Copyright (c) 2016, 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.
import 'package:logging/logging.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart' as S;
class VMUpdateEvent implements M.VMUpdateEvent {
final DateTime timestamp;
final M.VMRef vm;
VMUpdateEvent(this.timestamp, this.vm);
}
class IsolateStartEvent implements M.IsolateStartEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
IsolateStartEvent(this.timestamp, this.isolate);
}
class IsolateRunnableEvent implements M.IsolateRunnableEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
IsolateRunnableEvent(this.timestamp, this.isolate);
}
class IsolateExitEvent implements M.IsolateExitEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
IsolateExitEvent(this.timestamp, this.isolate);
}
class IsolateUpdateEvent implements M.IsolateUpdateEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
IsolateUpdateEvent(this.timestamp, this.isolate);
}
class IsolateReloadEvent implements M.IsolateReloadEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.ErrorRef error;
IsolateReloadEvent(this.timestamp, this.isolate, this.error);
}
class ServiceExtensionAddedEvent implements M.ServiceExtensionAddedEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final String extensionRPC;
ServiceExtensionAddedEvent(this.timestamp, this.isolate, this.extensionRPC);
}
class DebuggerSettingsUpdateEvent implements M.DebuggerSettingsUpdateEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
DebuggerSettingsUpdateEvent(this.timestamp, this.isolate);
}
class PauseStartEvent implements M.PauseStartEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
PauseStartEvent(this.timestamp, this.isolate);
}
class PauseExitEvent implements M.PauseExitEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
PauseExitEvent(this.timestamp, this.isolate);
}
class PauseBreakpointEvent implements M.PauseBreakpointEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final Iterable<M.Breakpoint> pauseBreakpoints;
final M.Frame topFrame;
final bool atAsyncSuspension;
/// [optional]
final M.Breakpoint? breakpoint;
PauseBreakpointEvent(
this.timestamp,
this.isolate,
Iterable<M.Breakpoint> pauseBreakpoints,
this.topFrame,
this.atAsyncSuspension,
[this.breakpoint])
: pauseBreakpoints = new List.unmodifiable(pauseBreakpoints) {}
}
class PauseInterruptedEvent implements M.PauseInterruptedEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Frame? topFrame;
final bool atAsyncSuspension;
PauseInterruptedEvent(
this.timestamp, this.isolate, this.topFrame, this.atAsyncSuspension);
}
class PausePostRequestEvent implements M.PausePostRequestEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Frame? topFrame;
final bool atAsyncSuspension;
PausePostRequestEvent(
this.timestamp, this.isolate, this.topFrame, this.atAsyncSuspension);
}
class PauseExceptionEvent implements M.PauseExceptionEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Frame topFrame;
final M.InstanceRef exception;
PauseExceptionEvent(
this.timestamp, this.isolate, this.topFrame, this.exception);
}
class ResumeEvent implements M.ResumeEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Frame? topFrame;
ResumeEvent(this.timestamp, this.isolate, this.topFrame);
}
class BreakpointAddedEvent implements M.BreakpointAddedEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Breakpoint breakpoint;
BreakpointAddedEvent(this.timestamp, this.isolate, this.breakpoint);
}
class BreakpointResolvedEvent implements M.BreakpointResolvedEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Breakpoint breakpoint;
BreakpointResolvedEvent(this.timestamp, this.isolate, this.breakpoint);
}
class BreakpointRemovedEvent implements M.BreakpointRemovedEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.Breakpoint breakpoint;
BreakpointRemovedEvent(this.timestamp, this.isolate, this.breakpoint);
}
class InspectEvent implements M.InspectEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final M.InstanceRef inspectee;
InspectEvent(this.timestamp, this.isolate, this.inspectee);
}
class NoneEvent implements M.NoneEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
NoneEvent(this.timestamp, this.isolate);
}
class GCEvent implements M.GCEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
GCEvent(this.timestamp, this.isolate);
}
class LoggingEvent implements M.LoggingEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final Map logRecord;
LoggingEvent(this.timestamp, this.isolate, this.logRecord);
}
class ExtensionEvent implements M.ExtensionEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final String extensionKind;
final M.ExtensionData extensionData;
ExtensionEvent(
this.timestamp, this.isolate, this.extensionKind, this.extensionData);
}
class TimelineEventsEvent implements M.TimelineEventsEvent {
final DateTime timestamp;
final M.IsolateRef isolate;
final Iterable<M.TimelineEvent> timelineEvents;
TimelineEventsEvent(
this.timestamp, this.isolate, Iterable<M.TimelineEvent> timelineEvents)
: timelineEvents = new List.unmodifiable(timelineEvents) {}
}
class ConnectionClosedEvent implements M.ConnectionClosedEvent {
final DateTime timestamp;
final String reason;
ConnectionClosedEvent(this.timestamp, this.reason);
}
class ServiceRegisteredEvent implements M.ServiceRegisteredEvent {
final DateTime timestamp;
final String service;
final String method;
final String alias;
ServiceRegisteredEvent(this.timestamp, this.service, this.method, this.alias);
}
class ServiceUnregisteredEvent implements M.ServiceUnregisteredEvent {
final DateTime timestamp;
final String service;
final String method;
ServiceUnregisteredEvent(this.timestamp, this.service, this.method);
}
M.Event? createEventFromServiceEvent(S.ServiceEvent event) {
switch (event.kind) {
case S.ServiceEvent.kVMUpdate:
return new VMUpdateEvent(event.timestamp!, event.vm);
case S.ServiceEvent.kIsolateStart:
return new IsolateStartEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kIsolateRunnable:
return new IsolateRunnableEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kIsolateUpdate:
return new IsolateUpdateEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kIsolateReload:
return new IsolateReloadEvent(
event.timestamp!, event.isolate!, event.error!);
case S.ServiceEvent.kIsolateExit:
return new IsolateExitEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kBreakpointAdded:
return new BreakpointAddedEvent(
event.timestamp!, event.isolate!, event.breakpoint!);
case S.ServiceEvent.kBreakpointResolved:
return new BreakpointResolvedEvent(
event.timestamp!, event.isolate!, event.breakpoint!);
case S.ServiceEvent.kBreakpointRemoved:
return new BreakpointRemovedEvent(
event.timestamp!, event.isolate!, event.breakpoint!);
case S.ServiceEvent.kDebuggerSettingsUpdate:
return new DebuggerSettingsUpdateEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kResume:
return new ResumeEvent(event.timestamp!, event.isolate!, event.topFrame);
case S.ServiceEvent.kPauseStart:
return new PauseStartEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kPauseExit:
return new PauseExitEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kPausePostRequest:
return new PausePostRequestEvent(event.timestamp!, event.isolate!,
event.topFrame, event.atAsyncSuspension!);
case S.ServiceEvent.kPauseBreakpoint:
return new PauseBreakpointEvent(
event.timestamp!,
event.isolate!,
event.pauseBreakpoints!,
event.topFrame!,
event.atAsyncSuspension!,
event.breakpoint);
case S.Isolate.kLoggingStream:
return new LoggingEvent(
event.timestamp!, event.isolate!, event.logRecord!);
case S.ServiceEvent.kPauseInterrupted:
return new PauseInterruptedEvent(event.timestamp!, event.isolate!,
event.topFrame, event.atAsyncSuspension!);
case S.ServiceEvent.kPauseException:
return new PauseExceptionEvent(
event.timestamp!, event.isolate!, event.topFrame!, event.exception!);
case S.ServiceEvent.kInspect:
return new InspectEvent(
event.timestamp!, event.isolate!, event.inspectee!);
case S.ServiceEvent.kGC:
return new GCEvent(event.timestamp!, event.isolate!);
case S.ServiceEvent.kServiceRegistered:
return new ServiceRegisteredEvent(
event.timestamp!, event.service!, event.method!, event.alias!);
case S.ServiceEvent.kServiceUnregistered:
return new ServiceUnregisteredEvent(
event.timestamp!, event.service!, event.method!);
case S.ServiceEvent.kNone:
return new NoneEvent(event.timestamp!, event.isolate!);
default:
// Ignore unrecognized events.
Logger.root.severe('Unrecognized event: $event');
return null;
}
}
-97
View File
@@ -1,97 +0,0 @@
// Copyright (c) 2016, 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 models;
import 'dart:async';
import 'package:observatory/object_graph.dart';
part 'src/models/exceptions.dart';
part 'src/models/objects/allocation_profile.dart';
part 'src/models/objects/breakpoint.dart';
part 'src/models/objects/class.dart';
part 'src/models/objects/code.dart';
part 'src/models/objects/context.dart';
part 'src/models/objects/error.dart';
part 'src/models/objects/event.dart';
part 'src/models/objects/extension_data.dart';
part 'src/models/objects/field.dart';
part 'src/models/objects/flag.dart';
part 'src/models/objects/frame.dart';
part 'src/models/objects/function.dart';
part 'src/models/objects/guarded.dart';
part 'src/models/objects/heap_space.dart';
part 'src/models/objects/icdata.dart';
part 'src/models/objects/inbound_references.dart';
part 'src/models/objects/instance.dart';
part 'src/models/objects/isolate.dart';
part 'src/models/objects/isolate_group.dart';
part 'src/models/objects/library.dart';
part 'src/models/objects/local_var_descriptors.dart';
part 'src/models/objects/map_association.dart';
part 'src/models/objects/megamorphiccache.dart';
part 'src/models/objects/metric.dart';
part 'src/models/objects/notification.dart';
part 'src/models/objects/object.dart';
part 'src/models/objects/objectpool.dart';
part 'src/models/objects/objectstore.dart';
part 'src/models/objects/pc_descriptors.dart';
part 'src/models/objects/persistent_handles.dart';
part 'src/models/objects/ports.dart';
part 'src/models/objects/retaining_path.dart';
part 'src/models/objects/sample_profile.dart';
part 'src/models/objects/script.dart';
part 'src/models/objects/sentinel.dart';
part 'src/models/objects/service.dart';
part 'src/models/objects/single_target_cache.dart';
part 'src/models/objects/source_location.dart';
part 'src/models/objects/subtype_test_cache.dart';
part 'src/models/objects/target.dart';
part 'src/models/objects/timeline.dart';
part 'src/models/objects/timeline_event.dart';
part 'src/models/objects/type_arguments.dart';
part 'src/models/objects/unknown.dart';
part 'src/models/objects/unlinked_call.dart';
part 'src/models/objects/vm.dart';
part 'src/models/repositories/allocation_profile.dart';
part 'src/models/repositories/breakpoint.dart';
part 'src/models/repositories/class.dart';
part 'src/models/repositories/context.dart';
part 'src/models/repositories/editor.dart';
part 'src/models/repositories/eval.dart';
part 'src/models/repositories/event.dart';
part 'src/models/repositories/field.dart';
part 'src/models/repositories/flag.dart';
part 'src/models/repositories/function.dart';
part 'src/models/repositories/heap_snapshot.dart';
part 'src/models/repositories/icdata.dart';
part 'src/models/repositories/inbound_references.dart';
part 'src/models/repositories/instance.dart';
part 'src/models/repositories/isolate.dart';
part 'src/models/repositories/isolate_group.dart';
part 'src/models/repositories/library.dart';
part 'src/models/repositories/megamorphiccache.dart';
part 'src/models/repositories/metric.dart';
part 'src/models/repositories/notification.dart';
part 'src/models/repositories/object.dart';
part 'src/models/repositories/objectpool.dart';
part 'src/models/repositories/objectstore.dart';
part 'src/models/repositories/persistent_handles.dart';
part 'src/models/repositories/ports.dart';
part 'src/models/repositories/reachable_size.dart';
part 'src/models/repositories/retained_size.dart';
part 'src/models/repositories/retaining_path.dart';
part 'src/models/repositories/sample_profile.dart';
part 'src/models/repositories/script.dart';
part 'src/models/repositories/single_target_cache.dart';
part 'src/models/repositories/strongly_reachable_instances.dart';
part 'src/models/repositories/subtype_test_cache.dart';
part 'src/models/repositories/target.dart';
part 'src/models/repositories/timeline.dart';
part 'src/models/repositories/type_arguments.dart';
part 'src/models/repositories/unlinked_call.dart';
part 'src/models/repositories/vm.dart';
File diff suppressed because it is too large Load Diff
-58
View File
@@ -1,58 +0,0 @@
// Copyright (c) 2016, 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 repositories;
import 'dart:async';
import 'dart:convert';
import 'package:web/web.dart';
import 'package:observatory/allocation_profile.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/object_graph.dart';
import 'package:observatory/sample_profile.dart';
import 'package:observatory/service.dart' as S;
import 'package:observatory/service_common.dart' as SC;
import 'package:observatory/src/repositories/timeline_base.dart';
part 'src/repositories/allocation_profile.dart';
part 'src/repositories/breakpoint.dart';
part 'src/repositories/class.dart';
part 'src/repositories/context.dart';
part 'src/repositories/editor.dart';
part 'src/repositories/eval.dart';
part 'src/repositories/event.dart';
part 'src/repositories/field.dart';
part 'src/repositories/flag.dart';
part 'src/repositories/function.dart';
part 'src/repositories/heap_snapshot.dart';
part 'src/repositories/icdata.dart';
part 'src/repositories/inbound_references.dart';
part 'src/repositories/instance.dart';
part 'src/repositories/isolate.dart';
part 'src/repositories/isolate_group.dart';
part 'src/repositories/library.dart';
part 'src/repositories/megamorphiccache.dart';
part 'src/repositories/metric.dart';
part 'src/repositories/notification.dart';
part 'src/repositories/object.dart';
part 'src/repositories/objectpool.dart';
part 'src/repositories/objectstore.dart';
part 'src/repositories/persistent_handles.dart';
part 'src/repositories/ports.dart';
part 'src/repositories/reachable_size.dart';
part 'src/repositories/retained_size.dart';
part 'src/repositories/retaining_path.dart';
part 'src/repositories/sample_profile.dart';
part 'src/repositories/script.dart';
part 'src/repositories/settings.dart';
part 'src/repositories/single_target_cache.dart';
part 'src/repositories/strongly_reachable_instances.dart';
part 'src/repositories/subtype_test_cache.dart';
part 'src/repositories/target.dart';
part 'src/repositories/timeline.dart';
part 'src/repositories/type_arguments.dart';
part 'src/repositories/unlinked_call.dart';
part 'src/repositories/vm.dart';
@@ -1,15 +0,0 @@
// Copyright (c) 2015, 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 sample_profiler;
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
part 'src/sample_profile/sample_profile.dart';
-21
View File
@@ -1,21 +0,0 @@
// Copyright (c) 2014, 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 service;
import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:logging/logging.dart';
import 'package:observatory/event.dart' show createEventFromServiceEvent;
import 'package:observatory/models.dart' as M;
import 'package:observatory/object_graph.dart';
import 'package:observatory/sample_profile.dart';
import 'package:observatory/service_common.dart';
import 'package:observatory/tracer.dart';
part 'src/service/object.dart';
-339
View File
@@ -1,339 +0,0 @@
// Copyright (c) 2014, 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 service_common;
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:logging/logging.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
// Export the service library.
export 'package:observatory/service.dart';
/// Description of a VM target.
class WebSocketVMTarget implements M.Target {
// Last time this VM has been connected to.
int lastConnectionTime = 0;
bool get hasEverConnected => lastConnectionTime > 0;
// Chrome VM or standalone;
bool chrome = false;
bool get standalone => !chrome;
// User defined name.
late String name;
// Network address of VM.
late String networkAddress;
WebSocketVMTarget(this.networkAddress) {
name = networkAddress;
}
WebSocketVMTarget.fromMap(Map json) {
lastConnectionTime = json['lastConnectionTime'];
chrome = json['chrome'];
networkAddress = json['networkAddress'];
name = json['name'] ?? networkAddress;
}
Map toJson() {
return {
'lastConnectionTime': lastConnectionTime,
'chrome': chrome,
'name': name,
'networkAddress': networkAddress,
};
}
}
class _WebSocketRequest {
final String method;
final Map params;
final Completer<Map> completer;
_WebSocketRequest(this.method, this.params)
: completer = new Completer<Map>();
}
/// Minimal common interface for 'WebSocket' in [dart:io] and [package:web/web.dart].
abstract class CommonWebSocket {
Future<void> connect(WebSocketVMTarget target, void onOpen(),
void onMessage(dynamic data), void onError(), void onClose());
bool get isOpen;
void send(dynamic data);
void close();
Future<ByteData> nonStringToByteData(dynamic data);
}
/// A [CommonWebSocketVM] communicates with a Dart VM over a CommonWebSocket.
/// The Dart VM can be embedded in Chromium or standalone.
abstract class CommonWebSocketVM extends VM {
final Completer _connected = new Completer();
final Completer<String> _disconnected = new Completer<String>();
final WebSocketVMTarget target;
final Map<String, _WebSocketRequest> _delayedRequests =
new Map<String, _WebSocketRequest>();
final Map<String, _WebSocketRequest> _pendingRequests =
new Map<String, _WebSocketRequest>();
int _requestSerial = 0;
bool _hasInitiatedConnect = false;
Utf8Decoder _utf8Decoder = const Utf8Decoder();
String get displayName => '${name}@${target.name}';
CommonWebSocket? _webSocket;
CommonWebSocketVM(this.target, this._webSocket);
void _notifyConnect() {
if (!_connected.isCompleted) {
Logger.root
.info('WebSocketVM connection opened: ${target.networkAddress}');
_connected.complete(this);
}
}
Future get onConnect => _connected.future;
bool get wasOrIsConnected => _connected.isCompleted;
bool get isConnected => wasOrIsConnected && !isDisconnected;
void _notifyDisconnect(String reason) {
if (!_disconnected.isCompleted) {
Logger.root
.info('WebSocketVM connection error: ${target.networkAddress}');
_disconnected.complete(reason);
}
}
Future<String> get onDisconnect => _disconnected.future;
bool get isDisconnected => _disconnected.isCompleted;
void disconnect({String reason = 'WebSocket closed'}) {
if (_hasInitiatedConnect) {
if (_webSocket != null) {
_webSocket!.close();
}
}
// We don't need to cancel requests and notify here. These
// functions will be called again when the onClose callback
// fires. However, we may have a better 'reason' string now, so
// let's take care of business.
_cancelAllRequests(reason);
_notifyDisconnect(reason);
}
Future<Map> invokeRpcRaw(String method, Map params) async {
if (!_hasInitiatedConnect) {
_hasInitiatedConnect = true;
try {
await _webSocket!
.connect(target, _onOpen, _onMessage, _onError, _onClose);
} catch (_, stack) {
_webSocket = null;
var exception = new NetworkRpcException('WebSocket closed');
return new Future.error(exception, stack);
}
}
if (_disconnected.isCompleted) {
// This connection was closed already.
var exception = new NetworkRpcException(await onDisconnect);
return new Future.error(exception);
}
String serial = (_requestSerial++).toString();
var request = new _WebSocketRequest(method, <String, dynamic>{
...params,
// Include internal response data.
'_includePrivateMembers': true,
});
if ((_webSocket != null) && _webSocket!.isOpen) {
// Already connected, send request immediately.
_sendRequest(serial, request);
} else {
// Not connected yet, add to delayed requests.
_delayedRequests[serial] = request;
}
return request.completer.future;
}
void _onClose() {
_cancelAllRequests('WebSocket closed');
_notifyDisconnect('WebSocket closed');
}
// WebSocket error event handler.
void _onError() {
// TODO(turnidge): The implementors of CommonWebSocket have more
// error information available. Consider providing that here.
_cancelAllRequests('WebSocket closed due to error');
_notifyDisconnect('WebSocket closed due to error');
}
// WebSocket open event handler.
void _onOpen() {
target.lastConnectionTime = new DateTime.now().millisecondsSinceEpoch;
_sendAllDelayedRequests();
_notifyConnect();
}
Map? _parseJSON(String message) {
var map;
try {
map = json.decode(message);
} catch (e, st) {
Logger.root.severe('Disconnecting: Error decoding message: $e\n$st');
disconnect(reason: 'Connection saw corrupt JSON message: $e');
return null;
}
if (map == null) {
Logger.root.severe("Disconnecting: Unable to decode 'null' message");
disconnect(reason: "Connection saw 'null' message");
return null;
}
return map;
}
void _onBinaryMessage(dynamic data) {
_webSocket!.nonStringToByteData(data).then((ByteData bytes) {
var metadataOffset = 4;
var dataOffset = bytes.getUint32(0, Endian.little);
var metadataLength = dataOffset - metadataOffset;
var dataLength = bytes.lengthInBytes - dataOffset;
var metadata = _utf8Decoder.convert(new Uint8List.view(
bytes.buffer, bytes.offsetInBytes + metadataOffset, metadataLength));
var data = new Uint8List.view(
bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
var map = _parseJSON(metadata);
if (map == null || map['method'] != 'streamNotify') {
return;
}
var event = map['params']['event'];
var streamId = map['params']['streamId'];
scheduleMicrotask(() {
postServiceEvent(streamId, event, data);
});
});
}
void _onStringMessage(String data) {
var map = _parseJSON(data);
if (map == null) {
return;
}
if (map['method'] == 'streamNotify') {
var event = map['params']['event'];
var streamId = map['params']['streamId'];
scheduleMicrotask(() {
postServiceEvent(streamId, event, null);
});
return;
}
// Extract serial and result.
var serial = map['id'];
// Complete request.
var request = _pendingRequests.remove(serial);
if (request == null) {
Logger.root.severe('Received unexpected message: ${map}');
return;
}
if (request.method != 'getTagProfile' &&
request.method != 'getIsolateMetric' &&
request.method != 'getVMMetric') {
Logger.root.info('RESPONSE [${serial}] ${request.method}');
}
var result = map['result'];
if (result != null) {
request.completer.complete(result);
} else {
var exception = new ServerRpcException.fromMap(map['error']);
request.completer.completeError(exception);
}
}
// WebSocket message event handler.
void _onMessage(dynamic data) {
if (data is! String) {
_onBinaryMessage(data);
} else {
_onStringMessage(data);
}
}
void _cancelRequests(
Map<String, _WebSocketRequest> requests, String message) {
requests.forEach((String serial, _WebSocketRequest request) {
var exception = new NetworkRpcException(message +
'(id: $serial method: ${request.method} params: ${request.params})');
request.completer.completeError(exception);
});
requests.clear();
}
/// Cancel all pending and delayed requests by completing them with an error.
void _cancelAllRequests(String reason) {
String message = 'Canceling request: $reason';
if (_pendingRequests.length > 0) {
Logger.root.info('Canceling all pending requests.');
_cancelRequests(_pendingRequests, message);
}
if (_delayedRequests.length > 0) {
Logger.root.info('Canceling all delayed requests.');
_cancelRequests(_delayedRequests, message);
}
}
/// Send all delayed requests.
void _sendAllDelayedRequests() {
assert(_webSocket!.isOpen);
if (_delayedRequests.length == 0) {
return;
}
Logger.root.info('Sending all delayed requests.');
// Send all delayed requests.
_delayedRequests.forEach(_sendRequest);
// Clear all delayed requests.
_delayedRequests.clear();
}
/// Send the request over WebSocket.
void _sendRequest(String serial, _WebSocketRequest request) {
assert(_webSocket!.isOpen);
// Mark request as pending.
assert(_pendingRequests.containsKey(serial) == false);
_pendingRequests[serial] = request;
var message;
// Encode message.
if (target.chrome) {
message = json.encode({
'id': int.parse(serial),
'method': 'Dart.observatoryQuery',
'params': {'id': serial, 'query': request.method}
});
} else {
message = json.encode({
'jsonrpc': '2.0',
'id': serial,
'method': request.method,
'params': request.params
});
}
if (request.method != 'getTagProfile' &&
request.method != 'getIsolateMetric' &&
request.method != 'getVMMetric') {
Logger.root.info(
'GET [${serial}] ${request.method}(${request.params}) from ${target.networkAddress}');
}
// Send message.
_webSocket!.send(message);
}
String toString() => displayName;
}
-79
View File
@@ -1,79 +0,0 @@
// Copyright (c) 2014, 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 service_html;
import 'dart:async';
import 'dart:typed_data';
import 'package:web/web.dart';
import 'package:observatory/service_common.dart';
// Export the service library.
export 'package:observatory/service_common.dart';
class _HtmlWebSocket implements CommonWebSocket {
WebSocket? _webSocket;
Future<void> connect(WebSocketVMTarget target, void onOpen(),
void onMessage(dynamic data), void onError(), void onClose()) async {
// The VM service will attempt to redirect our websocket connection request
// to DDS, but the package:web/web.dart WebSocket doesn't follow redirects. Instead of
// relying on a redirect, we'll request the websocket URI from the service.
// TODO(bkonyi): re-enable when DDS is enabled. Currently causing Observatory
// failures when running with Flutter (see
// https://github.com/flutter/flutter/issues/64333)
/*Uri getWebSocketUriRequest = Uri.parse(target.networkAddress);
getWebSocketUriRequest =
getWebSocketUriRequest.replace(scheme: 'http', pathSegments: [
...getWebSocketUriRequest.pathSegments.where((e) => e != 'ws'),
'getWebSocketTarget',
]);
final response = json.decode(await HttpRequest.getString(
getWebSocketUriRequest.toString(),
));
if (!response.containsKey('result') ||
!response['result'].containsKey('uri')) {
onError();
return;
}
target.networkAddress = response['result']['uri'];
*/
_webSocket = new WebSocket(target.networkAddress);
_webSocket!.onClose.listen((CloseEvent) => onClose());
_webSocket!.onError.listen((Event) => onError());
_webSocket!.onOpen.listen((Event) => onOpen());
_webSocket!.onMessage.listen((MessageEvent event) => onMessage(event.data));
}
bool get isOpen => _webSocket!.readyState == WebSocket.OPEN;
void send(dynamic data) {
_webSocket!.send(data);
}
void close() {
_webSocket!.close();
}
Future<ByteData> nonStringToByteData(dynamic data) {
assert(data is Blob);
FileReader fileReader = new FileReader();
fileReader.readAsArrayBuffer(data);
return fileReader.onLoadEnd.first.then((e) {
final Uint8List result = (fileReader.result as ByteBuffer).asUint8List();
return new ByteData.view(
result.buffer, result.offsetInBytes, result.length);
});
}
}
/// The [WebSocketVM] communicates with a Dart VM over WebSocket. The Dart VM
/// can be embedded in Chromium or standalone. In the case of Chromium, we
/// make the service requests via the Chrome Remote Debugging Protocol.
class WebSocketVM extends CommonWebSocketVM {
WebSocketVM(WebSocketVMTarget target) : super(target, new _HtmlWebSocket());
}
-57
View File
@@ -1,57 +0,0 @@
// Copyright (c) 2014, 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 service_io;
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:logging/logging.dart';
import 'package:observatory/service_common.dart';
// Export the service library.
export 'package:observatory/service_common.dart';
class _IOWebSocket implements CommonWebSocket {
WebSocket? _webSocket;
Future<void> connect(WebSocketVMTarget target, void onOpen(),
void onMessage(dynamic data), void onError(), void onClose()) async {
try {
_webSocket = await WebSocket.connect(target.networkAddress);
_webSocket!.listen(onMessage,
onError: (dynamic) => onError(),
onDone: onClose,
cancelOnError: true);
onOpen();
} catch (_) {
onError();
}
}
bool get isOpen =>
(_webSocket != null) && (_webSocket!.readyState == WebSocket.open);
void send(dynamic data) {
_webSocket!.add(data);
}
void close() {
_webSocket?.close();
}
Future<ByteData> nonStringToByteData(dynamic data) {
assert(data is Uint8List);
Logger.root.info('Binary data size in bytes: ${data.lengthInBytes}');
return new Future.sync(() =>
new ByteData.view(data.buffer, data.offsetInBytes, data.lengthInBytes));
}
}
/// The [WebSocketVM] communicates with a Dart VM over WebSocket.
class WebSocketVM extends CommonWebSocketVM {
WebSocketVM(WebSocketVMTarget target) : super(target, new _IOWebSocket());
}
@@ -1,91 +0,0 @@
// Copyright (c) 2015, 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.
part of allocation_profiler;
class AllocationProfile implements M.AllocationProfile {
static const _lastServiceGC = 'dateLastServiceGC';
final DateTime? lastServiceGC;
static const _lastAccumulatorReset = 'dateLastAccumulatorReset';
final DateTime? lastAccumulatorReset;
final S.HeapSpace newSpace;
final S.HeapSpace oldSpace;
final S.HeapSpace totalSpace;
final Iterable<M.ClassHeapStats> members;
AllocationProfile(S.ServiceMap map,
{Map/*<String, List<String>>*/ ? defaults})
: lastAccumulatorReset = _intString2DateTime(map[_lastAccumulatorReset]),
lastServiceGC = _intString2DateTime(map[_lastServiceGC]),
oldSpace = new S.HeapSpace()..update(map['_heaps']['old']),
newSpace = new S.HeapSpace()..update(map['_heaps']['new']),
totalSpace = new S.HeapSpace(),
members = _convertMembers(map['members'], defaults: defaults) {
totalSpace.add(oldSpace);
totalSpace.add(newSpace);
}
static DateTime? _intString2DateTime(String? milliseconds) {
if ((milliseconds == null) || milliseconds == '') {
return null;
}
return new DateTime.fromMillisecondsSinceEpoch(int.parse(milliseconds));
}
static ClassHeapStats _convertMember(/*S.ServiceMap*/ map) {
assert(map['type'] == 'ClassHeapStats');
return new ClassHeapStats(map);
}
static List<M.ClassHeapStats> _convertMembers(Iterable/*<S.ServiceMap>*/ raw,
{Map/*<String, List<String>>*/ ? defaults}) {
final List<M.ClassHeapStats> members =
raw.map<ClassHeapStats>(_convertMember).toList();
if (defaults == null) {
return members;
}
final Map<String, List<ClassHeapStats>> aliases =
new Map.fromIterable(defaults.keys, value: (_) => <ClassHeapStats>[]);
final Map<String, List<ClassHeapStats>> accumulators =
<String, List<ClassHeapStats>>{};
defaults.forEach((/*String*/ key, /*List<String>*/ values) {
final classes = aliases[key]!;
accumulators.addAll(new Map.fromIterable(values, value: (_) => classes));
});
final List<M.ClassHeapStats> result = <M.ClassHeapStats>[];
members.forEach((M.ClassHeapStats member) {
if (accumulators.containsKey(member.clazz!.id)) {
accumulators[member.clazz!.id]!.add(member as ClassHeapStats);
} else {
result.add(member as ClassHeapStats);
}
});
return result
..addAll(
aliases.keys.map((key) => new ClassesHeapStats(key, aliases[key]!)));
}
}
class ClassHeapStats implements M.ClassHeapStats {
final S.Class? clazz;
final String? displayName = null;
final S.Allocations newSpace;
final S.Allocations oldSpace;
ClassHeapStats(Map map)
: clazz = map['class'],
oldSpace = new S.Allocations()..update(map['_old']),
newSpace = new S.Allocations()..update(map['_new']);
}
class ClassesHeapStats implements M.ClassHeapStats {
final S.Class? clazz = null;
final String? displayName;
final S.Allocations newSpace;
final S.Allocations oldSpace;
ClassesHeapStats(this.displayName, Iterable<ClassHeapStats> classes)
: oldSpace = new S.Allocations()..combine(classes.map((m) => m.oldSpace)),
newSpace = new S.Allocations()..combine(classes.map((m) => m.newSpace));
}
@@ -1,291 +0,0 @@
// 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.
part of app;
/// The observatory application. Instances of this are created and owned
/// by the observatory_application custom element.
class ObservatoryApplication {
static late ObservatoryApplication app;
final RenderingQueue queue = new RenderingQueue();
final TargetRepository targets = new TargetRepository(isConnectedVMTarget);
final EventRepository events = new EventRepository();
final NotificationRepository notifications = new NotificationRepository();
final _pageRegistry = <Page>[];
late LocationManager _locationManager;
LocationManager get locationManager => _locationManager;
Page? currentPage;
bool _vmConnected = false;
VM? _vm;
VM get vm => _vm!;
static bool isConnectedVMTarget(M.Target target) {
if (app._vm is CommonWebSocketVM) {
if ((app._vm as CommonWebSocketVM).target == target) {
return app._vm!.isConnected;
}
}
return false;
}
_switchVM(VM? newVM) {
final VM? oldVM = _vm;
Logger.root.info('_switchVM from:${oldVM} to:${newVM}');
if (oldVM == newVM) {
// Do nothing.
return;
}
if (oldVM != null) {
print('disconnecting from the old VM ${oldVM}--');
// Disconnect from current VM.
stopGCEventListener();
notifications.deleteAll();
oldVM.disconnect();
}
if (newVM != null) {
// Mark that we haven't connected yet.
_vmConnected = false;
// On connect:
newVM.onConnect.then((_) async {
// We connected.
_vmConnected = true;
notifications.deleteDisconnectEvents();
await newVM.load();
// TODO(cbernaschina) smart connection of streams in the events object.
newVM.listenEventStream(VM.kVMStream, _onEvent);
newVM.listenEventStream(VM.kIsolateStream, _onEvent);
newVM.listenEventStream(VM.kDebugStream, _onEvent);
newVM.listenEventStream(VM.kServiceStream, _onEvent);
});
// On disconnect:
newVM.onDisconnect.then((String reason) {
if (this.vm != newVM) {
// This disconnect event occurred *after* a new VM was installed.
return;
}
// Let anyone looking at the targets know that we have disconnected
// from one.
targets.emitDisconnectEvent();
if (!_vmConnected) {
// Connection error. Navigate back to the connect page.
Logger.root.info('Connection failed, navigating to VM connect page.');
// Clear the vm.
_vm = null;
app.locationManager.go(Uris.vmConnect());
} else {
// Disconnect. Stay at the current page and push an a connection
// closed event.
Logger.root.info('Lost an existing connection to a VM');
events.add(new ConnectionClosedEvent(new DateTime.now(), reason));
}
});
}
_vm = newVM;
}
StreamSubscription? _gcSubscription;
StreamSubscription? _loggingSubscription;
Future startGCEventListener() async {
if (_gcSubscription != null || _vm == null) {
return;
}
_gcSubscription = await _vm!.listenEventStream(VM.kGCStream, _onEvent);
}
Future startLoggingEventListener() async {
if (_loggingSubscription != null || _vm == null) {
return;
}
_loggingSubscription =
await _vm!.listenEventStream(Isolate.kLoggingStream, _onEvent);
}
Future stopGCEventListener() async {
if (_gcSubscription == null) {
return;
}
_gcSubscription!.cancel();
_gcSubscription = null;
}
Future stopLoggingEventListener() async {
if (_loggingSubscription == null) {
return;
}
_loggingSubscription!.cancel();
_loggingSubscription = null;
}
final ObservatoryApplicationElement rootElement;
ServiceObject? lastErrorOrException;
void _initOnce() {
app = this;
_registerPages();
// Visit the current page.
locationManager._visit();
}
void _deletePauseEvents(e) {
notifications.deletePauseEvents(isolate: e.isolate);
}
void _addNotification(M.Event e) {
notifications.add(new EventNotification(e));
}
void _onEvent(ServiceEvent event) {
assert(event.kind != ServiceEvent.kNone);
M.Event? e = createEventFromServiceEvent(event);
if (e != null) {
events.add(e);
}
}
void _registerPages() {
_pageRegistry.add(new VMPage(this));
_pageRegistry.add(new FlagsPage(this));
_pageRegistry.add(new NativeMemoryProfilerPage(this));
_pageRegistry.add(new InspectPage(this));
_pageRegistry.add(new ClassTreePage(this));
_pageRegistry.add(new DebuggerPage(this));
_pageRegistry.add(new ObjectStorePage(this));
_pageRegistry.add(new CpuProfilerPage(this));
_pageRegistry.add(new TableCpuProfilerPage(this));
_pageRegistry.add(new AllocationProfilerPage(this));
_pageRegistry.add(new HeapMapPage(this));
_pageRegistry.add(new HeapSnapshotPage(this));
_pageRegistry.add(new VMConnectPage(this));
_pageRegistry.add(new IsolateReconnectPage(this));
_pageRegistry.add(new ErrorViewPage(this));
_pageRegistry.add(new MetricsPage(this));
_pageRegistry.add(new PersistentHandlesPage(this));
_pageRegistry.add(new PortsPage(this));
_pageRegistry.add(new LoggingPage(this));
_pageRegistry.add(new TimelinePage(this));
_pageRegistry.add(new ProcessSnapshotPage(this));
// Note that ErrorPage must be the last entry in the list as it is
// the catch all.
_pageRegistry.add(new ErrorPage(this));
}
void _visit(Uri uri, Map<String, String> internalArguments) {
if (internalArguments['trace'] != null) {
var traceArg = internalArguments['trace'];
if (traceArg == 'on') {
Tracer.start();
} else if (traceArg == 'off') {
Tracer.stop();
}
}
if (Tracer.current != null) {
Tracer.current!.reset();
}
for (var i = 0; i < _pageRegistry.length; i++) {
var page = _pageRegistry[i];
if (page.canVisit(uri)) {
_installPage(page);
page.visit(uri, internalArguments);
return;
}
}
throw new ArgumentError.value(uri, 'uri');
}
/// Set the Observatory application page.
void _installPage(Page page) {
if (currentPage == page) {
// Already installed.
return;
}
if (currentPage != null) {
Logger.root.info('Uninstalling page: $currentPage');
currentPage!.onUninstall();
// Clear children.
rootElement.removeChildren();
}
Logger.root.info('Installing page: $page');
try {
page.onInstall();
} catch (e) {
Logger.root.severe('Failed to install page: $e');
}
// Add new page.
rootElement.appendChild(page.element!);
// Remember page.
currentPage = page;
}
ObservatoryApplication(this.rootElement) {
_locationManager = new LocationManager(this);
targets.onChange.listen((TargetChangeEvent e) {
if (e.disconnected) {
// We don't care about disconnected events.
return;
}
if (targets.current == null) {
_switchVM(null);
} else {
final bool currentTarget =
(_vm as WebSocketVM?)?.target == targets.current;
final bool currentTargetConnected = (_vm != null) && _vm!.isConnected;
if (!currentTarget || !currentTargetConnected) {
_switchVM(new WebSocketVM(targets.current!));
_vm!.onConnect.then((_) {
app.locationManager.go(Uris.vm());
});
_vm!.load();
} else if (currentTargetConnected) {
app.locationManager.go(Uris.vm());
}
}
});
Logger.root.info('Setting initial target to ${targets.current!.name}');
_switchVM(new WebSocketVM(targets.current!));
_initOnce();
// delete pause events.
events.onIsolateExit.listen(_deletePauseEvents);
events.onResume.listen(_deletePauseEvents);
events.onPauseStart.listen(_deletePauseEvents);
events.onPauseExit.listen(_deletePauseEvents);
events.onPauseBreakpoint.listen(_deletePauseEvents);
events.onPauseInterrupted.listen(_deletePauseEvents);
events.onPauseException.listen(_deletePauseEvents);
// show notification for an event.
events.onIsolateReload.listen(_addNotification);
events.onPauseExit.listen(_addNotification);
events.onPauseBreakpoint.listen(_addNotification);
events.onPauseInterrupted.listen(_addNotification);
events.onPauseException.listen(_addNotification);
events.onInspect.listen(_addNotification);
events.onConnectionClosed.listen(_addNotification);
}
void handleException(e, st) {
if (e is ServerRpcException) {
if (e.code == ServerRpcException.kFeatureDisabled) return;
if (e.code == ServerRpcException.kIsolateMustBePaused) return;
if (e.code == ServerRpcException.kCannotAddBreakpoint) return;
Logger.root.fine('Dropping exception: ${e}\n${st}');
}
// TODO(turnidge): Report this failure via analytics.
Logger.root.warning('Caught exception: ${e}\n${st}');
notifications.add(new ExceptionNotification(e, stacktrace: st));
}
// This map keeps track of which curly-blocks have been expanded by the user.
Map<String, bool> expansions = {};
}
@@ -1,167 +0,0 @@
// 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.
part of app;
class LocationManager {
final ObservatoryApplication _app;
/// [internalArguments] are parameters specified after a '---' in the
/// application URL.
final Map<String, String> internalArguments = new Map<String, String>();
Uri? _uri;
/// [uri] is the application uri. Application uris consist of a path and
/// the queryParameters map.
Uri get uri => _uri!;
LocationManager(this._app) {
web.window.onPopState.listen(_onBrowserNavigation);
// Determine initial application path.
var applicationPath = '${web.window.location.hash}';
if ((web.window.location.hash == '') || (web.window.location.hash == '#')) {
// Observatory has loaded but no application path has been specified,
// use the default.
// By default we navigate to the VM page.
applicationPath = Uris.vm();
}
// Update current application path.
web.window.history.replaceState(
applicationPath.toJS, web.document.title, applicationPath);
_updateApplicationLocation(applicationPath);
}
bool getBoolParameter(String name, bool defaultValue) {
var value = uri.queryParameters[name];
if ("true" == value) return true;
if ("false" == value) return false;
return defaultValue;
}
/// Called whenever the browser changes the location bar (e.g. forward or
/// back button press).
void _onBrowserNavigation(web.PopStateEvent event) {
_updateApplicationLocation(web.window.location.hash);
_visit();
}
/// Given an application url, generate an href link.
String makeLink(String url) => '#$url';
/// Update the application location. After this function returns,
/// [uri] and [debugArguments] will be updated.
_updateApplicationLocation(String url) {
if (url == Uris.vmConnect()) {
// When we go to the vm-connect page, drop all notifications.
_app.notifications.deleteAll();
}
// Chop off leading '#'.
if (url.startsWith('#')) {
url = url.substring(1);
}
// Fall through handles '#/'
// Chop off leading '/'.
if (url.startsWith('/')) {
url = url.substring(1);
}
// Parse out debug arguments.
if (url.contains('---')) {
var chunks = url.split('---');
url = chunks[0];
if ((chunks.length > 1) && (chunks[1] != '')) {
internalArguments.clear();
try {
internalArguments.addAll(Uri.splitQueryString(chunks[1]));
} catch (e) {
Logger.root.warning('Could not parse debug arguments ${e}');
}
}
}
_uri = Uri.parse(url);
}
/// Add [url] to the browser history.
_addToBrowserHistory(String url) {
web.window.history.pushState(url.toJS, web.document.title, url);
}
/// Notify the current page that something has changed.
_visit() {
Chain.capture(() => _app._visit(_uri!, internalArguments),
onError: (e, st) {
if (e is IsolateNotFound) {
var newPath =
_app.vm.isDisconnected ? '/vm-connect' : '/isolate-reconnect';
var parameters = <String, dynamic>{};
parameters.addAll(_uri!.queryParameters);
parameters['originalUri'] = _uri.toString();
parameters['isolateId'] = parameters['isolateId'];
var generatedUri = new Uri(path: newPath, queryParameters: parameters);
go(makeLink(generatedUri.toString()), true);
return;
}
// Surface any uncaught exceptions.
_app.handleException(e, st);
});
}
/// Navigate to [url].
void go(String url, [bool addToBrowserHistory = true]) {
if (addToBrowserHistory) {
_addToBrowserHistory(url);
}
_updateApplicationLocation(url);
_visit();
}
/// Starting with the current uri path and queryParameters, update
/// queryParameters present in [updateParameters], then generate a new uri
/// and navigate to that.
goReplacingParameters(Map updatedParameters,
[bool addToBrowserHistory = true]) {
go(makeLinkReplacingParameters(updatedParameters), addToBrowserHistory);
}
makeLinkReplacingParameters(Map updatedParameters) {
var parameters = new Map<String, dynamic>.from(_uri!.queryParameters);
updatedParameters.forEach((k, v) {
parameters[k] = v;
});
// Ensure path starts with a slash.
var path = uri.path.startsWith('/') ? uri.path : '/${uri.path}';
var generatedUri = new Uri(path: path, queryParameters: parameters);
return makeLink(generatedUri.toString());
}
goForwardingParameters(String newPath, [bool addToBrowserHistory = true]) {
go(makeLinkForwardingParameters(newPath), addToBrowserHistory);
}
makeLinkForwardingParameters(String newPath) {
var parameters = _uri!.queryParameters;
var generatedUri = new Uri(path: newPath, queryParameters: parameters);
return makeLink(generatedUri.toString());
}
/// Utility event handler when clicking on application url link.
void onGoto(web.MouseEvent event) {
if ((event.button > 0) ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey) {
// Mouse event is not a left-click OR
// mouse event is a left-click with a modifier key:
// let browser handle.
return;
}
event.preventDefault();
// 'currentTarget' is the dom element that would process the event.
// If we use 'target' we might get an <em> element or somesuch.
web.HTMLElement target = event.currentTarget as web.HTMLElement;
go(target.attributes.getNamedItem('href')!.value);
}
}
@@ -1,18 +0,0 @@
// Copyright (c) 2016, 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.
part of app;
class ExceptionNotification implements M.ExceptionNotification {
final exception;
/// [optional]
final StackTrace? stacktrace;
ExceptionNotification(this.exception, {this.stacktrace});
}
class EventNotification implements M.EventNotification {
final M.Event event;
EventNotification(this.event);
}
-953
View File
@@ -1,953 +0,0 @@
// Copyright (c) 2014, 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.
part of app;
final _allocationProfileRepository = new AllocationProfileRepository();
final _breakpointRepository = new BreakpointRepository();
final _classRepository = new ClassRepository();
final _classSampleProfileRepository = new ClassSampleProfileRepository();
final _contextRepository = new ContextRepository();
final _evalRepository = new EvalRepository();
final _fieldRepository = new FieldRepository();
final _functionRepository = new FunctionRepository();
final _heapSnapshotRepository = new HeapSnapshotRepository();
final _icdataRepository = new ICDataRepository();
final _inboundReferencesRepository = new InboundReferencesRepository();
final _isolateSampleProfileRepository = new IsolateSampleProfileRepository();
final _libraryRepository = new LibraryRepository();
final _megamorphicCacheRepository = new MegamorphicCacheRepository();
final _metricRepository = new MetricRepository();
final _nativeMemorySampleProfileRepository =
new NativeMemorySampleProfileRepository();
final _objectPoolRepository = new ObjectPoolRepository();
final _objectRepository = new ObjectRepository();
final _objectstoreRepository = new ObjectStoreRepository();
final _persistentHandlesRepository = new PersistentHandlesRepository();
final _portsRepository = new PortsRepository();
final _scriptRepository = new ScriptRepository();
final _singleTargetCacheRepository = new SingleTargetCacheRepository();
final _stronglyReachangleInstancesRepository =
new StronglyReachableInstancesRepository();
final _subtypeTestCacheRepository = new SubtypeTestCacheRepository();
final _timelineRepository = new TimelineRepository();
final _typeArgumentsRepository = new TypeArgumentsRepository();
final _unlinkedCallRepository = new UnlinkedCallRepository();
final _vmrepository = new VMRepository();
class IsolateNotFound implements Exception {
String isolateId;
IsolateNotFound(this.isolateId);
String toString() => "IsolateNotFound: $isolateId";
}
RetainedSizeRepository _retainedSizeRepository = new RetainedSizeRepository();
ReachableSizeRepository _reachableSizeRepository =
new ReachableSizeRepository();
RetainingPathRepository _retainingPathRepository =
new RetainingPathRepository();
/// A [Page] controls the user interface of Observatory. At any given time
/// one page will be the current page. Pages are registered at startup.
/// When the user navigates within the application, each page is asked if it
/// can handle the current location, the first page to say yes, wins.
abstract class Page {
final ObservatoryApplication app;
final Map<String, String> internalArguments = <String, String>{};
web.HTMLElement? element;
Page(this.app);
/// Called when the page is installed, this callback must initialize
/// [element].
void onInstall();
/// Called when the page is uninstalled, this callback must clear
/// [element].
void onUninstall() {
element = null;
}
/// Called when the page should update its state based on [uri].
void visit(Uri uri, Map<String, String> internalArguments) {
this.internalArguments.clear();
this.internalArguments.addAll(internalArguments);
_visit(uri);
}
// Overridden by subclasses.
void _visit(Uri uri);
/// Called to test whether this page can visit [uri].
bool canVisit(Uri uri);
}
/// A [MatchingPage] matches a single uri path.
abstract class MatchingPage extends Page {
final String path;
MatchingPage(this.path, app) : super(app);
void _visit(Uri uri) {
assert(canVisit(uri));
}
Future<Isolate> getIsolate(Uri uri) {
var isolateId = uri.queryParameters['isolateId'];
return app.vm.getIsolate(isolateId!).then((isolate) {
return isolate;
});
}
EditorRepository getEditor(Uri uri) {
final editor = uri.queryParameters['editor'];
return new EditorRepository(app.vm, editor: editor);
}
bool canVisit(Uri uri) => uri.path == path;
}
/// A [SimplePage] matches a single uri path and displays a single element.
abstract class SimplePage extends MatchingPage {
final String elementTagName;
SimplePage(String path, this.elementTagName, app) : super(path, app);
void onInstall() {
if (element == null) {
element = createElement();
}
}
web.HTMLElement createElement();
}
/// Error page for unrecognized paths.
class ErrorPage extends Page {
ErrorPage(app) : super(app);
void onInstall() {
if (element == null) {
// Lazily create page.
element =
new GeneralErrorElement(app.notifications, queue: app.queue).element;
}
}
void _visit(Uri uri) {
assert(element != null);
assert(canVisit(uri));
(element as GeneralErrorElement).message = "Path '${uri.path}' not found";
}
/// Catch all.
bool canVisit(Uri uri) => true;
}
/// Top-level vm info page.
class VMPage extends MatchingPage {
VMPage(app) : super('vm', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
void _visit(Uri uri) {
super._visit(uri);
app.vm.reload().then((serviceObject) {
VM vm = serviceObject as VM;
container.removeChildren();
final vmview = new VMViewElement(
vm,
_vmrepository,
app.events,
app.notifications,
new IsolateRepository(app.vm),
new IsolateGroupRepository(),
_scriptRepository,
queue: app.queue)
.element;
container.appendChild(vmview);
}).catchError((e, stack) {
Logger.root.severe('VMPage visit error: $e');
Logger.root.severe('Stack: $stack');
// Reroute to vm-connect.
app.locationManager.go(Uris.vmConnect());
});
}
}
class FlagsPage extends SimplePage {
FlagsPage(app) : super('flags', 'flag-list', app);
@override
web.HTMLElement createElement() => new FlagListElement(
app.vm, app.events, new FlagsRepository(app.vm), app.notifications,
queue: app.queue)
.element;
void _visit(Uri uri) {
super._visit(uri);
}
}
class NativeMemoryProfilerPage extends SimplePage {
NativeMemoryProfilerPage(app)
: super('native-memory-profile', 'native-memory-profile', app);
@override
web.HTMLElement createElement() => NativeMemoryProfileElement(app.vm,
app.events, app.notifications, _nativeMemorySampleProfileRepository,
queue: app.queue)
.element;
void _visit(Uri uri) {
super._visit(uri);
}
}
class InspectPage extends MatchingPage {
InspectPage(app) : super('inspect', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
var objectId = uri.queryParameters['objectId'];
if (objectId == null) {
isolate.reload().then(_visitObject);
} else {
isolate.getObject(objectId).then(_visitObject);
}
});
}
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
Future _visitObject(obj) async {
container.removeChildren();
await obj.reload();
if (obj is Class) {
container.removeChildren();
container.appendChild(new ClassViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_classRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_fieldRepository,
_scriptRepository,
_objectRepository,
_evalRepository,
_stronglyReachangleInstancesRepository,
_classSampleProfileRepository,
queue: app.queue)
.element);
} else if (obj is Code) {
await obj.loadScript();
container.removeChildren();
container.appendChild(new CodeViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is Context) {
container.removeChildren();
container.appendChild(new ContextViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_contextRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is DartError) {
container.removeChildren();
container.appendChild(
new ErrorViewElement(app.notifications, obj, queue: app.queue)
.element);
} else if (obj is Field) {
container.removeChildren();
container.appendChild(new FieldViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_fieldRepository,
_classRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_scriptRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is Instance) {
container.removeChildren();
container.appendChild(new InstanceViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_objectRepository,
_classRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_scriptRepository,
_evalRepository,
_typeArgumentsRepository,
_breakpointRepository,
_functionRepository,
queue: app.queue)
.element);
} else if (obj is Isolate) {
container.removeChildren();
container.appendChild(new IsolateViewElement(
app.vm,
obj,
app.events,
app.notifications,
new IsolateRepository(app.vm),
_scriptRepository,
_functionRepository,
_libraryRepository,
_objectRepository,
_evalRepository,
queue: app.queue)
.element);
} else if (obj is ServiceFunction) {
container.removeChildren();
container.appendChild(new FunctionViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_functionRepository,
_classRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_scriptRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is ICData) {
container.removeChildren();
container.appendChild(new ICDataViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_icdataRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is SingleTargetCache) {
container.removeChildren();
container.appendChild(new SingleTargetCacheViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_singleTargetCacheRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is SubtypeTestCache) {
container.removeChildren();
container.appendChild(new SubtypeTestCacheViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_subtypeTestCacheRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is UnlinkedCall) {
container.removeChildren();
container.appendChild(new UnlinkedCallViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_unlinkedCallRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is Library) {
container.removeChildren();
container.appendChild(new LibraryViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_libraryRepository,
_fieldRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_scriptRepository,
_objectRepository,
_evalRepository,
queue: app.queue)
.element);
} else if (obj is MegamorphicCache) {
container.removeChildren();
container.appendChild(new MegamorphicCacheViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_megamorphicCacheRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is ObjectPool) {
container.removeChildren();
container.appendChild(new ObjectPoolViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_objectPoolRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
queue: app.queue)
.element);
} else if (obj is Script) {
var pos;
if (app.locationManager.internalArguments['pos'] != null) {
try {
pos = int.parse(app.locationManager.internalArguments['pos']!);
} catch (_) {}
}
container.removeChildren();
container.appendChild(new ScriptViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_scriptRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
_objectRepository,
pos: pos,
queue: app.queue)
.element);
} else if (obj is HeapObject) {
container.removeChildren();
container.appendChild(new ObjectViewElement(
app.vm,
obj.isolate as Isolate,
obj,
app.events,
app.notifications,
_objectRepository,
_retainedSizeRepository,
_reachableSizeRepository,
_inboundReferencesRepository,
_retainingPathRepository,
queue: app.queue)
.element);
} else if (obj is Sentinel) {
container.removeChildren();
container.appendChild(new SentinelViewElement(app.vm,
obj.isolate as Isolate, obj, app.events, app.notifications,
queue: app.queue)
.element);
} else {
container.removeChildren();
container.appendChild(
new JSONViewElement(obj, app.notifications, queue: app.queue)
.element);
}
}
}
/// Class tree page.
class ClassTreePage extends SimplePage {
ClassTreePage(app) : super('class-tree', 'class-tree', app);
final web.HTMLDivElement container = web.HTMLDivElement();
@override
web.HTMLElement createElement() => container;
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new ClassTreeElement(
app.vm, isolate, app.events, app.notifications, _classRepository)
.element);
});
}
}
class DebuggerPage extends MatchingPage {
DebuggerPage(app) : super('debugger', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) async {
container.removeChildren();
container.appendChild(new DebuggerPageElement(
isolate, _objectRepository, _scriptRepository, app.events)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
@override
void onUninstall() {
super.onUninstall();
}
}
class ObjectStorePage extends MatchingPage {
ObjectStorePage(app) : super('object-store', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) async {
container.removeChildren();
container.appendChild(new ObjectStoreViewElement(
isolate.vm,
isolate,
app.events,
app.notifications,
_objectstoreRepository,
_objectRepository)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
}
class CpuProfilerPage extends MatchingPage {
CpuProfilerPage(app) : super('profiler', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new CpuProfileElement(isolate.vm, isolate,
app.events, app.notifications, _isolateSampleProfileRepository)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
}
class TableCpuProfilerPage extends MatchingPage {
TableCpuProfilerPage(app) : super('profiler-table', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new CpuProfileTableElement(isolate.vm, isolate,
app.events, app.notifications, _isolateSampleProfileRepository)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
assert(element != null);
}
}
class AllocationProfilerPage extends MatchingPage {
AllocationProfilerPage(app) : super('allocation-profiler', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new AllocationProfileElement(isolate.vm, isolate,
app.events, app.notifications, _allocationProfileRepository,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
app.startGCEventListener();
}
@override
void onUninstall() {
super.onUninstall();
app.stopGCEventListener();
}
}
class PortsPage extends MatchingPage {
PortsPage(app) : super('ports', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new PortsElement(isolate.vm, isolate, app.events,
app.notifications, _portsRepository, _objectRepository,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
}
}
class PersistentHandlesPage extends MatchingPage {
PersistentHandlesPage(app) : super('persistent-handles', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new PersistentHandlesPageElement(
isolate.vm,
isolate,
app.events,
app.notifications,
_persistentHandlesRepository,
_objectRepository,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
}
}
class HeapMapPage extends MatchingPage {
HeapMapPage(app) : super('heap-map', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new HeapMapElement(
isolate.vm, isolate, app.events, app.notifications,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
}
}
class HeapSnapshotPage extends MatchingPage {
HeapSnapshotPage(app) : super('heap-snapshot', app);
final web.HTMLDivElement container = web.HTMLDivElement();
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new HeapSnapshotElement(
isolate.vm,
isolate,
app.events,
app.notifications,
_heapSnapshotRepository,
_objectRepository,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
}
}
class LoggingPage extends MatchingPage {
LoggingPage(app) : super('logging', app);
final web.HTMLDivElement container = web.HTMLDivElement();
@override
void onInstall() {
element = container;
app.startLoggingEventListener();
}
@override
void onUninstall() {
super.onUninstall();
app.stopLoggingEventListener();
}
void _visit(Uri uri) {
assert(element != null);
assert(canVisit(uri));
getIsolate(uri).then((isolate) {
container.removeChildren();
container.appendChild(new LoggingPageElement(
app.vm, isolate, app.events, app.notifications,
queue: app.queue)
.element);
});
}
}
class ErrorViewPage extends Page {
ErrorViewPage(app) : super(app);
void onInstall() {
element = new ErrorViewElement(
app.notifications, app.lastErrorOrException as DartError,
queue: app.queue)
.element;
}
void _visit(Uri uri) {
assert(element != null);
assert(canVisit(uri));
}
// TODO(turnidge): How to test this page?
bool canVisit(Uri uri) => uri.path == 'error';
}
class VMConnectPage extends Page {
VMConnectPage(app) : super(app);
void onInstall() {
if (element == null) {
element = new VMConnectElement(ObservatoryApplication.app.targets,
ObservatoryApplication.app.notifications,
queue: ObservatoryApplication.app.queue)
.element;
}
assert(element != null);
}
void _visit(Uri uri) {
assert(element != null);
assert(canVisit(uri));
}
bool canVisit(Uri uri) => uri.path == 'vm-connect';
}
class IsolateReconnectPage extends Page {
IsolateReconnectPage(app) : super(app);
final web.HTMLDivElement container = web.HTMLDivElement();
void onInstall() {
element = container;
}
void _visit(Uri uri) {
app.vm.reload();
container.removeChildren();
container.appendChild(new IsolateReconnectElement(
app.vm,
app.events,
app.notifications,
uri.queryParameters['isolateId']!,
Uri.parse(uri.queryParameters['originalUri']!))
.element);
assert(element != null);
assert(canVisit(uri));
}
bool canVisit(Uri uri) => uri.path == 'isolate-reconnect';
}
class MetricsPage extends MatchingPage {
MetricsPage(app) : super('metrics', app);
final web.HTMLDivElement container = web.HTMLDivElement();
Isolate? lastIsolate;
void _visit(Uri uri) {
super._visit(uri);
getIsolate(uri).then((isolate) async {
lastIsolate = isolate;
await _metricRepository.startSampling(isolate);
container.removeChildren();
container.appendChild(new MetricsPageElement(isolate.vm, isolate,
app.events, app.notifications, _metricRepository,
queue: app.queue)
.element);
});
}
void onInstall() {
if (element == null) {
element = container;
}
}
@override
void onUninstall() {
super.onUninstall();
_metricRepository.stopSampling(lastIsolate!);
}
}
class TimelinePage extends Page {
TimelinePage(app) : super(app);
void onInstall() {
element = new TimelinePageElement(
app.vm, _timelineRepository, app.events, app.notifications,
queue: app.queue)
.element;
}
void _visit(Uri uri) {
assert(canVisit(uri));
}
bool canVisit(Uri uri) => uri.path == 'timeline';
}
class ProcessSnapshotPage extends Page {
ProcessSnapshotPage(app) : super(app);
void onInstall() {
element = new ProcessSnapshotElement(app.vm, app.events, app.notifications,
queue: app.queue)
.element;
}
void _visit(Uri uri) {
assert(canVisit(uri));
}
bool canVisit(Uri uri) => uri.path == 'process-snapshot';
}
@@ -1,45 +0,0 @@
// Copyright (c) 2014, 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.
part of app;
/// Static settings database.
class _Settings {
static web.Storage _storage = web.window.localStorage;
/// Associated [value] with [key]. [value] must be JSON encodable.
static void set(String key, dynamic value) {
_storage.setItem(key, json.encode(value));
}
/// Get value associated with [key]. Return value will be a JSON encodable
/// object.
static dynamic get(String key) {
var value = _storage.getItem(key);
if (value == null) {
return null;
}
return json.decode(value);
}
}
/// A group of settings each prefixed with group name and a dot.
class SettingsGroup {
/// Group name
final String group;
SettingsGroup(this.group);
String _fullKey(String key) => '$group.$key';
void set(String key, dynamic value) {
var fullKey = _fullKey(key);
_Settings.set(fullKey, value);
}
dynamic get(String key) {
var fullKey = _fullKey(key);
return _Settings.get(fullKey);
}
}
@@ -1,104 +0,0 @@
// Copyright (c) 2014, 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.
part of app;
typedef String ValueFormatter(dynamic value);
class SortedTableColumn {
static String toStringFormatter(dynamic v) {
return v != null ? v.toString() : '<null>';
}
final String label;
final ValueFormatter formatter;
SortedTableColumn.withFormatter(this.label, this.formatter);
SortedTableColumn(this.label) : formatter = toStringFormatter;
}
class SortedTableRow {
final List values;
SortedTableRow(this.values);
}
class SortedTable {
final List<SortedTableColumn> columns;
final List<SortedTableRow> rows = <SortedTableRow>[];
final List<int> sortedRows = [];
SortedTable(this.columns);
int _sortColumnIndex = 0;
set sortColumnIndex(var index) {
assert(index >= 0);
assert(index < columns.length);
_sortColumnIndex = index;
}
int get sortColumnIndex => _sortColumnIndex;
bool _sortDescending = true;
bool get sortDescending => _sortDescending;
set sortDescending(var descending) {
_sortDescending = descending;
}
dynamic getSortKeyFor(int row, int col) {
return rows[row].values[col];
}
int _sortFuncDescending(int i, int j) {
var a = getSortKeyFor(i, _sortColumnIndex);
var b = getSortKeyFor(j, _sortColumnIndex);
return b.compareTo(a);
}
int _sortFuncAscending(int i, int j) {
var a = getSortKeyFor(i, _sortColumnIndex);
var b = getSortKeyFor(j, _sortColumnIndex);
return a.compareTo(b);
}
void sort() {
assert(_sortColumnIndex >= 0);
assert(_sortColumnIndex < columns.length);
if (_sortDescending) {
sortedRows.sort(_sortFuncDescending);
} else {
sortedRows.sort(_sortFuncAscending);
}
}
void clearRows() {
rows.clear();
sortedRows.clear();
}
void addRow(SortedTableRow row) {
sortedRows.add(rows.length);
rows.add(row);
}
String getFormattedValue(int row, int column) {
var value = getValue(row, column);
var formatter = columns[column].formatter;
return formatter(value);
}
String getColumnLabel(int column) {
assert(column >= 0);
assert(column < columns.length);
// TODO(johnmccutchan): Move expander display decisions into html once
// tables and templates are better supported.
const arrowUp = '\u25BC';
const arrowDown = '\u25B2';
if (column != _sortColumnIndex) {
return columns[column].label + '\u2003';
}
return columns[column].label + (_sortDescending ? arrowUp : arrowDown);
}
dynamic getValue(int row, int column) {
return rows[row].values[column];
}
}
@@ -1,279 +0,0 @@
// Copyright (c) 2015, 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.
part of cli;
// Splits a line into a list of string args. Each arg retains any
// trailing whitespace so that we can reconstruct the original command
// line from the pieces.
List<String> _splitLine(String line) {
line = line.trimLeft();
var args = <String>[];
int pos = 0;
while (pos < line.length) {
int startPos = pos;
// Advance to end of word.
for (; pos < line.length && line[pos] != ' '; pos++);
// Advance to end of spaces.
for (; pos < line.length && line[pos] == ' '; pos++);
args.add(line.substring(startPos, pos));
}
return args;
}
// Concatenates the first 'count' args.
String _concatArgs(List<String> args, int count) {
if (count == 0) {
return '';
}
return '${args.sublist(0, count).join('')}';
}
// Shared functionality for RootCommand and Command.
abstract class _CommandBase {
_CommandBase(List<Command> children) {
_children.addAll(children);
for (var child in _children) {
child._parent = this;
}
}
// A command may optionally have sub-commands.
List<Command> _children = <Command>[];
_CommandBase? _parent;
int get _depth => (_parent == null ? 0 : _parent!._depth + 1);
// Override in subclasses to provide command-specific argument completion.
//
// Given a list of arguments to this command, provide a list of
// possible completions for those arguments.
Future<List<String>> complete(List<String> args) =>
new Future.value(<String>[]);
// Override in subclasses to provide command-specific execution.
Future run(List<String> args);
// Returns a list of local subcommands which match the args.
List<Command> _matchLocal(String argWithSpace, bool preferExact) {
var matches = <Command>[];
var arg = argWithSpace.trimRight();
for (var child in _children) {
if (child.name.startsWith(arg)) {
if (preferExact && ((child.name == arg) || (child.alias == arg))) {
return [child];
}
matches.add(child);
}
}
return matches;
}
// Returns the set of commands could be triggered by a list of
// arguments.
List<Command> _match(List<String> args, bool preferExact) {
if (args.isEmpty) {
return <Command>[];
}
bool lastArg = (args.length == 1);
var matches = _matchLocal(args[0], !lastArg || preferExact);
if (matches.isEmpty) {
return <Command>[];
} else if (matches.length == 1) {
var childMatches = matches[0]._match(args.sublist(1), preferExact);
if (childMatches.isEmpty) {
return matches;
} else {
return childMatches;
}
} else {
return matches;
}
}
// Builds a list of completions for this command.
Future<List<String>> _buildCompletions(
List<String> args, bool addEmptyString) {
return complete(args.sublist(_depth, args.length)).then((completions) {
if (addEmptyString &&
completions.isEmpty &&
args[args.length - 1] == '') {
// Special case allowance for an empty particle at the end of
// the command.
completions = <String>[''];
}
var prefix = _concatArgs(args, _depth);
return completions.map((str) => '${prefix}${str}').toList();
});
}
}
// The root of a tree of commands.
class RootCommand extends _CommandBase {
RootCommand(List<Command> children, [List<String>? history])
: this._(children, history ?? ['']);
RootCommand._(List<Command> children, List<String> history)
: history = history,
historyPos = history.length - 1,
super(children);
// Provides a list of possible completions for a line of text.
Future<List<String>> completeCommand(String line) {
var args = _splitLine(line);
bool showAll = line.endsWith(' ') || args.isEmpty;
if (showAll) {
// Adding an empty string to the end causes us to match all
// subcommands of the last command.
args.add('');
}
var commands = _match(args, false);
if (commands.isEmpty) {
// No matching commands.
return new Future.value(<String>[]);
}
int matchLen = commands[0]._depth;
if (matchLen < args.length) {
// We were able to find a command which matches a prefix of the
// args, but not the full list.
if (commands.length == 1) {
// The matching command is unique. Attempt to provide local
// argument completion from the command.
return commands[0]._buildCompletions(args, true);
} else {
// An ambiguous prefix match leaves us nowhere. The user is
// typing a bunch of stuff that we don't know how to complete.
return new Future.value(<String>[]);
}
}
// We have found a set of commands which match all of the args.
// Return the completion strings.
var prefix = _concatArgs(args, args.length - 1);
var completions =
commands.map((command) => '${prefix}${command.name} ').toList();
if (matchLen == args.length) {
// If we are showing all possibilities, also include local
// completions for the parent command.
return commands[0]
._parent!
._buildCompletions(args, false)
.then((localCompletions) {
completions.addAll(localCompletions);
return completions;
});
}
return new Future.value(completions);
}
// Runs a command.
Future runCommand(String line) {
_historyAdvance(line);
var args = _splitLine(line);
var commands = _match(args, true);
if (commands.isEmpty) {
return new Future.error(new NoSuchCommandException(line));
} else if (commands.length == 1) {
return commands[0].run(args.sublist(commands[0]._depth));
} else {
return new Future.error(new AmbiguousCommandException(line, commands));
}
}
// Find all matching commands. Useful for implementing help systems.
List<Command> matchCommand(List<String> args, bool preferExact) {
if (args.isEmpty) {
// Adding an empty string to the end causes us to match all
// subcommands of the last command.
args.add('');
}
return _match(args, preferExact);
}
// Command line history always contains one slot to hold the current
// line, so we start off with one entry.
List<String> history;
int historyPos;
String historyPrev(String line) {
if (historyPos == 0) {
return line;
}
history[historyPos] = line;
historyPos--;
return history[historyPos];
}
String historyNext(String line) {
if (historyPos == history.length - 1) {
return line;
}
history[historyPos] = line;
historyPos++;
return history[historyPos];
}
void _historyAdvance(String line) {
// Replace the last history line.
historyPos = history.length - 1;
history[historyPos] = line;
// Create an empty spot for the next line.
history.add('');
historyPos++;
}
Future run(List<String> args) {
throw 'should-not-execute-the-root-command';
}
String toString() => 'RootCommand';
}
// A node in the command tree.
abstract class Command extends _CommandBase {
Command(this.name, List<Command> children) : super(children);
final String name;
String? alias;
String get fullName {
if (_parent is RootCommand) {
return name;
} else {
Command parent = _parent as Command;
return '${parent.fullName} $name';
}
}
String toString() => 'Command(${name})';
}
abstract class CommandException implements Exception {}
class AmbiguousCommandException extends CommandException {
AmbiguousCommandException(this.command, this.matches);
final String command;
final List<Command> matches;
@override
String toString() {
List<String> matchNames =
matches.map((Command command) => '${command.fullName}').toList();
return "Command '$command' is ambiguous: $matchNames";
}
}
class NoSuchCommandException extends CommandException {
NoSuchCommandException(this.command);
final String command;
@override
String toString() => "No such command: '$command'";
}
@@ -1,14 +0,0 @@
// Copyright (c) 2015, 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.
part of debugger;
// TODO(turnidge): Move more of ObservatoryDebugger to this class.
abstract class Debugger {
VM get vm;
Isolate get isolate;
M.ObjectRepository? objects;
ServiceMap? get stack;
int? get currentFrame;
}
@@ -1,452 +0,0 @@
// Copyright (c) 2015, 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.
part of debugger;
class DebuggerLocation {
DebuggerLocation.file(this.script, this.line, this.col);
DebuggerLocation.func(this.function);
DebuggerLocation.error(this.errorMessage);
static RegExp sourceLocMatcher = new RegExp(r'^([^\d:][^:]+:)?(\d+)(:\d+)?');
static RegExp packageLocMatcher =
new RegExp(r'^package:([^\d:][^:]+:)?(\d+)(:\d+)?');
static RegExp functionMatcher = new RegExp(r'^([^.]+)([.][^.]+)?');
/// Parses a source location description.
///
/// Formats:
/// '' - current position
/// 13 - line 13, current script
/// 13:20 - line 13, col 20, current script
/// script.dart:13 - line 13, script.dart
/// script.dart:13:20 - line 13, col 20, script.dart
/// package:a/b.dart:13 - line 13, "b.dart" in package "a".
/// package:a/b.dart:13:20 - line 13, col 20, "b.dart" in package "a".
/// main - function
/// FormatException - constructor
/// _SHA1._updateHash - method
static Future<DebuggerLocation> parse(Debugger debugger, String locDesc) {
if (locDesc == '') {
// Special case: '' means return current location.
return _currentLocation(debugger);
}
// Parse the location description.
var match = sourceLocMatcher.firstMatch(locDesc);
if (match != null) {
return _parseScriptLine(debugger, match);
}
match = packageLocMatcher.firstMatch(locDesc);
if (match != null) {
return _parseScriptLine(debugger, match, package: true);
}
match = functionMatcher.firstMatch(locDesc);
if (match != null) {
return _parseFunction(debugger, match);
}
return new Future.value(
new DebuggerLocation.error("Invalid source location '${locDesc}'"));
}
static Future<Frame?> _currentFrame(Debugger debugger) async {
ServiceMap? stack = debugger.stack;
if (stack == null || stack['frames'].length == 0) {
return null;
}
return stack['frames'][debugger.currentFrame] as Frame?;
}
static Future<DebuggerLocation> _currentLocation(Debugger debugger) async {
var frame = await _currentFrame(debugger);
if (frame == null) {
return new DebuggerLocation.error(
'A script must be provided when the stack is empty');
}
Script script = frame.location!.script;
await script.load();
var line = script.tokenToLine(frame.location!.tokenPos);
var col = script.tokenToCol(frame.location!.tokenPos);
return new DebuggerLocation.file(script, line, col);
}
static Future<DebuggerLocation> _parseScriptLine(
Debugger debugger, Match match,
{bool package = false}) async {
var scriptName = match.group(1);
if (package) {
scriptName = "package:$scriptName";
}
if (scriptName != null) {
scriptName = scriptName.substring(0, scriptName.length - 1);
}
var lineStr = match.group(2);
assert(lineStr != null);
var colStr = match.group(3);
if (colStr != null) {
colStr = colStr.substring(1);
}
var line = int.tryParse(lineStr!) ?? -1;
var col = (colStr != null ? int.tryParse(colStr) ?? -1 : null);
if (line == -1) {
return new Future.value(
new DebuggerLocation.error("Line '${lineStr}' must be an integer"));
}
if (col == -1) {
return new Future.value(
new DebuggerLocation.error("Column '${colStr}' must be an integer"));
}
if (scriptName != null) {
// Resolve the script.
Set<Script> scripts = await _lookupScript(debugger.isolate, scriptName);
if (scripts.length == 0) {
scripts =
await _lookupScript(debugger.isolate, scriptName, useUri: true);
}
if (scripts.length == 0) {
return new DebuggerLocation.error("Script '${scriptName}' not found");
} else if (scripts.length == 1) {
return new DebuggerLocation.file(scripts.single, line, col);
} else {
// TODO(turnidge): Allow the user to disambiguate.
return new DebuggerLocation.error(
"Script '${scriptName}' is ambiguous");
}
} else {
// No script provided. Default to top of stack for now.
var frame = await _currentFrame(debugger);
if (frame == null) {
return new Future.value(new DebuggerLocation.error(
'A script must be provided when the stack is empty'));
}
Script script = frame.location!.script;
await script.load();
return new DebuggerLocation.file(script, line, col);
}
}
static Future<Set<Script>> _lookupScript(Isolate isolate, String name,
{bool allowPrefix = false, bool useUri = false}) {
var pending = <Future>[];
for (var lib in isolate.libraries) {
if (!lib.loaded) {
pending.add(lib.load());
}
}
return Future.wait(pending).then((_) {
var matches = <Script>{};
for (var lib in isolate.libraries) {
for (var script in lib.scripts) {
final String haystack = useUri ? script.uri : script.name!;
if (allowPrefix) {
if (haystack.startsWith(name)) {
matches.add(script);
}
} else {
if (name == haystack) {
matches.add(script);
}
}
}
}
return matches;
});
}
static List<ServiceFunction> _lookupFunction(Isolate isolate, String name,
{bool allowPrefix = false}) {
var matches = <ServiceFunction>[];
for (var lib in isolate.libraries) {
assert(lib.loaded);
for (var function in lib.functions) {
if (allowPrefix) {
if (function.name!.startsWith(name)) {
matches.add(function);
}
} else {
if (name == function.name) {
matches.add(function);
}
}
}
}
return matches;
}
static Future<List<Class>> _lookupClass(Isolate isolate, String name,
{bool allowPrefix = false}) async {
var pending = <Future>[];
for (var lib in isolate.libraries) {
assert(lib.loaded);
for (var cls in lib.classes) {
if (!cls.loaded) {
pending.add(cls.load());
}
}
}
await Future.wait(pending);
var matches = <Class>[];
for (var lib in isolate.libraries) {
for (var cls in lib.classes) {
if (allowPrefix) {
if (cls.name!.startsWith(name)) {
matches.add(cls);
}
} else {
if (name == cls.name) {
matches.add(cls);
}
}
}
}
return matches;
}
static ServiceFunction? _getConstructor(Class cls, String name) {
for (var function in cls.functions) {
assert(cls.loaded);
if (name == function.name) {
return function;
}
}
return null;
}
// TODO(turnidge): This does not handle named functions which are
// inside of named functions, e.g. foo.bar.baz.
static Future<DebuggerLocation> _parseFunction(
Debugger debugger, Match match) {
Isolate isolate = debugger.isolate;
var base = match.group(1)!;
var qualifier = match.group(2);
return _lookupClass(isolate, base).then((classes) {
var functions = [];
if (qualifier == null) {
// Unqualified name is either a function or a constructor.
functions.addAll(_lookupFunction(isolate, base));
for (var cls in classes) {
// Look for a self-named constructor.
var constructor = _getConstructor(cls, cls.name!);
if (constructor != null) {
functions.add(constructor);
}
}
} else {
// Qualified name.
var functionName = qualifier.substring(1);
for (var cls in classes) {
assert(cls.loaded);
for (var function in cls.functions) {
if (function.kind == M.FunctionKind.constructor) {
// Constructor names are class-qualified.
if (match.group(0) == function.name) {
functions.add(function);
}
} else {
if (functionName == function.name) {
functions.add(function);
}
}
}
}
}
if (functions.length == 0) {
return new DebuggerLocation.error(
"Function '${match.group(0)}' not found");
} else if (functions.length == 1) {
return new DebuggerLocation.func(functions[0]);
} else {
// TODO(turnidge): Allow the user to disambiguate.
return new DebuggerLocation.error(
"Function '${match.group(0)}' is ambiguous");
}
});
}
static RegExp partialSourceLocMatcher =
new RegExp(r'^([^\d:]?[^:]+[:]?)?(\d+)?([:]\d*)?');
static RegExp partialFunctionMatcher = new RegExp(r'^([^.]*)([.][^.]*)?');
/// Completes a partial source location description.
static Future<List<String>> complete(Debugger debugger, String locDesc) {
var pending = <Future<List<String>>>[];
var match = partialFunctionMatcher.firstMatch(locDesc);
if (match != null) {
pending.add(_completeFunction(debugger, match));
}
match = partialSourceLocMatcher.firstMatch(locDesc);
if (match != null) {
pending.add(_completeFile(debugger, match));
}
return Future.wait(pending).then((List<List<String>> responses) {
var completions = <String>[];
for (var response in responses) {
completions.addAll(response);
}
return completions;
});
}
static Future<List<String>> _completeFunction(
Debugger debugger, Match match) {
Isolate isolate = debugger.isolate;
var base = match.group(1) ?? '';
var qualifier = match.group(2);
if (qualifier == null) {
return _lookupClass(isolate, base, allowPrefix: true).then((classes) {
var completions = <String>[];
// Complete top-level function names.
var functions = _lookupFunction(isolate, base, allowPrefix: true);
var funcNames = functions.map((f) => f.name!).toList();
funcNames.sort();
completions.addAll(funcNames);
// Complete class names.
var classNames = classes.map((f) => f.name!).toList();
classNames.sort();
completions.addAll(classNames);
return completions;
});
} else {
return _lookupClass(isolate, base, allowPrefix: false).then((classes) {
var completions = <String>[];
for (var cls in classes) {
for (var function in cls.functions) {
if (function.kind == M.FunctionKind.constructor) {
if (function.name!.startsWith(match.group(0)!)) {
completions.add(function.name!);
}
} else {
if (function.qualifiedName!.startsWith(match.group(0)!)) {
completions.add(function.qualifiedName!);
}
}
}
}
completions.sort();
return completions;
});
}
}
static bool _startsWithDigit(String s) {
return '0'.compareTo(s[0]) <= 0 && '9'.compareTo(s[0]) >= 0;
}
static Future<List<String>> _completeFile(
Debugger debugger, Match match) async {
var scriptName;
var scriptNameComplete = false;
var lineStr;
var lineStrComplete = false;
var colStr;
if (_startsWithDigit(match.group(1)!)) {
// CASE 1: We have matched a prefix of (lineStr:)(colStr)
var frame = await _currentFrame(debugger);
if (frame == null) {
return [];
}
scriptName = frame.location!.script.name;
scriptNameComplete = true;
lineStr = match.group(1) ?? '';
if (lineStr.endsWith(':')) {
lineStr = lineStr.substring(0, lineStr.length - 1);
lineStrComplete = true;
}
colStr = match.group(2) ?? '';
} else {
// CASE 2: We have matched a prefix of (scriptName:)(lineStr)(:colStr)
scriptName = match.group(1) ?? '';
if (scriptName.endsWith(':')) {
scriptName = scriptName.substring(0, scriptName.length - 1);
scriptNameComplete = true;
}
lineStr = match.group(2) ?? '';
colStr = match.group(3) ?? '';
if (colStr.startsWith(':')) {
lineStrComplete = true;
colStr = colStr.substring(1);
}
}
if (!scriptNameComplete) {
// The script name is incomplete. Complete it.
var scripts =
await _lookupScript(debugger.isolate, scriptName, allowPrefix: true);
var completions = <String>[];
for (var script in scripts) {
completions.add(script.name! + ':');
}
completions.sort();
return completions;
} else {
// The script name is complete. Look it up.
var scripts =
await _lookupScript(debugger.isolate, scriptName, allowPrefix: false);
if (scripts.isEmpty) {
return [];
}
var script = scripts.first;
await script.load();
if (!lineStrComplete) {
// Complete the line.
var sharedPrefix = '${script.name}:';
var completions = <String>[];
var report = await script.isolate!.getSourceReport(
[Isolate.kPossibleBreakpointsReport], script) as ServiceMap;
Set<int> possibleBpts = getPossibleBreakpointLines(report, script);
for (var line in possibleBpts) {
var currentLineStr = line.toString();
if (currentLineStr.startsWith(lineStr)) {
completions.add('${sharedPrefix}${currentLineStr} ');
completions.add('${sharedPrefix}${currentLineStr}:');
}
}
return completions;
} else {
// Complete the column.
int lineNum = int.parse(lineStr);
var scriptLine = script.getLine(lineNum)!;
var sharedPrefix = '${script.name}:${lineStr}:';
var completions = <String>[];
int maxCol = scriptLine.text.trimRight().runes.length;
for (int i = 1; i <= maxCol; i++) {
var currentColStr = i.toString();
if (currentColStr.startsWith(colStr)) {
completions.add('${sharedPrefix}${currentColStr} ');
}
}
return completions;
}
}
}
String toString() {
if (valid) {
if (function != null) {
return '${function!.qualifiedName}';
} else if (col != null) {
return '${script!.name}:${line}:${col}';
} else {
return '${script!.name}:${line}';
}
}
return 'invalid source location (${errorMessage})';
}
Script? script;
int? line;
int? col;
ServiceFunction? function;
String? errorMessage;
bool get valid => (errorMessage == null);
}
@@ -1,581 +0,0 @@
// Copyright (c) 2014, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/containers/virtual_collection.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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';
enum _SortingField {
newInstances,
newInternalSize,
newExternalSize,
newSize,
oldInstances,
oldInternalSize,
oldExternalSize,
oldSize,
instances,
internalSize,
externalSize,
size,
className,
}
enum _SortingDirection { ascending, descending }
class AllocationProfileElement extends CustomElement implements Renderable {
late RenderingScheduler<AllocationProfileElement> _r;
Stream<RenderedEvent<AllocationProfileElement>> get onRendered =>
_r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.AllocationProfileRepository _repository;
M.AllocationProfile? _profile;
bool _autoRefresh = false;
bool _isCompacted = false;
late StreamSubscription _gcSubscription;
_SortingField _sortingField = _SortingField.size;
_SortingDirection _sortingDirection = _SortingDirection.descending;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
factory AllocationProfileElement(
M.VM vm,
M.IsolateRef isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.AllocationProfileRepository repository,
{RenderingQueue? queue}) {
AllocationProfileElement e = new AllocationProfileElement.created();
e._r = new RenderingScheduler<AllocationProfileElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._repository = repository;
return e;
}
AllocationProfileElement.created() : super.created('allocation-profile');
@override
attached() {
super.attached();
_r.enable();
_refresh();
_gcSubscription = _events.onGCEvent.listen((e) {
if (_autoRefresh && (e.isolate.id == _isolate.id)) {
_refresh();
}
});
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
_gcSubscription.cancel();
}
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('allocation profile'),
(new NavRefreshElement(
label: 'Download', disabled: _profile == null, queue: _r.queue)
..onRefresh.listen((_) => _downloadCSV()))
.element,
(new NavRefreshElement(label: 'GC', queue: _r.queue)
..onRefresh.listen((_) => _refresh(gc: true)))
.element,
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((_) => _refresh()))
.element,
new HTMLDivElement()
..className = 'nav-option'
..appendChildren(<HTMLElement>[
new HTMLInputElement()
..id = 'allocation-profile-auto-refresh'
..type = 'checkbox'
..checked = _autoRefresh
..onChange.listen((_) => _autoRefresh = !_autoRefresh),
new HTMLLabelElement()
..htmlFor = 'allocation-profile-auto-refresh'
..textContent = 'Auto-refresh on GC'
]),
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Allocation Profile',
new HTMLHRElement()
])
];
if (_profile == null) {
appendChild(new HTMLDivElement()
..className = 'content-centered-big'
..append(new HTMLHeadingElement.h2()..textContent = 'Loading...'));
} else {
appendChildren([
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(_isCompacted
? []
: [
new HTMLDivElement()
..className = 'memberList'
..append(
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'last forced GC at',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _profile!.lastServiceGC == null
? '---'
: '${_profile!.lastServiceGC}'
]),
),
new HTMLHRElement(),
]),
new HTMLDivElement()
..className = 'content-centered-big compactable'
..appendChildren([
new HTMLDivElement()
..className = 'heap-space left'
..appendChildren(_isCompacted
? [
new HTMLHeadingElement.h2()
..textContent = 'New Generation '
'(${_usedCaption(_profile!.newSpace)})',
]
: [
new HTMLHeadingElement.h2()
..textContent = 'New Generation',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(
_createSpaceMembers(_profile!.newSpace)),
]),
new HTMLDivElement()
..className = 'heap-space left'
..appendChildren(_isCompacted
? [
new HTMLHeadingElement.h2()
..textContent = 'Old Generation '
'(${_usedCaption(_profile!.oldSpace)})',
]
: [
new HTMLHeadingElement.h2()
..textContent = 'Old Generation',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(
_createSpaceMembers(_profile!.oldSpace)),
]),
new HTMLDivElement()
..className = 'heap-space left'
..appendChildren(_isCompacted
? [
new HTMLHeadingElement.h2()
..textContent = 'Total '
'(${_usedCaption(_profile!.totalSpace)})',
]
: [
new HTMLHeadingElement.h2()..textContent = 'Total',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(
_createSpaceMembers(_profile!.totalSpace)),
]),
new HTMLButtonElement()
..className = 'compact'
..textContent = _isCompacted ? 'expand ▼' : 'compact ▲'
..onClick.listen((_) {
_isCompacted = !_isCompacted;
_r.dirty();
}),
new HTMLHRElement()
]),
new HTMLDivElement()
..className = _isCompacted ? 'collection expanded' : 'collection'
..appendChild(new VirtualCollectionElement(
_createCollectionLine, _updateCollectionLine,
createHeader: _createCollectionHeader,
search: _search,
items: _profile!.members.toList()..sort(_createSorter()),
queue: _r.queue)
.element)
]);
}
}
_createSorter() {
var getter;
switch (_sortingField) {
case _SortingField.newInternalSize:
getter = _getNewInternalSize;
break;
case _SortingField.newExternalSize:
getter = _getNewExternalSize;
break;
case _SortingField.newSize:
getter = _getNewSize;
break;
case _SortingField.newInstances:
getter = _getNewInstances;
break;
case _SortingField.oldInternalSize:
getter = _getOldInternalSize;
break;
case _SortingField.oldExternalSize:
getter = _getOldExternalSize;
break;
case _SortingField.oldSize:
getter = _getOldSize;
break;
case _SortingField.oldInstances:
getter = _getOldInstances;
break;
case _SortingField.internalSize:
getter = _getInternalSize;
break;
case _SortingField.externalSize:
getter = _getExternalSize;
break;
case _SortingField.size:
getter = _getSize;
break;
case _SortingField.instances:
getter = _getInstances;
break;
case _SortingField.className:
getter = (M.ClassHeapStats s) => s.clazz!.name;
break;
}
switch (_sortingDirection) {
case _SortingDirection.ascending:
int sort(M.ClassHeapStats a, M.ClassHeapStats b) {
return getter(a).compareTo(getter(b));
}
return sort;
case _SortingDirection.descending:
int sort(M.ClassHeapStats a, M.ClassHeapStats b) {
return getter(b).compareTo(getter(a));
}
return sort;
}
}
static HTMLElement _createCollectionLine() => new HTMLDivElement()
..className = 'collection-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'instances'
..textContent = '0',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'instances'
..textContent = '0',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'bytes'
..textContent = '0B',
new HTMLSpanElement()
..className = 'instances'
..textContent = '0',
new HTMLSpanElement()..className = 'name'
]);
List<HTMLElement> _createCollectionHeader() => [
new HTMLDivElement()
..className = 'collection-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'group'
..textContent = 'New Generation',
new HTMLSpanElement()
..className = 'group'
..textContent = 'Old Generation',
new HTMLSpanElement()
..className = 'group'
..textContent = 'Total',
new HTMLSpanElement()
..className = 'group'
..textContent = '',
]),
new HTMLDivElement()
..className = 'collection-item'
..appendChildren(<Node>[
_createHeaderButton('bytes', 'Internal',
_SortingField.newInternalSize, _SortingDirection.descending),
_createHeaderButton('bytes', 'External',
_SortingField.newExternalSize, _SortingDirection.descending),
_createHeaderButton('bytes', 'Size', _SortingField.newSize,
_SortingDirection.descending),
_createHeaderButton('instances', 'Instances',
_SortingField.newInstances, _SortingDirection.descending),
_createHeaderButton('bytes', 'Internal',
_SortingField.oldInternalSize, _SortingDirection.descending),
_createHeaderButton('bytes', 'External',
_SortingField.oldExternalSize, _SortingDirection.descending),
_createHeaderButton('bytes', 'Size', _SortingField.oldSize,
_SortingDirection.descending),
_createHeaderButton('instances', 'Instances',
_SortingField.oldInstances, _SortingDirection.descending),
_createHeaderButton('bytes', 'Internal', _SortingField.internalSize,
_SortingDirection.descending),
_createHeaderButton('bytes', 'External', _SortingField.externalSize,
_SortingDirection.descending),
_createHeaderButton('bytes', 'Size', _SortingField.size,
_SortingDirection.descending),
_createHeaderButton('instances', 'Instances',
_SortingField.instances, _SortingDirection.descending),
_createHeaderButton('name', 'Class', _SortingField.className,
_SortingDirection.ascending)
])
];
HTMLButtonElement _createHeaderButton(String className, String text,
_SortingField field, _SortingDirection direction) =>
new HTMLButtonElement()
..className = className
..textContent = _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();
}
void _updateCollectionLine(HTMLElement e, itemDynamic, index) {
M.ClassHeapStats item = itemDynamic;
e.childNodes.item(0)!.textContent =
Utils.formatSize(_getNewInternalSize(item));
e.childNodes.item(1)!.textContent =
Utils.formatSize(_getNewExternalSize(item));
e.childNodes.item(2)!.textContent = Utils.formatSize(_getNewSize(item));
e.childNodes.item(3)!.textContent = '${_getNewInstances(item)}';
e.childNodes.item(4)!.textContent =
Utils.formatSize(_getOldInternalSize(item));
e.childNodes.item(5)!.textContent =
Utils.formatSize(_getOldExternalSize(item));
e.childNodes.item(6)!.textContent = Utils.formatSize(_getOldSize(item));
e.childNodes.item(7)!.textContent = '${_getOldInstances(item)}';
e.childNodes.item(8)!.textContent =
Utils.formatSize(_getInternalSize(item));
e.childNodes.item(9)!.textContent =
Utils.formatSize(_getExternalSize(item));
e.childNodes.item(10)!.textContent = Utils.formatSize(_getSize(item));
e.childNodes.item(11)!.textContent = '${_getInstances(item)}';
final old = e.childNodes.item(12)!;
e.insertBefore(
old,
e.appendChild(
(new ClassRefElement(_isolate, item.clazz!, queue: _r.queue).element
..className = 'name')));
e.removeChild(old);
}
bool _search(Pattern pattern, itemDynamic) {
M.ClassHeapStats item = itemDynamic;
return item.clazz!.name!.contains(pattern);
}
static String _usedCaption(M.HeapSpace space) =>
'${Utils.formatSize(space.used)}'
' of '
'${Utils.formatSize(space.capacity)}';
static List<HTMLElement> _createSpaceMembers(M.HeapSpace space) {
final used = _usedCaption(space);
final ext = '${Utils.formatSize(space.external)}';
final collections = '${space.collections}';
final avgCollectionTime =
'${Utils.formatDurationInMilliseconds(space.avgCollectionTime)} ms';
return [
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'used',
new HTMLDivElement()
..className = 'memberValue'
..textContent = used
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'external',
new HTMLDivElement()
..className = 'memberValue'
..textContent = ext
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'collections',
new HTMLDivElement()
..className = 'memberValue'
..textContent = collections
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'average collection time',
new HTMLDivElement()
..className = 'memberValue'
..textContent = avgCollectionTime
]),
];
}
Future _refresh({bool gc = false, bool reset = false}) async {
_profile = null;
_r.dirty();
_profile = await _repository.get(_isolate, gc: gc, reset: reset);
_r.dirty();
}
void _downloadCSV() {
assert(_profile != null);
final header = [
'"New Internal"',
'"New External"',
'"New Size"',
'"New Instances"',
'"Old Internal"',
'"Old External"',
'"Old Size"',
'"Old Instances"',
'"Internal"',
'"External"',
'"Size"',
'"Instances"',
'Class'
].join(',') +
'\n';
HTMLAnchorElement tl = document.createElement('a') as HTMLAnchorElement;
tl
..attributes.setNamedItem(document.createAttribute('href')
..value = 'data:text/plain;charset=utf-8,' +
Uri.encodeComponent(header +
(_profile!.members.toList()..sort(_createSorter()))
.map(_csvOut)
.join('\n')))
..attributes.setNamedItem(
document.createAttribute('download')..value = 'heap-profile.csv')
..click();
}
static _csvOut(M.ClassHeapStats s) {
return [
_getNewInternalSize(s),
_getNewExternalSize(s),
_getNewSize(s),
_getNewInstances(s),
_getOldInternalSize(s),
_getOldExternalSize(s),
_getOldSize(s),
_getOldInstances(s),
_getInternalSize(s),
_getExternalSize(s),
_getSize(s),
_getInstances(s),
s.clazz!.name
].join(',');
}
static int _getNewInstances(M.ClassHeapStats s) => s.newSpace.instances;
static int _getNewInternalSize(M.ClassHeapStats s) => s.newSpace.internalSize;
static int _getNewExternalSize(M.ClassHeapStats s) => s.newSpace.externalSize;
static int _getNewSize(M.ClassHeapStats s) => s.newSpace.size;
static int _getOldInstances(M.ClassHeapStats s) => s.oldSpace.instances;
static int _getOldInternalSize(M.ClassHeapStats s) => s.oldSpace.internalSize;
static int _getOldExternalSize(M.ClassHeapStats s) => s.oldSpace.externalSize;
static int _getOldSize(M.ClassHeapStats s) => s.oldSpace.size;
static int _getInstances(M.ClassHeapStats s) =>
s.newSpace.instances + s.oldSpace.instances;
static int _getInternalSize(M.ClassHeapStats s) =>
s.newSpace.internalSize + s.oldSpace.internalSize;
static int _getExternalSize(M.ClassHeapStats s) =>
s.newSpace.externalSize + s.oldSpace.externalSize;
static int _getSize(M.ClassHeapStats s) => s.newSpace.size + s.oldSpace.size;
}
@@ -1,119 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/sample_buffer_control.dart';
import 'package:observatory/src/elements/stack_trace_tree_config.dart';
class ClassAllocationProfileElement extends CustomElement
implements Renderable {
late RenderingScheduler<ClassAllocationProfileElement> _r;
Stream<RenderedEvent<ClassAllocationProfileElement>> get onRendered =>
_r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.Class _cls;
late M.ClassSampleProfileRepository _profiles;
late Stream<M.SampleProfileLoadingProgressEvent> _progressStream;
M.SampleProfileLoadingProgress? _progress;
late M.SampleProfileTag _tag = M.SampleProfileTag.none;
late ProfileTreeMode _mode = ProfileTreeMode.function;
late M.ProfileTreeDirection _direction = M.ProfileTreeDirection.exclusive;
M.IsolateRef get isolate => _isolate;
M.Class get cls => _cls;
factory ClassAllocationProfileElement(M.VM vm, M.IsolateRef isolate,
M.Class cls, M.ClassSampleProfileRepository profiles,
{RenderingQueue? queue}) {
ClassAllocationProfileElement e =
new ClassAllocationProfileElement.created();
e._r =
new RenderingScheduler<ClassAllocationProfileElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._cls = cls;
e._profiles = profiles;
return e;
}
ClassAllocationProfileElement.created()
: super.created('class-allocation-profile');
@override
void attached() {
super.attached();
_r.enable();
_request();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
if (_progress == null) {
removeChildren();
return;
}
final content = <HTMLElement>[
(new SampleBufferControlElement(_vm, _progress!, _progressStream,
selectedTag: _tag, queue: _r.queue)
..onTagChange.listen((e) {
_tag = e.element.selectedTag;
_request(forceFetch: true);
}))
.element
];
if (_progress!.status == M.SampleProfileLoadingStatus.loaded) {
late CpuProfileVirtualTreeElement tree;
content.addAll([
new HTMLBRElement(),
(new StackTraceTreeConfigElement(
mode: _mode,
direction: _direction,
showFilter: false,
queue: _r.queue)
..onModeChange.listen((e) {
_mode = tree.mode = e.element.mode;
})
..onDirectionChange.listen((e) {
_direction = tree.direction = e.element.direction;
}))
.element,
new HTMLBRElement(),
(tree = new CpuProfileVirtualTreeElement(_isolate, _progress!.profile,
queue: _r.queue))
.element
]);
}
removeChildren();
appendChildren(content);
}
Future _request({bool forceFetch = false}) async {
_progress = null;
_progressStream =
_profiles.get(_isolate, _cls, _tag, forceFetch: forceFetch);
_r.dirty();
_progress = (await _progressStream.first).progress;
_r.dirty();
if (M.isSampleProcessRunning(_progress!.status)) {
_progress = (await _progressStream.last).progress;
_r.dirty();
}
}
}
@@ -1,323 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/sentinel_value.dart';
import 'package:observatory/src/elements/strongly_reachable_instances.dart';
import 'package:observatory/utils.dart';
class ClassInstancesElement extends CustomElement implements Renderable {
late RenderingScheduler<ClassInstancesElement> _r;
Stream<RenderedEvent<ClassInstancesElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.Class _cls;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.StronglyReachableInstancesRepository _stronglyReachableInstances;
late M.ObjectRepository _objects;
M.Guarded<M.InstanceRef>? _allInstances = null;
bool _loadingAllInstances = false;
M.Guarded<M.InstanceRef>? _allSubclassInstances = null;
bool _loadingAllSubclassInstances = false;
M.Guarded<M.InstanceRef>? _allImplementorInstances = null;
bool _loadingAllImplementorInstances = false;
M.Guarded<M.Instance>? _retainedSize = null;
bool _loadingRetainedBytes = false;
M.Guarded<M.Instance>? _reachableSize = null;
bool _loadingReachableBytes = false;
M.IsolateRef get isolate => _isolate;
M.Class get cls => _cls;
factory ClassInstancesElement(
M.IsolateRef isolate,
M.Class cls,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.StronglyReachableInstancesRepository stronglyReachableInstances,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
ClassInstancesElement e = new ClassInstancesElement.created();
e._r = new RenderingScheduler<ClassInstancesElement>(e, queue: queue);
e._isolate = isolate;
e._cls = cls;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._stronglyReachableInstances = stronglyReachableInstances;
e._objects = objects;
return e;
}
ClassInstancesElement.created() : super.created('class-instances');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
StronglyReachableInstancesElement? _strong;
void render() {
_strong = _strong ??
new StronglyReachableInstancesElement(
_isolate, _cls, _stronglyReachableInstances, _objects,
queue: _r.queue);
final instanceCount = _cls.newSpace!.instances + _cls.oldSpace!.instances;
final size = Utils.formatSize(_cls.newSpace!.size + _cls.oldSpace!.size);
removeChildren();
appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'currently allocated',
new HTMLDivElement()
..className = 'memberValue'
..textContent = 'count ${instanceCount} (shallow size ${size})'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'strongly reachable ',
new HTMLDivElement()
..className = 'memberValue'
..appendChild(_strong!.element)
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'all direct instances'
..title = 'All instances whose class is exactly this class',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createAllInstances())
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'all instances of subclasses'
..title =
'All instances whose class is a subclass of this class',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createAllSubclassInstances())
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'all instances of implementors'
..title =
'All instances whose class implements the implicit interface of this class',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createAllImplementorInstances())
]),
new HTMLDivElement()
..className = 'memberItem'
..title = 'Space reachable from this object, '
'excluding class references'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Reachable size ',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createReachableSizeValue())
]),
new HTMLDivElement()
..className = 'memberItem'
..title = 'Space that would be reclaimed if references to this '
'object were replaced with null'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Retained size ',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createRetainedSizeValue())
]),
])
]);
}
List<HTMLElement> _createAllInstances() {
final content = <HTMLElement>[];
if (_allInstances != null) {
if (_allInstances!.isSentinel) {
content.add(new SentinelValueElement(_allInstances!.asSentinel!,
queue: _r.queue)
.element);
} else {
content.add(anyRef(_isolate, _allInstances!.asValue!, _objects));
}
} else {
content.add(new HTMLSpanElement()..textContent = '...');
}
final button = new HTMLButtonElement()
..className = 'reachable_size'
..disabled = _loadingAllInstances
..textContent = '';
button.onClick.listen((_) async {
button.disabled = true;
_loadingAllInstances = true;
_allInstances =
await _stronglyReachableInstances.getAsArray(_isolate, _cls);
_loadingAllInstances = false;
_r.dirty();
});
content.add(button);
return content;
}
List<HTMLElement> _createAllSubclassInstances() {
final content = <HTMLElement>[];
if (_allSubclassInstances != null) {
if (_allSubclassInstances!.isSentinel) {
content.add(new SentinelValueElement(_allSubclassInstances!.asSentinel!,
queue: _r.queue)
.element);
} else {
content
.add(anyRef(_isolate, _allSubclassInstances!.asValue!, _objects));
}
} else {
content.add(new HTMLSpanElement()..textContent = '...');
}
final button = new HTMLButtonElement()
..className = 'reachable_size'
..disabled = _loadingAllSubclassInstances
..textContent = '';
button.onClick.listen((_) async {
button.disabled = true;
_loadingAllSubclassInstances = true;
_allSubclassInstances = await _stronglyReachableInstances
.getAsArray(_isolate, _cls, includeSubclasses: true);
_loadingAllSubclassInstances = false;
_r.dirty();
});
content.add(button);
return content;
}
List<HTMLElement> _createAllImplementorInstances() {
final content = <HTMLElement>[];
if (_allImplementorInstances != null) {
if (_allImplementorInstances!.isSentinel) {
content.add(new SentinelValueElement(
_allImplementorInstances!.asSentinel!,
queue: _r.queue)
.element);
} else {
content.add(
anyRef(_isolate, _allImplementorInstances!.asValue!, _objects));
}
} else {
content.add(new HTMLSpanElement()..textContent = '...');
}
final button = new HTMLButtonElement()
..className = 'reachable_size'
..disabled = _loadingAllImplementorInstances
..textContent = '';
button.onClick.listen((_) async {
button.disabled = true;
_loadingAllImplementorInstances = true;
_allImplementorInstances = await _stronglyReachableInstances
.getAsArray(_isolate, _cls, includeImplementors: true);
_loadingAllImplementorInstances = false;
_r.dirty();
});
content.add(button);
return content;
}
List<HTMLElement> _createReachableSizeValue() {
final content = <HTMLElement>[];
if (_reachableSize != null) {
if (_reachableSize!.isSentinel) {
content.add(new SentinelValueElement(_reachableSize!.asSentinel!,
queue: _r.queue)
.element);
} else {
content.add(new HTMLSpanElement()
..textContent = Utils.formatSize(
int.parse(_reachableSize!.asValue!.valueAsString!)));
}
} else {
content.add(new HTMLSpanElement()..textContent = '...');
}
final button = new HTMLButtonElement()
..className = 'reachable_size'
..disabled = _loadingReachableBytes
..textContent = '';
button.onClick.listen((_) async {
button.disabled = true;
_loadingReachableBytes = true;
_reachableSize = await _reachableSizes.get(_isolate, _cls.id!);
_loadingReachableBytes = false;
_r.dirty();
});
content.add(button);
return content;
}
List<HTMLElement> _createRetainedSizeValue() {
final content = <HTMLElement>[];
if (_retainedSize != null) {
if (_retainedSize!.isSentinel) {
content.add(new SentinelValueElement(_retainedSize!.asSentinel!,
queue: _r.queue)
.element);
} else {
content.add(new HTMLSpanElement()
..textContent = Utils.formatSize(
int.parse(_retainedSize!.asValue!.valueAsString!)));
}
} else {
content.add(new HTMLSpanElement()..textContent = '...');
}
final button = new HTMLButtonElement()
..className = 'retained_size'
..disabled = _loadingRetainedBytes
..textContent = '';
button.onClick.listen((_) async {
button.disabled = true;
_loadingRetainedBytes = true;
_retainedSize = await _retainedSizes.get(_isolate, _cls.id!);
_loadingRetainedBytes = false;
_r.dirty();
});
content.add(button);
return content;
}
}
@@ -1,55 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class ClassRefElement extends CustomElement implements Renderable {
late RenderingScheduler<ClassRefElement> _r;
Stream<RenderedEvent<ClassRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.ClassRef _class;
M.IsolateRef get isolate => _isolate;
M.ClassRef get cls => _class;
factory ClassRefElement(M.IsolateRef isolate, M.ClassRef cls,
{RenderingQueue? queue}) {
ClassRefElement e = new ClassRefElement.created();
e._r = new RenderingScheduler<ClassRefElement>(e, queue: queue);
e._isolate = isolate;
e._class = cls;
return e;
}
ClassRefElement.created() : super.created('class-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
removeChildren();
appendChild(new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _class)
..text = _class.name ?? '');
}
}
@@ -1,191 +0,0 @@
// Copyright (c) 2014, 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 class_tree_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/containers/virtual_tree.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
import 'package:observatory/src/elements/nav/vm_menu.dart';
class ClassTreeElement extends CustomElement implements Renderable {
late RenderingScheduler<ClassTreeElement> _r;
Stream<RenderedEvent<ClassTreeElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.ClassRepository _classes;
M.Class? _object;
final _subclasses = <String, Iterable<M.Class>>{};
final _mixins = <String, List<M.Instance>?>{};
factory ClassTreeElement(
M.VM vm,
M.IsolateRef isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.ClassRepository classes,
{RenderingQueue? queue}) {
ClassTreeElement e = new ClassTreeElement.created();
e._r = new RenderingScheduler<ClassTreeElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._classes = classes;
return e;
}
ClassTreeElement.created() : super.created('class-tree');
@override
void attached() {
super.attached();
_refresh();
_r.enable();
}
@override
void detached() {
super.detached();
children = <Element>[];
_r.disable(notify: true);
}
VirtualTreeElement? _tree;
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('class hierarchy'),
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h1()
..textContent = 'Class Hierarchy (${_subclasses.length})',
new HTMLBRElement(),
new HTMLHRElement(),
_object == null
? (new HTMLHeadingElement.h2()..textContent = 'Loading...')
: _createTree()
])
];
}
HTMLElement _createTree() {
_tree = new VirtualTreeElement(_create, _update, _children,
items: [_object], search: _search, queue: _r.queue);
_tree!.expand(_object, autoExpandSingleChildNodes: true);
return _tree!.element;
}
Future _refresh() async {
_object = null;
_subclasses.clear();
_mixins.clear();
_object = await _register(await _classes.getObject(_isolate));
_r.dirty();
}
Future<M.Class> _register(M.Class cls) async {
_subclasses[cls.id!] = await Future.wait(
(await Future.wait(cls.subclasses!.map(_getActualChildren)))
.expand((f) => f)
.map(_register));
return cls;
}
Future<Iterable<M.Class>> _getActualChildren(M.ClassRef ref) async {
var cls = await _classes.get(_isolate, ref.id!);
if (cls.isPatch!) {
return const [];
}
if (cls.mixin == null) {
return [cls];
}
return (await Future.wait(cls.subclasses!.map(_getActualChildren)))
.expand((f) => f)
..forEach((subcls) {
_mixins[subcls.id!] = (_mixins[subcls.id!] ?? [])
..add(cls.mixin as M.Instance);
});
}
static HTMLElement _create(toggle) {
return new HTMLDivElement()
..className = 'class-tree-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..className = 'lines',
new HTMLButtonElement()
..className = 'expander'
..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
new HTMLSpanElement()..className = 'name'
]);
}
void _update(HTMLElement el, classDynamic, int index) {
M.Class cls = classDynamic;
virtualTreeUpdateLines(el.childNodes.item(0) as HTMLSpanElement, index);
if (cls.subclasses!.isEmpty) {
(el.children.item(1) as HTMLElement).textContent = '';
} else {
(el.children.item(1) as HTMLElement).textContent =
_tree!.isExpanded(cls) ? '' : '';
}
(el.children.item(2) as HTMLElement)
..removeChildren()
..appendChild(
new ClassRefElement(_isolate, cls, queue: _r.queue).element);
if (_mixins[cls.id] != null) {
(el.children.item(2) as HTMLElement)
.appendChildren(_createMixins(_mixins[cls.id]!));
}
}
bool _search(Pattern pattern, classDynamic) {
M.Class cls = classDynamic;
return cls.name!.contains(pattern);
}
List<HTMLElement> _createMixins(List<M.Instance> types) {
final children = types
.expand((type) => <HTMLElement>[
new HTMLSpanElement()..textContent = ', ',
type.typeClass == null
? (new HTMLSpanElement()
..textContent = type.name!.split('<').first)
: new ClassRefElement(_isolate, type.typeClass!,
queue: _r.queue)
.element
])
.toList();
children.first.textContent = ' with ';
return children;
}
Iterable<M.Class> _children(classDynamic) {
M.Class cls = classDynamic;
return _subclasses[cls.id]!;
}
}
@@ -1,471 +0,0 @@
// 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 class_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_allocation_profile.dart';
import 'package:observatory/src/elements/class_instances.dart';
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/error_ref.dart';
import 'package:observatory/src/elements/eval_box.dart';
import 'package:observatory/src/elements/field_ref.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/instance_ref.dart';
import 'package:observatory/src/elements/library_ref.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/source_inset.dart';
import 'package:observatory/src/elements/source_link.dart';
class ClassViewElement extends CustomElement implements Renderable {
late RenderingScheduler<ClassViewElement> _r;
Stream<RenderedEvent<ClassViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Class _cls;
late M.ClassRepository _classes;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.StronglyReachableInstancesRepository _stronglyReachableInstances;
late M.FieldRepository _fields;
late M.ScriptRepository _scripts;
late M.ObjectRepository _objects;
late M.EvalRepository _eval;
late M.ClassSampleProfileRepository _profiles;
Iterable<M.Field>? _classFields;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Class get cls => _cls;
factory ClassViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Class cls,
M.EventRepository events,
M.NotificationRepository notifications,
M.ClassRepository classes,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.FieldRepository fields,
M.ScriptRepository scripts,
M.ObjectRepository objects,
M.EvalRepository eval,
M.StronglyReachableInstancesRepository stronglyReachable,
M.ClassSampleProfileRepository profiles,
{RenderingQueue? queue}) {
ClassViewElement e = new ClassViewElement.created();
e._r = new RenderingScheduler<ClassViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._cls = cls;
e._classes = classes;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._fields = fields;
e._scripts = scripts;
e._objects = objects;
e._eval = eval;
e._stronglyReachableInstances = stronglyReachable;
e._profiles = profiles;
return e;
}
ClassViewElement.created() : super.created('class-view');
@override
attached() {
super.attached();
_r.enable();
_loadAdditionalData();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
ObjectCommonElement? _common;
ClassInstancesElement? _classInstances;
bool _loadProfile = false;
void render() {
_common = _common ??
new ObjectCommonElement(_isolate, _cls, _retainedSizes, _reachableSizes,
_references, _retainingPaths, _objects,
queue: _r.queue);
_classInstances = _classInstances ??
new ClassInstancesElement(_isolate, _cls, _retainedSizes,
_reachableSizes, _stronglyReachableInstances, _objects,
queue: _r.queue);
var header = '';
if (_cls.isAbstract!) {
header += 'abstract ';
}
if (_cls.isPatch!) {
header += 'patch ';
}
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
new NavClassMenuElement(_isolate, _cls, queue: _r.queue).element,
(new NavRefreshElement(
label: 'Refresh Allocation Profile', queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_loadProfile = true;
_r.dirty();
}))
.element,
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_common = null;
_classInstances = null;
_fieldsExpanded = null;
_functionsExpanded = null;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()
..textContent = '$header class ${_cls.name}',
new HTMLHRElement(),
_common!.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_createMembers()),
new HTMLDivElement()
..appendChildren(_cls.error == null
? const []
: [
new HTMLHRElement(),
new ErrorRefElement(_cls.error!, queue: _r.queue).element
]),
new HTMLHRElement(),
new EvalBoxElement(_isolate, _cls, _objects, _eval, queue: _r.queue)
.element,
new HTMLHRElement(),
new HTMLHeadingElement.h2()..textContent = 'Fields & Functions',
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_createElements()),
new HTMLHRElement(),
new HTMLHeadingElement.h2()..textContent = 'Instances',
new HTMLDivElement()..appendChild(_classInstances!.element),
new HTMLHRElement(),
new HTMLHeadingElement.h2()..textContent = 'Allocations',
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Tracing allocations? ',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_cls.traceAllocations!
? [
new HTMLSpanElement()..textContent = 'Yes ',
new HTMLButtonElement()
..textContent = 'disable'
..onClick.listen((e) async {
(e.target as HTMLButtonElement).disabled = true;
await _profiles.disable(_isolate, _cls);
_loadProfile = true;
_refresh();
})
]
: [
new HTMLSpanElement()..textContent = 'No ',
new HTMLButtonElement()
..textContent = 'enable'
..onClick.listen((e) async {
(e.target as HTMLButtonElement).disabled = true;
await _profiles.enable(_isolate, _cls);
_refresh();
})
])
]),
new HTMLDivElement()
..appendChildren(_loadProfile
? [
new ClassAllocationProfileElement(
_vm, _isolate, _cls, _profiles,
queue: _r.queue)
.element
]
: const []),
new HTMLDivElement()
..appendChildren(_cls.location != null
? [
new HTMLHRElement(),
new SourceInsetElement(_isolate, _cls.location!, _scripts,
_objects, _events,
queue: _r.queue)
.element
]
: const []),
])
]);
}
bool? _fieldsExpanded;
bool? _functionsExpanded;
List<HTMLElement> _createMembers() {
final members = <HTMLElement>[];
if (_cls.library != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'library',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new LibraryRefElement(_isolate, _cls.library!, queue: _r.queue)
.element
])
]));
}
if (_cls.location != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'script',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new SourceLinkElement(_isolate, _cls.location!, _scripts,
queue: _r.queue)
.element
])
]));
}
if (_cls.superclass != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'superclass',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new ClassRefElement(_isolate, _cls.superclass!, queue: _r.queue)
.element
])
]));
}
if (_cls.superType != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'supertype',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new InstanceRefElement(_isolate, _cls.superType!, _objects,
queue: _r.queue)
.element
])
]));
}
if (cls.mixin != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'mixin',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new InstanceRefElement(_isolate, _cls.mixin!, _objects,
queue: _r.queue)
.element
])
]));
}
if (_cls.subclasses!.length > 0) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'extended by',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren((_cls.subclasses!.expand((subcls) => <HTMLElement>[
new ClassRefElement(_isolate, subcls, queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ', '
])).toList()
..removeLast())
]));
}
members.add(new HTMLBRElement());
if (_cls.interfaces!.length > 0) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'implements',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren((_cls.interfaces!.expand((interf) => <HTMLElement>[
new InstanceRefElement(_isolate, interf, _objects,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ', '
])).toList()
..removeLast())
]));
}
if (_cls.name != _cls.vmName) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'vm name',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '${_cls.vmName}'
]));
}
return members;
}
List<HTMLElement> _createElements() {
final members = <HTMLElement>[];
if (_classFields != null && _classFields!.isNotEmpty) {
final fields = _classFields!.toList();
_fieldsExpanded = _fieldsExpanded ?? (fields.length <= 8);
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'fields ${fields.length}',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(expanded: _fieldsExpanded!)
..onToggle
.listen((e) => _fieldsExpanded = e.control.expanded)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(
fields.map<HTMLElement>((f) => new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new FieldRefElement(_isolate, f, _objects,
queue: _r.queue)
.element
]),
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(f.staticValue == null
? const []
: [
anyRef(
_isolate, f.staticValue, _objects,
queue: _r.queue)
])
])))
])
.element
])
]));
}
if (_cls.functions!.isNotEmpty) {
final functions = _cls.functions!.toList();
_functionsExpanded = _functionsExpanded ?? (functions.length <= 8);
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'functions (${functions.length})',
new HTMLDivElement()
..className = 'memberValue'
..appendChild((new CurlyBlockElement(expanded: _functionsExpanded!)
..onToggle
.listen((e) => _functionsExpanded = e.control.expanded)
..content = (functions.map<HTMLElement>((f) =>
new HTMLDivElement()
..className = 'indent'
..appendChild(
new FunctionRefElement(_isolate, f, queue: _r.queue)
.element))))
.element)
]));
}
return members;
}
Future _refresh() async {
_cls = await _classes.get(_isolate, _cls.id!);
await _loadAdditionalData();
_r.dirty();
}
Future _loadAdditionalData() async {
_classFields = await Future.wait(
_cls.fields!.map((f) => _fields.get(_isolate, f.id!)));
_r.dirty();
}
}
@@ -1,62 +0,0 @@
// 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 code_ref_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/models.dart' as M
show IsolateRef, CodeRef, isSyntheticCode;
class CodeRefElement extends CustomElement implements Renderable {
late RenderingScheduler<CodeRefElement> _r;
Stream<RenderedEvent<CodeRefElement>> get onRendered => _r.onRendered;
M.IsolateRef? _isolate;
late M.CodeRef _code;
M.IsolateRef get isolate => _isolate!;
M.CodeRef get code => _code;
factory CodeRefElement(M.IsolateRef? isolate, M.CodeRef code,
{RenderingQueue? queue}) {
CodeRefElement e = new CodeRefElement.created();
e._r = new RenderingScheduler<CodeRefElement>(e, queue: queue);
e._isolate = isolate;
e._code = code;
return e;
}
CodeRefElement.created() : super.created('code-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
setChildren(<HTMLElement>[
new HTMLAnchorElement()
..href = ((M.isSyntheticCode(_code.kind)) || (_isolate == null))
? ''
: Uris.inspect(_isolate!, object: _code)
..textContent = _code.name ?? ''
]);
}
}
@@ -1,607 +0,0 @@
// 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 code_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/sample_profile.dart';
import 'package:observatory/service.dart' as S;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/objectpool_ref.dart';
import 'package:observatory/utils.dart';
import 'package:observatory/app.dart'
show SortedTable, SortedTableColumn, SortedTableRow;
class DisassemblyTable extends SortedTable {
DisassemblyTable(columns) : super(columns);
}
class InlineTable extends SortedTable {
InlineTable(columns) : super(columns);
}
class CodeViewElement extends CustomElement implements Renderable {
late RenderingScheduler<CodeViewElement> _r;
Stream<RenderedEvent<CodeViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Code _code;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ObjectRepository _objects;
late DisassemblyTable disassemblyTable;
late InlineTable inlineTable;
static const kDisassemblyColumnIndex = 3;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Code get context => _code;
factory CodeViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Code code,
M.EventRepository events,
M.NotificationRepository notifications,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
CodeViewElement e = new CodeViewElement.created();
e._r = new RenderingScheduler<CodeViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._code = code;
e._objects = objects;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
return e;
}
CodeViewElement.created() : super.created('code-view') {
var columns = [
new SortedTableColumn('Address'),
new SortedTableColumn('Inclusive'),
new SortedTableColumn('Exclusive'),
new SortedTableColumn('Disassembly'),
new SortedTableColumn('Objects'),
];
disassemblyTable = new DisassemblyTable(columns);
columns = [
new SortedTableColumn('Address'),
new SortedTableColumn('Inclusive'),
new SortedTableColumn('Exclusive'),
new SortedTableColumn('Functions'),
];
inlineTable = new InlineTable(columns);
}
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
HTMLTableElement? _disassemblyTable;
HTMLTableElement? _inlineRangeTable;
HTMLTableSectionElement? _disassemblyTableBody;
HTMLTableSectionElement? _inlineRangeTableBody;
void render() {
if (_inlineRangeTable == null) {
_inlineRangeTable = new HTMLTableElement()..className = 'table';
_inlineRangeTable!.createTHead().insertRow().appendChildren(<HTMLElement>[
new HTMLTableCellElement.th()
..className = 'address'
..textContent = 'Address Range',
new HTMLTableCellElement.th()
..className = 'tick'
..textContent = 'Inclusive',
new HTMLTableCellElement.th()
..className = 'tick'
..textContent = 'Exclusive',
new HTMLTableCellElement.th()..textContent = 'Functions',
]);
_inlineRangeTableBody = _inlineRangeTable!.createTBody()
..className = 'monospace';
}
if (_disassemblyTable == null) {
_disassemblyTable = new HTMLTableElement()..className = 'table';
_disassemblyTable!.createTHead().insertRow().appendChildren(<HTMLElement>[
new HTMLTableCellElement.th()
..className = 'address'
..textContent = 'Address Range',
new HTMLTableCellElement.th()
..className = 'tick'
..title = 'Ticks with PC on the stack'
..textContent = 'Inclusive',
new HTMLTableCellElement.th()
..className = 'tick'
..title = 'Ticks with PC at top of stack'
..textContent = 'Exclusive',
new HTMLTableCellElement.th()
..className = 'disassembly'
..textContent = 'Disassembly',
new HTMLTableCellElement.th()
..className = 'object'
..textContent = 'Object',
]);
_disassemblyTableBody = _disassemblyTable!.createTBody()
..className = 'monospace';
}
final inlinedFunctions = _code.inlinedFunctions!.toList();
final S.Code code = _code as S.Code;
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu(_code.name!),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_refresh();
}))
.element,
(new NavRefreshElement(label: 'refresh ticks', queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_refreshTicks();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h1()
..textContent = (M.isDartCode(_code.kind) && _code.isOptimized!)
? 'Optimized code for ${_code.name}'
: 'Code for ${_code.name}',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _code, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Kind',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _codeKindToString(_code.kind)
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(M.isDartCode(_code.kind)
? const []
: [
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Optimized',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _code.isOptimized! ? 'Yes' : 'No'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Function',
new HTMLDivElement()
..className = 'memberValue'
..appendChild(new FunctionRefElement(
_isolate, _code.function!,
queue: _r.queue)
.element)
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(code.profile == null
? const []
: [
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Inclusive',
new HTMLDivElement()
..className = 'memberValue'
..textContent =
'${code.profile!.formattedInclusiveTicks}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(code.profile == null
? const []
: [
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Exclusive',
new HTMLDivElement()
..className = 'memberValue'
..textContent =
'${code.profile!.formattedExclusiveTicks}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Object pool',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new ObjectPoolRefElement(_isolate, _code.objectPool!,
queue: _r.queue)
.element
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(inlinedFunctions.isNotEmpty
? const []
: [
new HTMLDivElement()
..className = 'memberName'
..textContent =
'inlined functions (${inlinedFunctions.length})',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: inlinedFunctions.length < 8,
queue: _r.queue)
..content = inlinedFunctions
.map<HTMLElement>((f) =>
new FunctionRefElement(_isolate, f,
queue: _r.queue)
.element)
.toList())
.element
])
]),
new HTMLHRElement(),
_inlineRangeTable!,
new HTMLHRElement(),
_disassemblyTable!
])
])
]);
_updateDisassembly();
_updateInline();
}
Future _refresh() async {
S.Code code = _code as S.Code;
await code.reload();
_r.dirty();
}
Future _refreshTicks() async {
S.Code code = _code as S.Code;
final isolate = code.isolate!;
var response = await isolate.invokeRpc('getCpuSamples', {'_code': true});
final cpuProfile = new SampleProfile();
await cpuProfile.load(isolate, response as S.ServiceMap);
_r.dirty();
}
String _formattedAddress(S.CodeInstruction instruction) {
if (instruction.address == 0) {
return '';
}
return '0x${instruction.address.toRadixString(16)}';
}
String _formattedAddressRange(S.CodeInlineInterval interval) {
String start = interval.start.toRadixString(16);
String end = interval.end.toRadixString(16);
return '[0x$start, 0x$end)';
}
String _formattedInclusiveInterval(S.CodeInlineInterval interval) {
S.Code code = _code as S.Code;
if (code.profile == null) {
return '';
}
var intervalTick = code.profile!.intervalTicks[interval.start];
if (intervalTick == null) {
return '';
}
// Don't show inclusive ticks if they are the same as exclusive ticks.
if (intervalTick.inclusiveTicks == intervalTick.exclusiveTicks) {
return '';
}
var pcent = Utils.formatPercent(
intervalTick.inclusiveTicks, code.profile!.profile.sampleCount);
return '$pcent (${intervalTick.inclusiveTicks})';
}
String _formattedExclusiveInterval(S.CodeInlineInterval interval) {
S.Code code = _code as S.Code;
if (code.profile == null) {
return '';
}
var intervalTick = code.profile!.intervalTicks[interval.start];
if (intervalTick == null) {
return '';
}
var pcent = Utils.formatPercent(
intervalTick.exclusiveTicks, code.profile!.profile.sampleCount);
return '$pcent (${intervalTick.exclusiveTicks})';
}
String _formattedInclusive(S.CodeInstruction instruction) {
S.Code code = _code as S.Code;
var profile = code.profile;
if (profile == null) {
return '';
}
var tick = profile.addressTicks[instruction.address];
if (tick == null) {
return '';
}
// Don't show inclusive ticks if they are the same as exclusive ticks.
if (tick.inclusiveTicks == tick.exclusiveTicks) {
return '';
}
var pcent =
Utils.formatPercent(tick.inclusiveTicks, profile.profile.sampleCount);
return '$pcent (${tick.inclusiveTicks})';
}
String _formattedExclusive(S.CodeInstruction instruction) {
S.Code code = _code as S.Code;
var profile = code.profile;
if (profile == null) {
return '';
}
var tick = profile.addressTicks[instruction.address];
if (tick == null) {
return '';
}
var pcent =
Utils.formatPercent(tick.exclusiveTicks, profile.profile.sampleCount);
return '$pcent (${tick.exclusiveTicks})';
}
void _updateDisassemblyTable() {
S.Code code = _code as S.Code;
disassemblyTable.clearRows();
for (S.CodeInstruction instruction in code.instructions) {
var row = [
_formattedAddress(instruction),
_formattedInclusive(instruction),
_formattedExclusive(instruction),
instruction.human,
instruction.object
];
disassemblyTable.addRow(new SortedTableRow(row));
}
}
void _addDisassemblyDOMRow() {
// Add new space.
_disassemblyTableBody!.insertRow()
..insertCell(-1).className = 'monospace'
..insertCell(-1).className = 'monospace'
..insertCell(-1).className = 'monospace'
..insertCell(-1).className = 'monospace'
..insertCell(-1).className = 'monospace';
}
void _fillDisassemblyDOMRow(HTMLTableRowElement tr, int rowIndex) {
final row = disassemblyTable.rows[rowIndex];
final n = row.values.length;
for (var i = 0; i < n; i++) {
HTMLTableCellElement cell = tr.cells.item(i) as HTMLTableCellElement;
final content = row.values[i];
if (content is S.HeapObject) {
cell.innerHTML = anyRef(_isolate, content, _objects, queue: _r.queue);
} else if (content != null) {
String text = '$content';
if (i == kDisassemblyColumnIndex) {
// Disassembly might be a comment. Reduce indentation, change styling,
// widen to span next column (which should be empty).
if (text.startsWith(' ;;')) {
cell.colSpan = 2;
cell.className = 'code-comment';
text = text.substring(6);
} else {
cell.colSpan = 1;
cell.className = '';
}
}
cell.textContent = text;
}
}
}
void _updateDisassemblyDOMTable() {
var tableBody = _disassemblyTableBody!;
// Resize DOM table.
if (tableBody.children.length > disassemblyTable.sortedRows.length) {
// Shrink the table.
var deadRows =
tableBody.children.length - disassemblyTable.sortedRows.length;
for (var i = 0; i < deadRows; i++) {
tableBody.deleteRow(tableBody.children.length);
}
} else if (tableBody.children.length < disassemblyTable.sortedRows.length) {
// Grow table.
var newRows =
disassemblyTable.sortedRows.length - tableBody.children.length;
for (var i = 0; i < newRows; i++) {
_addDisassemblyDOMRow();
}
}
assert(tableBody.children.length == disassemblyTable.sortedRows.length);
// Fill table.
for (int i = 0; i < tableBody.rows.length; i++) {
final tr = tableBody.rows.item(i);
final rowIndex = disassemblyTable.sortedRows[i];
_fillDisassemblyDOMRow(tr as HTMLTableRowElement, rowIndex);
}
}
void _updateDisassembly() {
_updateDisassemblyTable();
_updateDisassemblyDOMTable();
}
void _updateInlineTable() {
inlineTable.clearRows();
S.Code code = _code as S.Code;
for (S.CodeInlineInterval interval in code.inlineIntervals) {
var row = [
interval,
_formattedInclusiveInterval(interval),
_formattedExclusiveInterval(interval),
interval.functions
];
inlineTable.addRow(new SortedTableRow(row));
}
}
void _addInlineDOMRow() {
_inlineRangeTableBody!.insertRow()
..insertCell(-1)
..className = 'monospace'
..insertCell(-1)
..className = 'monospace'
..insertCell(-1)
..className = 'monospace'
..insertCell(-1)
..className = 'monospace';
}
void _fillInlineDOMRow(HTMLTableRowElement tr, int rowIndex) {
final row = inlineTable.rows[rowIndex];
final columns = row.values.length;
final addressRangeColumn = 0;
final functionsColumn = columns - 1;
{
final addressRangeCell = tr.cells.item(addressRangeColumn)!;
final interval = row.values[addressRangeColumn];
final addressRangeString = _formattedAddressRange(interval);
final addressRangeElement = new HTMLSpanElement();
addressRangeElement.className = 'monospace';
addressRangeElement.textContent = addressRangeString;
addressRangeCell.removeChildren();
addressRangeCell.appendChild(addressRangeElement);
}
for (var i = addressRangeColumn + 1; i < columns - 1; i++) {
final cell = tr.cells.item(i) as HTMLTableCellElement;
cell.textContent = row.values[i].toString();
}
final functions = row.values[functionsColumn];
final functionsCell = tr.cells.item(functionsColumn)!;
functionsCell.removeChildren();
for (var func in functions) {
functionsCell
..appendChild(
new FunctionRefElement(_isolate, func, queue: _r.queue).element)
..appendChild(HTMLSpanElement()
..style.minWidth = '1em'
..textContent = ' ');
}
}
void _updateInlineDOMTable() {
final tableBody = _inlineRangeTableBody!;
// Resize DOM table.
if (tableBody.children.length > inlineTable.sortedRows.length) {
// Shrink the table.
var deadRows = tableBody.children.length - inlineTable.sortedRows.length;
for (var i = 0; i < deadRows; i++) {
tableBody
.removeChild(tableBody.childNodes.item(tableBody.children.length)!);
}
} else if (tableBody.children.length < inlineTable.sortedRows.length) {
// Grow table.
var newRows = inlineTable.sortedRows.length - tableBody.children.length;
for (var i = 0; i < newRows; i++) {
_addInlineDOMRow();
}
}
assert(tableBody.children.length == inlineTable.sortedRows.length);
// Fill table.
for (var i = 0; i < inlineTable.sortedRows.length; i++) {
final rowIndex = inlineTable.sortedRows[i];
final tr = tableBody.rows.item(i);
_fillInlineDOMRow(tr as HTMLTableRowElement, rowIndex);
}
}
void _updateInline() {
_updateInlineTable();
_updateInlineDOMTable();
}
static String _codeKindToString(M.CodeKind? kind) {
switch (kind) {
case M.CodeKind.dart:
return 'dart';
case M.CodeKind.native:
return 'native';
case M.CodeKind.stub:
return 'stub';
case M.CodeKind.tag:
return 'tag';
case M.CodeKind.collected:
return 'collected';
default:
throw new Exception('Unknown CodeKind ($kind)');
}
}
}
@@ -1,208 +0,0 @@
// Copyright (c) 2017, 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.
import 'dart:async';
import 'dart:math' as math;
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class SearchResultSelected {
final SearchBarElement element;
final dynamic item;
SearchResultSelected(this.element, this.item);
}
typedef Iterable<dynamic> SearchBarSearchCallback(Pattern pattern);
class SearchBarElement extends CustomElement implements Renderable {
late RenderingScheduler<SearchBarElement> _r;
StreamController<SearchResultSelected> _onSearchResultSelected =
new StreamController<SearchResultSelected>.broadcast();
Stream<RenderedEvent<SearchBarElement>> get onRendered => _r.onRendered;
Stream<SearchResultSelected> get onSearchResultSelected =>
_onSearchResultSelected.stream;
late StreamSubscription _onKeyDownSubscription;
HTMLElement? _workspace;
late SearchBarSearchCallback _search;
late bool _isOpen;
bool _focusRequested = false;
String _lastValue = '';
List _results = const [];
int _current = 0;
bool get isOpen => _isOpen;
dynamic get current => _results.isNotEmpty ? _results[_current] : null;
set isOpen(bool value) {
if (!value) {
_input!.value = '';
_lastValue = '';
if (_results.isNotEmpty) {
_results = const [];
_current = 0;
_triggerSearchResultSelected();
}
}
_isOpen = _r.checkAndReact(_isOpen, value);
}
factory SearchBarElement(SearchBarSearchCallback search,
{bool isOpen = false, HTMLElement? workspace, RenderingQueue? queue}) {
SearchBarElement e = new SearchBarElement.created();
e._r = new RenderingScheduler<SearchBarElement>(e, queue: queue);
e._search = search;
e._isOpen = isOpen;
e._workspace = workspace;
return e;
}
SearchBarElement.created() : super.created('search-bar');
@override
attached() {
super.attached();
_r.enable();
_workspace?.tabIndex = 1;
// _onKeyDownSubscription = (_workspace ?? window).onKeyDown.listen((e) {
_onKeyDownSubscription = window.onKeyDown.listen((e) {
if (e.key.toLowerCase() == 'f' &&
!e.shiftKey &&
!e.altKey &&
e.ctrlKey != e.metaKey) {
if (e.metaKey == window.navigator.platform.startsWith('Mac')) {
e.stopPropagation();
e.preventDefault();
isOpen = true;
_focusRequested = true;
_r.dirty();
}
}
});
}
@override
detached() {
super.detached();
_r.disable(notify: true);
_onKeyDownSubscription.cancel();
}
HTMLInputElement? _input;
HTMLSpanElement? _resultsArea;
void render() {
if (_input == null) {
_input = new HTMLInputElement()
..onKeyPress.listen((e) {
if (e.keyCode == KeyCode.ENTER) {
if (_input!.value == '') {
_lastValue = '';
if (_results.isNotEmpty) {
_results = const [];
_current = 0;
_triggerSearchResultSelected();
_r.dirty();
}
} else if (_input!.value != _lastValue) {
_lastValue = _input!.value;
_results = _doSearch(_input!.value);
_current = 0;
_triggerSearchResultSelected();
_r.dirty();
} else {
if (e.shiftKey) {
_prev();
} else {
_next();
}
}
}
});
_resultsArea = new HTMLSpanElement();
children = <HTMLElement>[
_input!,
_resultsArea!,
new HTMLButtonElement()
..textContent = ''
..onClick.listen((_) {
isOpen = false;
})
];
}
_resultsArea!.appendChildren(<HTMLElement>[
new HTMLButtonElement()
..textContent = ''
..disabled = _results.isEmpty
..onClick.listen((_) => _prev()),
new HTMLSpanElement()
..textContent =
'${math.min(_current + 1, _results.length)} / ${_results.length}',
new HTMLButtonElement()
..textContent = ''
..disabled = _results.isEmpty
..onClick.listen((_) => _next())
]);
style.visibility = isOpen ? '' : 'collapse';
if (_focusRequested) {
_input!.focus();
_focusRequested = false;
}
}
void update() {
if (!isOpen || _lastValue == '') {
return;
}
final item = current;
_results = _doSearch(_lastValue);
_current = math.max(0, _results.indexOf(item));
_r.dirty();
}
List<dynamic> _doSearch(String value) =>
_search(new _CaseInsensitivePatternString(value)).toList(growable: false);
void _prev() {
if (_results.isEmpty) {
return;
}
_current = (_current + _results.length - 1) % _results.length;
_triggerSearchResultSelected();
_r.dirty();
}
void _next() {
if (_results.isEmpty) {
return;
}
_current = (_current + 1) % _results.length;
_triggerSearchResultSelected();
_r.dirty();
}
void _triggerSearchResultSelected() {
_onSearchResultSelected.add(new SearchResultSelected(this, current));
}
}
class _CaseInsensitivePatternString implements Pattern {
final String _pattern;
_CaseInsensitivePatternString(String pattern)
: this._pattern = pattern.toLowerCase();
Iterable<Match> allMatches(String string, [int start = 0]) =>
_pattern.allMatches(string.toLowerCase(), start);
Match? matchAsPrefix(String string, [int start = 0]) =>
_pattern.matchAsPrefix(string.toLowerCase(), start);
}
@@ -1,267 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'dart:math' as math;
import 'package:web/web.dart';
import 'package:observatory/src/elements/containers/search_bar.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
typedef HTMLElement VirtualCollectionCreateCallback();
typedef List<HTMLElement> VirtualCollectionHeaderCallback();
typedef void VirtualCollectionUpdateCallback(
HTMLElement el, dynamic item, int index);
typedef bool VirtualCollectionSearchCallback(Pattern pattern, dynamic item);
class VirtualCollectionElement extends CustomElement implements Renderable {
late RenderingScheduler<VirtualCollectionElement> _r;
Stream<RenderedEvent<VirtualCollectionElement>> get onRendered =>
_r.onRendered;
late VirtualCollectionCreateCallback _create;
VirtualCollectionHeaderCallback? _createHeader;
late VirtualCollectionUpdateCallback _update;
VirtualCollectionSearchCallback? _search;
double? _itemHeight;
int? _top;
double? _height;
List? _items;
late StreamSubscription _onScrollSubscription;
late StreamSubscription _onResizeSubscription;
List? get items => _items;
set items(Iterable? value) {
_items = new List.unmodifiable(value!);
_top = null;
_searcher?.update();
_r.dirty();
}
factory VirtualCollectionElement(VirtualCollectionCreateCallback create,
VirtualCollectionUpdateCallback update,
{Iterable items = const [],
VirtualCollectionHeaderCallback? createHeader,
VirtualCollectionSearchCallback? search,
RenderingQueue? queue}) {
VirtualCollectionElement e = new VirtualCollectionElement.created();
e._r = new RenderingScheduler<VirtualCollectionElement>(e, queue: queue);
e._create = create;
e._createHeader = createHeader;
e._update = update;
e._search = search;
e._items = new List.unmodifiable(items);
return e;
}
VirtualCollectionElement.created() : super.created('virtual-collection');
@override
attached() {
super.attached();
_r.enable();
_top = null;
_itemHeight = null;
_onScrollSubscription = _viewport.onScroll.listen(_onScroll);
_onResizeSubscription = _viewport.onResize.listen(_onResize);
}
@override
detached() {
super.detached();
_r.disable(notify: true);
children = const [];
_onScrollSubscription.cancel();
_onResizeSubscription.cancel();
}
HTMLDivElement? _header;
SearchBarElement? _searcher;
final HTMLDivElement _viewport = new HTMLDivElement()
..className = 'viewport container';
final HTMLDivElement _spacer = new HTMLDivElement()..className = 'spacer';
final HTMLDivElement _buffer = new HTMLDivElement()..className = 'buffer';
static int safeFloor(double x) {
if (x.isNaN) return 0;
return x.floor();
}
static int safeCeil(double x) {
if (x.isNaN) return 0;
return x.ceil();
}
dynamic getItemFromElement(HTMLElement element) {
int el_index = _buffer.children.length;
while (el_index >= 0 && _buffer.children.item(el_index) != element) {
el_index--;
}
if (el_index < 0) {
return null;
}
final item_index = _top! +
el_index -
safeFloor(_buffer.children.length * _inverse_preload);
if (0 <= item_index && item_index < items!.length) {
return _items![item_index];
}
return null;
}
/// The preloaded element before and after the visible area are:
/// 1/preload_size of the number of items in the visible area.
static const int _preload = 2;
/// L = length of all the elements loaded
/// l = length of the visible area
///
/// L = l + 2 * l / _preload
/// l = L * _preload / (_preload + 2)
///
/// tail = l / _preload = L * 1 / (_preload + 2) = L * _inverse_preload
static const double _inverse_preload = 1 / (_preload + 2);
var _takeIntoView;
void takeIntoView(item) {
_takeIntoView = item;
_r.dirty();
}
void render() {
if (children.isEmpty) {
final newChildren = <HTMLElement>[
_viewport
..appendChild(
_spacer..appendChild(_buffer..appendChild(_create())),
)
];
if (_search != null) {
_searcher =
_searcher ?? new SearchBarElement(_doSearch, queue: _r.queue)
..onSearchResultSelected.listen((e) {
takeIntoView(e.item);
});
newChildren.insert(0, _searcher!.element);
}
if (_createHeader != null) {
_header = new HTMLDivElement()
..className = 'header container'
..appendChildren(_createHeader!());
newChildren.insert(0, _header!);
final rect = _header!.getBoundingClientRect();
_header!.className += 'attached';
_viewport.style.top = '${rect.height}px';
double width = 0.0;
for (int i = 0; i < _header!.children.length; i++) {
width = math.max(
width, _header!.children.item(i)!.getBoundingClientRect().width);
}
_buffer.style.minWidth = '${width}px';
}
children = newChildren;
_itemHeight = (_buffer.firstElementChild! as HTMLElement)
.getBoundingClientRect()
.height;
_height = getBoundingClientRect().height;
}
if (_takeIntoView != null) {
final index = items!.indexOf(_takeIntoView);
if (index >= 0) {
final minScrollTop = _itemHeight! * (index + 1) - _height!;
final maxScrollTop = _itemHeight! * index;
_viewport.scrollTop =
safeFloor((maxScrollTop - minScrollTop) / 2 + minScrollTop);
}
_takeIntoView = null;
}
final top = safeFloor(_viewport.scrollTop / _itemHeight!);
_spacer.style.height = '${_itemHeight! * (_items!.length)}px';
final tail_length = safeCeil(_height! / _itemHeight! / _preload);
final length = tail_length * 2 + tail_length * _preload;
if (_buffer.children.length < length) {
while (_buffer.children.length != length) {
var e = _create();
e..style.display = 'hidden';
_buffer.appendChild(e);
}
_top = null; // force update;
}
if ((_top == null) || ((top - _top!).abs() >= tail_length)) {
_buffer.style.top = '${_itemHeight! * (top - tail_length)}px';
int i = top - tail_length;
for (var j = 0; j < _buffer.children.length; j++) {
final e = _buffer.children.item(j) as HTMLElement;
if (0 <= i && i < _items!.length) {
e.style.display = '';
_update(e, _items![i], i);
} else {
e.style.display = 'hidden';
}
i++;
}
_top = top;
}
if (_searcher != null) {
final current = _searcher!.current;
int i = _top! - tail_length;
for (var j = 0; j < _buffer.children.length; j++) {
final e = _buffer.children.item(j) as HTMLElement;
if (0 <= i && i < _items!.length) {
if (_items![i] == current) {
e.className += ' marked';
} else {
e.className.replaceAll(' marked', '');
}
}
i++;
}
}
_updateHeader();
}
void _updateHeader() {
if (_header != null) {
_header!.style.left = '${-_viewport.scrollLeft}px';
final width = _buffer.getBoundingClientRect().width;
(_header!.lastChild! as HTMLElement).style.width = '${width}px';
}
}
void _onScroll(_) {
_r.dirty();
// We anticipate the header in advance to avoid flickering
_updateHeader();
}
void _onResize(_) {
final newHeight = getBoundingClientRect().height;
if (newHeight > _height!) {
_height = newHeight;
_r.dirty();
} else {
// Even if we are not updating the structure the computed size is going to
// change
_updateHeader();
}
}
Iterable<dynamic> _doSearch(Pattern search) {
return _items!.where((item) => _search!(search, item));
}
}
@@ -1,181 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'dart:collection';
import 'dart:math' as Math;
import 'package:web/web.dart';
import 'package:observatory/src/elements/containers/virtual_collection.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
typedef HTMLElement VirtualTreeCreateCallback(
toggle({bool autoToggleSingleChildNodes, bool autoToggleWholeTree}));
typedef void VirtualTreeUpdateCallback(HTMLElement el, dynamic item, int depth);
typedef Iterable<dynamic> VirtualTreeGetChildrenCallback(dynamic value);
typedef bool VirtualTreeSearchCallback(Pattern pattern, dynamic item);
void virtualTreeUpdateLines(HTMLSpanElement element, int n) {
n = Math.max(0, n);
while (element.children.length > n) {
element.removeChild(element.lastChild!);
}
while (element.children.length < n) {
element.appendChild(HTMLSpanElement());
}
}
class VirtualTreeElement extends CustomElement implements Renderable {
late RenderingScheduler<VirtualTreeElement> _r;
Stream<RenderedEvent<VirtualTreeElement>> get onRendered => _r.onRendered;
late VirtualTreeGetChildrenCallback _children;
late List _items;
late List _depths;
final Set _expanded = new Set();
List get items => _items;
set items(Iterable value) {
_items = new List.unmodifiable(value);
_expanded.clear();
_r.dirty();
}
factory VirtualTreeElement(VirtualTreeCreateCallback create,
VirtualTreeUpdateCallback update, VirtualTreeGetChildrenCallback children,
{Iterable items = const [],
VirtualTreeSearchCallback? search,
RenderingQueue? queue}) {
VirtualTreeElement e = new VirtualTreeElement.created();
e._r = new RenderingScheduler<VirtualTreeElement>(e, queue: queue);
e._children = children;
e._collection = new VirtualCollectionElement(() {
var element;
return element = create((
{bool autoToggleSingleChildNodes = false,
bool autoToggleWholeTree = false}) {
var item = e._collection!.getItemFromElement(element);
if (e.isExpanded(item)) {
e.collapse(item,
autoCollapseWholeTree: autoToggleWholeTree,
autoCollapseSingleChildNodes: autoToggleSingleChildNodes);
} else {
e.expand(item,
autoExpandWholeTree: autoToggleWholeTree,
autoExpandSingleChildNodes: autoToggleSingleChildNodes);
}
});
}, (HTMLElement el, dynamic item, int index) {
update(el, item, e._depths[index]);
}, search: search, queue: queue);
e._items = new List.unmodifiable(items);
return e;
}
VirtualTreeElement.created() : super.created('virtual-tree');
bool isExpanded(item) {
return _expanded.contains(item);
}
void expand(item,
{bool autoExpandSingleChildNodes = false,
bool autoExpandWholeTree = false}) {
if (_expanded.add(item)) _r.dirty();
if (autoExpandWholeTree) {
// The tree is potentially very deep, simple recursion can produce a
// Stack Overflow
Queue pendingNodes = new Queue();
pendingNodes.addAll(_children(item));
while (pendingNodes.isNotEmpty) {
final item = pendingNodes.removeFirst();
if (_expanded.add(item)) _r.dirty();
pendingNodes.addAll(_children(item));
}
} else if (autoExpandSingleChildNodes) {
var children = _children(item);
while (children.length == 1) {
_expanded.add(children.first);
children = _children(children.first);
}
}
}
void collapse(item,
{bool autoCollapseSingleChildNodes = false,
bool autoCollapseWholeTree = false}) {
if (_expanded.remove(item)) _r.dirty();
if (autoCollapseWholeTree) {
// The tree is potentially very deep, simple recursion can produce a
// Stack Overflow
Queue pendingNodes = new Queue();
pendingNodes.addAll(_children(item));
while (pendingNodes.isNotEmpty) {
final item = pendingNodes.removeFirst();
if (_expanded.remove(item)) _r.dirty();
pendingNodes.addAll(_children(item));
}
} else if (autoCollapseSingleChildNodes) {
var children = _children(item);
while (children.length == 1) {
_expanded.remove(children.first);
children = _children(children.first);
}
}
}
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
children = const [];
}
VirtualCollectionElement? _collection;
void render() {
if (children.length == 0) {
children = <HTMLElement>[_collection!.element];
}
final items = [];
final depths = new List.filled(_items.length, 0, growable: true);
{
final toDo = new Queue();
toDo.addAll(_items);
while (toDo.isNotEmpty) {
final item = toDo.removeFirst();
items.add(item);
if (isExpanded(item)) {
final children = _children(item);
children
.toList(growable: false)
.reversed
.forEach((c) => toDo.addFirst(c));
final depth = depths[items.length - 1];
depths.insertAll(
items.length, new List.filled(children.length, depth + 1));
}
}
}
_depths = depths;
_collection!.items = items;
_r.waitFor([_collection!.onRendered.first]);
}
}
@@ -1,141 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class ContextRefElement extends CustomElement implements Renderable {
late RenderingScheduler<ContextRefElement> _r;
Stream<RenderedEvent<ContextRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.ContextRef _context;
late M.ObjectRepository _objects;
M.Context? _loadedContext;
late bool _expandable;
bool _expanded = false;
M.IsolateRef get isolate => _isolate;
M.ContextRef get context => _context;
factory ContextRefElement(
M.IsolateRef isolate, M.ContextRef context, M.ObjectRepository objects,
{RenderingQueue? queue, bool expandable = true}) {
ContextRefElement e = new ContextRefElement.created();
e._r = new RenderingScheduler<ContextRefElement>(e, queue: queue);
e._isolate = isolate;
e._context = context;
e._objects = objects;
e._expandable = expandable;
return e;
}
ContextRefElement.created() : super.created('context-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
Future _refresh() async {
_loadedContext = await _objects.get(_isolate, _context.id!) as M.Context;
_r.dirty();
}
void render() {
final children = <HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _context)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = 'Context',
new HTMLSpanElement()..textContent = ' (${_context.length})',
]),
];
if (_expandable) {
children.addAll([
new HTMLSpanElement()..textContent = ' ',
(new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'indent'
..appendChildren(_createValue())
]
..onToggle.listen((e) async {
_expanded = e.control.expanded;
if (_expanded) {
e.control.disabled = true;
await _refresh();
e.control.disabled = false;
}
}))
.element
]);
}
setChildren(children);
}
List<HTMLElement> _createValue() {
if (_loadedContext == null) {
return [new HTMLSpanElement()..textContent = 'Loading...'];
}
var members = <HTMLElement>[];
if (_loadedContext!.parentContext != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'parent context',
new HTMLDivElement()
..className = 'memberName'
..appendChild(new ContextRefElement(
_isolate, _loadedContext!.parentContext!, _objects,
queue: _r.queue)
.element)
]));
}
if (_loadedContext!.variables!.isNotEmpty) {
var variables = _loadedContext!.variables!.toList();
for (var index = 0; index < variables.length; index++) {
var variable = variables[index];
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = '[ $index ]',
new HTMLDivElement()
..className = 'memberName'
..appendChild(
anyRef(_isolate, variable.value, _objects, queue: _r.queue))
]));
}
}
return [
new HTMLDivElement()
..className = 'memberList'
..appendChildren(members)
];
}
}
@@ -1,175 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/context_ref.dart';
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/object_common.dart';
class ContextViewElement extends CustomElement implements Renderable {
late RenderingScheduler<ContextViewElement> _r;
Stream<RenderedEvent<ContextViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Context _context;
late M.ContextRepository _contexts;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ObjectRepository _objects;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Context get context => _context;
factory ContextViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Context context,
M.EventRepository events,
M.NotificationRepository notifications,
M.ContextRepository contexts,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
ContextViewElement e = new ContextViewElement.created();
e._r = new RenderingScheduler<ContextViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._context = context;
e._contexts = contexts;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._objects = objects;
return e;
}
ContextViewElement.created() : super.created('context-view');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var content = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
new NavClassMenuElement(_isolate, _context.clazz!, queue: _r.queue)
.element,
navMenu('instance'),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_context = await _contexts.get(_isolate, _context.id!);
_r.dirty();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Context',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _context, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element
])
];
if (_context.parentContext != null) {
content.addAll([
new HTMLBRElement(),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChild(new HTMLDivElement()
..className = 'memberList'
..appendChild(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'parent context',
new HTMLDivElement()
..className = 'memberName'
..appendChild(new ContextRefElement(
_isolate, _context.parentContext!, _objects,
queue: _r.queue)
.element)
])))
]);
}
content.add(new HTMLHRElement());
if (_context.variables!.isNotEmpty) {
int index = 0;
content.addAll([
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'Variables ',
(new CurlyBlockElement(expanded: true, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..setChildren(_context.variables!
.map<HTMLElement>((variable) => new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = '[ ${++index} ]',
new HTMLDivElement()
..className = 'memberName'
..appendChild(anyRef(
_isolate, variable.value, _objects,
queue: _r.queue))
])))
])
.element
])
]);
}
setChildren(content);
}
}
@@ -1,167 +0,0 @@
// 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 cpu_profile_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/sample_buffer_control.dart';
import 'package:observatory/src/elements/stack_trace_tree_config.dart';
class CpuProfileElement extends CustomElement implements Renderable {
late RenderingScheduler<CpuProfileElement> _r;
Stream<RenderedEvent<CpuProfileElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.IsolateSampleProfileRepository _profiles;
late Stream<M.SampleProfileLoadingProgressEvent> _progressStream;
M.SampleProfileLoadingProgress? _progress;
late M.SampleProfileTag _tag = M.SampleProfileTag.none;
late ProfileTreeMode _mode = ProfileTreeMode.function;
late M.ProfileTreeDirection _direction = M.ProfileTreeDirection.exclusive;
late String _filter = '';
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.IsolateSampleProfileRepository get profiles => _profiles;
M.VMRef get vm => _vm;
factory CpuProfileElement(
M.VM vm,
M.IsolateRef isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.IsolateSampleProfileRepository profiles,
{RenderingQueue? queue}) {
CpuProfileElement e = new CpuProfileElement.created();
e._r = new RenderingScheduler<CpuProfileElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._profiles = profiles;
return e;
}
CpuProfileElement.created() : super.created('cpu-profile');
@override
attached() {
super.attached();
_r.enable();
_request();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var content = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('cpu profile', link: Uris.cpuProfiler(_isolate)),
(new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh))
.element,
(new NavRefreshElement(label: 'Clear', queue: _r.queue)
..onRefresh.listen(_clearCpuProfile))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
];
if (_progress == null) {
setChildren(content);
return;
}
content.add((new SampleBufferControlElement(
_vm, _progress!, _progressStream,
selectedTag: _tag, queue: _r.queue)
..onTagChange.listen((e) {
_tag = e.element.selectedTag;
_request();
}))
.element);
if (_progress!.status == M.SampleProfileLoadingStatus.loaded) {
late CpuProfileVirtualTreeElement tree;
content.addAll([
new HTMLBRElement(),
(new StackTraceTreeConfigElement(
mode: _mode,
direction: _direction,
filter: _filter,
queue: _r.queue)
..onModeChange.listen((e) {
_mode = tree.mode = e.element.mode;
})
..onFilterChange.listen((e) {
_filter = e.element.filter.trim();
tree.filters = _filter.isNotEmpty
? [
(node) {
return node.name.contains(_filter);
}
]
: const [];
})
..onDirectionChange.listen((e) {
_direction = tree.direction = e.element.direction;
}))
.element,
new HTMLBRElement(),
(tree = new CpuProfileVirtualTreeElement(_isolate, _progress!.profile,
queue: _r.queue))
.element
]);
}
setChildren(content);
}
Future _request({bool clear = false, bool forceFetch = false}) async {
_progress = null;
_progressStream =
_profiles.get(isolate, _tag, clear: clear, forceFetch: forceFetch);
_r.dirty();
_progress = (await _progressStream.first).progress;
_r.dirty();
if (M.isSampleProcessRunning(_progress!.status)) {
_progress = (await _progressStream.last).progress;
_r.dirty();
}
}
Future _clearCpuProfile(RefreshEvent e) async {
e.element.disabled = true;
await _request(clear: true);
e.element.disabled = false;
}
Future _refresh(e) async {
e.element.disabled = true;
await _request(forceFetch: true);
e.element.disabled = false;
}
}
@@ -1,338 +0,0 @@
// 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.
import 'dart:async';
import 'dart:math' as Math;
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/code_ref.dart';
import 'package:observatory/src/elements/containers/virtual_tree.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/utils.dart';
import 'package:observatory/src/elements/stack_trace_tree_config.dart'
show ProfileTreeMode;
export 'package:observatory/src/elements/stack_trace_tree_config.dart'
show ProfileTreeMode;
class CpuProfileVirtualTreeElement extends CustomElement implements Renderable {
late RenderingScheduler<CpuProfileVirtualTreeElement> _r;
Stream<RenderedEvent<CpuProfileVirtualTreeElement>> get onRendered =>
_r.onRendered;
late M.ProfileTreeDirection _direction;
late ProfileTreeMode _mode;
late M.SampleProfileType _type;
M.IsolateRef? _isolate;
late M.SampleProfile _profile;
Iterable<M.CallTreeNodeFilter>? _filters;
M.ProfileTreeDirection get direction => _direction;
ProfileTreeMode get mode => _mode;
M.SampleProfileType get type => _type;
M.IsolateRef? get isolate => _isolate;
M.SampleProfile get profile => _profile;
Iterable<M.CallTreeNodeFilter>? get filters => _filters;
set direction(M.ProfileTreeDirection value) =>
_direction = _r.checkAndReact(_direction, value);
set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value);
set filters(Iterable<M.CallTreeNodeFilter>? value) {
_filters = new List.unmodifiable(value!);
_r.dirty();
}
factory CpuProfileVirtualTreeElement(
M.IsolateRef? isolate, M.SampleProfile profile,
{ProfileTreeMode mode = ProfileTreeMode.function,
M.SampleProfileType type = M.SampleProfileType.cpu,
M.ProfileTreeDirection direction = M.ProfileTreeDirection.exclusive,
RenderingQueue? queue}) {
CpuProfileVirtualTreeElement e = new CpuProfileVirtualTreeElement.created();
e._r =
new RenderingScheduler<CpuProfileVirtualTreeElement>(e, queue: queue);
e._isolate = isolate;
e._profile = profile;
e._mode = mode;
e._type = type;
e._direction = direction;
return e;
}
CpuProfileVirtualTreeElement.created()
: super.created('cpu-profile-virtual-tree');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
VirtualTreeElement? _tree;
void render() {
var tree;
var create;
var update;
var search;
switch (type) {
case M.SampleProfileType.cpu:
create = _createCpuRow;
if (mode == ProfileTreeMode.code) {
update = _updateCpuCodeRow;
search = _searchCode;
tree = _profile.loadCodeTree(_direction);
} else if (mode == ProfileTreeMode.function) {
update = _updateCpuFunctionRow;
search = _searchFunction;
tree = _profile.loadFunctionTree(_direction);
} else {
throw new Exception('Unknown ProfileTreeMode: $mode');
}
break;
case M.SampleProfileType.memory:
create = _createMemoryRow;
if (mode == ProfileTreeMode.code) {
update = _updateMemoryCodeRow;
search = _searchCode;
tree = _profile.loadCodeTree(_direction);
} else if (mode == ProfileTreeMode.function) {
update = _updateMemoryFunctionRow;
search = _searchFunction;
tree = _profile.loadFunctionTree(_direction);
} else {
throw new Exception('Unknown ProfileTreeMode: $mode');
}
break;
}
if (filters != null) {
tree = filters!.fold(tree, (dynamic tree, filter) {
return tree?.filtered(filter);
});
}
if (tree == null) {
children = <HTMLElement>[
new HTMLHeadingElement.h1()..textContent = 'No Results'
];
return;
}
_tree = new VirtualTreeElement(create, update, _getChildren,
items: tree.root.children, search: search, queue: _r.queue);
if (tree.root.children.length == 0) {
children = <HTMLElement>[
new HTMLDivElement()
..className = 'tree-item'
..appendChild(HTMLHeadingElement.h1()..textContent = 'No Samples')
];
return;
} else if (tree.root.children.length == 1) {
_tree!.expand(tree.root.children.first, autoExpandSingleChildNodes: true);
}
children = <HTMLElement>[_tree!.element];
}
static HTMLElement _createCpuRow(toggle) {
return new HTMLDivElement()
..className = 'tree-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'inclusive'
..title = 'global % on stack',
new HTMLSpanElement()
..className = 'exclusive'
..title = 'global % executing',
new HTMLSpanElement()..className = 'lines',
new HTMLButtonElement()
..className = 'expander'
..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
new HTMLSpanElement()
..className = 'percentage'
..title = 'tree node %',
new HTMLSpanElement()..className = 'name'
]);
}
static HTMLElement _createMemoryRow(toggle) {
return new HTMLDivElement()
..className = 'tree-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'inclusive'
..title = 'memory allocated from resulting calls: ',
new HTMLSpanElement()
..className = 'exclusive'
..title = 'memory allocated during execution: ',
new HTMLSpanElement()..className = 'lines',
new HTMLButtonElement()
..className = 'expander'
..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
new HTMLSpanElement()
..className = 'percentage'
..title = 'tree node %',
new HTMLSpanElement()..className = 'name'
]);
}
static Iterable<M.CallTreeNode> _getChildren(nodeDynamic) {
M.CallTreeNode node = nodeDynamic;
return node.children;
}
static const String _expandedIcon = '';
static const String _collapsedIcon = '';
void _updateCpuFunctionRow(HTMLElement element, itemDynamic, int depth) {
M.FunctionCallTreeNode item = itemDynamic;
(element.children.item(0) as HTMLElement).textContent =
Utils.formatPercentNormalized(
item.profileFunction.normalizedInclusiveTicks);
(element.children.item(1) as HTMLElement).textContent =
Utils.formatPercentNormalized(
item.profileFunction.normalizedExclusiveTicks);
_updateLines(element.children.item(2) as HTMLElement, depth);
if (item.children.isNotEmpty) {
(element.children.item(3) as HTMLElement).textContent =
_tree!.isExpanded(item) ? _expandedIcon : _collapsedIcon;
} else {
(element.children.item(3) as HTMLElement).textContent = '';
}
(element.children.item(4) as HTMLElement).textContent =
Utils.formatPercentNormalized(item.percentage);
final old = element.children.item(5)!;
element.insertBefore(
old,
element.appendChild((new FunctionRefElement(
_isolate, item.profileFunction.function!,
queue: _r.queue)
..className = 'name')
.element));
element.removeChild(old);
}
void _updateMemoryFunctionRow(HTMLElement element, itemDynamic, int depth) {
M.FunctionCallTreeNode item = itemDynamic;
(element.children.item(0) as HTMLElement).textContent =
Utils.formatSize(item.inclusiveNativeAllocations);
(element.children.item(0) as HTMLElement).title =
'memory allocated from resulting calls: '
'${item.inclusiveNativeAllocations}B';
(element.children.item(1) as HTMLElement).textContent =
Utils.formatSize(item.exclusiveNativeAllocations);
(element.children.item(1) as HTMLElement).title =
'memory allocated during execution: '
'${item.exclusiveNativeAllocations}B';
_updateLines(element.children.item(2)!, depth);
if (item.children.isNotEmpty) {
(element.children.item(3) as HTMLElement).textContent =
_tree!.isExpanded(item) ? _expandedIcon : _collapsedIcon;
} else {
(element.children.item(3) as HTMLElement).textContent = '';
}
(element.children.item(4) as HTMLElement).textContent =
Utils.formatPercentNormalized(item.percentage);
final old = element.children.item(5)!;
element.insertBefore(
old,
(new FunctionRefElement(null, item.profileFunction.function!,
queue: _r.queue)
..className = 'name')
.element);
element.removeChild(old);
}
bool _searchFunction(Pattern pattern, itemDynamic) {
M.FunctionCallTreeNode item = itemDynamic;
return M
.getFunctionFullName(item.profileFunction.function!)
.contains(pattern);
}
void _updateCpuCodeRow(HTMLElement element, itemDynamic, int depth) {
M.CodeCallTreeNode item = itemDynamic;
(element.children.item(0) as HTMLElement).textContent =
Utils.formatPercentNormalized(
item.profileCode.normalizedInclusiveTicks);
(element.children.item(1) as HTMLElement).textContent =
Utils.formatPercentNormalized(
item.profileCode.normalizedExclusiveTicks);
_updateLines(element.children.item(2)!, depth);
if (item.children.isNotEmpty) {
(element.children.item(3) as HTMLElement).textContent =
_tree!.isExpanded(item) ? _expandedIcon : _collapsedIcon;
} else {
(element.children.item(3) as HTMLElement).textContent = '';
}
(element.children.item(4) as HTMLElement).textContent =
Utils.formatPercentNormalized(item.percentage);
final old = element.children.item(5)!;
element.insertBefore(
old,
element.appendChild((new CodeRefElement(
_isolate, item.profileCode.code!,
queue: _r.queue)
..className = 'name')
.element));
element.removeChild(old);
}
void _updateMemoryCodeRow(HTMLElement element, itemDynamic, int depth) {
M.CodeCallTreeNode item = itemDynamic;
(element.children.item(0) as HTMLElement).textContent =
Utils.formatSize(item.inclusiveNativeAllocations);
(element.children.item(0) as HTMLElement).title =
'memory allocated from resulting calls: '
'${item.inclusiveNativeAllocations}B';
(element.children.item(1) as HTMLElement).textContent =
Utils.formatSize(item.exclusiveNativeAllocations);
(element.children.item(1) as HTMLElement).title =
'memory allocated during execution: '
'${item.exclusiveNativeAllocations}B';
_updateLines(element.children.item(2)!, depth);
if (item.children.isNotEmpty) {
(element.children.item(3) as HTMLElement).textContent =
_tree!.isExpanded(item) ? _expandedIcon : _collapsedIcon;
} else {
(element.children.item(3) as HTMLElement).textContent = '';
}
(element.children.item(4) as HTMLElement).textContent =
Utils.formatPercentNormalized(item.percentage);
final old = element.children.item(5)!;
element.insertBefore(
old,
element.appendChild(
(new CodeRefElement(null, item.profileCode.code!, queue: _r.queue)
..className = 'name')
.element));
element.removeChild(old);
}
bool _searchCode(Pattern pattern, itemDynamic) {
M.CodeCallTreeNode item = itemDynamic;
return item.profileCode.code!.name!.contains(pattern);
}
static _updateLines(Element element, int n) {
n = Math.max(0, n);
while (element.children.length > n) {
element.removeChild(element.lastChild!);
}
while (element.children.length < n) {
element.appendChild(HTMLSpanElement());
}
}
}
@@ -1,467 +0,0 @@
// 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 cpu_profile_table_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/containers/virtual_collection.dart';
import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/sample_buffer_control.dart';
import 'package:observatory/src/elements/stack_trace_tree_config.dart';
import 'package:observatory/utils.dart';
enum _Table { functions, caller, callee }
enum _SortingField { exclusive, inclusive, caller, callee, method }
enum _SortingDirection { ascending, descending }
class CpuProfileTableElement extends CustomElement implements Renderable {
late RenderingScheduler<CpuProfileTableElement> _r;
Stream<RenderedEvent<CpuProfileTableElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.IsolateSampleProfileRepository _profiles;
late Stream<M.SampleProfileLoadingProgressEvent> _progressStream;
M.SampleProfileLoadingProgress? _progress;
final _sortingField = <_Table, _SortingField>{
_Table.functions: _SortingField.exclusive,
_Table.caller: _SortingField.caller,
_Table.callee: _SortingField.callee,
};
final _sortingDirection = <_Table, _SortingDirection>{
_Table.functions: _SortingDirection.descending,
_Table.caller: _SortingDirection.descending,
_Table.callee: _SortingDirection.descending,
};
String _filter = '';
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.IsolateSampleProfileRepository get profiles => _profiles;
M.VMRef get vm => _vm;
factory CpuProfileTableElement(
M.VM vm,
M.IsolateRef isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.IsolateSampleProfileRepository profiles,
{RenderingQueue? queue}) {
CpuProfileTableElement e = new CpuProfileTableElement.created();
e._r = new RenderingScheduler<CpuProfileTableElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._profiles = profiles;
return e;
}
CpuProfileTableElement.created() : super.created('cpu-profile-table');
@override
attached() {
super.attached();
_r.enable();
_request();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var content = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('cpu profile (table)'),
(new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh))
.element,
(new NavRefreshElement(label: 'Clear', queue: _r.queue)
..onRefresh.listen(_clearCpuSamples))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
];
if (_progress == null) {
setChildren(content);
return;
}
content.add(new SampleBufferControlElement(_vm, _progress!, _progressStream,
showTag: false, queue: _r.queue)
.element);
if (_progress!.status == M.SampleProfileLoadingStatus.loaded) {
content.add(new HTMLBRElement());
content.addAll(_createTables());
content.add(new HTMLBRElement());
content.addAll(_createTree());
}
setChildren(content);
}
M.ProfileFunction? _selected;
VirtualCollectionElement? _functions;
VirtualCollectionElement? _callers;
VirtualCollectionElement? _callees;
List<HTMLElement> _createTables() {
_functions = _functions ??
new VirtualCollectionElement(_createFunction, _updateFunction,
createHeader: _createFunctionHeader,
search: _searchFunction,
queue: _r.queue);
// If there's no samples, don't populate the function list.
_functions!.items = (_progress!.profile.sampleCount != 0)
? _progress!.profile.functions.toList()
: []
..sort(_createSorter(_Table.functions));
_functions!.takeIntoView(_selected);
_callers = _callers ??
new VirtualCollectionElement(_createCaller, _updateCaller,
createHeader: _createCallerHeader,
search: _searchFunction,
queue: _r.queue);
_callees = _callees ??
new VirtualCollectionElement(_createCallee, _updateCallee,
createHeader: _createCalleeHeader,
search: _searchFunction,
queue: _r.queue);
if (_selected != null) {
_callers!.items = _selected!.callers.keys.toList()
..sort(_createSorter(_Table.caller));
_callees!.items = _selected!.callees.keys.toList()
..sort(_createSorter(_Table.callee));
} else {
_callers!.items = const [];
_callees!.items = const [];
}
return <HTMLElement>[
new HTMLDivElement()
..className = 'profile-trees'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'profile-trees-all'
..appendChildren(<HTMLElement>[_functions!.element]),
new HTMLDivElement()
..className = 'profile-trees-current'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'profile-trees-caller'
..appendChildren(<HTMLElement>[_callers!.element]),
new HTMLDivElement()
..className = 'profile-trees-selected'
..setChildren(_selected == null
? [
new HTMLSpanElement()
..textContent = 'No element selected'
]
: [
new FunctionRefElement(_isolate, _selected!.function!,
queue: _r.queue)
.element
]),
new HTMLDivElement()
..className = 'profile-trees-callee'
..appendChildren(<HTMLElement>[_callees!.element])
])
])
];
}
HTMLElement _createFunction() {
final element = new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'exclusive'
..textContent = '0%',
new HTMLSpanElement()
..className = 'inclusive'
..textContent = '0%',
new HTMLSpanElement()..className = 'name'
]);
element.onClick.listen((e) {
if (e.target is HTMLAnchorElement) {
return;
}
_selected = _functions!.getItemFromElement(element);
_r.dirty();
});
return element;
}
void _updateFunction(HTMLElement e, itemDynamic, int index) {
M.ProfileFunction item = itemDynamic;
if (item == _selected) {
e.className = 'function-item selected';
} else {
e.className = 'function-item';
}
(e.children.item(0) as HTMLElement).textContent =
Utils.formatPercentNormalized(_getExclusiveT(item));
(e.children.item(1) as HTMLElement).textContent =
Utils.formatPercentNormalized(_getInclusiveT(item));
(e.children.item(2) as HTMLElement).textContent =
M.getFunctionFullName(item.function!);
}
List<HTMLElement> _createFunctionHeader() => [
new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
_createHeaderButton('exclusive', 'Execution(%)', _Table.functions,
_SortingField.exclusive, _SortingDirection.descending),
_createHeaderButton('inclusive', 'Stack(%)', _Table.functions,
_SortingField.inclusive, _SortingDirection.descending),
_createHeaderButton('name', 'Method', _Table.functions,
_SortingField.method, _SortingDirection.ascending),
])
];
bool _searchFunction(Pattern pattern, itemDynamic) {
M.ProfileFunction item = itemDynamic;
return M.getFunctionFullName(item.function!).contains(pattern);
}
void _setSorting(
_Table table, _SortingField field, _SortingDirection defaultDirection) {
if (_sortingField[table] == field) {
switch (_sortingDirection[table]!) {
case _SortingDirection.descending:
_sortingDirection[table] = _SortingDirection.ascending;
break;
case _SortingDirection.ascending:
_sortingDirection[table] = _SortingDirection.descending;
break;
}
} else {
_sortingDirection[table] = defaultDirection;
_sortingField[table] = field;
}
_r.dirty();
}
HTMLElement _createCallee() {
final element = new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'inclusive'
..textContent = '0%',
new HTMLSpanElement()..className = 'name'
]);
element.onClick.listen((e) {
if (e.target is HTMLAnchorElement) {
return;
}
_selected = _callees!.getItemFromElement(element);
_r.dirty();
});
return element;
}
void _updateCallee(HTMLElement e, item, int index) {
(e.children.item(0) as HTMLElement).textContent =
Utils.formatPercentNormalized(_getCalleeT(item));
(e.children.item(1) as HTMLElement).textContent =
M.getFunctionFullName(item.function);
}
List<HTMLElement> _createCalleeHeader() => [
new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
_createHeaderButton('inclusive', 'Callees(%)', _Table.callee,
_SortingField.callee, _SortingDirection.descending),
_createHeaderButton('name', 'Method', _Table.callee,
_SortingField.method, _SortingDirection.ascending),
])
];
HTMLElement _createCaller() {
final element = new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'inclusive'
..textContent = '0%',
new HTMLSpanElement()..className = 'name'
]);
element.onClick.listen((e) {
if (e.target is HTMLAnchorElement) {
return;
}
_selected = _callers!.getItemFromElement(element);
_r.dirty();
});
return element;
}
void _updateCaller(HTMLElement e, item, int index) {
(e.children.item(0) as HTMLElement).textContent =
Utils.formatPercentNormalized(_getCallerT(item));
(e.children.item(1) as HTMLElement).textContent =
M.getFunctionFullName(item.function);
}
List<HTMLElement> _createCallerHeader() => [
new HTMLDivElement()
..className = 'function-item'
..appendChildren(<HTMLElement>[
_createHeaderButton('inclusive', 'Callers(%)', _Table.caller,
_SortingField.caller, _SortingDirection.descending),
_createHeaderButton('name', 'Method', _Table.caller,
_SortingField.method, _SortingDirection.ascending),
])
];
HTMLButtonElement _createHeaderButton(String className, String text,
_Table table, _SortingField field, _SortingDirection direction) =>
new HTMLButtonElement()
..className = className
..textContent = _sortingField[table] != field
? text
: _sortingDirection[table] == _SortingDirection.ascending
? '$text'
: '$text'
..onClick.listen((_) => _setSorting(table, field, direction));
List<HTMLElement> _createTree() {
late CpuProfileVirtualTreeElement tree;
return [
(new StackTraceTreeConfigElement(
showMode: false,
showDirection: false,
mode: ProfileTreeMode.function,
direction: M.ProfileTreeDirection.exclusive,
filter: _filter,
queue: _r.queue)
..onFilterChange.listen((e) {
_filter = e.element.filter.trim();
tree.filters = _filter.isNotEmpty
? [
_filterTree,
(node) {
return node.name.contains(_filter);
}
]
: [_filterTree];
}))
.element,
new HTMLBRElement(),
(tree = new CpuProfileVirtualTreeElement(_isolate, _progress!.profile,
mode: ProfileTreeMode.function,
direction: M.ProfileTreeDirection.exclusive,
queue: _r.queue)
..filters = _filter.isNotEmpty
? [
_filterTree,
(node) {
return node.name.contains(_filter);
}
]
: [_filterTree])
.element
];
}
bool _filterTree(nodeDynamic) {
M.FunctionCallTreeNode node = nodeDynamic;
return node.profileFunction == _selected;
}
Future _request({bool clear = false, bool forceFetch = false}) async {
_progress = null;
_progressStream = _profiles.get(isolate, M.SampleProfileTag.vmOnly,
clear: clear, forceFetch: forceFetch);
_r.dirty();
_progress = (await _progressStream.first).progress;
_r.dirty();
if (M.isSampleProcessRunning(_progress!.status)) {
_progress = (await _progressStream.last).progress;
_r.dirty();
}
}
Future _clearCpuSamples(RefreshEvent e) async {
e.element.disabled = true;
await _request(clear: true);
e.element.disabled = false;
}
Future _refresh(e) async {
e.element.disabled = true;
await _request(forceFetch: true);
e.element.disabled = false;
}
_createSorter(_Table table) {
var getter;
switch (_sortingField[table]!) {
case _SortingField.exclusive:
getter = _getExclusiveT;
break;
case _SortingField.inclusive:
getter = _getInclusiveT;
break;
case _SortingField.callee:
getter = _getCalleeT;
break;
case _SortingField.caller:
getter = _getCallerT;
break;
case _SortingField.method:
getter = (M.ProfileFunction s) => M.getFunctionFullName(s.function!);
break;
}
switch (_sortingDirection[table]!) {
case _SortingDirection.ascending:
int sort(a, b) {
return getter(a).compareTo(getter(b));
}
return sort;
case _SortingDirection.descending:
int sort(a, b) {
return getter(b).compareTo(getter(a));
}
return sort;
}
}
static double _getExclusiveT(M.ProfileFunction f) =>
f.normalizedExclusiveTicks;
static double _getInclusiveT(M.ProfileFunction f) =>
f.normalizedInclusiveTicks;
double _getCalleeT(M.ProfileFunction f) =>
_selected!.callees[f]! /
_selected!.callees.values.reduce((a, b) => a + b);
double _getCallerT(M.ProfileFunction f) =>
_selected!.callers[f]! /
_selected!.callers.values.reduce((a, b) => a + b);
}
File diff suppressed because it is too large Load Diff
@@ -1,102 +0,0 @@
// 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 curly_block_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class CurlyBlockToggleEvent {
final CurlyBlockElement control;
CurlyBlockToggleEvent(this.control);
}
class CurlyBlockElement extends CustomElement implements Renderable {
late RenderingScheduler<CurlyBlockElement> _r;
final StreamController<CurlyBlockToggleEvent> _onToggle =
new StreamController<CurlyBlockToggleEvent>.broadcast();
Stream<CurlyBlockToggleEvent> get onToggle => _onToggle.stream;
Stream<RenderedEvent<CurlyBlockElement>> get onRendered => _r.onRendered;
late bool _expanded;
late bool _disabled;
Iterable<HTMLElement> _content = const [];
bool get expanded => _expanded;
bool get disabled => _disabled;
Iterable<HTMLElement> get content => _content;
set expanded(bool value) {
if (_expanded != value) _onToggle.add(new CurlyBlockToggleEvent(this));
_expanded = _r.checkAndReact(_expanded, value);
}
set disabled(bool value) => _disabled = _r.checkAndReact(_disabled, value);
set content(Iterable<HTMLElement> value) {
_content = value.toList();
_r.dirty();
}
factory CurlyBlockElement(
{bool expanded = false, bool disabled = false, RenderingQueue? queue}) {
CurlyBlockElement e = new CurlyBlockElement.created();
e._r = new RenderingScheduler<CurlyBlockElement>(e, queue: queue);
e._expanded = expanded;
e._disabled = disabled;
return e;
}
CurlyBlockElement.created() : super.created('curly-block');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void toggle() {
if (disabled) {
_r.scheduleNotification();
return;
}
expanded = !expanded;
}
void render() {
List<HTMLElement> content = <HTMLElement>[
new HTMLSpanElement()..textContent = '{'
];
HTMLSpanElement label = new HTMLSpanElement()
..className = disabled ? 'curly-block disabled' : 'curly-block'
..textContent = expanded ? '\xa0\xa0\xa0\xa0' : '\xa0\xa0\xa0\xa0';
if (disabled) {
content.add(label);
} else {
content.add(new HTMLAnchorElement()
..onClick.listen((_) {
toggle();
})
..appendChild(label));
}
if (expanded) {
content.add(new HTMLBRElement());
content.addAll(_content);
}
content.add(new HTMLSpanElement()..textContent = '}');
setChildren(content);
}
}
File diff suppressed because it is too large Load Diff
@@ -1,51 +0,0 @@
// Copyright (c) 2016, 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 error_ref_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' show ErrorRef;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class ErrorRefElement extends CustomElement implements Renderable {
late RenderingScheduler<ErrorRefElement> _r;
Stream<RenderedEvent<ErrorRefElement>> get onRendered => _r.onRendered;
late ErrorRef _error;
ErrorRef get error => _error;
factory ErrorRefElement(ErrorRef error, {RenderingQueue? queue}) {
ErrorRefElement e = new ErrorRefElement.created();
e._r = new RenderingScheduler<ErrorRefElement>(e, queue: queue);
e._error = error;
return e;
}
ErrorRefElement.created() : super.created('error-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
setChildren(<HTMLElement>[
new HTMLPreElement.pre()..textContent = error.message ?? ''
]);
}
}
@@ -1,88 +0,0 @@
// 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 error_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
class ErrorViewElement extends CustomElement implements Renderable {
late RenderingScheduler<ErrorViewElement> _r;
Stream<RenderedEvent<ErrorViewElement>> get onRendered => _r.onRendered;
late M.Error _error;
late M.NotificationRepository _notifications;
M.Error get error => _error;
factory ErrorViewElement(
M.NotificationRepository notifications, M.Error error,
{RenderingQueue? queue}) {
ErrorViewElement e = new ErrorViewElement.created();
e._r = new RenderingScheduler<ErrorViewElement>(e, queue: queue);
e._error = error;
e._notifications = notifications;
return e;
}
ErrorViewElement.created() : super.created('error-view');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h1()
..textContent = 'Error: ${_kindToString(_error.kind)}',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'well'
..appendChild(
new HTMLPreElement.pre()..textContent = error.message ?? '')
]),
]);
}
static String _kindToString(M.ErrorKind? kind) {
switch (kind) {
case M.ErrorKind.unhandledException:
return 'Unhandled Exception';
case M.ErrorKind.languageError:
return 'Language Error';
case M.ErrorKind.internalError:
return 'Internal Error';
case M.ErrorKind.terminationError:
return 'Termination Error';
default:
throw new Exception('Unknown M.ErrorKind ($kind)');
}
}
}
@@ -1,205 +0,0 @@
// 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 eval_box_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class EvalBoxElement extends CustomElement implements Renderable {
late RenderingScheduler<EvalBoxElement> _r;
Stream<RenderedEvent<EvalBoxElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.ObjectRef _context;
late M.ObjectRepository _objects;
late M.EvalRepository _eval;
final _results = <_ExpressionDescription>[];
String? _expression = '';
late bool _multiline;
late Iterable<String> _quickExpressions;
M.IsolateRef get isolate => _isolate;
M.ObjectRef get context => _context;
factory EvalBoxElement(M.IsolateRef isolate, M.ObjectRef context,
M.ObjectRepository objects, M.EvalRepository eval,
{bool multiline = false,
Iterable<String> quickExpressions = const [],
RenderingQueue? queue}) {
EvalBoxElement e = new EvalBoxElement.created();
e._r = new RenderingScheduler<EvalBoxElement>(e, queue: queue);
e._isolate = isolate;
e._context = context;
e._objects = objects;
e._eval = eval;
e._multiline = multiline;
e._quickExpressions = new List.unmodifiable(quickExpressions);
return e;
}
EvalBoxElement.created() : super.created('eval-box');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
_results.clear();
}
void render() {
setChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'quicks'
..appendChildren(
_quickExpressions.map<HTMLElement>((q) => new HTMLButtonElement()
..textContent = q
..onClick.listen((_) {
_expression = q;
_run();
}))),
new HTMLDivElement()
..className = 'heading'
..appendChildren(<HTMLElement>[
new HTMLFormElement()
..autocomplete = 'on'
..appendChildren(<HTMLElement>[
_multiline ? _createEvalTextArea() : _createEvalTextBox(),
new HTMLSpanElement()
..className = 'buttons'
..appendChildren(<HTMLElement>[
_createEvalButton(),
_createMultilineCheckbox(),
new HTMLSpanElement()..textContent = 'Multi-line'
])
])
]),
new HTMLTableElement()
..appendChildren(_results.reversed
.map<HTMLElement>((result) => new HTMLTableRowElement()
..appendChildren(<HTMLElement>[
new HTMLTableCellElement.td()
..className = 'historyExpr'
..appendChildren(<HTMLElement>[
new HTMLButtonElement()
..textContent = result.expression
..onClick.listen((_) {
_expression = result.expression;
_r.dirty();
})
]),
new HTMLTableCellElement.td()
..className = 'historyValue'
..appendChildren(<HTMLElement>[
result.isPending
? (new HTMLSpanElement()..textContent = 'Pending...')
: anyRef(_isolate, result.value, _objects,
queue: _r.queue)
]),
new HTMLTableCellElement.td()
..className = 'historyDelete'
..appendChildren(<HTMLElement>[
new HTMLButtonElement()
..textContent = '✖ Remove'
..onClick.listen((_) {
_results.remove(result);
_r.dirty();
})
])
]))
.toList())
]);
}
HTMLTextAreaElement _createEvalTextArea() {
var area = new HTMLTextAreaElement()
..className = 'textbox'
..placeholder = 'evaluate an expression'
..value = _expression ?? ''
..onKeyUp.where((e) => e.key == '\n').listen((e) {
e.preventDefault();
_run();
});
area.onInput.listen((e) {
_expression = area.value;
});
return area;
}
HTMLInputElement _createEvalTextBox() {
final expression = (_expression ?? '').split('\n')[0];
_expression = expression;
var textbox = new HTMLInputElement()
..className = 'textbox'
..placeholder = 'evaluate an expression'
..value = expression
..onKeyUp.where((e) => e.key == '\n').listen((e) {
e.preventDefault();
_run();
});
textbox.onInput.listen((e) {
_expression = textbox.value;
});
return textbox;
}
HTMLButtonElement _createEvalButton() {
final button = new HTMLButtonElement()
..textContent = 'Evaluate'
..onClick.listen((e) {
e.preventDefault();
_run();
});
return button;
}
HTMLInputElement _createMultilineCheckbox() {
final checkbox = new HTMLInputElement()
..type = 'checkbox'
..checked = _multiline;
checkbox.onClick.listen((e) {
e.preventDefault();
_multiline = checkbox.checked;
_r.dirty();
});
return checkbox;
}
Future _run() async {
final expression = _expression;
if (expression == null || expression.isEmpty) return;
_expression = null;
final result = new _ExpressionDescription.pending(expression);
_results.add(result);
_r.dirty();
final index = _results.indexOf(result);
_results[index] = new _ExpressionDescription(
expression, await _eval.evaluate(_isolate, _context, expression));
_r.dirty();
}
}
class _ExpressionDescription {
final String expression;
final M.ObjectRef? value;
bool get isPending => value == null;
_ExpressionDescription(this.expression, this.value);
_ExpressionDescription.pending(this.expression) : value = null;
}
@@ -1,91 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/instance_ref.dart';
class FieldRefElement extends CustomElement implements Renderable {
late RenderingScheduler<FieldRefElement> _r;
Stream<RenderedEvent<FieldRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.FieldRef _field;
late M.ObjectRepository _objects;
late bool _expandable;
M.IsolateRef get isolate => _isolate;
M.FieldRef get field => _field;
factory FieldRefElement(
M.IsolateRef isolate, M.FieldRef field, M.ObjectRepository objects,
{RenderingQueue? queue, bool expandable = true}) {
FieldRefElement e = new FieldRefElement.created();
e._r = new RenderingScheduler<FieldRefElement>(e, queue: queue);
e._isolate = isolate;
e._field = field;
e._objects = objects;
e._expandable = expandable;
return e;
}
FieldRefElement.created() : super.created('field-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var header = '';
if (_field.isStatic!) {
if (_field.dartOwner is M.ClassRef) {
header += 'static ';
} else {
header += 'top-level ';
}
}
if (_field.isFinal!) {
header += 'final ';
} else if (_field.isConst!) {
header += 'const ';
} else if (_field.declaredType!.name == 'dynamic') {
header += 'var ';
}
if (_field.declaredType!.name == 'dynamic') {
setChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = header,
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _field)
..text = _field.name ?? ''
]);
} else {
setChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = header,
new InstanceRefElement(_isolate, _field.declaredType!, _objects,
queue: _r.queue, expandable: _expandable)
.element,
new HTMLSpanElement()..textContent = ' ',
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _field)
..text = _field.name ?? ''
]);
}
}
}
@@ -1,279 +0,0 @@
// 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 field_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/library_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/script_inset.dart';
import 'package:observatory/src/elements/source_link.dart';
class FieldViewElement extends CustomElement implements Renderable {
late RenderingScheduler<FieldViewElement> _r;
Stream<RenderedEvent<FieldViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Field _field;
M.LibraryRef? _library;
late M.FieldRepository _fields;
late M.ClassRepository _classes;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ScriptRepository _scripts;
late M.ObjectRepository _objects;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Field get field => _field;
factory FieldViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Field field,
M.EventRepository events,
M.NotificationRepository notifications,
M.FieldRepository fields,
M.ClassRepository classes,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ScriptRepository scripts,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
FieldViewElement e = new FieldViewElement.created();
e._r = new RenderingScheduler<FieldViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._field = field;
e._fields = fields;
e._classes = classes;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._scripts = scripts;
e._objects = objects;
if (field.dartOwner is M.LibraryRef) {
e._library = field.dartOwner as M.LibraryRef;
}
return e;
}
FieldViewElement.created() : super.created('field-view');
@override
attached() {
super.attached();
_r.enable();
_refresh();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var header = '';
if (_field.isStatic!) {
if (_field.dartOwner is M.ClassRef) {
header += 'static ';
} else {
header += 'top-level ';
}
}
if (_field.isFinal!) {
header += 'final ';
} else if (_field.isConst!) {
header += 'const ';
}
if (_field.declaredType!.name == 'dynamic') {
header += 'var';
} else {
header += _field.declaredType!.name!;
}
setChildren(<HTMLElement>[
navBar(_createMenu()),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = '$header ${field.name}',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _field, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_createMembers()),
new HTMLHRElement(),
new HTMLDivElement()
..appendChildren(_field.location == null
? const []
: [
new ScriptInsetElement(_isolate, _field.location!.script!,
_scripts, _objects, _events,
startPos: field.location!.tokenPos,
endPos: field.location!.tokenPos,
queue: _r.queue)
.element
]),
])
]);
}
List<HTMLElement> _createMenu() {
final menu = <HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element
];
if (_library != null) {
menu.add(new NavLibraryMenuElement(_isolate, _library!, queue: _r.queue)
.element);
} else if (_field.dartOwner is M.ClassRef) {
menu.add(new NavClassMenuElement(_isolate, _field.dartOwner as M.ClassRef,
queue: _r.queue)
.element);
}
menu.addAll(<HTMLElement>[
navMenu(_field.name!),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]);
return menu;
}
List<HTMLElement> _createMembers() {
final members = <HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'owner',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
_field.dartOwner == null
? (new HTMLSpanElement()..textContent = '...')
: anyRef(_isolate, _field.dartOwner, _objects,
queue: _r.queue)
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'script',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new SourceLinkElement(_isolate, field.location!, _scripts,
queue: _r.queue)
.element
])
])
];
if (!_field.isStatic!) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..title = 'The types observed for this field at runtime. '
'Fields that are observed to have a single type at runtime '
'or to never be null may allow for additional optimization.'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'observed types',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(_createGuard())
]));
}
if (_field.staticValue != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'static value',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
anyRef(_isolate, _field.staticValue, _objects, queue: _r.queue)
])
]));
}
return members;
}
List<HTMLElement> _createGuard() {
final guard = <HTMLElement>[];
switch (_field.guardClassKind!) {
case M.GuardClassKind.unknown:
guard.add(new HTMLSpanElement()..textContent = 'none');
break;
case M.GuardClassKind.dynamic:
guard.add(new HTMLSpanElement()..textContent = 'various');
break;
case M.GuardClassKind.single:
guard.add(
new ClassRefElement(_isolate, _field.guardClass!, queue: _r.queue)
.element);
break;
}
guard.add(new HTMLSpanElement()
..textContent =
_field.guardNullable! ? '— null observed' : '— null not observed');
return guard;
}
Future _refresh() async {
_field = await _fields.get(_isolate, _field.id!);
if (_field.dartOwner is M.LibraryRef) {
_library = _field.dartOwner as M.LibraryRef;
} else if (_field.dartOwner is M.ClassRef) {
var cls = _field.dartOwner as M.ClassRef;
_library = (await _classes.get(_isolate, cls.id!)).library!;
}
_r.dirty();
}
}
@@ -1,144 +0,0 @@
// 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 flag_list_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.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';
class FlagListElement extends CustomElement implements Renderable {
late RenderingScheduler<FlagListElement> _r;
Stream<RenderedEvent<FlagListElement>> get onRendered => _r.onRendered;
late M.VMRef _vm;
late M.EventRepository _events;
late M.FlagsRepository _repository;
late M.NotificationRepository _notifications;
Iterable<M.Flag>? _flags;
M.VMRef get vm => _vm;
factory FlagListElement(M.VMRef vm, M.EventRepository events,
M.FlagsRepository repository, M.NotificationRepository notifications,
{RenderingQueue? queue}) {
FlagListElement e = new FlagListElement.created();
e._r = new RenderingScheduler<FlagListElement>(e, queue: queue);
e._vm = vm;
e._events = events;
e._repository = repository;
e._notifications = notifications;
return e;
}
FlagListElement.created() : super.created('flag-list');
@override
void attached() {
super.attached();
_refresh();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
final content = <HTMLElement>[];
if (_flags == null) {
content
.add(new HTMLHeadingElement.h1()..textContent = 'Loading Flags...');
} else {
final modified = _flags!.where(_isModified);
final unmodified = _flags!.where(_isUnmodified);
if (modified.isNotEmpty) {
content
.add(new HTMLHeadingElement.h1()..textContent = 'Modified Flags');
content.add(new HTMLBRElement());
content.addAll(modified.expand(_renderFlag));
content.add(new HTMLHRElement());
}
content
.add(new HTMLHeadingElement.h1()..textContent = 'Unmodified Flags');
content.add(new HTMLBRElement());
if (unmodified.isEmpty) {
content.add(new HTMLHeadingElement.h2()..textContent = 'None');
} else {
content.addAll(unmodified.expand(_renderFlag));
}
}
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm as M.VM, _events, queue: _r.queue).element,
navMenu('flags', link: Uris.flags()),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
try {
await _refresh();
} finally {
e.element.disabled = false;
}
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered'
..appendChildren(content),
]);
}
Future _refresh() {
return _repository.list().then((flags) {
_flags = flags;
_r.dirty();
});
}
static bool _isModified(M.Flag flag) => flag.modified;
static bool _isUnmodified(M.Flag flag) => !flag.modified;
static List<HTMLElement> _renderFlag(M.Flag flag) {
return [
new HTMLSpanElement()
..className = 'comment'
..textContent = '// ${flag.comment}',
new HTMLDivElement()
..className = flag.modified ? 'flag modified' : 'flag unmodified'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'name'
..textContent = flag.name,
new HTMLSpanElement()..textContent = '=',
new HTMLSpanElement()
..className = 'value'
..textContent = flag.valueAsString ?? ''
]),
new HTMLBRElement(),
];
}
}
@@ -1,95 +0,0 @@
// 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 function_ref_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/models.dart' as M
show
IsolateRef,
FunctionRef,
isSyntheticFunction,
ClassRef,
ObjectRef,
getFunctionFullName;
class FunctionRefElement extends CustomElement implements Renderable {
late RenderingScheduler<FunctionRefElement> _r;
Stream<RenderedEvent<FunctionRefElement>> get onRendered => _r.onRendered;
M.IsolateRef? _isolate;
late M.FunctionRef _function;
late bool _qualified;
M.IsolateRef? get isolate => _isolate;
M.FunctionRef get function => _function;
bool get qualified => _qualified;
factory FunctionRefElement(M.IsolateRef? isolate, M.FunctionRef function,
{bool qualified = true, RenderingQueue? queue}) {
FunctionRefElement e = new FunctionRefElement.created();
e._r = new RenderingScheduler<FunctionRefElement>(e, queue: queue);
e._isolate = isolate;
e._function = function;
e._qualified = qualified;
return e;
}
FunctionRefElement.created() : super.created('function-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
title = '';
_r.disable(notify: true);
}
void render() {
var content = <HTMLElement>[
new HTMLAnchorElement()
..href = (M.isSyntheticFunction(_function.kind) || (_isolate == null))
? ''
: Uris.inspect(_isolate!, object: _function)
..text = _function.name ?? ''
];
if (qualified) {
M.ObjectRef? owner = _function.dartOwner;
while (owner is M.FunctionRef) {
content.addAll([
new HTMLSpanElement()..textContent = '.',
new HTMLAnchorElement()
..href = (M.isSyntheticFunction(owner.kind) || (_isolate == null))
? ''
: Uris.inspect(_isolate!, object: owner)
..text = owner.name!
]);
owner = owner.dartOwner;
}
if (owner is M.ClassRef) {
content.addAll([
new HTMLSpanElement()..textContent = '.',
new ClassRefElement(_isolate!, owner, queue: _r.queue).element
]);
}
}
children = content.reversed.toList(growable: false);
title = M.getFunctionFullName(_function);
}
}
@@ -1,422 +0,0 @@
// 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 function_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/code_ref.dart';
import 'package:observatory/src/elements/field_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/instance_ref.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/library_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/source_inset.dart';
import 'package:observatory/src/elements/source_link.dart';
class FunctionViewElement extends CustomElement implements Renderable {
late RenderingScheduler<FunctionViewElement> _r;
Stream<RenderedEvent<FunctionViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.ServiceFunction _function;
M.LibraryRef? _library;
late M.FunctionRepository _functions;
late M.ClassRepository _classes;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ScriptRepository _scripts;
late M.ObjectRepository _objects;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.ServiceFunction get function => _function;
factory FunctionViewElement(
M.VM vm,
M.IsolateRef isolate,
M.ServiceFunction function,
M.EventRepository events,
M.NotificationRepository notifications,
M.FunctionRepository functions,
M.ClassRepository classes,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ScriptRepository scripts,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
FunctionViewElement e = new FunctionViewElement.created();
e._r = new RenderingScheduler<FunctionViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._function = function;
e._functions = functions;
e._classes = classes;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._scripts = scripts;
e._objects = objects;
if (function.dartOwner is M.LibraryRef) {
e._library = function.dartOwner as M.LibraryRef;
}
return e;
}
FunctionViewElement.created() : super.created('function-view');
@override
attached() {
super.attached();
_r.enable();
_refresh();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
setChildren(<HTMLElement>[
navBar(_createMenu()),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()
..textContent = 'Function ${_function.name}',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _function, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_createMembers()),
new HTMLHRElement(),
new HTMLDivElement()
..appendChildren(_function.location == null
? const []
: [
new SourceInsetElement(_isolate, _function.location!,
_scripts, _objects, _events,
queue: _r.queue)
.element
]),
])
]);
}
List<HTMLElement> _createMenu() {
final menu = <HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element
];
if (_library != null) {
menu.add(new NavLibraryMenuElement(_isolate, _library!, queue: _r.queue)
.element);
} else if (_function.dartOwner is M.ClassRef) {
menu.add(new NavClassMenuElement(
_isolate, _function.dartOwner as M.ClassRef,
queue: _r.queue)
.element);
}
menu.addAll(<HTMLElement>[
navMenu(_function.name!),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]);
return menu;
}
List<HTMLElement> _createMembers() {
final members = <HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'kind',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..textContent = '${_function.isStatic! ? "static " : ""}'
'${_function.isConst! ? "const " : ""}'
'${_functionKindToString(_function.kind)}'
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'owner',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
_function.dartOwner == null
? (new HTMLSpanElement()..textContent = '...')
: anyRef(_isolate, _function.dartOwner, _objects,
queue: _r.queue)
])
])
];
if (_function.field != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'script',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new FieldRefElement(_isolate, _function.field!, _objects,
queue: _r.queue)
.element
])
]));
}
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'script',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new SourceLinkElement(_isolate, _function.location!, _scripts,
queue: _r.queue)
.element
])
]));
if (_function.code != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'current code',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new CodeRefElement(_isolate, _function.code!, queue: _r.queue)
.element
])
]));
}
if (_function.unoptimizedCode != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'unoptimized code',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new CodeRefElement(_isolate, _function.unoptimizedCode!,
queue: _r.queue)
.element,
new HTMLSpanElement()
..title = 'This count is used to determine when a function '
'will be optimized. It is a combination of call '
'counts and other factors.'
..textContent = ' (usage count: ${function.usageCounter})'
])
]));
}
members.add(new HTMLDivElement()
..className = 'memberItem'
..textContent = ' ');
if (_function.icDataArray != null) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'ic data array',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new InstanceRefElement(_isolate, _function.icDataArray!, _objects,
queue: _r.queue)
.element
])
]));
}
members.addAll([
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'deoptimizations',
new HTMLDivElement()
..className = 'memberName'
..textContent = '${_function.deoptimizations}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'optimizable',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.isOptimizable! ? 'yes' : 'no'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'inlinable',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.isInlinable! ? 'yes' : 'no'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'intrinsic',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.hasIntrinsic! ? 'yes' : 'no'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'recognized',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.isRecognized! ? 'yes' : 'no'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'native',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.isNative! ? 'yes' : 'no'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'vm name',
new HTMLDivElement()
..className = 'memberName'
..textContent = _function.vmName ?? ''
])
]);
return members;
}
Future _refresh() async {
_function = await _functions.get(_isolate, _function.id!);
if (_function.dartOwner is M.LibraryRef) {
_library = _function.dartOwner as M.LibraryRef;
} else if (_function.dartOwner is M.ClassRef) {
var cls = _function.dartOwner as M.ClassRef;
_library = (await _classes.get(_isolate, cls.id!)).library!;
}
_r.dirty();
}
static String _functionKindToString(M.FunctionKind? kind) {
switch (kind) {
case M.FunctionKind.regular:
return 'regular';
case M.FunctionKind.closure:
return 'closure';
case M.FunctionKind.implicitClosure:
return 'implicit closure';
case M.FunctionKind.getter:
return 'getter';
case M.FunctionKind.setter:
return 'setter';
case M.FunctionKind.constructor:
return 'constructor';
case M.FunctionKind.implicitGetter:
return 'implicit getter';
case M.FunctionKind.implicitSetter:
return 'implicit setter';
case M.FunctionKind.implicitStaticGetter:
return 'implicit static getter';
case M.FunctionKind.fieldInitializer:
return 'field initializer';
case M.FunctionKind.irregexpFunction:
return 'irregexp function';
case M.FunctionKind.methodExtractor:
return 'method extractor';
case M.FunctionKind.noSuchMethodDispatcher:
return 'noSuchMethod dispatcher';
case M.FunctionKind.invokeFieldDispatcher:
return 'invokeField dispatcher';
case M.FunctionKind.collected:
return 'collected';
case M.FunctionKind.native:
return 'native';
case M.FunctionKind.ffiTrampoline:
return 'ffi trampoline';
case M.FunctionKind.stub:
return 'stub';
case M.FunctionKind.tag:
return 'tag';
case M.FunctionKind.dynamicInvocationForwarder:
return 'dynamic invocation forwarder';
case M.FunctionKind.recordFieldGetter:
return 'record field getter';
default:
throw new Exception('Unknown Functionkind ($kind)');
}
}
}
@@ -1,72 +0,0 @@
// Copyright (c) 2016, 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 general_error_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
class GeneralErrorElement extends CustomElement implements Renderable {
late RenderingScheduler<GeneralErrorElement> _r;
Stream<RenderedEvent<GeneralErrorElement>> get onRendered => _r.onRendered;
late M.NotificationRepository _notifications;
late String _message;
String get message => _message;
set message(String value) => _message = _r.checkAndReact(_message, value);
factory GeneralErrorElement(M.NotificationRepository notifications,
{String message = '', RenderingQueue? queue}) {
GeneralErrorElement e = new GeneralErrorElement.created();
e._r = new RenderingScheduler<GeneralErrorElement>(e, queue: queue);
e._message = message;
e._notifications = notifications;
return e;
}
GeneralErrorElement.created() : super.created('general-error');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h1()..textContent = 'Error',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'well'
..textContent = message
])
]);
}
}
@@ -1,319 +0,0 @@
// Copyright (c) 2014, 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 heap_map_element;
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart' as S;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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';
class HeapMapElement extends CustomElement implements Renderable {
late RenderingScheduler<HeapMapElement> _r;
Stream<RenderedEvent<HeapMapElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
factory HeapMapElement(M.VM vm, M.IsolateRef isolate,
M.EventRepository events, M.NotificationRepository notifications,
{RenderingQueue? queue}) {
HeapMapElement e = new HeapMapElement.created();
e._r = new RenderingScheduler<HeapMapElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
return e;
}
HeapMapElement.created() : super.created('heap-map');
@override
attached() {
super.attached();
_r.enable();
_refresh();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
HTMLCanvasElement? _canvas;
ImageData? _fragmentationData;
int? _pageHeight;
final _classIdToColor = {};
final _colorToClassId = {};
final _classIdToName = {};
static final _freeColor = [255, 255, 255, 255];
static final _pageSeparationColor = [0, 0, 0, 255];
static const _PAGE_SEPARATION_HEIGHT = 4;
// Many browsers will not display a very tall canvas.
// TODO(koda): Improve interface for huge heaps.
static const _MAX_CANVAS_HEIGHT = 6000;
String _status = 'Loading';
S.ServiceMap? _fragmentation;
void render() {
if (_canvas == null) {
_canvas = new HTMLCanvasElement()
..width = 1
..height = 1
..onMouseMove.listen(_handleMouseMove);
}
// Set hover text to describe the object under the cursor.
_canvas!.title = _status;
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('heap map'),
(new NavRefreshElement(label: 'Mark-Compact', queue: _r.queue)
..onRefresh.listen((_) => _refresh(gc: "mark-compact")))
.element,
(new NavRefreshElement(label: 'Mark-Sweep', queue: _r.queue)
..onRefresh.listen((_) => _refresh(gc: "mark-sweep")))
.element,
(new NavRefreshElement(label: 'Scavenge', queue: _r.queue)
..onRefresh.listen((_) => _refresh(gc: "scavenge")))
.element,
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((_) => _refresh()))
.element,
(new NavNotifyElement(_notifications, queue: _r.queue)).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = _status,
new HTMLHRElement(),
]),
new HTMLDivElement()
..className = 'flex-row'
..appendChild(_canvas!)
]);
}
// Encode color as single integer, to enable using it as a map key.
int _packColor(Iterable<int> color) {
int packed = 0;
for (var component in color) {
packed = packed * 256 + component;
}
return packed;
}
void _addClass(int classId, String name, Iterable<int> color) {
_classIdToName[classId] = name.split('@')[0];
_classIdToColor[classId] = color;
_colorToClassId[_packColor(color)] = classId;
}
void _updateClassList(classList, int freeClassId) {
for (var member in classList['classes']) {
if (member is! S.Class) {
// TODO(turnidge): The printing for some of these non-class
// members is broken. Fix this:
//
// Logger.root.info('$member');
print('Ignoring non-class in class list');
continue;
}
var classId = int.parse(member.id!.split('/').last);
var color = _classIdToRGBA(classId);
_addClass(classId, member.name!, color);
}
_addClass(freeClassId, 'Free', _freeColor);
_addClass(0, '', _pageSeparationColor);
}
Iterable<int> _classIdToRGBA(int classId) {
// TODO(koda): Pick random hue, but fixed saturation and value.
var rng = new Random(classId);
return [rng.nextInt(128), rng.nextInt(128), rng.nextInt(128), 255];
}
String _classNameAt(Point<num> point) {
var color = new PixelReference(_fragmentationData!, point).color;
return _classIdToName[_colorToClassId[_packColor(color)]];
}
ObjectInfo? _objectAt(Point<num> point) {
if (_fragmentation == null || _canvas == null) {
return null;
}
var pagePixels = _pageHeight! * _fragmentationData!.width;
var index = new PixelReference(_fragmentationData!, point).index;
var pageIndex = index ~/ pagePixels;
num pageOffset = index % pagePixels;
var pages = _fragmentation!['pages'];
if (pageIndex < 0 || pageIndex >= pages.length) {
return null;
}
// Scan the page to find start and size.
var page = pages[pageIndex];
var objects = page['objects'];
var offset = 0;
var size = 0;
for (var i = 0; i < objects.length; i += 2) {
size = objects[i];
offset += size;
if (offset > pageOffset) {
pageOffset = offset - size;
break;
}
}
return new ObjectInfo(
int.parse(page['objectStart']) +
pageOffset * _fragmentation!['unitSizeBytes'],
size * _fragmentation!['unitSizeBytes']);
}
void _handleMouseMove(MouseEvent event) {
var info = _objectAt(Point(event.offsetX, event.offsetY));
if (info == null) {
_status = '';
_r.dirty();
return;
}
var addressString = '${info.size}B @ 0x${info.address.toRadixString(16)}';
var className = _classNameAt(Point(event.offsetX, event.offsetY));
_status = (className == '') ? '-' : '$className $addressString';
_r.dirty();
}
void _updateFragmentationData() {
if (_fragmentation == null || _canvas == null) {
return;
}
_updateClassList(
_fragmentation!['classList'], _fragmentation!['freeClassId']);
final pages = _fragmentation!['pages'];
final int width = max(_canvas!.parentElement!.clientWidth, 1);
_pageHeight = _PAGE_SEPARATION_HEIGHT +
(_fragmentation!['pageSizeBytes'] as int) ~/
(_fragmentation!['unitSizeBytes'] as int) ~/
width;
final height = min(_pageHeight! * pages.length, _MAX_CANVAS_HEIGHT) as int;
_fragmentationData =
_canvas!.context2D.createImageData(width as dynamic, height);
_canvas!.width = _fragmentationData!.width;
_canvas!.height = _fragmentationData!.height;
_renderPages(0);
}
// Renders and draws asynchronously, one page at a time to avoid
// blocking the UI.
void _renderPages(int startPage) {
var pages = _fragmentation!['pages'];
_status = 'Loaded $startPage of ${pages.length} pages';
_r.dirty();
var startY = (startPage * _pageHeight!).round();
var endY = startY + _pageHeight!.round();
if (startPage >= pages.length || endY > _fragmentationData!.height) {
return;
}
var pixel = new PixelReference(_fragmentationData!, new Point(0, startY));
var objects = pages[startPage]['objects'];
for (var i = 0; i < objects.length; i += 2) {
var count = objects[i];
var classId = objects[i + 1];
var color = _classIdToColor[classId];
while (count-- > 0) {
pixel.color = color;
pixel = pixel.next();
}
}
while (pixel.point.y < endY) {
pixel.color = _pageSeparationColor;
pixel = pixel.next();
}
_canvas!.context2D.putImageData(
_fragmentationData!, 0, 0, 0, startY, _fragmentationData!.width, endY);
// Continue with the next page, asynchronously.
new Future(() {
_renderPages(startPage + 1);
});
}
Future _refresh({String? gc}) {
final isolate = _isolate as S.Isolate;
var params = {};
if (gc != null) {
params['gc'] = gc;
}
return isolate.invokeRpc('_getHeapMap', params).then((serviceObject) {
S.ServiceMap response = serviceObject as S.ServiceMap;
assert(response['type'] == 'HeapMap');
_fragmentation = response;
_updateFragmentationData();
});
}
}
// A reference to a particular pixel of ImageData.
class PixelReference {
final ImageData _data;
final int _dataIndex;
static const NUM_COLOR_COMPONENTS = 4;
PixelReference(ImageData data, Point<num> point)
: _data = data,
_dataIndex =
(point.y * data.width + point.x) * NUM_COLOR_COMPONENTS as int;
PixelReference._fromDataIndex(this._data, this._dataIndex);
Point<num> get point => new Point(index % _data.width, index ~/ _data.width);
void set color(Iterable<int> color) {
(_data.data as Uint8ClampedList)
.setRange(_dataIndex, _dataIndex + NUM_COLOR_COMPONENTS, color);
}
Iterable<int> get color => (_data.data as Uint8ClampedList)
.getRange(_dataIndex, _dataIndex + NUM_COLOR_COMPONENTS);
// Returns the next pixel in row-major order.
PixelReference next() => new PixelReference._fromDataIndex(
_data, _dataIndex + NUM_COLOR_COMPONENTS);
// The row-major index of this pixel.
int get index => _dataIndex ~/ NUM_COLOR_COMPONENTS;
}
class ObjectInfo {
final address;
final size;
ObjectInfo(this.address, this.size);
}
File diff suppressed because it is too large Load Diff
@@ -1,102 +0,0 @@
// 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.
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/code_ref.dart';
import 'package:observatory/src/elements/context_ref.dart';
import 'package:observatory/src/elements/error_ref.dart';
import 'package:observatory/src/elements/field_ref.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/icdata_ref.dart';
import 'package:observatory/src/elements/instance_ref.dart';
import 'package:observatory/src/elements/library_ref.dart';
import 'package:observatory/src/elements/local_var_descriptors_ref.dart';
import 'package:observatory/src/elements/megamorphiccache_ref.dart';
import 'package:observatory/src/elements/objectpool_ref.dart';
import 'package:observatory/src/elements/pc_descriptors_ref.dart';
import 'package:observatory/src/elements/script_ref.dart';
import 'package:observatory/src/elements/sentinel_value.dart';
import 'package:observatory/src/elements/singletargetcache_ref.dart';
import 'package:observatory/src/elements/subtypetestcache_ref.dart';
import 'package:observatory/src/elements/type_arguments_ref.dart';
import 'package:observatory/src/elements/unknown_ref.dart';
import 'package:observatory/src/elements/unlinkedcall_ref.dart';
HTMLElement anyRef(M.IsolateRef isolate, ref, M.ObjectRepository objects,
{RenderingQueue? queue, bool expandable = true}) {
if (ref == null) {
return new HTMLSpanElement()..textContent = "???";
}
if (ref is M.Guarded) {
if (ref.isSentinel) {
return anyRef(isolate, ref.asSentinel, objects,
queue: queue, expandable: expandable);
} else {
return anyRef(isolate, ref.asValue, objects,
queue: queue, expandable: expandable);
}
} else if (ref is M.ObjectRef) {
if (ref is M.ClassRef) {
return new ClassRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.CodeRef) {
return new CodeRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.ContextRef) {
return new ContextRefElement(isolate, ref, objects,
queue: queue, expandable: expandable)
.element;
} else if (ref is M.Error) {
return new ErrorRefElement(ref, queue: queue).element;
} else if (ref is M.FieldRef) {
return new FieldRefElement(isolate, ref, objects,
queue: queue, expandable: expandable)
.element;
} else if (ref is M.FunctionRef) {
return new FunctionRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.ICDataRef) {
return new ICDataRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.InstanceRef) {
return new InstanceRefElement(isolate, ref, objects,
queue: queue, expandable: expandable)
.element;
} else if (ref is M.LibraryRef) {
return new LibraryRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.LocalVarDescriptorsRef) {
return new LocalVarDescriptorsRefElement(isolate, ref, queue: queue)
.element;
} else if (ref is M.MegamorphicCacheRef) {
return new MegamorphicCacheRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.ObjectPoolRef) {
return new ObjectPoolRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.PcDescriptorsRef) {
return new PcDescriptorsRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.ScriptRef) {
return new ScriptRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.SingleTargetCacheRef) {
return new SingleTargetCacheRefElement(isolate, ref, queue: queue)
.element;
} else if (ref is M.SubtypeTestCacheRef) {
return new SubtypeTestCacheRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.TypeArgumentsRef) {
return new TypeArgumentsRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.UnknownObjectRef) {
return new UnknownObjectRefElement(isolate, ref, queue: queue).element;
} else if (ref is M.UnlinkedCallRef) {
return new UnlinkedCallRefElement(isolate, ref, queue: queue).element;
} else {
return new HTMLAnchorElement()
..href = Uris.inspect(isolate, object: ref)
..text = 'object';
}
} else if (ref is M.Sentinel) {
return new SentinelValueElement(ref, queue: queue).element;
} else if (ref is num || ref is String) {
return new HTMLSpanElement()..textContent = ref.toString();
}
throw new Exception('Unknown ref type (${ref.runtimeType})');
}
@@ -1,126 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
HTMLElement element(CustomElement e) => e.element;
class CustomElement {
static Expando reverseElements = new Expando();
static CustomElement reverse(HTMLElement element) =>
reverseElements[element] as CustomElement;
static List<CustomElement> toBeAttached = <CustomElement>[];
static void drainAttached() {
// Send 'attached' to elements that have been attached to the document.
bool fired = false;
var connectedElements = toBeAttached
.where((CustomElement element) => element.element.isConnected)
.toList();
for (CustomElement element in connectedElements) {
toBeAttached.remove(element);
element.attached();
fired = true;
}
if (toBeAttached.isEmpty) {
return; // Done.
}
if (fired) {
// The 'attached' events above may have scheduled microtasks that will
// will add more CustomElements to be document, e.g. 'render'.
scheduleMicrotask(() => drainAttached());
}
while (!toBeAttached.isEmpty) {
// Either this element will never be attached or it will be attached
// after a turn of the outer event loop. Fire 'attached' in case it is
// the latter, since firing it out of order is preferable to not firing
// it at all.
CustomElement element = toBeAttached.removeLast();
print("Warning: created but not in document: $element");
element.attached();
}
}
final HTMLElement element;
CustomElement.created(String elementClass)
: element = document.createElement("shadow") as HTMLElement {
reverseElements[element] = this;
element.className = elementClass;
if (toBeAttached.isEmpty) {
scheduleMicrotask(() => drainAttached());
}
toBeAttached.add(this);
}
void attached() {}
void detached() {}
HTMLElement? get parent => element.parentElement as HTMLElement?;
List<Node> get children {
final list = <Node>[];
for (var i = 0; i < element.children.length; i++) {
final child = element.children.item(i);
if (child != null) {
list.add(child);
}
}
return list;
}
set children(List<Node> nodes) {
element.removeChildren();
for (var node in nodes) {
element.appendChild(node);
}
}
CustomElement appendChild(Node node) {
element.appendChild(node);
return this;
}
CustomElement removeChildren() {
element.removeChildren();
return this;
}
CustomElement appendChildren(Iterable<Node> nodes) {
element.appendChildren(nodes);
return this;
}
CustomElement setChildren(Iterable<Node> nodes) {
element.setChildren(nodes);
return this;
}
String get className => element.className;
set className(String c) => element.className = c;
String get title => element.title;
set title(String t) => element.title = t;
String get innerText => element.innerText;
set innerText(String t) => element.innerText = t;
CSSStyleDeclaration get style => element.style;
ElementStream<MouseEvent> get onClick => element.onClick;
DOMRect getBoundingClientRect() => element.getBoundingClientRect();
HTMLCollection getElementsByClassName(String c) =>
element.getElementsByClassName(c);
void scrollIntoView() => element.scrollIntoView();
}
@@ -1,40 +0,0 @@
// Copyright (c) 2025, 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.
import 'package:web/web.dart';
extension ElementAppendChildren on Element {
Element appendChildren(Iterable<Node> nodes) {
for (final node in nodes) {
this.appendChild(node);
}
return this;
}
removeChildren() {
while (true) {
var child = childNodes.item(0);
if (child == null) {
break;
}
removeChild(child);
}
return this;
}
Element setChildren(Iterable<Node> nodes) {
removeChildren();
appendChildren(nodes);
return this;
}
}
HTMLElement toggleClass(HTMLElement element, String classMember) {
if (element.className.contains(classMember)) {
element.className = element.className.replaceAll(classMember, '');
} else {
element.className += classMember;
}
return element;
}
@@ -1,15 +0,0 @@
// Copyright (c) 2016, 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.
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
HTMLElement navBar(List<HTMLElement> content) {
return (document.createElement('nav')
..className = 'nav-bar'
..appendChild(
new HTMLUListElement()..appendChildren(content),
)) as HTMLElement;
}
@@ -1,20 +0,0 @@
// Copyright (c) 2016, 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.
import 'package:web/web.dart';
navMenu(String label, {String? link, List<HTMLElement> content = const []}) {
final ulist = new HTMLUListElement();
for (final element in content) {
ulist.appendChild(element);
}
return new HTMLLIElement()
..className = 'nav-menu'
..appendChild(new HTMLSpanElement()
..className = 'nav-menu_label'
..appendChild(new HTMLAnchorElement()
..href = link ?? ''
..text = label)
..appendChild(ulist));
}
@@ -1,90 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'dart:collection';
import 'dart:js_interop';
import 'package:web/web.dart';
/// A generic rendering task that can be scheduled.
abstract class RenderingTask {
/// Rendering synchronous callback.
void render();
}
/// A generic synchronization system for rendering operations.
abstract class RenderingBarrier {
/// Future to the next synchronization barrier (ms from application start).
Future<num> get next;
}
/// Synchronization system based on the AnimationFrame.
class NextAnimationFrameBarrier implements RenderingBarrier {
Future<num> get next {
final c = Completer<num>();
window.requestAnimationFrame(
((num n) => c.complete(DateTime.now().microsecondsSinceEpoch)).toJS);
return c.future;
}
}
/// MOCK synchronization system for manual barrier triggering.
class RenderingBarrierMock implements RenderingBarrier {
final StreamController<num> _stream = new StreamController<num>.broadcast();
num _ms = 0;
Future<num> get next => _stream.stream.first;
/// Trigger the next barrier with an optional number of ms elapsed.
void triggerRenderingBarrier({num step = 20}) {
_stream.add(_ms += step);
}
}
/// RenderingTask queuing and synchronization system.
class RenderingQueue {
final RenderingBarrier _barrier;
final Queue<RenderingTask> _queue = new Queue<RenderingTask>();
bool get isEmpty => _queue.isEmpty;
bool get isNotEmpty => _queue.isNotEmpty;
/// Creates a RenderingQueue with the default synchronization barrier.
RenderingQueue() : this.fromBarrier(new NextAnimationFrameBarrier());
/// Creates a RenderingQueue with a custom synchronization barrier.
RenderingQueue.fromBarrier(this._barrier);
/// Add a task to the queue.
/// If the current rendering phase is running it will be executed during this
/// rendering cycle, otherwise it will be queued for the next one.
void enqueue(RenderingTask r, {bool waitForBarrier = true}) {
final wasEmpty = _queue.isEmpty;
_queue.addLast(r);
// If no task are in the queue there is no rendering phase scheduled.
if (wasEmpty) {
if (waitForBarrier) {
_render();
} else {
// We schedule the _renderLoop as a microtask to allow the
// scheduleRendering method to terminate, due to the fact that it is
// generally invoked from inside a HtmlElement.attached method
scheduleMicrotask(_renderLoop);
}
}
}
Future _render() async {
await _barrier.next;
_renderLoop();
}
void _renderLoop() {
while (_queue.isNotEmpty) {
_queue.first.render();
_queue.removeFirst();
}
}
}
@@ -1,139 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:observatory/src/elements/helpers/rendering_queue.dart';
export 'package:observatory/src/elements/helpers/rendering_queue.dart';
/// A generic renderable object.
abstract class Renderable {
void render();
}
/// Event related to a Renderable rendering phase.
class RenderedEvent<T> {
/// Renderable to which the event is related
final T element;
/// Is another rendering scheduled for this element.
final bool otherRenderScheduled;
RenderedEvent(this.element, this.otherRenderScheduled) {
assert(element != null);
}
}
/// Scheduler for rendering operations.
class RenderingScheduler<T extends Renderable> implements RenderingTask {
bool _enabled = false;
bool _dirty = false;
bool _renderingScheduled = false;
bool _notificationScheduled = false;
bool _waitForBarrier = false;
/// HTMLElement managed by this scheduler.
final T element;
/// Queue used for rendering operations.
final RenderingQueue queue;
final List<Future> _wait = <Future>[];
/// Does the element need a new rendering cycle.
bool get isDirty => _dirty;
/// Is the scheduler enabled.
bool get isEnabled => _enabled;
final StreamController<RenderedEvent<T>> _onRendered =
new StreamController<RenderedEvent<T>>.broadcast();
Stream<RenderedEvent<T>> get onRendered => _onRendered.stream;
/// Creates a new scheduler for an element.
/// If no queue is provided it will create a new default configured queue.
factory RenderingScheduler(T element, {RenderingQueue? queue}) {
if (queue == null) {
queue = new RenderingQueue();
}
return new RenderingScheduler<T>._(element, queue);
}
RenderingScheduler._(this.element, this.queue);
/// Enable the scheduler.
/// New dirty or schedule request will be considered.
void enable() {
if (_enabled) return;
_enabled = true;
scheduleRendering();
}
/// Disable the scheduler.
/// New dirty or schedule request will be discarded.
/// [optional] notify: send a final RenderEvent.
void disable({bool notify = false}) {
if (!_enabled) return;
_enabled = false;
if (notify) scheduleNotification();
}
/// Set the object as dirty. A rendering will be scheduled.
void dirty() {
if (_dirty) return;
_dirty = true;
scheduleRendering();
}
/// Checks for modification during attribute set.
/// If value changes a new rendering is scheduled.
/// set attr(T v) => _attr = _r.checkAndReact(_attr, v);
T checkAndReact<T>(T oldValue, T newValue) {
if (oldValue != newValue)
dirty();
else
scheduleNotification();
return newValue;
}
/// Schedules a new rendering phase.
void scheduleRendering() {
if (_renderingScheduled) return;
if (!_enabled) return;
queue.enqueue(this, waitForBarrier: _waitForBarrier);
_waitForBarrier = true;
_renderingScheduled = true;
}
/// Renders the element (if the scheduler is enabled).
/// It will clear the dirty flag.
void render() {
_renderingScheduled = false;
if (!_enabled) return;
_dirty = false;
_wait.clear();
element.render();
scheduleNotification();
if (_dirty) scheduleRendering();
}
/// Schedules a notification.
void scheduleNotification() {
if (_notificationScheduled) return;
_notify();
_notificationScheduled = true;
}
void waitFor(Iterable<Future> it) {
_wait.addAll(it);
}
Future _notify() async {
await Future.wait(_wait);
_wait.clear();
_onRendered.add(new RenderedEvent<T>(element, _dirty));
_notificationScheduled = false;
}
}
@@ -1,52 +0,0 @@
// Copyright (c) 2016, 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.
import 'package:observatory/models.dart' as M;
/// Utility class for URIs generation.
abstract class Uris {
static String _isolatePage(String path, M.IsolateRef isolate,
{M.ObjectRef? object}) {
final parameters = {'isolateId': isolate.id};
if (object != null) parameters['objectId'] = object.id;
return '#' + new Uri(path: path, queryParameters: parameters).toString();
}
static String allocationProfiler(M.IsolateRef isolate) =>
_isolatePage('/allocation-profiler', isolate);
static String classTree(M.IsolateRef isolate) =>
_isolatePage('/class-tree', isolate);
static String cpuProfiler(M.IsolateRef isolate) =>
_isolatePage('/profiler', isolate);
static String cpuProfilerTable(M.IsolateRef isolate) =>
_isolatePage('/profiler-table', isolate);
static String debugger(M.IsolateRef isolate) =>
_isolatePage('/debugger', isolate);
static String flags() => '#/flags';
static String heapMap(M.IsolateRef isolate) =>
_isolatePage('/heap-map', isolate);
static String heapSnapshot(M.IsolateRef isolate) =>
_isolatePage('/heap-snapshot', isolate);
static String inspect(M.IsolateRef isolate, {M.ObjectRef? object, int? pos}) {
if (pos == null) {
return _isolatePage('/inspect', isolate, object: object);
}
return _isolatePage('/inspect', isolate, object: object) + '---pos=${pos}';
}
static String logging(M.IsolateRef isolate) =>
_isolatePage('/logging', isolate);
static String metrics(M.IsolateRef isolate) =>
_isolatePage('/metrics', isolate);
static String nativeMemory() => '#/native-memory-profile';
static String processSnapshot() => '#/process-snapshot';
static String objectStore(M.IsolateRef isolate) =>
_isolatePage('/object-store', isolate);
static String persistentHandles(M.IsolateRef isolate) =>
_isolatePage('/persistent-handles', isolate);
static String ports(M.IsolateRef isolate) => _isolatePage('/ports', isolate);
static String timeline() => '#/timeline';
static String vm() => '#/vm';
static String vmConnect() => '#/vm-connect';
}
@@ -1,62 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, ICDataRef;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class ICDataRefElement extends CustomElement implements Renderable {
late RenderingScheduler<ICDataRefElement> _r;
Stream<RenderedEvent<ICDataRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.ICDataRef _icdata;
M.IsolateRef get isolate => _isolate;
M.ICDataRef get icdata => _icdata;
factory ICDataRefElement(M.IsolateRef isolate, M.ICDataRef icdata,
{RenderingQueue? queue}) {
ICDataRefElement e = new ICDataRefElement.created();
e._r = new RenderingScheduler<ICDataRefElement>(e, queue: queue);
e._isolate = isolate;
e._icdata = icdata;
return e;
}
ICDataRefElement.created() : super.created('icdata-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
setChildren(<HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _icdata)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = 'ICData',
new HTMLSpanElement()..textContent = ' (${_icdata.selector})'
])
]);
}
}
@@ -1,178 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/object_common.dart';
class ICDataViewElement extends CustomElement implements Renderable {
late RenderingScheduler<ICDataViewElement> _r;
Stream<RenderedEvent<ICDataViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.ICData _icdata;
late M.ICDataRepository _icdatas;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ObjectRepository _objects;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.ICData get icdata => _icdata;
factory ICDataViewElement(
M.VM vm,
M.IsolateRef isolate,
M.ICData icdata,
M.EventRepository events,
M.NotificationRepository notifications,
M.ICDataRepository icdatas,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
ICDataViewElement e = new ICDataViewElement.created();
e._r = new RenderingScheduler<ICDataViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._icdata = icdata;
e._icdatas = icdatas;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._objects = objects;
return e;
}
ICDataViewElement.created() : super.created('icdata-view');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
setChildren(<HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('icdata'),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_icdata = await _icdatas.get(_isolate, _icdata.id!);
_r.dirty();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'ICData',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _icdata, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'selector',
new HTMLDivElement()
..className = 'memberName'
..textContent = _icdata.selector ?? ''
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'owner',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
_icdata.dartOwner == null
? (new HTMLSpanElement()..textContent = '<none>')
: anyRef(_isolate, _icdata.dartOwner, _objects,
queue: _r.queue)
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'argumentsDescriptor',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
_icdata.argumentsDescriptor == null
? (new HTMLSpanElement()..textContent = '<none>')
: anyRef(
_isolate, _icdata.argumentsDescriptor, _objects,
queue: _r.queue)
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'entries',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
_icdata.entries == null
? (new HTMLSpanElement()..textContent = '<none>')
: anyRef(_isolate, _icdata.entries, _objects,
queue: _r.queue)
])
])
]),
new HTMLHRElement(),
])
]);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 B

@@ -1,121 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class InboundReferencesElement extends CustomElement implements Renderable {
late RenderingScheduler<InboundReferencesElement> _r;
Stream<RenderedEvent<InboundReferencesElement>> get onRendered =>
_r.onRendered;
late M.IsolateRef _isolate;
late M.ObjectRef _object;
late M.InboundReferencesRepository _references;
late M.ObjectRepository _objects;
M.InboundReferences? _inbounds;
bool _expanded = false;
M.IsolateRef get isolate => _isolate;
M.ObjectRef get object => _object;
factory InboundReferencesElement(M.IsolateRef isolate, M.ObjectRef object,
M.InboundReferencesRepository references, M.ObjectRepository objects,
{RenderingQueue? queue}) {
InboundReferencesElement e = new InboundReferencesElement.created();
e._r = new RenderingScheduler<InboundReferencesElement>(e, queue: queue);
e._isolate = isolate;
e._object = object;
e._references = references;
e._objects = objects;
return e;
}
InboundReferencesElement.created() : super.created('inbound-references');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
final curlyBlock =
new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
..content = _createContent()
..onToggle.listen((e) async {
_expanded = e.control.expanded;
if (_expanded) {
e.control.disabled = true;
await _refresh();
e.control.disabled = false;
}
});
setChildren(<HTMLElement>[curlyBlock.element]);
_r.waitFor([curlyBlock.onRendered.first]);
}
Future _refresh() async {
_inbounds = await _references.get(_isolate, _object.id!);
_r.dirty();
}
List<HTMLElement> _createContent() {
if (_inbounds == null) {
return const [];
}
return _inbounds!.elements.map<HTMLElement>(_createItem).toList();
}
HTMLElement _createItem(M.InboundReference reference) {
final content = <HTMLElement>[];
if (reference.parentField is M.Object) {
content.addAll([
new HTMLSpanElement()..textContent = 'referenced by ',
anyRef(_isolate, reference.parentField, _objects, queue: _r.queue),
new HTMLSpanElement()..textContent = ' of '
]);
} else if (reference.parentField is String ||
reference.parentField is int) {
content.add(new HTMLSpanElement()
..textContent = 'referenced by [ ${reference.parentField} ] of ');
} else if (reference.parentListIndex != null) {
content.add(new HTMLSpanElement()
..textContent = 'referenced by [ ${reference.parentListIndex} ] of ');
} else if (reference.parentWordOffset != null) {
content.add(new HTMLSpanElement()
..textContent =
'referenced by offset ${reference.parentWordOffset} of ');
}
content.addAll([
anyRef(_isolate, reference.source, _objects, queue: _r.queue),
new InboundReferencesElement(
_isolate, reference.source, _references, _objects,
queue: _r.queue)
.element
]);
return new HTMLDivElement()
..className = 'indent'
..appendChildren(content);
}
}
@@ -1,433 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/field_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/utils.dart';
class InstanceRefElement extends CustomElement implements Renderable {
late RenderingScheduler<InstanceRefElement> _r;
Stream<RenderedEvent<InstanceRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.InstanceRef _instance;
late M.ObjectRepository _objects;
M.Instance? _loadedInstance;
late bool _expandable;
late bool _expanded = false;
M.IsolateRef get isolate => _isolate;
M.InstanceRef get instance => _instance;
factory InstanceRefElement(
M.IsolateRef isolate, M.InstanceRef instance, M.ObjectRepository objects,
{RenderingQueue? queue, bool expandable = true}) {
InstanceRefElement e = new InstanceRefElement.created();
e._r = new RenderingScheduler<InstanceRefElement>(e, queue: queue);
e._isolate = isolate;
e._instance = instance;
e._objects = objects;
e._expandable = expandable;
return e;
}
InstanceRefElement.created() : super.created('instance-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
final content = _createLink();
if (_expandable && _hasValue()) {
content.addAll([
new HTMLSpanElement()..textContent = ' ',
(new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'indent'
..appendChildren(_createValue())
]
..onToggle.listen((e) async {
_expanded = e.control.expanded;
if (_expanded) {
e.control.disabled = true;
await _refresh();
e.control.disabled = false;
}
}))
.element
]);
}
children = content;
}
Future _refresh() async {
_loadedInstance = await _objects.get(_isolate, _instance.id!) as M.Instance;
_r.dirty();
}
List<HTMLElement> _createShowMoreButton() {
if (_loadedInstance!.count == null) {
return [];
}
final count = _loadedInstance!.count;
final button = new HTMLButtonElement()..textContent = 'show next ${count}';
button.onClick.listen((_) async {
button.disabled = true;
_loadedInstance =
await _objects.get(_isolate, _instance.id!) as M.Instance;
_r.dirty();
});
return [button];
}
List<HTMLElement> _createLink() {
switch (_instance.kind) {
case M.InstanceKind.vNull:
case M.InstanceKind.bool:
case M.InstanceKind.int:
case M.InstanceKind.double:
case M.InstanceKind.float32x4:
case M.InstanceKind.float64x2:
case M.InstanceKind.int32x4:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..text = _instance.valueAsString ?? ''
];
case M.InstanceKind.string:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..text = Utils.formatStringAsLiteral(
_instance.valueAsString!, _instance.valueAsStringIsTruncated!)
];
case M.InstanceKind.type:
case M.InstanceKind.functionType:
case M.InstanceKind.typeParameter:
case M.InstanceKind.recordType:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..text = _instance.name ?? ''
];
case M.InstanceKind.closure:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = 'Closure',
new HTMLSpanElement()
..textContent = ' (${_instance.closureFunction!.name})'
])
];
case M.InstanceKind.regExp:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = _instance.clazz!.name ?? '',
new HTMLSpanElement()
..textContent = ' (${_instance.pattern!.valueAsString})'
])
];
case M.InstanceKind.userTag:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = _instance.clazz!.name ?? '',
new HTMLSpanElement()..textContent = ' (${_instance.name})'
])
];
case M.InstanceKind.stackTrace:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = _instance.clazz!.name ?? '',
])
];
case M.InstanceKind.plainInstance:
case M.InstanceKind.receivePort:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..className = 'emphasize'
..text = _instance.clazz!.name ?? ''
];
case M.InstanceKind.list:
case M.InstanceKind.map:
case M.InstanceKind.set:
case M.InstanceKind.uint8ClampedList:
case M.InstanceKind.uint8List:
case M.InstanceKind.uint16List:
case M.InstanceKind.uint32List:
case M.InstanceKind.uint64List:
case M.InstanceKind.int8List:
case M.InstanceKind.int16List:
case M.InstanceKind.int32List:
case M.InstanceKind.int64List:
case M.InstanceKind.float32List:
case M.InstanceKind.float64List:
case M.InstanceKind.int32x4List:
case M.InstanceKind.float32x4List:
case M.InstanceKind.float64x2List:
return [
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = _instance.clazz!.name ?? '',
new HTMLSpanElement()..textContent = ' (${_instance.length})'
])
];
case M.InstanceKind.mirrorReference:
case M.InstanceKind.weakProperty:
case M.InstanceKind.finalizer:
case M.InstanceKind.nativeFinalizer:
case M.InstanceKind.finalizerEntry:
case M.InstanceKind.weakReference:
case M.InstanceKind.record:
return [
HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _instance)
..className = 'emphasize'
..textContent = _instance.clazz!.name ?? ''
];
default:
throw new Exception('Unknown InstanceKind: ${_instance.kind}');
}
}
bool _hasValue() {
switch (_instance.kind) {
case M.InstanceKind.closure:
case M.InstanceKind.plainInstance:
case M.InstanceKind.mirrorReference:
case M.InstanceKind.stackTrace:
case M.InstanceKind.weakReference:
case M.InstanceKind.weakProperty:
case M.InstanceKind.recordType:
case M.InstanceKind.finalizer:
case M.InstanceKind.nativeFinalizer:
case M.InstanceKind.finalizerEntry:
return true;
case M.InstanceKind.list:
case M.InstanceKind.map:
case M.InstanceKind.set:
case M.InstanceKind.uint8ClampedList:
case M.InstanceKind.uint8List:
case M.InstanceKind.uint16List:
case M.InstanceKind.uint32List:
case M.InstanceKind.uint64List:
case M.InstanceKind.int8List:
case M.InstanceKind.int16List:
case M.InstanceKind.int32List:
case M.InstanceKind.int64List:
case M.InstanceKind.float32List:
case M.InstanceKind.float64List:
case M.InstanceKind.int32x4List:
case M.InstanceKind.float32x4List:
case M.InstanceKind.float64x2List:
return _instance.length! > 0;
default:
return false;
}
}
List<HTMLElement> _createValue() {
if (_loadedInstance == null) {
return [new HTMLSpanElement()..textContent = 'Loading...'];
}
switch (_instance.kind) {
case M.InstanceKind.closure:
{
var members = <HTMLElement>[];
if (_loadedInstance!.closureFunction != null) {
members.add(new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'function = ',
anyRef(_isolate, _loadedInstance!.closureFunction, _objects,
queue: _r.queue)
]));
}
if (_loadedInstance!.closureContext != null) {
members.add(new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'context = ',
anyRef(_isolate, _loadedInstance!.closureContext, _objects,
queue: _r.queue)
]));
}
if (_loadedInstance!.closureReceiver != null) {
members.add(new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'receiver = ',
anyRef(_isolate, _loadedInstance!.closureReceiver, _objects,
queue: _r.queue)
]));
}
return members;
}
case M.InstanceKind.plainInstance:
return _loadedInstance!.fields!
.map<HTMLElement>((f) => new HTMLDivElement()
..appendChildren(<HTMLElement>[
new FieldRefElement(_isolate, f.decl!, _objects,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ' = ',
anyRef(_isolate, f.value, _objects, queue: _r.queue)
]))
.toList();
case M.InstanceKind.list:
var index = 0;
return _loadedInstance!.elements!
.map<HTMLElement>((element) => new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = '[ ${index++} ] : ',
anyRef(_isolate, element, _objects, queue: _r.queue)
]))
.toList()
..addAll(_createShowMoreButton());
case M.InstanceKind.map:
return _loadedInstance!.associations!
.map<HTMLElement>((association) => new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = '[ ',
anyRef(_isolate, association.key, _objects, queue: _r.queue),
new HTMLSpanElement()..textContent = ' ] : ',
anyRef(_isolate, association.value, _objects, queue: _r.queue)
]))
.toList()
..addAll(_createShowMoreButton());
case M.InstanceKind.set:
return _loadedInstance!.elements!
.map<HTMLElement>((element) => new HTMLDivElement()
..appendChildren(<HTMLElement>[
anyRef(_isolate, element, _objects, queue: _r.queue)
]))
.toList()
..addAll(_createShowMoreButton());
case M.InstanceKind.uint8ClampedList:
case M.InstanceKind.uint8List:
case M.InstanceKind.uint16List:
case M.InstanceKind.uint32List:
case M.InstanceKind.uint64List:
case M.InstanceKind.int8List:
case M.InstanceKind.int16List:
case M.InstanceKind.int32List:
case M.InstanceKind.int64List:
case M.InstanceKind.float32List:
case M.InstanceKind.float64List:
case M.InstanceKind.int32x4List:
case M.InstanceKind.float32x4List:
case M.InstanceKind.float64x2List:
var index = 0;
return _loadedInstance!.typedElements!
.map<HTMLElement>((e) =>
new HTMLDivElement()..textContent = '[ ${index++} ] : $e')
.toList()
..addAll(_createShowMoreButton());
case M.InstanceKind.mirrorReference:
return [
new HTMLSpanElement()..textContent = '<referent> : ',
anyRef(_isolate, _loadedInstance!.referent, _objects, queue: _r.queue)
];
case M.InstanceKind.stackTrace:
return [
new HTMLDivElement()
..className = 'stackTraceBox'
..textContent = _instance.valueAsString ?? ''
];
case M.InstanceKind.weakReference:
return [
new HTMLSpanElement()..textContent = '<target> : ',
anyRef(_isolate, _loadedInstance!.target, _objects, queue: _r.queue)
];
case M.InstanceKind.weakProperty:
return [
new HTMLSpanElement()..textContent = '<key> : ',
anyRef(_isolate, _loadedInstance!.key!, _objects, queue: _r.queue),
new HTMLBRElement(),
new HTMLSpanElement()..textContent = '<value> : ',
anyRef(_isolate, _loadedInstance!.value!, _objects, queue: _r.queue),
];
case M.InstanceKind.recordType:
final fields = _loadedInstance!.fields!.toList();
return [
for (int i = 0; i < fields.length; ++i) ...[
new HTMLSpanElement()..textContent = '${fields[i].name} = ',
new InstanceRefElement(
_isolate, fields[i].value!.asValue!, _objects,
queue: _r.queue)
.element,
if (i + 1 != fields.length) new HTMLBRElement(),
]
];
case M.InstanceKind.finalizer:
return [
new HTMLSpanElement()..textContent = 'callback = ',
anyRef(_isolate, _loadedInstance!.callback!, _objects,
queue: _r.queue),
new HTMLBRElement(),
new HTMLSpanElement()..textContent = 'allEntries = ',
anyRef(_isolate, _loadedInstance!.allEntries!, _objects,
queue: _r.queue),
];
case M.InstanceKind.nativeFinalizer:
return [
new HTMLSpanElement()..textContent = 'allEntries = ',
anyRef(_isolate, _loadedInstance!.allEntries!, _objects,
queue: _r.queue),
];
case M.InstanceKind.finalizerEntry:
return [
new HTMLSpanElement()..textContent = 'value = ',
anyRef(_isolate, _loadedInstance!.value!, _objects, queue: _r.queue),
new HTMLBRElement(),
new HTMLSpanElement()..textContent = 'detach = ',
anyRef(_isolate, _loadedInstance!.detach!, _objects, queue: _r.queue),
new HTMLBRElement(),
new HTMLSpanElement()..textContent = 'token = ',
anyRef(_isolate, _loadedInstance!.token!, _objects, queue: _r.queue),
];
default:
return [];
}
}
}
@@ -1,517 +0,0 @@
// 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 instance_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/eval_box.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/instance_ref.dart';
import 'package:observatory/src/elements/nav/class_menu.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/library_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/source_inset.dart';
import 'package:observatory/utils.dart';
class InstanceViewElement extends CustomElement implements Renderable {
late RenderingScheduler<InstanceViewElement> _r;
Stream<RenderedEvent<InstanceViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Instance _instance;
M.LibraryRef? _library;
late M.ObjectRepository _objects;
late M.ClassRepository _classes;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ScriptRepository _scripts;
late M.EvalRepository _eval;
M.TypeArguments? _typeArguments;
late M.TypeArgumentsRepository _arguments;
late M.BreakpointRepository _breakpoints;
late M.FunctionRepository _functions;
M.SourceLocation? _location;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Instance get instance => _instance;
factory InstanceViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Instance instance,
M.EventRepository events,
M.NotificationRepository notifications,
M.ObjectRepository objects,
M.ClassRepository classes,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ScriptRepository scripts,
M.EvalRepository eval,
M.TypeArgumentsRepository arguments,
M.BreakpointRepository breakpoints,
M.FunctionRepository functions,
{RenderingQueue? queue}) {
InstanceViewElement e = new InstanceViewElement.created();
e._r = new RenderingScheduler<InstanceViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._instance = instance;
e._objects = objects;
e._classes = classes;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._scripts = scripts;
e._eval = eval;
e._arguments = arguments;
e._breakpoints = breakpoints;
e._functions = functions;
return e;
}
InstanceViewElement.created() : super.created('instance-view');
@override
attached() {
super.attached();
_r.enable();
_loadExtraData();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
final content = <HTMLElement>[
new HTMLHeadingElement.h2()
..textContent = M.isAbstractType(_instance.kind)
? 'type ${_instance.name}'
: 'instance of ${_instance.clazz!.name}',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _instance, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_createMembers()),
new HTMLHRElement(),
new EvalBoxElement(_isolate, _instance, _objects, _eval,
quickExpressions: const ['toString()', 'runtimeType'],
queue: _r.queue)
.element
];
if (_location != null) {
content.addAll([
new HTMLHRElement(),
new SourceInsetElement(
_isolate, _location!, _scripts, _objects, _events,
queue: _r.queue)
.element
]);
}
children = <HTMLElement>[
navBar(_createMenu()),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(content)
];
}
List<HTMLElement> _createMenu() {
final menu = <HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element
];
if (_library != null) {
menu.add(new NavLibraryMenuElement(_isolate, _library!, queue: _r.queue)
.element);
}
menu.addAll(<HTMLElement>[
new NavClassMenuElement(_isolate, _instance.clazz!, queue: _r.queue)
.element,
navMenu('instance'),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]);
return menu;
}
HTMLElement memberHalf(String cssClass, dynamic half) {
var result = new HTMLDivElement()..className = cssClass;
if (half is String) {
result.textContent = half;
} else {
result.setChildren(
<HTMLElement>[anyRef(_isolate, half, _objects, queue: _r.queue)]);
}
return result;
}
HTMLElement member(dynamic name, dynamic value) {
return new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
memberHalf('memberName', name),
memberHalf('memberValue', value),
]);
}
List<HTMLElement> _createMembers() {
final members = <HTMLElement>[];
if (_instance.valueAsString != null) {
if (_instance.kind == M.InstanceKind.string) {
members.add(member(
'value as literal',
Utils.formatStringAsLiteral(_instance.valueAsString!,
_instance.valueAsStringIsTruncated!)));
} else {
members.add(member('value', _instance.valueAsString));
}
}
if (_instance.typeClass != null) {
members.add(member('type class', _instance.typeClass));
}
if (_typeArguments != null && _typeArguments!.types!.isNotEmpty) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'type arguments',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(([new HTMLSpanElement()..textContent = '< ']
..addAll(_typeArguments!.types!.expand((type) => [
new InstanceRefElement(_isolate, type, _objects,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ', '
]))
..removeLast()
..add(new HTMLSpanElement()..textContent = ' >')))
]));
}
if (_instance.parameterizedClass != null) {
members.add(member('parameterized class', _instance.parameterizedClass));
}
if (_instance.parameterIndex != null) {
members.add(member('parameter index', '${_instance.parameterIndex}'));
}
if (_instance.bound != null) {
members.add(member('bound', _instance.bound));
}
if (_instance.closureFunction != null) {
members.add(member('closure function', _instance.closureFunction));
}
if (_instance.closureContext != null) {
members.add(member('closure context', _instance.closureContext));
}
if (_instance.closureReceiver != null) {
members.add(member('closure receiver', _instance.closureReceiver));
}
if (_instance.kind == M.InstanceKind.closure) {
late HTMLButtonElement btn;
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'closure breakpoint',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
btn = new HTMLButtonElement()
..textContent = _instance.activationBreakpoint == null
? 'break on activation'
: 'remove'
..onClick.listen((_) {
btn.disabled = true;
_toggleBreakpoint();
})
])
]));
}
if (_instance.nativeFields != null && _instance.nativeFields!.isNotEmpty) {
int i = 0;
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'native fields (${_instance.nativeFields!.length})',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: _instance.nativeFields!.length <= 100,
queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(_instance.nativeFields!
.map<HTMLElement>(
(f) => member('[ ${i++} ]', '[ ${f.value} ]')))
])
.element
])
]));
}
if (_instance.fields != null && _instance.fields!.isNotEmpty) {
final fields = _instance.fields!.toList();
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'fields (${fields.length})',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: fields.length <= 100, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(fields.map<HTMLElement>((f) {
final name = _instance.kind == M.InstanceKind.record
? f.name
: f.decl;
return member(name, f.value);
}))
])
.element
])
]));
}
if (_instance.elements != null && _instance.elements!.isNotEmpty) {
final elements = _instance.elements!.toList();
int i = 0;
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'elements (${_instance.length})',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: elements.length <= 100, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(elements.map<HTMLElement>(
(element) => member('[ ${i++} ]', element)))
])
.element
])
]));
if (_instance.length != elements.length) {
members.add(member(
'...', '${_instance.length! - elements.length} omitted elements'));
}
}
if (_instance.associations != null && _instance.associations!.isNotEmpty) {
final associations = _instance.associations!.toList();
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'associations (${_instance.length})',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: associations.length <= 100, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(associations
.map<HTMLElement>((a) => new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = '[ ',
anyRef(_isolate, a.key, _objects,
queue: _r.queue),
new HTMLSpanElement()..textContent = ' ]',
]),
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
anyRef(_isolate, a.value, _objects,
queue: _r.queue)
])
])))
])
.element
])
]));
if (_instance.length != associations.length) {
members.add(member('...',
'${_instance.length! - associations.length} omitted elements'));
}
}
if (_instance.typedElements != null &&
_instance.typedElements!.isNotEmpty) {
final typedElements = _instance.typedElements!.toList();
int i = 0;
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'elements (${_instance.length})',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(
expanded: typedElements.length <= 100, queue: _r.queue)
..content = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(typedElements.map<HTMLElement>(
(e) => member('[ ${i++} ]', '$e')))
])
.element
])
]));
if (_instance.length != typedElements.length) {
members.add(member('...',
'${_instance.length! - typedElements.length} omitted elements'));
}
}
if (_instance.kind == M.InstanceKind.regExp) {
members.add(member('pattern', _instance.pattern));
members.add(
member('isCaseSensitive', _instance.isCaseSensitive! ? 'yes' : 'no'));
members.add(member('isMultiLine', _instance.isMultiLine! ? 'yes' : 'no'));
if (_instance.oneByteFunction != null) {
members.add(member('oneByteFunction', _instance.oneByteFunction));
}
if (_instance.twoByteFunction != null) {
members.add(member('twoByteFunction', _instance.twoByteFunction));
}
if (_instance.oneByteBytecode != null) {
members.add(member('oneByteBytecode', _instance.oneByteBytecode));
}
if (_instance.twoByteBytecode != null) {
members.add(member('twoByteBytecode', _instance.twoByteBytecode));
}
}
if (_instance.kind == M.InstanceKind.mirrorReference) {
members.add(member('referent', _instance.referent));
}
if (_instance.kind == M.InstanceKind.weakReference) {
members.add(member('target', _instance.target));
}
if (_instance.kind == M.InstanceKind.weakProperty) {
members.add(member('key', _instance.key));
members.add(member('value', _instance.value));
}
if (_instance.kind == M.InstanceKind.finalizer) {
members.add(member('callback', _instance.callback));
members.add(member('allEntries', _instance.allEntries));
}
if (_instance.kind == M.InstanceKind.nativeFinalizer) {
members.add(member('callback', _instance.allEntries));
}
if (_instance.kind == M.InstanceKind.finalizerEntry) {
members.add(member('value', _instance.value));
members.add(member('detach', _instance.detach));
members.add(member('token', _instance.token));
}
return members;
}
Future _refresh() async {
_instance = await _objects.get(_isolate, _instance.id!) as M.Instance;
await _loadExtraData();
_r.dirty();
}
Future _loadExtraData() async {
_library = (await _classes.get(_isolate, _instance.clazz!.id!)).library!;
if (_instance.typeArguments != null) {
_typeArguments =
await _arguments.get(_isolate, _instance.typeArguments!.id!);
} else {
_typeArguments = null;
}
if (_instance.closureFunction != null) {
_location =
(await _functions.get(_isolate, _instance.closureFunction!.id!))
.location;
} else if (_instance.typeClass != null) {
_location =
(await _classes.get(_isolate, _instance.typeClass!.id!)).location;
}
_r.dirty();
}
Future _toggleBreakpoint() async {
if (_instance.activationBreakpoint == null) {
await _breakpoints.addOnActivation(_isolate, _instance);
} else {
await _breakpoints.remove(_isolate, _instance.activationBreakpoint!);
}
await _refresh();
}
}
@@ -1,67 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class IsolateCounterChartElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateCounterChartElement> _r;
Stream<RenderedEvent<IsolateCounterChartElement>> get onRendered =>
_r.onRendered;
late Map _counters;
late StreamSubscription _subscription;
factory IsolateCounterChartElement(Map counters, {RenderingQueue? queue}) {
IsolateCounterChartElement e = new IsolateCounterChartElement.created();
e._r = new RenderingScheduler<IsolateCounterChartElement>(e, queue: queue);
e._counters = counters;
return e;
}
IsolateCounterChartElement.created() : super.created('isolate-counter-chart');
@override
void attached() {
super.attached();
_r.enable();
_subscription = element(this).onResize.listen((_) => _r.dirty());
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_subscription.cancel();
}
void render() {
var members = <HTMLElement>[];
_counters.forEach((key, value) {
members.add(new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = key,
new HTMLDivElement()
..className = 'memberValue'
..textContent = value,
]));
});
children = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(members)
];
}
}
@@ -1,129 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/source_link.dart';
class IsolateLocationElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateLocationElement> _r;
Stream<RenderedEvent<IsolateLocationElement>> get onRendered => _r.onRendered;
late M.Isolate _isolate;
late M.EventRepository _events;
late M.ScriptRepository _scripts;
late StreamSubscription _debugSubscription;
late StreamSubscription _isolateSubscription;
factory IsolateLocationElement(
M.Isolate isolate, M.EventRepository events, M.ScriptRepository scripts,
{RenderingQueue? queue}) {
IsolateLocationElement e = new IsolateLocationElement.created();
e._r = new RenderingScheduler<IsolateLocationElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
e._scripts = scripts;
return e;
}
IsolateLocationElement.created() : super.created('isolate-location');
@override
void attached() {
super.attached();
_r.enable();
_debugSubscription = _events.onDebugEvent.listen(_eventListener);
_isolateSubscription = _events.onIsolateEvent.listen(_eventListener);
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_debugSubscription.cancel();
_isolateSubscription.cancel();
}
void render() {
switch (_isolate.status) {
case M.IsolateStatus.loading:
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'not yet runnable'
];
break;
case M.IsolateStatus.running:
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'at ',
new FunctionRefElement(
_isolate, M.topFrame(_isolate.pauseEvent)!.function!,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ' (',
new SourceLinkElement(_isolate,
M.topFrame(_isolate.pauseEvent)!.location!, _scripts,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ') '
];
break;
case M.IsolateStatus.paused:
if (_isolate.pauseEvent is M.PauseStartEvent) {
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'at isolate start'
];
} else if (_isolate.pauseEvent is M.PauseExitEvent) {
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'at isolate exit'
];
} else if (_isolate.pauseEvent is M.NoneEvent) {
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'not yet runnable'
];
} else {
final content = <HTMLElement>[];
if (_isolate.pauseEvent is M.PauseBreakpointEvent) {
content.add(new HTMLSpanElement()..textContent = 'by breakpoint');
} else if (_isolate.pauseEvent is M.PauseExceptionEvent) {
content.add(new HTMLSpanElement()..textContent = 'by exception');
}
if (M.topFrame(_isolate.pauseEvent) != null) {
content.addAll([
new HTMLSpanElement()..textContent = ' at ',
new FunctionRefElement(
_isolate, M.topFrame(_isolate.pauseEvent)!.function!,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ' (',
new SourceLinkElement(_isolate,
M.topFrame(_isolate.pauseEvent)!.location!, _scripts,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ') '
]);
}
children = content;
}
break;
default:
children = const [];
}
}
void _eventListener(e) {
if (e.isolate.id == _isolate.id) {
// This view doesn't display registered service extensions.
if (e is! M.ServiceRegisteredEvent && e is! M.ServiceUnregisteredEvent) {
_r.dirty();
}
}
}
}
@@ -1,85 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class IsolateRunStateElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateRunStateElement> _r;
Stream<RenderedEvent<IsolateRunStateElement>> get onRendered => _r.onRendered;
late M.Isolate _isolate;
late M.EventRepository _events;
late StreamSubscription _debugSubscription;
late StreamSubscription _isolateSubscription;
factory IsolateRunStateElement(M.Isolate isolate, M.EventRepository events,
{RenderingQueue? queue}) {
IsolateRunStateElement e = new IsolateRunStateElement.created();
e._r = new RenderingScheduler<IsolateRunStateElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
return e;
}
IsolateRunStateElement.created() : super.created('isolate-run-state');
@override
void attached() {
super.attached();
_r.enable();
_debugSubscription = _events.onDebugEvent.listen(_eventListener);
_isolateSubscription = _events.onIsolateEvent.listen(_eventListener);
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_debugSubscription.cancel();
_isolateSubscription.cancel();
}
void render() {
switch (_isolate.status!) {
case M.IsolateStatus.loading:
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'loading... '
];
break;
case M.IsolateStatus.running:
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'running '
];
break;
case M.IsolateStatus.idle:
children = <HTMLElement>[new HTMLSpanElement()..textContent = 'idle '];
break;
case M.IsolateStatus.paused:
children = <HTMLElement>[
new HTMLSpanElement()
..title = '${_isolate.pauseEvent!.timestamp}'
..textContent = 'paused '
];
break;
}
}
void _eventListener(e) {
if (e.isolate.id == _isolate.id) {
// This view doesn't display registered service extensions.
if (e is! M.ServiceRegisteredEvent && e is! M.ServiceUnregisteredEvent) {
_isolate = e.isolate;
_r.dirty();
}
}
}
}
@@ -1,197 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/isolate/counter_chart.dart';
import 'package:observatory/utils.dart';
class IsolateSharedSummaryElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateSharedSummaryElement> _r;
Stream<RenderedEvent<IsolateSharedSummaryElement>> get onRendered =>
_r.onRendered;
late M.Isolate _isolate;
late M.EventRepository _events;
late StreamSubscription _isolateSubscription;
factory IsolateSharedSummaryElement(
M.Isolate isolate, M.EventRepository events,
{RenderingQueue? queue}) {
IsolateSharedSummaryElement e = new IsolateSharedSummaryElement.created();
e._r = new RenderingScheduler<IsolateSharedSummaryElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
return e;
}
IsolateSharedSummaryElement.created()
: super.created('isolate-shared-summary');
@override
void attached() {
super.attached();
_r.enable();
_isolateSubscription = _events.onIsolateEvent.listen(_eventListener);
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_isolateSubscription.cancel();
}
void render() {
final newHeapUsed = Utils.formatSize(_isolate.newSpace!.used);
final newHeapCapacity = Utils.formatSize(_isolate.newSpace!.capacity);
final oldHeapUsed = Utils.formatSize(_isolate.oldSpace!.used);
final oldHeapCapacity = Utils.formatSize(_isolate.oldSpace!.capacity);
final content = <HTMLElement>[
new HTMLDivElement()
..className = 'menu'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'new heap',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$newHeapUsed of $newHeapCapacity',
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'old heap',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$oldHeapUsed of $oldHeapCapacity',
])
]),
new HTMLBRElement(),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.debugger(_isolate)
..textContent = 'debugger'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.classTree(_isolate)
..textContent = 'class hierarchy'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.cpuProfiler(_isolate)
..textContent = 'cpu profile'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.cpuProfilerTable(_isolate)
..textContent = 'cpu profile (table)'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.allocationProfiler(_isolate)
..textContent = 'allocation profile'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.heapSnapshot(_isolate)
..textContent = 'heap snapshot'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.heapMap(_isolate)
..textContent = 'heap map'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.metrics(_isolate)
..textContent = 'metrics'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.persistentHandles(_isolate)
..textContent = 'persistent handles'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.ports(_isolate)
..textContent = 'ports'
]),
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'see ',
new HTMLAnchorElement()
..href = Uris.logging(_isolate)
..textContent = 'logging'
])
]),
new IsolateCounterChartElement(_isolate.counters!, queue: _r.queue)
.element
];
if (_isolate.error != null) {
appendChildren(<HTMLElement>[
new HTMLPreElement.pre()
..className = 'errorBox'
..textContent = _isolate.error!.message ?? '',
new HTMLDivElement()
..className = 'summary'
..appendChildren(content)
]);
} else {
appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'summary'
..appendChildren(content)
]);
}
}
void _eventListener(e) {
if (e.isolate.id == _isolate.id) {
// This view doesn't display registered service extensions.
if (e is! M.ServiceRegisteredEvent && e is! M.ServiceUnregisteredEvent) {
_isolate = e.isolate;
_r.dirty();
}
}
}
}
@@ -1,192 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/isolate/location.dart';
import 'package:observatory/src/elements/isolate/run_state.dart';
import 'package:observatory/src/elements/isolate_ref.dart';
import 'package:observatory/utils.dart';
class IsolateSummaryElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateSummaryElement> _r;
Stream<RenderedEvent<IsolateSummaryElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.IsolateRepository _isolates;
late M.ScriptRepository _scripts;
M.Isolate? _loadedIsolate;
factory IsolateSummaryElement(
M.IsolateRef isolate,
M.IsolateRepository isolates,
M.EventRepository events,
M.ScriptRepository scripts,
{RenderingQueue? queue}) {
IsolateSummaryElement e = new IsolateSummaryElement.created();
e._r = new RenderingScheduler<IsolateSummaryElement>(e, queue: queue);
e._isolate = isolate;
e._isolates = isolates;
e._events = events;
e._scripts = scripts;
return e;
}
IsolateSummaryElement.created() : super.created('isolate-summary');
@override
void attached() {
super.attached();
_r.enable();
_load();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
if (_loadedIsolate == null) {
children = <HTMLElement>[
new HTMLSpanElement()..textContent = 'loading ',
new IsolateRefElement(_isolate, _events, queue: _r.queue).element
];
} else {
children = <HTMLElement>[
linkAndStatusRow(),
new HTMLBRElement(),
memoryRow(),
new HTMLBRElement(),
toolsRow(),
];
}
}
HTMLElement linkAndStatusRow() {
return new HTMLDivElement()
..className = 'flex-row-wrap'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'isolate-ref-container'
..appendChildren(<HTMLElement>[
new IsolateRefElement(_isolate, _events, queue: _r.queue).element
]),
new HTMLDivElement()..style.flex = '1',
new HTMLDivElement()
..className = 'flex-row isolate-state-container'
..appendChildren(<HTMLElement>[
new IsolateRunStateElement(_isolate as M.Isolate, _events,
queue: _r.queue)
.element,
new IsolateLocationElement(_isolate as M.Isolate, _events, _scripts,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ' [',
new HTMLAnchorElement()
..href = Uris.debugger(_isolate)
..textContent = 'debug',
new HTMLSpanElement()..textContent = ']'
])
]);
}
HTMLElement memoryRow() {
final isolate = _isolate as M.Isolate;
final newHeapUsed = Utils.formatSize(isolate.newSpace!.used);
final newHeapCapacity = Utils.formatSize(isolate.newSpace!.capacity);
final oldHeapUsed = Utils.formatSize(isolate.oldSpace!.used);
final oldHeapCapacity = Utils.formatSize(isolate.oldSpace!.capacity);
final heapUsed =
Utils.formatSize(isolate.newSpace!.used + isolate.oldSpace!.used);
final heapCapacity = Utils.formatSize(
isolate.newSpace!.capacity + isolate.oldSpace!.capacity);
return new HTMLDivElement()
..className = 'flex-row-wrap-right'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..style.padding = '5px'
..textContent = 'new-space $newHeapUsed of $newHeapCapacity',
new HTMLDivElement()
..style.padding = '5px'
..textContent = '/',
new HTMLDivElement()
..style.padding = '5px'
..textContent = 'old-space $oldHeapUsed of $oldHeapCapacity',
new HTMLDivElement()
..style.padding = '5px'
..textContent = '/',
new HTMLDivElement()
..style.padding = '5px'
..textContent = 'heap $heapUsed of $heapCapacity',
]);
}
HTMLElement toolsRow() {
return new HTMLDivElement()
..className = 'flex-row-spaced'
..appendChildren(<HTMLElement>[
new HTMLAnchorElement()
..href = Uris.debugger(_isolate)
..className = 'flex-item-even'
..text = 'debugger',
new HTMLAnchorElement()
..href = Uris.classTree(_isolate)
..className = 'flex-item-even'
..text = 'class hierarchy',
new HTMLAnchorElement()
..href = Uris.cpuProfiler(_isolate)
..className = 'flex-item-even'
..text = 'cpu profile',
new HTMLAnchorElement()
..href = Uris.cpuProfilerTable(_isolate)
..className = 'flex-item-even'
..text = 'cpu profile (table)',
new HTMLAnchorElement()
..href = Uris.allocationProfiler(_isolate)
..className = 'flex-item-even'
..text = 'allocation profile',
new HTMLAnchorElement()
..href = Uris.heapSnapshot(_isolate)
..className = 'flex-item-even'
..text = 'heap snapshot',
new HTMLAnchorElement()
..href = Uris.heapMap(_isolate)
..className = 'flex-item-even'
..text = 'heap map',
new HTMLAnchorElement()
..href = Uris.metrics(_isolate)
..className = 'flex-item-even'
..text = 'metrics',
new HTMLAnchorElement()
..href = Uris.persistentHandles(_isolate)
..className = 'flex-item-even'
..text = 'persistent handles',
new HTMLAnchorElement()
..href = Uris.ports(_isolate)
..className = 'flex-item-even'
..text = 'ports',
new HTMLAnchorElement()
..href = Uris.logging(_isolate)
..className = 'flex-item-even'
..text = 'logging',
]);
}
Future _load() async {
_loadedIsolate = await _isolates.get(_isolate);
_r.dirty();
}
}
@@ -1,110 +0,0 @@
// Copyright (c) 2014, 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 isolate_reconnect_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
class IsolateReconnectElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateReconnectElement> _r;
Stream<RenderedEvent<IsolateReconnectElement>> get onRendered =>
_r.onRendered;
late M.VM _vm;
late String _missing;
late Uri _uri;
late M.EventRepository _events;
late StreamSubscription _subscription;
M.VM get vm => _vm;
String get missing => _missing;
Uri get uri => _uri;
late M.NotificationRepository _notifications;
factory IsolateReconnectElement(M.VM vm, M.EventRepository events,
M.NotificationRepository notifications, String missing, Uri uri,
{RenderingQueue? queue}) {
IsolateReconnectElement e = new IsolateReconnectElement.created();
e._r = new RenderingScheduler<IsolateReconnectElement>(e, queue: queue);
e._vm = vm;
e._events = events;
e._missing = missing;
e._uri = uri;
e._notifications = notifications;
return e;
}
IsolateReconnectElement.created() : super.created('isolate-reconnect');
@override
void attached() {
super.attached();
_subscription = _events.onVMUpdate.listen((e) {
_vm = e.vm as M.VM;
_r.dirty();
});
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_subscription.cancel();
}
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h1()
..textContent = 'Isolate $_missing no longer exists',
new HTMLHRElement(),
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren((_vm.isolates.map<HTMLElement>((isolate) {
final query = new Map<String, dynamic>.from(_uri.queryParameters);
query['isolateId'] = isolate.id;
final href = new Uri(path: _uri.path, queryParameters: query);
return new HTMLDivElement()
..className = 'memberItem doubleSpaced'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'Continue in ',
new HTMLAnchorElement()
..href = '#$href'
..className = 'isolate-link'
..text = '${isolate.id} (${isolate.name})'
]);
}).toList()
..add(new HTMLDivElement()
..className = 'memberItem doubleSpaced'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'Go to ',
new HTMLAnchorElement()
..href = Uris.vm()
..text = 'isolates summary',
]))))
]),
];
}
}
@@ -1,67 +0,0 @@
// 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 isolate_ref_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, EventRepository;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class IsolateRefElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateRefElement> _r;
Stream<RenderedEvent<IsolateRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late StreamSubscription _updatesSubscription;
M.IsolateRef get isolate => _isolate;
factory IsolateRefElement(M.IsolateRef isolate, M.EventRepository events,
{RenderingQueue? queue}) {
IsolateRefElement e = new IsolateRefElement.created();
e._r = new RenderingScheduler<IsolateRefElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
return e;
}
IsolateRefElement.created() : super.created('isolate-ref');
@override
void attached() {
super.attached();
_updatesSubscription = _events.onIsolateUpdate
.where((e) => e.isolate.id == isolate.id)
.listen((e) {
_isolate = e.isolate;
_r.dirty();
});
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
_updatesSubscription.cancel();
}
void render() {
final isolateType = isolate.isSystemIsolate! ? 'System Isolate' : 'Isolate';
children = <HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(isolate)
..text = '$isolateType ${isolate.number} (${isolate.name})'
..className = 'isolate-ref'
];
}
}
@@ -1,318 +0,0 @@
// 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 isolate_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/eval_box.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/isolate/location.dart';
import 'package:observatory/src/elements/isolate/run_state.dart';
import 'package:observatory/src/elements/isolate/shared_summary.dart';
import 'package:observatory/src/elements/library_ref.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/refresh.dart';
import 'package:observatory/src/elements/nav/reload.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
import 'package:observatory/src/elements/nav/vm_menu.dart';
import 'package:observatory/src/elements/script_inset.dart';
import 'package:observatory/src/elements/source_inset.dart';
class IsolateViewElement extends CustomElement implements Renderable {
late RenderingScheduler<IsolateViewElement> _r;
Stream<RenderedEvent<IsolateViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.Isolate _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.IsolateRepository _isolates;
late M.ScriptRepository _scripts;
late M.FunctionRepository _functions;
late M.LibraryRepository _libraries;
late M.ObjectRepository _objects;
late M.EvalRepository _eval;
M.ServiceFunction? _function;
M.ScriptRef? _rootScript;
late StreamSubscription _subscription;
M.VMRef get vm => _vm;
M.Isolate get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
factory IsolateViewElement(
M.VM vm,
M.Isolate isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.IsolateRepository isolates,
M.ScriptRepository scripts,
M.FunctionRepository functions,
M.LibraryRepository libraries,
M.ObjectRepository objects,
M.EvalRepository eval,
{RenderingQueue? queue}) {
IsolateViewElement e = new IsolateViewElement.created();
e._r = new RenderingScheduler<IsolateViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._isolates = isolates;
e._scripts = scripts;
e._functions = functions;
e._objects = objects;
e._eval = eval;
e._libraries = libraries;
return e;
}
IsolateViewElement.created() : super.created('isolate-view');
@override
attached() {
super.attached();
_r.enable();
_loadExtraData();
_subscription = _events.onIsolateUpdate.listen((e) {
if (e.isolate.id == _isolate) {
_isolate = isolate;
_r.dirty();
}
});
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
_subscription.cancel();
}
void render() {
final uptime = new DateTime.now().difference(_isolate.startTime!);
final libraries = _isolate.libraries!.toList();
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
(new NavReloadElement(_isolate, _isolates, _events, queue: _r.queue)
..onReload.listen((_) async {
_isolate = await _isolates.get(_isolate);
await _loadExtraData();
_r.dirty();
}))
.element,
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_isolate = await _isolates.get(_isolate);
await _loadExtraData();
_r.dirty();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Isolate ${_isolate.name}',
new HTMLBRElement(),
new HTMLDivElement()
..className = 'flex-row'
..appendChildren(<HTMLElement>[
new HTMLDivElement()..style.flex = '1',
new HTMLDivElement()
..appendChildren(<HTMLElement>[
new IsolateRunStateElement(_isolate, _events, queue: _r.queue)
.element,
new IsolateLocationElement(_isolate, _events, _scripts,
queue: _r.queue)
.element,
new HTMLSpanElement()..textContent = ' [',
new HTMLAnchorElement()
..href = Uris.debugger(_isolate)
..textContent = 'debug',
new HTMLSpanElement()..textContent = ']'
])
]),
new HTMLDivElement()
..appendChildren(_function != null
? [
new HTMLBRElement(),
(new SourceInsetElement(_isolate, _function!.location!,
_scripts, _objects, _events,
currentPos: M
.topFrame(isolate.pauseEvent)!
.location!
.tokenPos,
queue: _r.queue)
..className = 'header_inset')
.element
]
: const []),
new HTMLHRElement(),
new IsolateSharedSummaryElement(_isolate, _events, queue: _r.queue)
.element,
new HTMLHRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'started at',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '${_isolate.startTime}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'uptime',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$uptime'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'root library',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
_isolate.rootLibrary == null
? (new HTMLSpanElement()..textContent = 'loading...')
: new LibraryRefElement(
_isolate, _isolate.rootLibrary!,
queue: _r.queue)
.element
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(_isolate.entry != null
? [
new HTMLDivElement()
..className = 'memberName'
..textContent = 'entry',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new FunctionRefElement(_isolate, _isolate.entry!,
queue: _r.queue)
.element
])
]
: const []),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'isolate id',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '${_isolate.number}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'service protocol extensions',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '${_isolate.extensionRPCs}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'object store',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
HTMLAnchorElement()
..href = Uris.objectStore(_isolate)
..textContent = 'object store'
])
]),
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'libraries (${libraries.length})',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
(new CurlyBlockElement(queue: _r.queue)
..content = libraries
.map<HTMLElement>((l) => new HTMLDivElement()
..appendChildren(<HTMLElement>[
new LibraryRefElement(_isolate, l,
queue: _r.queue)
.element
]))
.toList())
.element
])
]),
]),
new HTMLHRElement(),
new EvalBoxElement(_isolate, _isolate.rootLibrary!, _objects, _eval,
queue: _r.queue)
.element,
new HTMLDivElement()
..appendChildren(_rootScript != null
? [
new HTMLHRElement(),
new ScriptInsetElement(
_isolate, _rootScript!, _scripts, _objects, _events,
queue: _r.queue)
.element
]
: const []),
])
];
}
Future _loadExtraData() async {
_function = null;
_rootScript = null;
final frame = M.topFrame(_isolate.pauseEvent);
if (frame != null) {
_function = await _functions.get(_isolate, frame.function!.id!);
}
if (_isolate.rootLibrary != null) {
final rootLibrary =
await _libraries.get(_isolate, _isolate.rootLibrary!.id!);
_rootScript = rootLibrary.rootScript;
}
_r.dirty();
}
}
@@ -1,146 +0,0 @@
// 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 json_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/notify.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
class JSONViewElement extends CustomElement implements Renderable {
late RenderingScheduler<JSONViewElement> _r;
Stream<RenderedEvent<JSONViewElement>> get onRendered => _r.onRendered;
late M.NotificationRepository _notifications;
late Map _map;
M.NotificationRepository get notifications => _notifications;
Map get map => _map;
factory JSONViewElement(Map map, M.NotificationRepository notifications,
{RenderingQueue? queue}) {
JSONViewElement e = new JSONViewElement.created();
e._r = new RenderingScheduler<JSONViewElement>(e, queue: queue);
e._notifications = notifications;
e._map = map;
return e;
}
JSONViewElement.created() : super.created('json-view');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Object',
new HTMLHRElement(),
new HTMLPreElement.pre()..textContent = JSONPretty.stringify(_map),
])
];
}
}
class JSONPretty {
JSONPretty._();
static String stringify(Map map) => new JSONPretty._()._stringify(map);
String _stringify(Map map) {
_buffer.clear();
_buffer.write('{\n');
_printMap(map, 0);
_buffer.write('}\n');
return _buffer.toString();
}
void _printMap(Map map, int depth) {
if (_seen.contains(map)) {
return;
}
_seen.add(map);
for (var k in map.keys) {
var v = map[k];
if (v is Map) {
_writeIndent(depth);
_buffer.write('"$k": {\n');
_printMap(v, depth + 1);
_writeIndent(depth);
_buffer.write('}\n');
} else if (v is List) {
_writeIndent(depth);
_buffer.write('"$k": [\n');
_printList(v, depth + 1);
_writeIndent(depth);
_buffer.write(']\n');
} else {
_writeIndent(depth);
_buffer.write('"$k": $v');
_buffer.write('\n');
}
}
_seen.remove(map);
}
void _printList(List list, int depth) {
if (_seen.contains(list)) {
return;
}
_seen.add(list);
for (var v in list) {
if (v is Map) {
_writeIndent(depth);
_buffer.write('{\n');
_printMap(v, depth + 1);
_writeIndent(depth);
_buffer.write('}\n');
} else if (v is List) {
_writeIndent(depth);
_buffer.write('[\n');
_printList(v, depth + 1);
_writeIndent(depth);
_buffer.write(']\n');
} else {
_writeIndent(depth);
_buffer.write(v);
_buffer.write('\n');
}
}
_seen.remove(list);
}
void _writeIndent(int depth) {
const tab = ' '; // 2 spaces.
_buffer.write(tab * depth);
}
final _buffer = new StringBuffer();
final _seen = new Set();
}
@@ -1,59 +0,0 @@
// 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 library_ref_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, LibraryRef;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class LibraryRefElement extends CustomElement implements Renderable {
late RenderingScheduler<LibraryRefElement> _r;
Stream<RenderedEvent<LibraryRefElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.LibraryRef _library;
M.IsolateRef get isolate => _isolate;
M.LibraryRef get library => _library;
factory LibraryRefElement(M.IsolateRef isolate, M.LibraryRef library,
{RenderingQueue? queue}) {
LibraryRefElement e = new LibraryRefElement.created();
e._r = new RenderingScheduler<LibraryRefElement>(e, queue: queue);
e._isolate = isolate;
e._library = library;
return e;
}
LibraryRefElement.created() : super.created('library-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
final name = _library.name;
children = <HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _library)
..text = (name == null || name.isEmpty) ? 'unnamed' : name
];
}
}
@@ -1,321 +0,0 @@
// 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 library_view_element;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/class_ref.dart';
import 'package:observatory/src/elements/curly_block.dart';
import 'package:observatory/src/elements/eval_box.dart';
import 'package:observatory/src/elements/field_ref.dart';
import 'package:observatory/src/elements/function_ref.dart';
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/library_ref.dart';
import 'package:observatory/src/elements/nav/isolate_menu.dart';
import 'package:observatory/src/elements/nav/library_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/src/elements/object_common.dart';
import 'package:observatory/src/elements/script_inset.dart';
import 'package:observatory/src/elements/script_ref.dart';
class LibraryViewElement extends CustomElement implements Renderable {
late RenderingScheduler<LibraryViewElement> _r;
Stream<RenderedEvent<LibraryViewElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.Library _library;
late M.LibraryRepository _libraries;
late M.FieldRepository _fields;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ScriptRepository _scripts;
late M.ObjectRepository _objects;
late M.EvalRepository _eval;
Iterable<M.Field>? _variables;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.Library get library => _library;
factory LibraryViewElement(
M.VM vm,
M.IsolateRef isolate,
M.Library library,
M.EventRepository events,
M.NotificationRepository notifications,
M.LibraryRepository libraries,
M.FieldRepository fields,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ScriptRepository scripts,
M.ObjectRepository objects,
M.EvalRepository eval,
{RenderingQueue? queue}) {
LibraryViewElement e = new LibraryViewElement.created();
e._r = new RenderingScheduler<LibraryViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._library = library;
e._libraries = libraries;
e._fields = fields;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._scripts = scripts;
e._objects = objects;
e._eval = eval;
return e;
}
LibraryViewElement.created() : super.created('library-view');
@override
attached() {
super.attached();
_r.enable();
_refresh();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
final rootScript = library.rootScript;
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
new NavLibraryMenuElement(_isolate, _library, queue: _r.queue).element,
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Library',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _library, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'uri',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _library.uri ?? ''
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'vm name',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _library.vmName ?? ''
])
]),
new HTMLHRElement(),
new EvalBoxElement(_isolate, _library, _objects, _eval,
queue: _r.queue)
.element,
new HTMLHRElement(),
_createDependencies(),
new HTMLBRElement(),
_createScripts(),
new HTMLBRElement(),
_createClasses(),
new HTMLBRElement(),
_createVariables(),
new HTMLBRElement(),
_createFunctions(),
if (rootScript != null) ...[
new HTMLHRElement(),
new ScriptInsetElement(
_isolate, rootScript, _scripts, _objects, _events,
queue: _r.queue)
.element
],
])
];
}
Future _refresh() async {
_library = await _libraries.get(_isolate, _library.id!);
_variables = null;
_r.dirty();
_variables = await Future.wait(
_library.variables!.map((field) => _fields.get(_isolate, field.id!)));
_r.dirty();
}
HTMLElement _createDependencies() {
if (_library.dependencies!.isEmpty) {
return new HTMLSpanElement();
}
final dependencies = _library.dependencies!.toList();
return new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..textContent = 'dependencies (${dependencies.length}) ',
(new CurlyBlockElement(queue: _r.queue)
..content = dependencies
.map<HTMLElement>((d) => new HTMLDivElement()
..className = 'indent'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..textContent = d.isImport ? 'import ' : 'export ',
new LibraryRefElement(_isolate, d.target, queue: _r.queue)
.element,
new HTMLSpanElement()
..textContent =
d.prefix == null ? '' : ' as ${d.prefix}',
new HTMLSpanElement()
..textContent = d.isDeferred ? ' deferred' : '',
]))
.toList())
.element
]);
}
HTMLElement _createScripts() {
if (_library.scripts!.isEmpty) {
return new HTMLSpanElement();
}
final scripts = _library.scripts!.toList();
return new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'scripts (${scripts.length}) ',
(new CurlyBlockElement(queue: _r.queue)
..content = scripts
.map<HTMLElement>((s) => new HTMLDivElement()
..className = 'indent'
..appendChildren(<HTMLElement>[
new ScriptRefElement(_isolate, s, queue: _r.queue).element
]))
.toList())
.element
]);
}
HTMLElement _createClasses() {
if (_library.classes!.isEmpty) {
return new HTMLSpanElement();
}
final classes = _library.classes!.toList();
return new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'classes (${classes.length}) ',
(new CurlyBlockElement(queue: _r.queue)
..content = classes
.map<HTMLElement>((c) => new HTMLDivElement()
..className = 'indent'
..appendChildren(<HTMLElement>[
new ClassRefElement(_isolate, c, queue: _r.queue).element
]))
.toList())
.element
]);
}
HTMLElement _createVariables() {
if (_library.variables!.isEmpty) {
return new HTMLSpanElement();
}
final variables = _library.variables!.toList();
return new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'variables (${variables.length}) ',
(new CurlyBlockElement(queue: _r.queue)
..content = <HTMLElement>[
_variables == null
? (new HTMLSpanElement()..textContent = 'loading...')
: (new HTMLDivElement()
..className = 'indent memberList'
..appendChildren(_variables!
.map<HTMLElement>((f) => new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
new FieldRefElement(_isolate, f, _objects,
queue: _r.queue)
.element
]),
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = ' = ',
anyRef(_isolate, f.staticValue, _objects,
queue: _r.queue)
])
]))))
])
.element
]);
}
HTMLElement _createFunctions() {
if (_library.functions!.isEmpty) {
return new HTMLSpanElement();
}
final functions = _library.functions!.toList();
return new HTMLDivElement()
..appendChildren(<HTMLElement>[
new HTMLSpanElement()..textContent = 'functions (${functions.length}) ',
(new CurlyBlockElement(queue: _r.queue)
..content = functions
.map<HTMLElement>((f) => new HTMLDivElement()
..className = 'indent'
..appendChildren(<HTMLElement>[
new FunctionRefElement(_isolate, f, queue: _r.queue)
.element
]))
.toList())
.element
]);
}
}
@@ -1,66 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/models.dart' as M
show IsolateRef, LocalVarDescriptorsRef;
class LocalVarDescriptorsRefElement extends CustomElement
implements Renderable {
late RenderingScheduler<LocalVarDescriptorsRefElement> _r;
Stream<RenderedEvent<LocalVarDescriptorsRefElement>> get onRendered =>
_r.onRendered;
late M.IsolateRef _isolate;
late M.LocalVarDescriptorsRef _localVar;
M.IsolateRef get isolate => _isolate;
M.LocalVarDescriptorsRef get localVar => _localVar;
factory LocalVarDescriptorsRefElement(
M.IsolateRef isolate, M.LocalVarDescriptorsRef localVar,
{RenderingQueue? queue}) {
LocalVarDescriptorsRefElement e =
new LocalVarDescriptorsRefElement.created();
e._r =
new RenderingScheduler<LocalVarDescriptorsRefElement>(e, queue: queue);
e._isolate = isolate;
e._localVar = localVar;
return e;
}
LocalVarDescriptorsRefElement.created() : super.created('var-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
final text = (_localVar.name == null || _localVar.name == '')
? 'LocalVarDescriptors'
: _localVar.name;
children = <HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _localVar)
..text = text ?? ''
];
}
}
@@ -1,112 +0,0 @@
// Copyright (c) 2015, 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 logging_page;
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/logging_list.dart';
import 'package:observatory/src/elements/nav/isolate_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';
class LoggingPageElement extends CustomElement implements Renderable {
late RenderingScheduler<LoggingPageElement> _r;
Stream<RenderedEvent<LoggingPageElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late Level _level = Level.ALL;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
factory LoggingPageElement(M.VM vm, M.IsolateRef isolate,
M.EventRepository events, M.NotificationRepository notifications,
{RenderingQueue? queue}) {
LoggingPageElement e = new LoggingPageElement.created();
e._r = new RenderingScheduler<LoggingPageElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
return e;
}
LoggingPageElement.created() : super.created('logging-page');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
LoggingListElement? _logs;
void render() {
_logs = _logs ?? new LoggingListElement(_isolate, _events);
_logs!.level = _level;
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('logging'),
(new NavRefreshElement(label: 'clear', queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_logs = null;
_r.dirty();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Logging',
new HTMLSpanElement()..textContent = 'Show messages with severity ',
_createLevelSelector(),
new HTMLHRElement(),
_logs!.element
])
];
}
HTMLElement _createLevelSelector() {
final s = HTMLSelectElement()
..value = _level.name
..appendChildren(Level.LEVELS.map((level) => HTMLOptionElement()
..value = level.name
..selected = _level == level
..text = level.name));
s.onChange.listen((_) {
_level = Level.LEVELS[s.selectedIndex];
_r.dirty();
});
return s;
}
}
@@ -1,85 +0,0 @@
// Copyright (c) 2015, 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.
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/utils.dart';
class LoggingListElement extends CustomElement implements Renderable {
late RenderingScheduler<LoggingListElement> _r;
Stream<RenderedEvent<LoggingListElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late StreamSubscription _subscription;
Level _level = Level.ALL;
final _logs = <Map>[];
M.IsolateRef get isolate => _isolate;
Level get level => _level;
set level(Level value) => _level = _r.checkAndReact(_level, value);
factory LoggingListElement(M.IsolateRef isolate, M.EventRepository events,
{RenderingQueue? queue}) {
LoggingListElement e = new LoggingListElement.created();
e._r = new RenderingScheduler<LoggingListElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
return e;
}
LoggingListElement.created() : super.created('logging-list');
@override
attached() {
super.attached();
_r.enable();
_subscription = _events.onLoggingEvent.listen((e) {
if (e.isolate.id == _isolate.id) {
_logs.add(e.logRecord);
if (_shouldBeVisible(_logs.last)) {
_r.dirty();
}
}
});
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
_subscription.cancel();
}
void render() {
children = _logs
.where(_shouldBeVisible)
.map<HTMLElement>((logRecord) => new HTMLDivElement()
..className = 'logItem ${logRecord["level"].name}'
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'level'
..textContent = logRecord['level'].name,
new HTMLSpanElement()
..className = 'time'
..textContent = Utils.formatDateTime(logRecord['time']),
new HTMLSpanElement()
..className = 'message'
..textContent = logRecord["message"].valueAsString
]))
.toList();
}
bool _shouldBeVisible(Map record) => _level.compareTo(record['level']) <= 0;
}
@@ -1,66 +0,0 @@
// 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/models.dart' as M
show IsolateRef, MegamorphicCacheRef;
class MegamorphicCacheRefElement extends CustomElement implements Renderable {
late RenderingScheduler<MegamorphicCacheRefElement> _r;
Stream<RenderedEvent<MegamorphicCacheRefElement>> get onRendered =>
_r.onRendered;
late M.IsolateRef _isolate;
late M.MegamorphicCacheRef _cache;
M.IsolateRef get isolate => _isolate;
M.MegamorphicCacheRef get cache => _cache;
factory MegamorphicCacheRefElement(
M.IsolateRef isolate, M.MegamorphicCacheRef cache,
{RenderingQueue? queue}) {
MegamorphicCacheRefElement e = new MegamorphicCacheRefElement.created();
e._r = new RenderingScheduler<MegamorphicCacheRefElement>(e, queue: queue);
e._isolate = isolate;
e._cache = cache;
return e;
}
MegamorphicCacheRefElement.created() : super.created('megamorphic-cache-ref');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
new HTMLAnchorElement()
..href = Uris.inspect(_isolate, object: _cache)
..appendChildren(<HTMLElement>[
new HTMLSpanElement()
..className = 'emphasize'
..textContent = 'MegamorphicCache',
new HTMLSpanElement()..textContent = ' (${_cache.selector})'
])
];
}
}
@@ -1,172 +0,0 @@
// Copyright (c) 2015, 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 megamorphiccache_view;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/any_ref.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/nav/isolate_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/src/elements/object_common.dart';
class MegamorphicCacheViewElement extends CustomElement implements Renderable {
late RenderingScheduler<MegamorphicCacheViewElement> _r;
Stream<RenderedEvent<MegamorphicCacheViewElement>> get onRendered =>
_r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.MegamorphicCache _cache;
late M.MegamorphicCacheRepository _caches;
late M.RetainedSizeRepository _retainedSizes;
late M.ReachableSizeRepository _reachableSizes;
late M.InboundReferencesRepository _references;
late M.RetainingPathRepository _retainingPaths;
late M.ObjectRepository _objects;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
M.MegamorphicCache get cache => _cache;
factory MegamorphicCacheViewElement(
M.VM vm,
M.IsolateRef isolate,
M.MegamorphicCache cache,
M.EventRepository events,
M.NotificationRepository notifications,
M.MegamorphicCacheRepository caches,
M.RetainedSizeRepository retainedSizes,
M.ReachableSizeRepository reachableSizes,
M.InboundReferencesRepository references,
M.RetainingPathRepository retainingPaths,
M.ObjectRepository objects,
{RenderingQueue? queue}) {
MegamorphicCacheViewElement e = new MegamorphicCacheViewElement.created();
e._r = new RenderingScheduler<MegamorphicCacheViewElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._cache = cache;
e._caches = caches;
e._retainedSizes = retainedSizes;
e._reachableSizes = reachableSizes;
e._references = references;
e._retainingPaths = retainingPaths;
e._objects = objects;
return e;
}
MegamorphicCacheViewElement.created()
: super.created('megamorphiccache-view');
@override
attached() {
super.attached();
_r.enable();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('megamorphic inline cache'),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) async {
e.element.disabled = true;
_cache = await _caches.get(_isolate, _cache.id!);
_r.dirty();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Megamorphic Cache',
new HTMLHRElement(),
new ObjectCommonElement(_isolate, _cache, _retainedSizes,
_reachableSizes, _references, _retainingPaths, _objects,
queue: _r.queue)
.element,
new HTMLBRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'selector',
new HTMLDivElement()
..className = 'memberName'
..textContent = '${_cache.selector}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'mask',
new HTMLDivElement()
..className = 'memberName'
..textContent = '${_cache.mask}'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'buckets',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
anyRef(_isolate, _cache.buckets, _objects,
queue: _r.queue)
])
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'argumentsDescriptor',
new HTMLDivElement()
..className = 'memberName'
..appendChildren(<HTMLElement>[
anyRef(_isolate, _cache.argumentsDescriptor, _objects,
queue: _r.queue)
])
])
]),
])
];
}
}
@@ -1,166 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class MetricDetailsElement extends CustomElement implements Renderable {
late RenderingScheduler<MetricDetailsElement> _r;
Stream<RenderedEvent<MetricDetailsElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.Metric _metric;
late M.MetricRepository _metrics;
M.IsolateRef get isolate => _isolate;
M.Metric get metric => _metric;
factory MetricDetailsElement(
M.IsolateRef isolate, M.Metric metric, M.MetricRepository metrics,
{RenderingQueue? queue}) {
MetricDetailsElement e = new MetricDetailsElement.created();
e._r = new RenderingScheduler<MetricDetailsElement>(e, queue: queue);
e._isolate = isolate;
e._metric = metric;
e._metrics = metrics;
return e;
}
MetricDetailsElement.created() : super.created('metric-details');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'name',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _metric.name ?? '',
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'description',
new HTMLDivElement()
..className = 'memberValue'
..textContent = _metric.description ?? '',
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'refresh rate',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createRefreshRateSelect()),
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'buffer size',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_createBufferSizeSelect()),
])
])
];
}
List<HTMLElement> _createRefreshRateSelect() {
final current = _metrics.getSamplingRate(_isolate, _metric);
final s = new HTMLSelectElement()
..value = _rateToString(current)
..appendChildren(
M.MetricSamplingRate.values.map((rate) => HTMLOptionElement()
..value = _rateToString(current)
..selected = current == rate
..textContent = _rateToString(rate)));
return [
s
..onChange.listen((_) {
_metrics.setSamplingRate(
_isolate, _metric, M.MetricSamplingRate.values[s.selectedIndex]);
_r.dirty();
})
];
}
List<HTMLElement> _createBufferSizeSelect() {
final current = _metrics.getBufferSize(_isolate, _metric);
final s = HTMLSelectElement()
..value = _sizeToString(current)
..appendChildren(
M.MetricBufferSize.values.map((rate) => HTMLOptionElement()
..value = _sizeToString(current)
..selected = current == rate
..textContent = _sizeToString(rate)));
return [
s
..onChange.listen((_) {
_metrics.setBufferSize(
_isolate, _metric, M.MetricBufferSize.values[s.selectedIndex]);
_r.dirty();
})
];
}
static String _rateToString(M.MetricSamplingRate rate) {
switch (rate) {
case M.MetricSamplingRate.off:
return 'Never';
case M.MetricSamplingRate.e100ms:
return 'Ten times per second';
case M.MetricSamplingRate.e1s:
return 'Once a second';
case M.MetricSamplingRate.e2s:
return 'Every two seconds';
case M.MetricSamplingRate.e4s:
return 'Every four seconds';
case M.MetricSamplingRate.e8s:
return 'Every eight seconds';
}
}
static String _sizeToString(M.MetricBufferSize size) {
switch (size) {
case M.MetricBufferSize.n10samples:
return '10';
case M.MetricBufferSize.n100samples:
return '100';
case M.MetricBufferSize.n1000samples:
return '1000';
}
}
}
@@ -1,108 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class MetricGraphElement extends CustomElement implements Renderable {
late RenderingScheduler<MetricGraphElement> _r;
Stream<RenderedEvent<MetricGraphElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.Metric _metric;
late M.MetricRepository _metrics;
late Timer _timer;
M.IsolateRef get isolate => _isolate;
M.Metric get metric => _metric;
factory MetricGraphElement(
M.IsolateRef isolate, M.Metric metric, M.MetricRepository metrics,
{RenderingQueue? queue}) {
MetricGraphElement e = new MetricGraphElement.created();
e._r = new RenderingScheduler<MetricGraphElement>(e, queue: queue);
e._isolate = isolate;
e._metric = metric;
e._metrics = metrics;
return e;
}
MetricGraphElement.created() : super.created('metric-graph');
@override
void attached() {
super.attached();
_r.enable();
_timer = new Timer.periodic(const Duration(seconds: 1), (_) => _r.dirty());
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
_timer.cancel();
}
void render() {
final min = _metrics.getMinValue(_isolate, _metric);
final max = _metrics.getMaxValue(_isolate, _metric);
final rows = _metrics
.getSamples(_isolate, _metric)!
.map((s) => [s.time!.millisecondsSinceEpoch, s.value])
.toList();
final current = rows.last.last;
var message = 'current: $current';
message = 'min: $min, $message';
message = message + ', max: $max';
children = <HTMLElement>[
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren([
new HTMLDivElement()
..className = 'memberName'
..textContent = 'min',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$min'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'current',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$current'
]),
new HTMLDivElement()
..className = 'memberItem'
..appendChildren([
new HTMLDivElement()
..className = 'memberName'
..textContent = 'max',
new HTMLDivElement()
..className = 'memberValue'
..textContent = '$max'
])
]),
];
if (rows.length <= 1) {
return;
}
}
}
@@ -1,157 +0,0 @@
// Copyright (c) 2014, 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 metrics;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/metric/details.dart';
import 'package:observatory/src/elements/metric/graph.dart';
import 'package:observatory/src/elements/nav/isolate_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';
class MetricsPageElement extends CustomElement implements Renderable {
late RenderingScheduler<MetricsPageElement> _r;
Stream<RenderedEvent<MetricsPageElement>> get onRendered => _r.onRendered;
late M.VM _vm;
late M.IsolateRef _isolate;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.MetricRepository _metrics;
List<M.Metric>? _available;
M.Metric? _selected;
M.VMRef get vm => _vm;
M.IsolateRef get isolate => _isolate;
M.NotificationRepository get notifications => _notifications;
factory MetricsPageElement(
M.VM vm,
M.IsolateRef isolate,
M.EventRepository events,
M.NotificationRepository notifications,
M.MetricRepository metrics,
{RenderingQueue? queue}) {
MetricsPageElement e = new MetricsPageElement.created();
e._r = new RenderingScheduler<MetricsPageElement>(e, queue: queue);
e._vm = vm;
e._isolate = isolate;
e._events = events;
e._notifications = notifications;
e._metrics = metrics;
return e;
}
MetricsPageElement.created() : super.created('metrics-page');
@override
attached() {
super.attached();
_r.enable();
_refresh();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
new NavIsolateMenuElement(_isolate, _events, queue: _r.queue).element,
navMenu('metrics'),
(new NavRefreshElement(queue: _r.queue)
..onRefresh.listen((e) {
e.element.disabled = true;
_refresh();
}))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
new HTMLDivElement()
..className = 'content-centered-big'
..appendChildren(<HTMLElement>[
new HTMLHeadingElement.h2()..textContent = 'Metrics',
new HTMLHRElement(),
new HTMLDivElement()
..className = 'memberList'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberItem'
..appendChildren(<HTMLElement>[
new HTMLDivElement()
..className = 'memberName'
..textContent = 'Metric',
new HTMLDivElement()
..className = 'memberValue'
..appendChildren(_available == null
? [new HTMLSpanElement()..textContent = 'Loading..']
: _createMetricSelect())
])
]),
new HTMLHRElement(),
new HTMLDivElement()
..appendChildren(_selected == null
? const []
: [
new MetricDetailsElement(_isolate, _selected!, _metrics,
queue: _r.queue)
.element
]),
new HTMLHRElement(),
new HTMLDivElement()
..className = 'graph'
..appendChildren(_selected == null
? const []
: [
new MetricGraphElement(_isolate, _selected!, _metrics,
queue: _r.queue)
.element
])
]),
];
}
Future _refresh() async {
_available = (await _metrics.list(_isolate)).toList();
if (!_available!.contains(_selected)) {
_selected = _available!.first;
}
_r.dirty();
}
List<HTMLElement> _createMetricSelect() {
final s = new HTMLSelectElement()
..value = _selected!.name!
..appendChildren(_available!.map((metric) => HTMLOptionElement()
..value = metric.name!
..selected = _selected == metric
..textContent = metric.name!));
return [
s
..onChange.listen((_) {
_selected = _available![s.selectedIndex];
_r.dirty();
})
];
}
}
@@ -1,156 +0,0 @@
// 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 native_memory_profile;
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/nav_bar.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.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/src/elements/sample_buffer_control.dart';
import 'package:observatory/src/elements/stack_trace_tree_config.dart';
class NativeMemoryProfileElement extends CustomElement implements Renderable {
late RenderingScheduler<NativeMemoryProfileElement> _r;
Stream<RenderedEvent<NativeMemoryProfileElement>> get onRendered =>
_r.onRendered;
late M.VM _vm;
late M.EventRepository _events;
late M.NotificationRepository _notifications;
late M.NativeMemorySampleProfileRepository _profiles;
Stream<M.SampleProfileLoadingProgressEvent>? _progressStream;
M.SampleProfileLoadingProgress? _progress;
late M.SampleProfileTag _tag = M.SampleProfileTag.none;
late ProfileTreeMode _mode = ProfileTreeMode.function;
late M.ProfileTreeDirection _direction = M.ProfileTreeDirection.exclusive;
late String _filter = '';
M.NotificationRepository get notifications => _notifications;
M.NativeMemorySampleProfileRepository get profiles => _profiles;
factory NativeMemoryProfileElement(
M.VM vm,
M.EventRepository events,
M.NotificationRepository notifications,
M.NativeMemorySampleProfileRepository profiles,
{RenderingQueue? queue}) {
NativeMemoryProfileElement e = new NativeMemoryProfileElement.created();
e._r = new RenderingScheduler<NativeMemoryProfileElement>(e, queue: queue);
e._vm = vm;
e._events = events;
e._notifications = notifications;
e._profiles = profiles;
return e;
}
NativeMemoryProfileElement.created() : super.created('native-memory-profile');
@override
attached() {
super.attached();
_r.enable();
_request();
}
@override
detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
var content = <HTMLElement>[
navBar(<HTMLElement>[
new NavTopMenuElement(queue: _r.queue).element,
new NavVMMenuElement(_vm, _events, queue: _r.queue).element,
navMenu('native memory profile', link: Uris.nativeMemory()),
(new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
];
if (_progress == null) {
children = content;
return;
}
content.add((new SampleBufferControlElement(
_vm, _progress!, _progressStream!,
selectedTag: _tag, queue: _r.queue)
..onTagChange.listen((e) {
_tag = e.element.selectedTag;
_request();
}))
.element);
if (_progress!.status == M.SampleProfileLoadingStatus.loaded) {
late CpuProfileVirtualTreeElement tree;
content.addAll([
new HTMLBRElement(),
(new StackTraceTreeConfigElement(
mode: _mode,
direction: _direction,
filter: _filter,
queue: _r.queue)
..onModeChange.listen((e) {
_mode = tree.mode = e.element.mode;
})
..onFilterChange.listen((e) {
_filter = e.element.filter.trim();
tree.filters = _filter.isNotEmpty
? [
(node) {
return node.name.contains(_filter);
}
]
: const [];
})
..onDirectionChange.listen((e) {
_direction = tree.direction = e.element.direction;
}))
.element,
new HTMLBRElement(),
(tree = new CpuProfileVirtualTreeElement(null, _progress!.profile,
queue: _r.queue, type: M.SampleProfileType.memory))
.element,
]);
}
children = content;
}
Future _request({bool forceFetch = false}) async {
if (forceFetch) {
for (M.IsolateRef isolate in _vm.isolates) {
await isolate.collectAllGarbage();
}
}
_progress = null;
_progressStream = _profiles.get(_vm, _tag, forceFetch: forceFetch);
_r.dirty();
_progress = (await _progressStream!.first).progress;
_r.dirty();
if (M.isSampleProcessRunning(_progress!.status)) {
_progress = (await _progressStream!.last).progress;
_r.dirty();
}
}
Future _refresh(e) async {
e.element.disabled = true;
await _request(forceFetch: true);
e.element.disabled = false;
}
}
@@ -1,63 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, ClassRef;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class NavClassMenuElement extends CustomElement implements Renderable {
late RenderingScheduler<NavClassMenuElement> _r;
Stream<RenderedEvent<NavClassMenuElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.ClassRef _cls;
List<HTMLElement> _content = const [];
M.IsolateRef get isolate => _isolate;
M.ClassRef get cls => _cls;
List<HTMLElement> get content => _content;
set content(Iterable<HTMLElement> value) {
_content = value.toList();
_r.dirty();
}
factory NavClassMenuElement(M.IsolateRef isolate, M.ClassRef cls,
{RenderingQueue? queue}) {
NavClassMenuElement e = new NavClassMenuElement.created();
e._r = new RenderingScheduler<NavClassMenuElement>(e, queue: queue);
e._isolate = isolate;
e._cls = cls;
return e;
}
NavClassMenuElement.created() : super.created('nav-class-menu');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
children = <HTMLElement>[
navMenu(cls.name!,
content: _content, link: Uris.inspect(isolate, object: cls))
];
}
}
@@ -1,107 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, EventRepository;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
import 'package:observatory/src/elements/nav/menu_item.dart';
class NavIsolateMenuElement extends CustomElement implements Renderable {
late RenderingScheduler<NavIsolateMenuElement> _r;
Stream<RenderedEvent<NavIsolateMenuElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.EventRepository _events;
StreamSubscription? _updatesSubscription;
late Iterable<HTMLElement> _content = const [];
M.IsolateRef get isolate => _isolate;
Iterable<HTMLElement> get content => _content;
set content(Iterable<HTMLElement> value) {
_content = value.toList();
_r.dirty();
}
factory NavIsolateMenuElement(M.IsolateRef isolate, M.EventRepository events,
{RenderingQueue? queue}) {
NavIsolateMenuElement e = new NavIsolateMenuElement.created();
e._r = new RenderingScheduler<NavIsolateMenuElement>(e, queue: queue);
e._isolate = isolate;
e._events = events;
return e;
}
NavIsolateMenuElement.created() : super.created('nav-isolate-menu');
@override
void attached() {
super.attached();
_updatesSubscription = _events.onIsolateUpdate
.where((e) => e.isolate.id == isolate.id)
.listen((e) {
_isolate = e.isolate;
_r.dirty();
});
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
assert(_updatesSubscription != null);
_updatesSubscription!.cancel();
_updatesSubscription = null;
}
void render() {
final content = <HTMLElement>[
new NavMenuItemElement('debugger',
queue: _r.queue, link: Uris.debugger(isolate))
.element,
new NavMenuItemElement('class hierarchy',
queue: _r.queue, link: Uris.classTree(isolate))
.element,
new NavMenuItemElement('cpu profile',
queue: _r.queue, link: Uris.cpuProfiler(isolate))
.element,
new NavMenuItemElement('cpu profile (table)',
queue: _r.queue, link: Uris.cpuProfilerTable(isolate))
.element,
new NavMenuItemElement('allocation profile',
queue: _r.queue, link: Uris.allocationProfiler(isolate))
.element,
new NavMenuItemElement('heap snapshot',
queue: _r.queue, link: Uris.heapSnapshot(isolate))
.element,
new NavMenuItemElement('heap map',
queue: _r.queue, link: Uris.heapMap(isolate))
.element,
new NavMenuItemElement('metrics',
queue: _r.queue, link: Uris.metrics(isolate))
.element,
new NavMenuItemElement('persistent handles',
queue: _r.queue, link: Uris.persistentHandles(isolate))
.element,
new NavMenuItemElement('ports',
queue: _r.queue, link: Uris.ports(isolate))
.element,
new NavMenuItemElement('logging',
queue: _r.queue, link: Uris.logging(isolate))
.element,
]..addAll(_content);
children = <HTMLElement>[
navMenu(isolate.name!, content: content, link: Uris.inspect(isolate))
];
}
}
@@ -1,64 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/models.dart' as M show IsolateRef, LibraryRef;
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/nav_menu.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
import 'package:observatory/src/elements/helpers/uris.dart';
class NavLibraryMenuElement extends CustomElement implements Renderable {
late RenderingScheduler<NavLibraryMenuElement> _r;
Stream<RenderedEvent<NavLibraryMenuElement>> get onRendered => _r.onRendered;
late M.IsolateRef _isolate;
late M.LibraryRef _library;
List<HTMLElement> _content = const [];
M.IsolateRef get isolate => _isolate;
M.LibraryRef get library => _library;
List<HTMLElement> get content => _content;
set content(Iterable<HTMLElement> value) {
_content = value.toList();
_r.dirty();
}
factory NavLibraryMenuElement(M.IsolateRef isolate, M.LibraryRef library,
{RenderingQueue? queue}) {
NavLibraryMenuElement e = new NavLibraryMenuElement.created();
e._r = new RenderingScheduler<NavLibraryMenuElement>(e, queue: queue);
e._isolate = isolate;
e._library = library;
return e;
}
NavLibraryMenuElement.created() : super.created('nav-library-menu');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
removeChildren();
_r.disable(notify: true);
}
void render() {
children = <HTMLElement>[
navMenu(library.name!,
content: _content,
link: Uris.inspect(isolate, object: library).toString())
];
}
}
@@ -1,69 +0,0 @@
// Copyright (c) 2016, 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.
import 'dart:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/custom_element.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
class NavMenuItemElement extends CustomElement implements Renderable {
late RenderingScheduler<NavMenuItemElement> _r;
Stream<RenderedEvent<NavMenuItemElement>> get onRendered => _r.onRendered;
late String _label;
late String _link;
List<HTMLElement> _content = const <HTMLElement>[];
String get label => _label;
String get link => _link;
List<HTMLElement> get content => _content;
set label(String value) => _label = _r.checkAndReact(_label, value);
set link(String value) => _link = _r.checkAndReact(_link, value);
set content(Iterable<HTMLElement> value) {
_content = value.toList();
_r.dirty();
}
factory NavMenuItemElement(String label,
{String link = '', RenderingQueue? queue}) {
NavMenuItemElement e = new NavMenuItemElement.created();
e._r = new RenderingScheduler<NavMenuItemElement>(e, queue: queue);
e._label = label;
e._link = link;
return e;
}
NavMenuItemElement.created() : super.created('nav-menu-item');
@override
void attached() {
super.attached();
_r.enable();
}
@override
void detached() {
super.detached();
_r.disable(notify: true);
removeChildren();
}
void render() {
children = <HTMLElement>[
new HTMLLIElement()
..className = 'nav-menu-item'
..appendChildren(<HTMLElement>[
new HTMLAnchorElement()
..href = link
..text = label,
new HTMLUListElement()..appendChildren(_content)
])
];
}
}

Some files were not shown because too many files have changed in this diff Show More