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