Version 1.12.0-dev.5.4
Cherry-pick 54b7e9fec4773305a37b5c91310e4efae088ce49 to dev
Cherry-pick fbe47ffa538a99c388d455abe023ad975344fbb3 to dev
Cherry-pick d0f216eb30f764470cca62413938f7cc4192c8ed to dev
Cherry-pick 5979d9341eeaf37c1b7e5bf26598c4e0266df921 to dev
Cherry-pick 62dbce855558492323b8f0344ddff59f07f4ff11 to dev
Cherry-pick 919f79e0449a49f35c1d466a28b3e19e779a8586 to dev
Cherry-pick 10de20f2307cfc96cba12a47343bae4ddfb61418 to dev
Cherry-pick 82b4f03dec5cbe98aa3510d88dd11e07b8164acb to dev
Cherry-pick f9944c1c4c31f528a64cdce2c0ca2b28df5954db to dev
Cherry-pick 8e91f1a7c3d6a41ea17c4527059de944ac86b2b5 to dev
Cherry-pick 7af879a084aa5d9c90666e634e7dfbc60dfc92cb to dev
Cherry-pick 2ecf40450c43ef91f9e73d324267c7d9dd8a9a4b to dev
Cherry-pick cacacfa64549b4b275f3877ac12e86f98b049f3c to dev
Cherry-pick 3dd39ef37cb8529af55201f8bc72e613ba6acaf2 to dev
Cherry-pick 71d7d7a4de18e2ff63d6f8e78fc307f5f7001ba8 to dev
Cherry-pick 67a7aeaf12b718a8564e804bcfd4851f3879559e to dev
Cherry-pick ec675a3b0d2e3267631c58cfae3568af28aa693c to dev
Cherry-pick 22a1159f4b080a206e21e106a6aa5395cab9b65e to dev
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index b879a36..3820db5 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -19,6 +19,7 @@
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/source/path_filter.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/source/sdk_ext.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -1345,7 +1346,8 @@
@override
Iterable<UriResolver> createPackageUriResolvers(
ResourceProvider resourceProvider) =>
- <UriResolver>[new PackageMapUriResolver(resourceProvider, packageMap)];
+ <UriResolver>[new SdkExtUriResolver(packageMap),
+ new PackageMapUriResolver(resourceProvider, packageMap)];
}
/**
@@ -1363,5 +1365,19 @@
@override
Iterable<UriResolver> createPackageUriResolvers(
- ResourceProvider resourceProvider) => const <UriResolver>[];
+ ResourceProvider resourceProvider) {
+ if (packages != null) {
+ // Construct package map for the SdkExtUriResolver.
+ Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
+ packages.asMap().forEach((String name, Uri uri) {
+ if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
+ var path = resourceProvider.pathContext.fromUri(uri);
+ packageMap[name] = <Folder>[resourceProvider.getFolder(path)];
+ }
+ });
+ return <UriResolver>[new SdkExtUriResolver(packageMap)];
+ } else {
+ return const <UriResolver>[];
+ }
+ }
}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 14b24a9..1c469f6 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -321,6 +321,45 @@
expect(contexts[1].name, equals('/my/proj/lib'));
}
+ // TODO(paulberry): This test only tests PackagesFileDisposition.
+ // Once http://dartbug.com/23909 is fixed, add a test for sdk extensions
+ // and PackageMapDisposition.
+ test_sdk_ext_packagespec() async {
+ // Create files.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([libPath, 'nope.dart']);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([sdkExtPath, 'entry.dart']);
+ String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+ newFile([sdkExtSrcPath, 'part.dart']);
+ // Setup sdk extension mapping.
+ newFile(
+ [libPath, '_sdkext'],
+ r'''
+{
+ "dart:foobar": "../sdk_ext/entry.dart"
+}
+''');
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Confirm that one context was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts, isNotNull);
+ expect(contexts.length, equals(1));
+ var context = contexts[0];
+ var source = context.sourceFactory.forUri('dart:foobar');
+ expect(source.fullName, equals('/my/proj/sdk_ext/entry.dart'));
+ }
+
+
test_refresh_folder_with_packagespec() {
// create a context with a .packages file
String packagespecFile = posix.join(projPath, '.packages');
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index ffc4703..fbc3083 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -32,7 +32,7 @@
static int _socketType(nativeSocket) {
var result = _getSocketType(nativeSocket);
if (result is OSError) {
- throw new FileSystemException("Error retreiving socket type", result);
+ throw new FileSystemException("Error retreiving socket type", "", result);
}
return result;
}
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
index 237c154..c71a41e 100644
--- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -43,10 +43,10 @@
}
_recordCallerAndCalleesInner(CodeCallTreeNode caller,
- CodeCallTreeNode callee) {
+ CodeCallTreeNode callee) {
if (caller != null) {
caller.profileCode._recordCallee(callee.profileCode, callee.count);
- callee.profileCode._recordCaller(caller.profileCode, callee.count);
+ callee.profileCode._recordCaller(caller.profileCode, caller.count);
}
for (var child in callee.children) {
@@ -290,10 +290,10 @@
}
_markFunctionCallsInner(FunctionCallTreeNode caller,
- FunctionCallTreeNode callee) {
+ FunctionCallTreeNode callee) {
if (caller != null) {
caller.profileFunction._recordCallee(callee.profileFunction, callee.count);
- callee.profileFunction._recordCaller(caller.profileFunction, callee.count);
+ callee.profileFunction._recordCaller(caller.profileFunction, caller.count);
}
for (var child in callee.children) {
_markFunctionCallsInner(callee, child);
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index cfd535b..998f82d 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -62,9 +62,11 @@
shadowRoot.querySelector('#stackTraceTreeConfig');
assert(stackTraceTreeConfigElement != null);
stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
+ stackTraceTreeConfigElement.show = false;
cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
assert(cpuProfileTreeElement != null);
cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
+ cpuProfileTreeElement.show = false;
cls.fields.forEach((field) => field.reload());
sampleBufferControlElement.allocationProfileClass = cls;
}
@@ -84,6 +86,8 @@
}
onSampleBufferChange(CpuProfile sampleBuffer) {
+ stackTraceTreeConfigElement.show = sampleBuffer.sampleCount > 0;
+ cpuProfileTreeElement.show = sampleBuffer.sampleCount > 0;
cpuProfileTreeElement.render();
}
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index e1d6d47..087daa5 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -458,6 +458,7 @@
}
await _changeState(kLoadingState);
profile.load(isolate, response);
+ profile.buildFunctionCallerAndCallees();
_update(profile);
await _changeState(kLoadedState);
// Notify listener.
@@ -500,7 +501,11 @@
refreshTime = new DateTime.now().toString();
stackDepth = profile.stackDepth.toString();
sampleRate = profile.sampleRate.toStringAsFixed(0);
- timeSpan = formatTime(profile.timeSpan);
+ if (profile.sampleCount == 0) {
+ timeSpan = '0s';
+ } else {
+ timeSpan = formatTime(profile.timeSpan);
+ }
}
void tagSelectorChanged(oldValue) {
@@ -555,6 +560,7 @@
}
Function onTreeConfigChange;
+ @observable bool show = true;
@observable bool showModeSelector = true;
@observable bool showDirectionSelector = true;
@observable String modeSelector = 'Function';
@@ -863,15 +869,22 @@
}
checkParameters() {
- var functionId = app.locationManager.uri.queryParameters['functionId'];
- if (functionId == null) {
- _focusOnFunction(null);
- return;
- }
if (isolate == null) {
return;
}
- isolate.getObject(functionId).then((func) => _focusOnFunction(func));
+ var functionId = app.locationManager.uri.queryParameters['functionId'];
+ var functionName =
+ app.locationManager.uri.queryParameters['functionName'];
+ if (functionId == '') {
+ // Fallback to searching by name.
+ _focusOnFunction(_findFunction(functionName));
+ } else {
+ if (functionId == null) {
+ _focusOnFunction(null);
+ return;
+ }
+ isolate.getObject(functionId).then((func) => _focusOnFunction(func));
+ }
}
_clearView() {
@@ -907,6 +920,8 @@
tableBody.children[row].offsetHeight;
tableBody.children[row].scrollIntoView(ScrollAlignment.CENTER);
tableBody.children[row].classes.add('shake');
+ // Focus on clicked function.
+ _focusOnFunction(function);
}
_clearFocusedFunction() {
@@ -919,6 +934,15 @@
focusedFunction = null;
}
+ ServiceFunction _findFunction(String functionName) {
+ for (var func in profile.functions) {
+ if (func.function.name == functionName) {
+ return func.function;
+ }
+ }
+ return null;
+ }
+
_focusOnFunction(ServiceFunction function) {
if (focusedFunction == function) {
// Do nothing.
@@ -956,7 +980,8 @@
var function = row.values[NameSortedTable.FUNCTION_COLUMN];
app.locationManager.goReplacingParameters(
{
- 'functionId': function.id
+ 'functionId': function.id,
+ 'functionName': function.vmName
}
);
}
@@ -1121,6 +1146,7 @@
TableTree codeTree;
TableTree functionTree;
FunctionCallTreeNodeFilter functionFilter;
+ @observable bool show = true;
CpuProfileTreeElement.created() : super.created();
@@ -1128,6 +1154,12 @@
_updateView();
}
+ showChanged(oldValue) {
+ var treeTable = shadowRoot.querySelector('#treeTable');
+ assert(treeTable != null);
+ treeTable.style.display = show ? 'table' : 'none';
+ }
+
void _updateView() {
if (functionTree != null) {
functionTree.clear();
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 588f869..d76cb19 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -34,8 +34,10 @@
}
</style>
<div class="content-centered-big">
- <h2>Sample buffer</h2>
- <hr>
+ <template if="{{ state != 'kNotLoaded' }}">
+ <h2>Sample buffer</h2>
+ <hr>
+ </template>
<template if="{{ state == 'kFetching' }}">
<div class="statusBox shadow center">
<div class="statusMessage">Fetching profile from VM...</div>
@@ -115,47 +117,49 @@
}
</style>
<div class="content-centered-big">
- <h2>Tree display</h2>
- <hr>
- <div class="memberList">
- <template if="{{ showModeSelector }}">
- <div class="memberItem">
- <div class="memberName">Mode</div>
- <div class="memberValue">
- <select value="{{modeSelector}}">
- <option value="Code">Code</option>
- <option value="Function">Function</option>
- </select>
+ <template if="{{ show }}">
+ <h2>Tree display</h2>
+ <hr>
+ <div class="memberList">
+ <template if="{{ showModeSelector }}">
+ <div class="memberItem">
+ <div class="memberName">Mode</div>
+ <div class="memberValue">
+ <select value="{{modeSelector}}">
+ <option value="Code">Code</option>
+ <option value="Function">Function</option>
+ </select>
+ </div>
</div>
+ </template>
+ <template if="{{ showDirectionSelector }}">
+ <div class="memberItem">
+ <div class="memberName">Call Tree Direction</div>
+ <div class="memberValue">
+ <select value="{{directionSelector}}">
+ <option value="Down">Top down</option>
+ <option value="Up">Bottom up</option>
+ </select>
+ </div>
+ </div>
+ </template>
+ </div>
+ <template if="{{ directionSelector == 'Down' }}">
+ <br>
+ <div class="statusBox shadow">
+ <div>Tree is rooted at main.</div>
+ <br>
+ <div>Child nodes are callees.</div>
</div>
</template>
- <template if="{{ showDirectionSelector }}">
- <div class="memberItem">
- <div class="memberName">Call Tree Direction</div>
- <div class="memberValue">
- <select value="{{directionSelector}}">
- <option value="Down">Top down</option>
- <option value="Up">Bottom up</option>
- </select>
- </div>
+ <template if="{{ directionSelector == 'Up' }}">
+ <br>
+ <div class="statusBox shadow">
+ <div>Tree is rooted at executing function / code.</div>
+ <br>
+ <div>Child nodes are callers.</div>
</div>
</template>
- </div>
- <template if="{{ directionSelector == 'Down' }}">
- <br>
- <div class="statusBox shadow">
- <div>Tree is rooted at main.</div>
- <br>
- <div>Child nodes are callees.</div>
- </div>
- </template>
- <template if="{{ directionSelector == 'Up' }}">
- <br>
- <div class="statusBox shadow">
- <div>Tree is rooted at executing function / code.</div>
- <br>
- <div>Child nodes are callers.</div>
- </div>
</template>
</div>
</template>
@@ -220,7 +224,7 @@
width: 100%;
}
</style>
- <table class="full-width tree">
+ <table id="treeTable" class="full-width tree">
<thead id="treeHeader">
<tr>
<th>Method</th>
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 2034b95..ede4571 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -1706,8 +1706,20 @@
app.vm.listenEventStream(VM.kDebugStream, debugger.onEvent);
_stdoutSubscriptionFuture =
app.vm.listenEventStream(VM.kStdoutStream, debugger.onStdout);
+ if (_stdoutSubscriptionFuture != null) {
+ // TODO(turnidge): How do we want to handle this in general?
+ _stdoutSubscriptionFuture.catchError((e, st) {
+ Logger.root.info('Failed to subscribe to stdout: $e\n$st\n');
+ });
+ }
_stderrSubscriptionFuture =
app.vm.listenEventStream(VM.kStderrStream, debugger.onStderr);
+ if (_stderrSubscriptionFuture != null) {
+ // TODO(turnidge): How do we want to handle this in general?
+ _stderrSubscriptionFuture.catchError((e, st) {
+ Logger.root.info('Failed to subscribe to stderr: $e\n$st\n');
+ });
+ }
_logSubscriptionFuture =
app.vm.listenEventStream(Isolate.kLoggingStream, debugger.onEvent);
// Turn on the periodic poll timer for this page.
diff --git a/runtime/observatory/lib/src/elements/function_ref.dart b/runtime/observatory/lib/src/elements/function_ref.dart
index 1f4d06f..d91a512 100644
--- a/runtime/observatory/lib/src/elements/function_ref.dart
+++ b/runtime/observatory/lib/src/elements/function_ref.dart
@@ -26,6 +26,10 @@
if (ref == null) {
return;
}
+ if (!function.kind.isDart()) {
+ insertTextSpanIntoShadowRoot(name);
+ return;
+ }
if (qualified) {
if (function.dartOwner is ServiceFunction) {
var functionRef = new Element.tag('function-ref');
diff --git a/runtime/observatory/lib/src/elements/heap_map.dart b/runtime/observatory/lib/src/elements/heap_map.dart
index 7b7be4f..a91e316 100644
--- a/runtime/observatory/lib/src/elements/heap_map.dart
+++ b/runtime/observatory/lib/src/elements/heap_map.dart
@@ -51,7 +51,7 @@
@CustomTag('heap-map')
class HeapMapElement extends ObservatoryElement {
- var _fragmentationCanvas;
+ CanvasElement _fragmentationCanvas;
var _fragmentationData;
var _pageHeight;
var _classIdToColor = {};
@@ -125,6 +125,9 @@
}
ObjectInfo _objectAt(Point<int> point) {
+ if (fragmentation == null || _fragmentationCanvas == null) {
+ return null;
+ }
var pagePixels = _pageHeight * _fragmentationData.width;
var index = new PixelReference(_fragmentationData, point).index;
var pageIndex = index ~/ pagePixels;
@@ -153,6 +156,10 @@
void _handleMouseMove(MouseEvent event) {
var info = _objectAt(event.offset);
+ if (info == null) {
+ status = '';
+ return;
+ }
var addressString = '${info.size}B @ 0x${info.address.toRadixString(16)}';
var className = _classNameAt(event.offset);
status = (className == '') ? '-' : '$className $addressString';
diff --git a/runtime/observatory/lib/src/elements/heap_map.html b/runtime/observatory/lib/src/elements/heap_map.html
index 1fb9aa0..8c95e22 100644
--- a/runtime/observatory/lib/src/elements/heap_map.html
+++ b/runtime/observatory/lib/src/elements/heap_map.html
@@ -19,6 +19,10 @@
height: 16px;
background-color: red;
}
+ #fragmentation {
+ width: 100%;
+ height: 100%;
+ }
</style>
<nav-bar pad="{{ false }}">
<top-nav-menu></top-nav-menu>
diff --git a/runtime/observatory/lib/src/elements/heap_profile.dart b/runtime/observatory/lib/src/elements/heap_profile.dart
index c5dbc76..25b5d54 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.dart
+++ b/runtime/observatory/lib/src/elements/heap_profile.dart
@@ -235,6 +235,7 @@
cell.text = classTable.getFormattedValue(rowIndex, i);
if (i > 1) { // Numbers.
cell.style.textAlign = 'right';
+ cell.style.paddingLeft = '1em';
}
}
}
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index de8487c..fe4fd95 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -6,126 +6,27 @@
import 'dart:async';
import 'observatory_element.dart';
-import 'package:observatory/app.dart';
import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
-class TagProfileChart {
- var _table = new DataTable();
- var _chart;
-
- void update(TagProfile tagProfile) {
- if (_table.columns == 0) {
- // Initialize.
- _table.addColumn('string', 'Time');
- for (var tagName in tagProfile.names) {
- if (tagName == 'Idle') {
- // Skip Idle tag.
- continue;
- }
- _table.addColumn('number', tagName);
- }
- }
- _table.clearRows();
- var idleIndex = tagProfile.names.indexOf('Idle');
- assert(idleIndex != -1);
- var t = tagProfile.updatedAtSeconds;
- for (var i = 0; i < tagProfile.snapshots.length; i++) {
- var snapshotTime = tagProfile.snapshots[i].seconds;
- var row = [];
- if (snapshotTime > 0.0) {
- row.add('t ${(snapshotTime - t).toStringAsFixed(2)}');
- } else {
- row.add('');
- }
- var sum = tagProfile.snapshots[i].sum;
- if (sum == 0) {
- for (var j = 0; j < tagProfile.snapshots[i].counters.length; j++) {
- if (j == idleIndex) {
- // Skip idle.
- continue;
- }
- row.add(0);
- }
- } else {
- for (var j = 0; j < tagProfile.snapshots[i].counters.length; j++) {
- if (j == idleIndex) {
- // Skip idle.
- continue;
- }
- var percentage = tagProfile.snapshots[i].counters[j] / sum * 100.0;
- row.add(percentage.toInt());
- }
- }
- _table.addRow(row);
- }
- }
-
- void draw(var element) {
- if (_chart == null) {
- assert(element != null);
- _chart = new Chart('SteppedAreaChart', element);
- _chart.options['isStacked'] = true;
- _chart.options['connectSteps'] = false;
- _chart.options['vAxis'] = {
- 'minValue': 0.0,
- 'maxValue': 100.0,
- };
- }
- _chart.draw(_table);
- }
-}
-
@CustomTag('isolate-view')
class IsolateViewElement extends ObservatoryElement {
@published Isolate isolate;
@published Library rootLibrary;
- Timer _updateTimer;
- TagProfileChart tagProfileChart = new TagProfileChart();
IsolateViewElement.created() : super.created();
Future<ServiceObject> evaluate(String expression) {
return isolate.rootLibrary.evaluate(expression);
}
- void _updateTagProfile() {
- isolate.updateTagProfile().then((tagProfile) {
- tagProfileChart.update(tagProfile);
- _drawTagProfileChart();
- if (_updateTimer != null) {
- // Start the timer again.
- _updateTimer = new Timer(new Duration(seconds: 1), _updateTagProfile);
- }
- });
- }
-
- @override
void attached() {
super.attached();
- // Start a timer to update the isolate summary once a second.
- _updateTimer = new Timer(new Duration(seconds: 1), _updateTagProfile);
if (isolate.topFrame != null) {
isolate.topFrame.function.load();
}
isolate.rootLibrary.load().then((lib) => rootLibrary = lib);
}
- @override
- void detached() {
- super.detached();
- if (_updateTimer != null) {
- _updateTimer.cancel();
- _updateTimer = null;
- }
- }
-
- void _drawTagProfileChart() {
- var element = shadowRoot.querySelector('#tagProfileChart');
- if (element != null) {
- tagProfileChart.draw(element);
- }
- }
-
Future refresh() async {
await isolate.reload();
if (isolate.topFrame != null) {
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 46b49ee..8a928e7 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -132,12 +132,6 @@
<hr>
<div class="content">
- <div id="tagProfileChart" class="miniProfileChart" style="height: 600px"></div>
- </div>
-
- <hr>
-
- <div class="content">
<eval-box callback="{{ evaluate }}"></eval-box>
</div>
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index 408916d..26ecc8e 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -54,7 +54,7 @@
<div class="content">
<template if="{{ library.dependencies.isNotEmpty }}">
dependencies ({{ library.dependencies.length }})
- <curly-block expand="{{ library.dependencies.length <= 8 }}">
+ <curly-block expand="{{ false }}">
<div class="memberList">
<template repeat="{{ dep in library.dependencies }}">
<div class="memberItem">
@@ -81,7 +81,7 @@
<template if="{{ library.scripts.isNotEmpty }}">
scripts ({{ library.scripts.length }})
- <curly-block expand="{{ library.scripts.length <= 8 }}">
+ <curly-block expand="{{ false }}">
<div class="memberList">
<template repeat="{{ script in library.scripts }}">
<div class="memberItem">
@@ -97,7 +97,7 @@
<template if="{{ library.classes.isNotEmpty }}">
classes ({{ library.classes.length }})
- <curly-block expand="{{ library.classes.length <= 8 }}">
+ <curly-block expand="{{ false }}">
<div class="memberList">
<template repeat="{{ cls in library.classes }}">
<div class="memberItem">
@@ -134,7 +134,7 @@
<template if="{{ library.functions.isNotEmpty }}">
functions ({{ library.functions.length }})
- <curly-block expand="{{ library.functions.length <= 8 }}">
+ <curly-block expand="{{ false }}">
<div class="memberList">
<template repeat="{{ function in library.functions }}">
<div class="memberItem">
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index c2e379f..c52370d 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -193,12 +193,24 @@
<nav-menu link="{{ makeLink('/inspect', isolate) }}" anchor="{{ isolate.name }}" last="{{ last }}">
<nav-menu-item link="{{ makeLink('/debugger', isolate) }}"
anchor="debugger"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/class-tree', isolate) }}"
+ anchor="class hierarchy"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/profiler', isolate) }}"
anchor="cpu profile"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/profiler-table', isolate) }}"
+ anchor="cpu profile (table)"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/allocation-profiler', isolate) }}"
anchor="allocation profile"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/heap-map', isolate) }}"
anchor="heap map"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/metrics', isolate) }}"
+ anchor="metrics"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/heap-snapshot', isolate) }}"
+ anchor="heap snapshot"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/ports', isolate) }}"
+ anchor="ports"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/logging', isolate) }}"
+ anchor="logging"></nav-menu-item>
<content></content>
</nav-menu>
</template>
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 3aeaf67..ee555ca 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -43,6 +43,16 @@
content.style.cursor = 'pointer';
}
+
+void addLink(Element content, String target) {
+ // Ick, destructive but still compatible with also adding an info box.
+ var a = new AnchorElement(href: target);
+ a.text = content.text;
+ content.text = '';
+ content.append(a);
+}
+
+
abstract class Annotation implements Comparable<Annotation> {
int line;
int columnStart;
@@ -101,47 +111,29 @@
class LibraryAnnotation extends Annotation {
Library target;
- LibraryAnnotation(this.target);
+ String url;
+ LibraryAnnotation(this.target, this.url);
void applyStyleTo(element) {
if (element == null) {
return; // TODO(rmacnak): Handling overlapping annotations.
}
- element.style.fontWeight = "bold";
element.title = "library ${target.uri}";
-
- addInfoBox(element, () {
- var details = table();
- var r = row();
- r.append(cell("Library"));
- r.append(cell(serviceRef(target)));
- details.append(r);
-
- return details;
- });
+ addLink(element, url);
}
}
class PartAnnotation extends Annotation {
Script part;
- PartAnnotation(this.part);
+ String url;
+ PartAnnotation(this.part, this.url);
void applyStyleTo(element) {
if (element == null) {
return; // TODO(rmacnak): Handling overlapping annotations.
}
- element.style.fontWeight = "bold";
element.title = "script ${part.uri}";
-
- addInfoBox(element, () {
- var details = table();
- var r = row();
- r.append(cell("Script"));
- r.append(cell(serviceRef(part)));
- details.append(r);
-
- return details;
- });
+ addLink(element, url);
}
}
@@ -207,7 +199,8 @@
}
abstract class DeclarationAnnotation extends Annotation {
- DeclarationAnnotation(decl) {
+ String url;
+ DeclarationAnnotation(decl, this.url) {
assert(decl.loaded);
SourceLocation location = decl.location;
if (location == null) {
@@ -244,119 +237,66 @@
class ClassDeclarationAnnotation extends DeclarationAnnotation {
Class klass;
- ClassDeclarationAnnotation(Class cls) : klass = cls, super(cls);
+ ClassDeclarationAnnotation(Class cls, String url)
+ : klass = cls,
+ super(cls, url);
void applyStyleTo(element) {
if (element == null) {
return; // TODO(rmacnak): Handling overlapping annotations.
}
- element.style.fontWeight = "bold";
element.title = "class ${klass.name}";
-
- addInfoBox(element, () {
- var details = table();
- var r = row();
- r.append(cell("Class"));
- r.append(cell(serviceRef(klass)));
- details.append(r);
-
- return details;
- });
+ addLink(element, url);
}
}
class FieldDeclarationAnnotation extends DeclarationAnnotation {
Field field;
- FieldDeclarationAnnotation(Field fld) : field = fld, super(fld);
+ FieldDeclarationAnnotation(Field fld, String url)
+ : field = fld,
+ super(fld, url);
void applyStyleTo(element) {
if (element == null) {
return; // TODO(rmacnak): Handling overlapping annotations.
}
- element.style.fontWeight = "bold";
- element.title = "field ${field.name}";
-
- addInfoBox(element, () {
- var details = table();
- var r = row();
- r.append(cell("Field"));
- r.append(cell(serviceRef(field)));
- details.append(r);
-
- if (field.isStatic) {
- if (field.loaded) {
- r = row();
- r.append(cell("Value"));
- r.append(cell(serviceRef(field.staticValue)));
- details.append(r);
- }
- } else {
- r = row();
- r.append(cell("Nullable"));
- r.append(cell(field.guardNullable ? "null observed"
- : "null not observed"));
- details.append(r);
-
- r = row();
- r.append(cell("Types"));
- if (field.guardClass == "dynamic") {
- r.append(cell("various"));
- } else if (field.guardClass == "unknown") {
- r.append(cell("none"));
- } else {
- r.append(cell(serviceRef(field.guardClass)));
- }
- details.append(r);
- }
-
- return details;
- });
+ var tooltip = "field ${field.name}";
+ element.title = tooltip;
+ addLink(element, url);
}
}
class FunctionDeclarationAnnotation extends DeclarationAnnotation {
ServiceFunction function;
- FunctionDeclarationAnnotation(ServiceFunction func)
- : function = func, super(func);
+ FunctionDeclarationAnnotation(ServiceFunction func, String url)
+ : function = func,
+ super(func, url);
void applyStyleTo(element) {
if (element == null) {
return; // TODO(rmacnak): Handling overlapping annotations.
}
- element.style.fontWeight = "bold";
- element.title = "method ${function.name}";
+ var tooltip = "method ${function.name}";
+ if (function.isOptimizable == false) {
+ tooltip += "\nUnoptimizable!";
+ }
+ if (function.isInlinable == false) {
+ tooltip += "\nNot inlinable!";
+ }
+ if (function.deoptimizations > 0) {
+ tooltip += "\nDeoptimized ${function.deoptimizations} times!";
+ }
+ element.title = tooltip;
if (function.isOptimizable == false ||
function.isInlinable == false ||
function.deoptimizations >0) {
- element.style.backgroundColor = "red";
+ element.style.backgroundColor = "#EEA7A7"; // Low-saturation red.
}
- addInfoBox(element, () {
- var details = table();
- var r = row();
- r.append(cell("Function"));
- r.append(cell(serviceRef(function)));
- details.append(r);
-
- r = row();
- r.append(cell("Usage Count"));
- r.append(cell("${function.usageCounter}"));
- details.append(r);
-
- if (function.isOptimizable == false) {
- details.append(row(cell("Unoptimizable!")));
- }
- if (function.isInlinable == false) {
- details.append(row(cell("Not inlinable!")));
- }
- if (function.deoptimizations > 0) {
- details.append(row("Deoptimized ${function.deoptimizations} times!"));
- }
- return details;
- });
+ addLink(element, url);
}
}
@@ -385,12 +325,14 @@
StreamSubscription scriptChangeSubscription;
+ bool hasLoadedLibraryDeclarations = false;
+
String makeLineId(int line) {
return 'line-$line';
}
void _scrollToCurrentPos() {
- var line = querySelector('#${makeLineId(_currentLine)}');
+ var line = shadowRoot.getElementById(makeLineId(_currentLine));
if (line != null) {
line.scrollIntoView();
}
@@ -469,14 +411,19 @@
computeAnnotations();
var table = linesTable();
+ var firstBuild = false;
if (container == null) {
// Indirect to avoid deleting the style element.
container = new DivElement();
shadowRoot.append(container);
+ firstBuild = true;
}
container.children.clear();
container.children.add(table);
makeCssClassUncopyable(table, "noCopy");
+ if (firstBuild) {
+ _scrollToCurrentPos();
+ }
}
void computeAnnotations() {
@@ -502,14 +449,20 @@
addCurrentExecutionAnnotation();
if (!inDebuggerContext && script.library != null) {
- loadDeclarationsOfLibrary(script.library);
- addLibraryAnnotations();
- addDependencyAnnotations();
- addPartAnnotations();
- addClassAnnotations();
- addFieldAnnotations();
- addFunctionAnnotations();
- addCallSiteAnnotations();
+ if (hasLoadedLibraryDeclarations) {
+ addLibraryAnnotations();
+ addDependencyAnnotations();
+ addPartAnnotations();
+ addClassAnnotations();
+ addFieldAnnotations();
+ addFunctionAnnotations();
+ addCallSiteAnnotations();
+ } else {
+ loadDeclarationsOfLibrary(script.library).then((_) {
+ hasLoadedLibraryDeclarations = true;
+ update();
+ });
+ }
}
addLocalVariableAnnotations();
@@ -527,34 +480,47 @@
}
}
- void loadDeclarationsOfLibrary(Library lib) {
- lib.load().then((lib) {
+ Future loadDeclarationsOfLibrary(Library lib) {
+ return lib.load().then((lib) {
+ var loads = [];
for (var func in lib.functions) {
- func.load();
+ loads.add(func.load());
}
for (var field in lib.variables) {
- field.load();
+ loads.add(field.load());
}
for (var cls in lib.classes) {
- cls.load().then((cls) {
- for (var func in cls.functions) {
- func.load();
- }
- for (var field in cls.fields) {
- field.load();
- }
- });
+ loads.add(loadDeclarationsOfClass(cls));
}
+ return Future.wait(loads);
});
}
+ Future loadDeclarationsOfClass(Class cls) {
+ return cls.load().then((cls) {
+ var loads = [];
+ for (var func in cls.functions) {
+ loads.add(func.load());
+ }
+ for (var field in cls.fields) {
+ loads.add(field.load());
+ }
+ return Future.wait(loads);
+ });
+ }
+
+ String inspectLink(ServiceObject ref) {
+ return gotoLink('/inspect', ref);
+ }
+
void addLibraryAnnotations() {
for (ScriptLine line in script.lines) {
// TODO(rmacnak): Use a real scanner.
var pattern = new RegExp("library ${script.library.name}");
var match = pattern.firstMatch(line.text);
if (match != null) {
- var anno = new LibraryAnnotation(script.library);
+ var anno = new LibraryAnnotation(script.library,
+ inspectLink(script.library));
anno.line = line.line;
anno.columnStart = match.start + 8;
anno.columnStop = match.end;
@@ -564,7 +530,8 @@
pattern = new RegExp("part of ${script.library.name}");
match = pattern.firstMatch(line.text);
if (match != null) {
- var anno = new LibraryAnnotation(script.library);
+ var anno = new LibraryAnnotation(script.library,
+ inspectLink(script.library));
anno.line = line.line;
anno.columnStart = match.start + 8;
anno.columnStop = match.end;
@@ -598,7 +565,7 @@
if (match != null) {
Library target = resolveDependency(match[1]);
if (target != null) {
- var anno = new LibraryAnnotation(target);
+ var anno = new LibraryAnnotation(target, inspectLink(target));
anno.line = line.line;
anno.columnStart = match.start + 8;
anno.columnStop = match.end - 1;
@@ -637,7 +604,7 @@
if (match != null) {
Script part = resolvePart(match[1]);
if (part != null) {
- var anno = new PartAnnotation(part);
+ var anno = new PartAnnotation(part, inspectLink(part));
anno.line = line.line;
anno.columnStart = match.start + 6;
anno.columnStop = match.end - 1;
@@ -651,7 +618,8 @@
void addClassAnnotations() {
for (var cls in script.library.classes) {
if ((cls.location != null) && (cls.location.script == script)) {
- annotations.add(new ClassDeclarationAnnotation(cls));
+ var a = new ClassDeclarationAnnotation(cls, inspectLink(cls));
+ annotations.add(a);
}
}
}
@@ -659,13 +627,15 @@
void addFieldAnnotations() {
for (var field in script.library.variables) {
if ((field.location != null) && (field.location.script == script)) {
- annotations.add(new FieldDeclarationAnnotation(field));
+ var a = new FieldDeclarationAnnotation(field, inspectLink(field));
+ annotations.add(a);
}
}
for (var cls in script.library.classes) {
for (var field in cls.fields) {
if ((field.location != null) && (field.location.script == script)) {
- annotations.add(new FieldDeclarationAnnotation(field));
+ var a = new FieldDeclarationAnnotation(field, inspectLink(field));
+ annotations.add(a);
}
}
}
@@ -679,7 +649,8 @@
(func.kind != FunctionKind.kImplicitSetterFunction)) {
// We annotate a field declaration with the field instead of the
// implicit getter or setter.
- annotations.add(new FunctionDeclarationAnnotation(func));
+ var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
+ annotations.add(a);
}
}
for (var cls in script.library.classes) {
@@ -690,7 +661,8 @@
(func.kind != FunctionKind.kImplicitSetterFunction)) {
// We annotate a field declaration with the field instead of the
// implicit getter or setter.
- annotations.add(new FunctionDeclarationAnnotation(func));
+ var a = new FunctionDeclarationAnnotation(func, inspectLink(func));
+ annotations.add(a);
}
}
}
diff --git a/runtime/observatory/lib/src/elements/script_inset.html b/runtime/observatory/lib/src/elements/script_inset.html
index 30b20d8..167816d 100644
--- a/runtime/observatory/lib/src/elements/script_inset.html
+++ b/runtime/observatory/lib/src/elements/script_inset.html
@@ -4,6 +4,13 @@
<polymer-element name="script-inset" extends="observatory-element">
<template>
<style>
+ a {
+ color: #0489c3;
+ text-decoration: none;
+ }
+ a:hover {
+ text-decoration: underline;
+ }
.sourceInset {
}
.sourceTable {
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index 19554d6..26ffd36 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -78,26 +78,27 @@
element.connection = object;
return element;
case 'Object':
- switch (object.vmType) {
- case 'ICData':
- ICDataViewElement element = new Element.tag('icdata-view');
- element.icData = object;
- return element;
- case 'Instructions':
- InstructionsViewElement element =
- new Element.tag('instructions-view');
- element.instructions = object;
- return element;
- case 'ObjectPool':
- ObjectPoolViewElement element = new Element.tag('objectpool-view');
- element.pool = object;
- return element;
- default:
- ObjectViewElement element = new Element.tag('object-view');
- element.object = object;
- return element;
- }
- break;
+ return (object) {
+ switch (object.vmType) {
+ case 'ICData':
+ ICDataViewElement element = new Element.tag('icdata-view');
+ element.icData = object;
+ return element;
+ case 'Instructions':
+ InstructionsViewElement element =
+ new Element.tag('instructions-view');
+ element.instructions = object;
+ return element;
+ case 'ObjectPool':
+ ObjectPoolViewElement element = new Element.tag('objectpool-view');
+ element.pool = object;
+ return element;
+ default:
+ ObjectViewElement element = new Element.tag('object-view');
+ element.object = object;
+ return element;
+ }
+ }(object);
case 'SocketList':
IOSocketListViewElement element =
new Element.tag('io-socket-list-view');
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 2e69952..3c8e639 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -1114,11 +1114,15 @@
});
}
- Future<ServiceObject> getObject(String objectId) {
+ Future<ServiceObject> getObject(String objectId, {bool reload: true}) {
assert(objectId != null && objectId != '');
var obj = _cache[objectId];
if (obj != null) {
- return obj.reload();
+ if (reload) {
+ return obj.reload();
+ }
+ // Returned cached object.
+ return new Future.value(obj);
}
Map params = {
'objectId': objectId,
@@ -2386,6 +2390,7 @@
@observable ProfileFunction profile;
@observable Instance icDataArray;
+ bool get canCache => true;
bool get immutable => false;
ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
diff --git a/runtime/observatory/tests/service/coverage_test.dart b/runtime/observatory/tests/service/coverage_test.dart
index 9ae233f..9a6db65 100644
--- a/runtime/observatory/tests/service/coverage_test.dart
+++ b/runtime/observatory/tests/service/coverage_test.dart
@@ -6,18 +6,18 @@
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
+import 'dart:developer';
int globalVar = 100;
class MyClass {
static void myFunction(int value) {
- print(value); // line 14
if (value < 0) {
print("negative");
} else {
print("positive");
}
+ debugger();
}
static void otherFunction(int value) {
@@ -31,128 +31,73 @@
void testFunction() {
MyClass.otherFunction(-100);
- int i = 0;
- while (true) {
- if (++i % 100000000 == 0) {
- MyClass.myFunction(10000);
- }
- }
-}
-
-List normalize(List coverage) {
- // The exact coverage numbers may vary based on how many times
- // things run. Normalize the data to 0 or 1.
- List normalized = [];
- for (int i = 0; i < coverage.length; i += 2) {
- normalized.add(coverage[i]);
- normalized.add(coverage[i+1] == 0 ? 0 : 1);
- }
- return normalized;
+ MyClass.myFunction(10000);
}
var tests = [
-// Go to breakpoint at line 14.
-(Isolate isolate) {
- return isolate.rootLibrary.load().then((_) {
- // Set up a listener to wait for breakpoint events.
- Completer completer = new Completer();
- isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
- var subscription;
- subscription = stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- print('Breakpoint reached');
- completer.complete();
- subscription.cancel();
- }
- });
- });
-
- // Create a timer to set a breakpoint with a short delay.
- new Timer(new Duration(milliseconds: 2000), () {
- // Add the breakpoint.
- print('Setting breakpoint.');
- var script = isolate.rootLibrary.scripts[0];
- var line = 14;
- isolate.addBreakpoint(script, line);
- });
-
- return completer.future;
- });
-},
+hasStoppedAtBreakpoint,
// Get coverage for function, class, library, script, and isolate.
-(Isolate isolate) {
- return isolate.getStack().then((ServiceMap stack) {
- // Make sure we are in the right place.
- expect(stack.type, equals('Stack'));
- expect(stack['frames'].length, greaterThanOrEqualTo(2));
- expect(stack['frames'][0].function.name, equals('myFunction'));
- expect(stack['frames'][0].function.dartOwner.name, equals('MyClass'));
+(Isolate isolate) async {
+ var stack = await isolate.getStack();
- var lib = isolate.rootLibrary;
- var func = stack['frames'][0].function;
- expect(func.name, equals('myFunction'));
- var cls = func.dartOwner;
- expect(cls.name, equals('MyClass'));
+ // Make sure we are in the right place.
+ expect(stack.type, equals('Stack'));
+ expect(stack['frames'].length, greaterThanOrEqualTo(2));
+ expect(stack['frames'][0].function.name, equals('myFunction'));
+ expect(stack['frames'][0].function.dartOwner.name, equals('MyClass'));
- List tests = [];
- // Function
- tests.add(isolate.invokeRpcNoUpgrade('_getCoverage',
- { 'targetId': func.id })
- .then((Map coverage) {
- expect(coverage['type'], equals('CodeCoverage'));
- expect(coverage['coverage'].length, equals(1));
- expect(normalize(coverage['coverage'][0]['hits']),
- equals([15, 1, 16, 1, 17, 0, 19, 1]));
- }));
- // Class
- tests.add(isolate.invokeRpcNoUpgrade('_getCoverage',
- { 'targetId': cls.id })
- .then((Map coverage) {
- expect(coverage['type'], equals('CodeCoverage'));
- expect(coverage['coverage'].length, equals(1));
- expect(normalize(coverage['coverage'][0]['hits']),
- equals([15, 1, 16, 1, 17, 0, 19, 1,
- 24, 1, 25, 1, 27, 0]));
- }));
- // Library
- tests.add(isolate.invokeRpcNoUpgrade('_getCoverage',
- { 'targetId': lib.id })
- .then((Map coverage) {
- expect(coverage['type'], equals('CodeCoverage'));
- expect(coverage['coverage'].length, equals(3));
- expect(normalize(coverage['coverage'][0]['hits']),
- equals([15, 1, 16, 1, 17, 0, 19, 1,
- 24, 1, 25, 1, 27, 0]));
- expect(normalize(coverage['coverage'][1]['hits']).take(12),
- equals([33, 1, 36, 1, 37, 0, 32, 1, 45, 0, 46, 0]));
- }));
- // Script
- tests.add(cls.load().then((_) {
- return isolate.invokeRpcNoUpgrade(
- '_getCoverage',
- { 'targetId': cls.location.script.id })
- .then((Map coverage) {
- expect(coverage['type'], equals('CodeCoverage'));
- expect(coverage['coverage'].length, equals(3));
- expect(normalize(coverage['coverage'][0]['hits']),
- equals([15, 1, 16, 1, 17, 0, 19, 1,
- 24, 1, 25, 1, 27, 0]));
- expect(normalize(coverage['coverage'][1]['hits']).take(12),
- equals([33, 1, 36, 1, 37, 0, 32, 1, 45, 0, 46, 0]));
- });
- }));
- // Isolate
- tests.add(cls.load().then((_) {
- return isolate.invokeRpcNoUpgrade('_getCoverage', {})
- .then((Map coverage) {
- expect(coverage['type'], equals('CodeCoverage'));
- expect(coverage['coverage'].length, greaterThan(100));
- });
- }));
- return Future.wait(tests);
- });
+ var lib = isolate.rootLibrary;
+ var func = stack['frames'][0].function;
+ expect(func.name, equals('myFunction'));
+ var cls = func.dartOwner;
+ expect(cls.name, equals('MyClass'));
+
+ // Function
+ var coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
+ { 'targetId': func.id });
+ expect(coverage['type'], equals('CodeCoverage'));
+ expect(coverage['coverage'].length, equals(1));
+ expect(coverage['coverage'][0]['hits'],
+ equals([15, 1, 16, 0, 18, 1, 20, 1]));
+
+ // Class
+ coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
+ { 'targetId': cls.id });
+ expect(coverage['type'], equals('CodeCoverage'));
+ expect(coverage['coverage'].length, equals(1));
+ expect(coverage['coverage'][0]['hits'],
+ equals([15, 1, 16, 0, 18, 1, 20, 1,
+ 24, 1, 25, 1, 27, 0]));
+
+ // Library
+ coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
+ { 'targetId': lib.id });
+ expect(coverage['type'], equals('CodeCoverage'));
+ expect(coverage['coverage'].length, equals(3));
+ expect(coverage['coverage'][0]['hits'],
+ equals([15, 1, 16, 0, 18, 1, 20, 1,
+ 24, 1, 25, 1, 27, 0]));
+ expect(coverage['coverage'][1]['hits'].take(12),
+ equals([33, 1, 34, 1, 32, 1, 105, 2, 105, 1]));
+
+ // Script
+ await cls.load();
+ coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
+ { 'targetId': cls.location.script.id });
+ expect(coverage['type'], equals('CodeCoverage'));
+ expect(coverage['coverage'].length, equals(3));
+ expect(coverage['coverage'][0]['hits'],
+ equals([15, 1, 16, 0, 18, 1, 20, 1,
+ 24, 1, 25, 1, 27, 0]));
+ expect(coverage['coverage'][1]['hits'].take(12),
+ equals([33, 1, 34, 1, 32, 1, 105, 2, 105, 1]));
+
+ // Isolate
+ coverage = await isolate.invokeRpcNoUpgrade('_getCoverage', {});
+ expect(coverage['type'], equals('CodeCoverage'));
+ expect(coverage['coverage'].length, greaterThan(100));
},
];
diff --git a/runtime/observatory/tests/service/debugger_location_test.dart b/runtime/observatory/tests/service/debugger_location_test.dart
index 0672907..1c26e31 100644
--- a/runtime/observatory/tests/service/debugger_location_test.dart
+++ b/runtime/observatory/tests/service/debugger_location_test.dart
@@ -8,13 +8,14 @@
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
import 'dart:async';
+import 'dart:developer';
void testFunction() {
int i = 0;
- while (true) {
- if (++i % 100000000 == 0) { // line 15
- print(i);
- }
+ while (i == 0) {
+ debugger();
+ print('loop');
+ print('loop');
}
}
@@ -51,35 +52,14 @@
var tests = [
-// Bring the isolate to a breakpoint at line 15.
-(Isolate isolate) {
- return isolate.rootLibrary.load().then((_) {
- // Listen for breakpoint event.
- Completer completer = new Completer();
- isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
- var subscription;
- subscription = stream.listen((ServiceEvent event) {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- subscription.cancel();
- completer.complete();
- }
- });
- });
-
- // Add the breakpoint.
- var script = isolate.rootLibrary.scripts[0];
- return isolate.addBreakpoint(script, 15).then((ServiceObject bpt) {
- return completer.future; // Wait for breakpoint events.
- });
- });
-},
+hasStoppedAtBreakpoint,
// Parse '' => current position
(Isolate isolate) {
return initDebugger(isolate).then((debugger) {
return DebuggerLocation.parse(debugger, '').then((DebuggerLocation loc) {
expect(loc.valid, isTrue);
- expect(loc.toString(), equals('debugger_location_test.dart:15'));
+ expect(loc.toString(), equals('debugger_location_test.dart:17'));
});
});
},
@@ -87,9 +67,9 @@
// Parse line
(Isolate isolate) {
return initDebugger(isolate).then((debugger) {
- return DebuggerLocation.parse(debugger, '16').then((DebuggerLocation loc) {
+ return DebuggerLocation.parse(debugger, '18').then((DebuggerLocation loc) {
expect(loc.valid, isTrue);
- expect(loc.toString(), equals('debugger_location_test.dart:16'));
+ expect(loc.toString(), equals('debugger_location_test.dart:18'));
});
});
},
diff --git a/runtime/observatory/tests/service/pause_on_start_and_exit_test.dart b/runtime/observatory/tests/service/pause_on_start_and_exit_test.dart
index 012a68f..b7f7935 100644
--- a/runtime/observatory/tests/service/pause_on_start_and_exit_test.dart
+++ b/runtime/observatory/tests/service/pause_on_start_and_exit_test.dart
@@ -1,10 +1,9 @@
// 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.
-// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
+// VMOptions=--error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
import 'test_helper.dart';
import 'dart:async';
diff --git a/runtime/observatory/tests/service/pause_on_start_then_step_test.dart b/runtime/observatory/tests/service/pause_on_start_then_step_test.dart
index 2c7b3b6..20e91c5 100644
--- a/runtime/observatory/tests/service/pause_on_start_then_step_test.dart
+++ b/runtime/observatory/tests/service/pause_on_start_then_step_test.dart
@@ -1,10 +1,9 @@
// 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.
-// VMOptions=--compile_all --error_on_bad_type --error_on_bad_override
+// VMOptions=--error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
import 'test_helper.dart';
import 'dart:async';
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 28b7f75..e57178c 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -82,12 +82,18 @@
}
-void ClassTable::TraceAllocationsFor(intptr_t cid, bool trace) {
+void ClassTable::SetTraceAllocationFor(intptr_t cid, bool trace) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
stats->set_trace_allocation(trace);
}
+bool ClassTable::TraceAllocationFor(intptr_t cid) {
+ ClassHeapStats* stats = PreliminaryStatsAt(cid);
+ return stats->trace_allocation();
+}
+
+
void ClassTable::Register(const Class& cls) {
intptr_t index = cls.id();
if (index != kIllegalCid) {
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index aebf15c..d7917de 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -218,7 +218,8 @@
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
- void TraceAllocationsFor(intptr_t cid, bool trace);
+ void SetTraceAllocationFor(intptr_t cid, bool trace);
+ bool TraceAllocationFor(intptr_t cid);
private:
friend class MarkingVisitor;
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 1eb55f3..001f980 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -958,10 +958,18 @@
if (function.IsNull()) {
Class& cls = Class::Handle();
cls ^= code.owner();
- ISL_Print(" 0x%" Px ": allocation stub for %s, %p\n",
- start + offset.Value(),
- cls.ToCString(),
- code.raw());
+ if (cls.IsNull()) {
+ const String& code_name = String::Handle(code.Name());
+ ISL_Print(" 0x%" Px ": %s, %p\n",
+ start + offset.Value(),
+ code_name.ToCString(),
+ code.raw());
+ } else {
+ ISL_Print(" 0x%" Px ": allocation stub for %s, %p\n",
+ start + offset.Value(),
+ cls.ToCString(),
+ code.raw());
+ }
} else {
ISL_Print(" 0x%" Px ": %s, %p\n",
start + offset.Value(),
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 1db4ad1..cc2ebcd 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -2393,6 +2393,9 @@
return;
}
}
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateArray_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(token_pos(),
*StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
@@ -2680,6 +2683,9 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(R1, instruction_->num_context_variables());
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateContext_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(instruction_->token_pos(),
*StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 9587767..e126292 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -2119,6 +2119,9 @@
return;
}
}
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateArray_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(token_pos(),
*StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
@@ -2394,6 +2397,9 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(R1, instruction_->num_context_variables());
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateContext_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(instruction_->token_pos(),
*StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 2e02c21..3f4d4dc 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -2128,6 +2128,9 @@
}
__ Bind(&slow_path);
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateArray_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(token_pos(),
*StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
@@ -2400,6 +2403,9 @@
compiler->SaveLiveRegisters(locs);
__ movl(EDX, Immediate(instruction_->num_context_variables()));
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateContext_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(instruction_->token_pos(),
*StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index df32f00..309198c 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -2246,6 +2246,9 @@
}
__ Bind(&slow_path);
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateArray_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(token_pos(),
*StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
@@ -2495,6 +2498,9 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(T1, instruction_->num_context_variables());
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateContext_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(instruction_->token_pos(),
*StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 84afa6f..927c699 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -2127,6 +2127,9 @@
}
__ Bind(&slow_path);
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateArray_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(token_pos(),
*StubCode::AllocateArray_entry(),
RawPcDescriptors::kOther,
@@ -2397,6 +2400,9 @@
compiler->SaveLiveRegisters(locs);
__ LoadImmediate(R10, Immediate(instruction_->num_context_variables()));
+ const Code& stub = Code::Handle(compiler->isolate(),
+ StubCode::AllocateContext_entry()->code());
+ compiler->AddStubCallTarget(stub);
compiler->GenerateCall(instruction_->token_pos(),
*StubCode::AllocateContext_entry(),
RawPcDescriptors::kOther,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 38c5c6b..8e2460e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1752,7 +1752,7 @@
class_table->UpdateAllocatedOld(cls_id, size);
}
const Class& cls = Class::Handle(class_table->At(cls_id));
- if (cls.trace_allocation()) {
+ if (cls.TraceAllocation(isolate)) {
Profiler::RecordAllocation(isolate, cls_id);
}
NoSafepointScope no_safepoint;
@@ -2750,14 +2750,18 @@
}
+bool Class::TraceAllocation(Isolate* isolate) const {
+ ClassTable* class_table = isolate->class_table();
+ return class_table->TraceAllocationFor(id());
+}
+
+
void Class::SetTraceAllocation(bool trace_allocation) const {
- const bool changed = trace_allocation != this->trace_allocation();
+ Isolate* isolate = Isolate::Current();
+ const bool changed = trace_allocation != this->TraceAllocation(isolate);
if (changed) {
- set_state_bits(
- TraceAllocationBit::update(trace_allocation, raw_ptr()->state_bits_));
- Isolate* isolate = Isolate::Current();
ClassTable* class_table = isolate->class_table();
- class_table->TraceAllocationsFor(id(), trace_allocation);
+ class_table->SetTraceAllocationFor(id(), trace_allocation);
DisableAllocationStub();
}
}
@@ -4202,6 +4206,7 @@
void Class::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ Isolate* isolate = Isolate::Current();
JSONObject jsobj(stream);
if ((raw() == Class::null()) || (id() == kFreeListElement)) {
// TODO(turnidge): This is weird and needs to be changed.
@@ -4226,7 +4231,7 @@
jsobj.AddProperty("_finalized", is_finalized());
jsobj.AddProperty("_implemented", is_implemented());
jsobj.AddProperty("_patch", is_patch());
- jsobj.AddProperty("_traceAllocations", trace_allocation());
+ jsobj.AddProperty("_traceAllocations", TraceAllocation(isolate));
const Class& superClass = Class::Handle(SuperClass());
if (!superClass.IsNull()) {
jsobj.AddProperty("super", superClass);
@@ -10129,13 +10134,15 @@
void Library::PrintJSONImpl(JSONStream* stream, bool ref) const {
- const char* library_name = String::Handle(name()).ToCString();
intptr_t id = index();
ASSERT(id >= 0);
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Library", ref);
jsobj.AddFixedServiceId("libraries/%" Pd "", id);
- jsobj.AddProperty("name", library_name);
+ const String& vm_name = String::Handle(name());
+ const String& user_name =
+ String::Handle(String::IdentifierPrettyName(vm_name));
+ AddNameProperties(&jsobj, user_name, vm_name);
const String& library_url = String::Handle(url());
jsobj.AddPropertyStr("uri", library_url);
if (ref) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 8d3ef5e..16dc598 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1366,9 +1366,7 @@
RawArray* cha_codes() const { return raw_ptr()->cha_codes_; }
void set_cha_codes(const Array& value) const;
- bool trace_allocation() const {
- return TraceAllocationBit::decode(raw_ptr()->state_bits_);
- }
+ bool TraceAllocation(Isolate* isolate) const;
void SetTraceAllocation(bool trace_allocation) const;
private:
@@ -1394,7 +1392,6 @@
kFieldsMarkedNullableBit = 11,
kCycleFreeBit = 12,
kEnumBit = 13,
- kTraceAllocationBit = 14,
kIsAllocatedBit = 15,
};
class ConstBit : public BitField<bool, kConstBit, 1> {};
@@ -1412,7 +1409,6 @@
kFieldsMarkedNullableBit, 1> {}; // NOLINT
class CycleFreeBit : public BitField<bool, kCycleFreeBit, 1> {};
class EnumBit : public BitField<bool, kEnumBit, 1> {};
- class TraceAllocationBit : public BitField<bool, kTraceAllocationBit, 1> {};
class IsAllocatedBit : public BitField<bool, kIsAllocatedBit, 1> {};
void set_name(const String& value) const;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 872b600..e773e95 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1071,6 +1071,13 @@
timestamp > profile_->max_time_ ? timestamp : profile_->max_time_;
}
+ void SanitizeMinMaxTimes() {
+ if ((profile_->min_time_ == kMaxInt64) && (profile_->max_time_ == 0)) {
+ profile_->min_time_ = 0;
+ profile_->max_time_ = 0;
+ }
+ }
+
void BuildCodeTable() {
ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler);
for (intptr_t sample_index = 0;
@@ -1105,6 +1112,7 @@
code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index);
}
}
+ SanitizeMinMaxTimes();
}
void FinalizeCodeIndexes() {
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index b40b477..89cf1fa 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1934,6 +1934,7 @@
static const MethodParameter* get_coverage_params[] = {
ISOLATE_PARAMETER,
+ new IdParameter("targetId", false),
NULL,
};
@@ -1946,7 +1947,7 @@
static const MethodParameter* get_call_site_data_params[] = {
ISOLATE_PARAMETER,
- new IdParameter("targetId", true),
+ new IdParameter("targetId", false),
NULL,
};
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 9459b29..2625200 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -857,6 +857,8 @@
ASSERT(kSmiTagShift == 1);
__ bic(R2, R2, Operand(kObjectAlignment - 1));
+ __ MaybeTraceAllocation(kContextCid, R4, &slow_case,
+ /* inline_isolate = */ false);
// Now allocate the object.
// R1: number of context variables.
// R2: object size.
@@ -1057,8 +1059,9 @@
const int kInlineInstanceSize = 12;
const intptr_t instance_size = cls.instance_size();
ASSERT(instance_size > 0);
+ Isolate* isolate = Isolate::Current();
if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size) &&
- !cls.trace_allocation()) {
+ !cls.TraceAllocation(isolate)) {
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index b3bd552..c8ef95a 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -921,6 +921,8 @@
ASSERT(kSmiTagShift == 1);
__ andi(R2, R2, Immediate(~(kObjectAlignment - 1)));
+ __ MaybeTraceAllocation(kContextCid, R4, &slow_case,
+ /* inline_isolate = */ false);
// Now allocate the object.
// R1: number of context variables.
// R2: object size.
@@ -1100,8 +1102,9 @@
__ ldr(R1, Address(SP));
// R1: instantiated type arguments.
}
+ Isolate* isolate = Isolate::Current();
if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size) &&
- !cls.trace_allocation()) {
+ !cls.TraceAllocation(isolate)) {
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 3b21fb7..5469d45 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -582,7 +582,7 @@
__ MaybeTraceAllocation(kArrayCid,
EAX,
&slow_case,
- /* near_jump = */ false,
+ Assembler::kFarJump,
/* inline_isolate = */ false);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
@@ -815,6 +815,12 @@
__ leal(EBX, Address(EDX, TIMES_4, fixed_size));
__ andl(EBX, Immediate(-kObjectAlignment));
+ __ MaybeTraceAllocation(kContextCid,
+ EAX,
+ &slow_case,
+ Assembler::kFarJump,
+ /* inline_isolate = */ false);
+
// Now allocate the object.
// EDX: number of context variables.
const intptr_t cid = kContextCid;
@@ -1027,8 +1033,9 @@
__ movl(EDX, Address(ESP, kObjectTypeArgumentsOffset));
// EDX: instantiated type arguments.
}
+ Isolate* isolate = Isolate::Current();
if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size) &&
- !cls.trace_allocation()) {
+ !cls.TraceAllocation(isolate)) {
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 1f7e244..73a0ba4 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -957,6 +957,8 @@
__ LoadImmediate(T0, ~((kObjectAlignment) - 1));
__ and_(T2, T2, T0);
+ __ MaybeTraceAllocation(kContextCid, T4, &slow_case,
+ /* inline_isolate = */ false);
// Now allocate the object.
// T1: number of context variables.
// T2: object size.
@@ -1151,8 +1153,9 @@
__ lw(T1, Address(SP, 0 * kWordSize));
// T1: type arguments.
}
+ Isolate* isolate = Isolate::Current();
if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size) &&
- !cls.trace_allocation()) {
+ !cls.TraceAllocation(isolate)) {
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index cdbcabb..877d750 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -602,7 +602,7 @@
// Check for allocation tracing.
__ MaybeTraceAllocation(kArrayCid,
&slow_case,
- /* near_jump = */ false,
+ Assembler::kFarJump,
/* inline_isolate = */ false);
const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
@@ -857,6 +857,12 @@
__ leaq(R13, Address(R10, TIMES_8, fixed_size));
__ andq(R13, Immediate(-kObjectAlignment));
+ // Check for allocation tracing.
+ __ MaybeTraceAllocation(kContextCid,
+ &slow_case,
+ Assembler::kFarJump,
+ /* inline_isolate = */ false);
+
// Now allocate the object.
// R10: number of context variables.
const intptr_t cid = kContextCid;
@@ -1065,8 +1071,9 @@
__ movq(RDX, Address(RSP, kObjectTypeArgumentsOffset));
// RDX: instantiated type arguments.
}
+ Isolate* isolate = Isolate::Current();
if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size) &&
- !cls.trace_allocation()) {
+ !cls.TraceAllocation(isolate)) {
Label slow_case;
// Allocate the object and update top to point to
// next object start and initialize the allocated object.
diff --git a/tools/VERSION b/tools/VERSION
index 3f0c944..6c0f4ac 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 12
PATCH 0
PRERELEASE 5
-PRERELEASE_PATCH 3
+PRERELEASE_PATCH 4