Version 1.9.0-dev.10.8

svn merge -c 44268 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44269 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44353 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44355 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44382 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44417 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44419 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44440 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44443 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44459 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44461 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44465 https://dart.googlecode.com/svn/branches/bleeding_edge trunk (mc resolve conflict)
svn merge -c 44466 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44480 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44499 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44505 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44520 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44523 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44525 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44526 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44528 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

Merge cl from:
https://codereview.chromium.org/1010753002


git-svn-id: https://dart.googlecode.com/svn/trunk@44530 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart/pkg/compiler/lib/src/js/rewrite_async.dart b/dart/pkg/compiler/lib/src/js/rewrite_async.dart
index 0f1f433..8e900c0 100644
--- a/dart/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/dart/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -996,18 +996,10 @@
     addStatement(node);
   }
 
-  void visitExpressionInStatementContext(js.Expression node) {
-    if (node is js.VariableDeclarationList) {
-      // Treat js.VariableDeclarationList as a statement.
-      visitVariableDeclarationList(node);
-    } else {
-      visitExpressionIgnoreResult(node);
-    }
-  }
 
   @override
   void visitExpressionStatement(js.ExpressionStatement node) {
-    visitExpressionInStatementContext(node.expression);
+    visitExpressionIgnoreResult(node.expression);
   }
 
   @override
@@ -1030,7 +1022,7 @@
     }
 
     if (node.init != null) {
-      visitExpressionInStatementContext(node.init);
+      addExpressionStatement(visitExpression(node.init));
     }
     int startLabel = newLabel("for condition");
     // If there is no update, continuing the loop is the same as going to the
@@ -1154,12 +1146,12 @@
           new js.LabeledStatement(node.label, translateInBlock(node.body)));
       return;
     }
+    // `continue label` is really continuing the nested loop.
+    // This is set up in [PreTranslationAnalysis.visitContinue].
+    // Here we only need a breakLabel:
     int breakLabel = newLabel("break ${node.label}");
-    int continueLabel = newLabel("continue ${node.label}");
     breakLabels[node] = breakLabel;
-    continueLabels[node] = continueLabel;
 
-    beginLabel(continueLabel);
     jumpTargets.add(node);
     visitStatement(node.body);
     jumpTargets.removeLast();
@@ -1535,7 +1527,9 @@
   }
 
   @override
-  void visitVariableDeclarationList(js.VariableDeclarationList node) {
+  js.Expression visitVariableDeclarationList(js.VariableDeclarationList node) {
+    List<js.Assignment> initializations = new List<js.Assignment>();
+
     // Declaration of local variables is hoisted outside the helper but the
     // initialization is done here.
     for (js.VariableInitialization initialization in node.declarations) {
@@ -1543,11 +1537,20 @@
       localVariables.add(declaration);
       if (initialization.value != null) {
         withExpression(initialization.value, (js.Expression value) {
-          addStatement(new js.ExpressionStatement(
-              new js.Assignment(new js.VariableUse(declaration.name), value)));
+          initializations.add(
+              new js.Assignment(new js.VariableUse(declaration.name), value));
         }, store: false);
       }
     }
+    if (initializations.isEmpty) {
+      // Dummy expression. Will be dropped by [visitExpressionIgnoreResult].
+      return js.number(0);
+    } else {
+      return initializations.reduce(
+          (js.Expression first, js.Expression second) {
+        return new js.Binary(",", first, second);
+      });
+    }
   }
 
   @override
@@ -2251,8 +2254,10 @@
   @override
   bool visitContinue(js.Continue node) {
     if (node.targetLabel != null) {
-      targets[node] = labelledStatements.lastWhere(
+      js.LabeledStatement targetLabel = labelledStatements.lastWhere(
           (js.LabeledStatement stm) => stm.label == node.targetLabel);
+      js.Loop targetStatement = targetLabel.body;
+      targets[node] = targetStatement;
     } else {
       targets[node] =
           loopsAndSwitches.lastWhere((js.Node node) => node is! js.Switch);
diff --git a/dart/pkg/compiler/lib/src/ssa/builder.dart b/dart/pkg/compiler/lib/src/ssa/builder.dart
index 2db55a0..93b0896 100644
--- a/dart/pkg/compiler/lib/src/ssa/builder.dart
+++ b/dart/pkg/compiler/lib/src/ssa/builder.dart
@@ -6034,6 +6034,7 @@
     // body-block will be used, but for loops we will add (unnecessary) phis
     // that will reference the body variables. This makes it look as if the
     // variables were used in a non-dominated block.
+    LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
     HBasicBlock enterBlock = openNewBlock();
     HTry tryInstruction = new HTry();
     close(tryInstruction);
@@ -6056,6 +6057,7 @@
 
     SubGraph finallyGraph = null;
 
+    localsHandler = new LocalsHandler.from(savedLocals);
     startFinallyBlock = graph.addNewBlock();
     open(startFinallyBlock);
     buildFinally();
@@ -6099,6 +6101,11 @@
     // block and the finally block.
     addExitTrySuccessor(startFinallyBlock);
 
+    // Use the locals handler not altered by the catch and finally
+    // blocks.
+    // TODO(sigurdm): We can probably do this, because try-variables are boxed.
+    // Need to verify.
+    localsHandler = savedLocals;
     open(exitBlock);
     enterBlock.setBlockFlow(
         new HTryBlockInformation(
diff --git a/dart/runtime/bin/builtin.dart b/dart/runtime/bin/builtin.dart
index d8c586c..27d751a 100644
--- a/dart/runtime/bin/builtin.dart
+++ b/dart/runtime/bin/builtin.dart
@@ -350,7 +350,7 @@
   _finishedOneLoadRequest(uri);
 }
 
-void _asyncLoadError(tag, uri, libraryUri, error) {
+void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) {
   if (_logBuiltin) {
     _print("_asyncLoadError($uri), error: $error");
   }
@@ -359,7 +359,7 @@
     // uri.
     libraryUri = uri;
   }
-  _asyncLoadErrorCallback(uri, libraryUri, new LoadError(error.toString()));
+  _asyncLoadErrorCallback(uri, libraryUri, error);
   _finishedOneLoadRequest(uri);
 }
 
@@ -373,10 +373,15 @@
     if (dataOrError is List<int>) {
       _loadScript(tag, uri, libraryUri, dataOrError);
     } else {
-      _asyncLoadError(tag, uri, libraryUri, dataOrError);
+      assert(dataOrError is String);
+      var error = new LoadError(dataOrError.toString());
+      _asyncLoadError(tag, uri, libraryUri, error);
     }
   }).catchError((e) {
-    _asyncLoadError(tag, uri, libraryUri, e.toString());
+    // Wrap inside a LoadError unless we are already propagating a previously
+    // seen LoadError.
+    var error = (e is LoadError) ? e : new LoadError(e.toString);
+    _asyncLoadError(tag, uri, libraryUri, error);
   });
 
   try {
@@ -387,7 +392,10 @@
     if (_logBuiltin) {
       _print("Exception when communicating with service isolate: $e");
     }
-    _asyncLoadError(tag, uri, libraryUri, e.toString());
+    // Wrap inside a LoadError unless we are already propagating a previously
+    // seen LoadError.
+    var error = (e is LoadError) ? e : new LoadError(e.toString);
+    _asyncLoadError(tag, uri, libraryUri, error);
     receivePort.close();
   }
 }
diff --git a/dart/runtime/bin/dbg_message.cc b/dart/runtime/bin/dbg_message.cc
index 91558bf..1d8c22c 100644
--- a/dart/runtime/bin/dbg_message.cc
+++ b/dart/runtime/bin/dbg_message.cc
@@ -1098,10 +1098,6 @@
     // request.
     bool resume = false;
     while (!resume && Dart_HasServiceMessages()) {
-      // Release the message queue lock before handling service
-      // messages.  This allows notifications to come in while we are
-      // processing long requests and avoids deadlock with the PortMap
-      // lock in the vm.
       msg_queue_lock_.Exit();
       resume = Dart_HandleServiceMessages();
       msg_queue_lock_.Enter();
diff --git a/dart/runtime/bin/file_patch.dart b/dart/runtime/bin/file_patch.dart
index 14499af..479bb9f 100644
--- a/dart/runtime/bin/file_patch.dart
+++ b/dart/runtime/bin/file_patch.dart
@@ -193,6 +193,10 @@
             if (event == null) continue;
             eventCount++;
             int pathId = event[4];
+            if (!_idMap.containsKey(pathId)) {
+              // Path is no longer being wathed.
+              continue;
+            }
             bool isDir = getIsDir(event);
             var path = getPath(event);
             if ((event[0] & FileSystemEvent.CREATE) != 0) {
diff --git a/dart/runtime/bin/vmservice/server.dart b/dart/runtime/bin/vmservice/server.dart
index 55f36e0..c6e7ce4 100644
--- a/dart/runtime/bin/vmservice/server.dart
+++ b/dart/runtime/bin/vmservice/server.dart
@@ -31,8 +31,7 @@
         return;
       }
       var serial = map['id'];
-
-      onMessage(serial, new Message.fromJsonRpc(map['method'], map['params']));
+      onMessage(serial, new Message.fromJsonRpc(map));
     } else {
       socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
     }
diff --git a/dart/runtime/include/dart_api.h b/dart/runtime/include/dart_api.h
index acea977..2d2dbc3 100755
--- a/dart/runtime/include/dart_api.h
+++ b/dart/runtime/include/dart_api.h
@@ -1108,6 +1108,9 @@
  * This function may be used by an embedder at a breakpoint to avoid
  * pausing the vm service.
  *
+ * This function can indirectly cause the message notify callback to
+ * be called.
+ *
  * \return true if the vm service requests the program resume
  * execution, false otherwise
  */
diff --git a/dart/runtime/observatory/lib/service_common.dart b/dart/runtime/observatory/lib/service_common.dart
index 7aebc81..3add115 100644
--- a/dart/runtime/observatory/lib/service_common.dart
+++ b/dart/runtime/observatory/lib/service_common.dart
@@ -203,6 +203,12 @@
       Logger.root.severe('Received unexpected message: ${map}');
       return;
     }
+    if (request.method != 'getTagProfile' &&
+        request.method != 'getIsolateMetric' &&
+        request.method != 'getVMMetric') {
+      Logger.root.info(
+          'RESPONSE [${serial}] ${request.method}');
+    }
     request.completer.complete(response);
   }
 
@@ -260,11 +266,6 @@
   /// Send the request over WebSocket.
   void _sendRequest(String serial, _WebSocketRequest request) {
     assert (_webSocket.isOpen);
-    if (request.method != 'getTagProfile' &&
-        request.method != 'getIsolateMetric' &&
-        request.method != 'getVMMetric') {
-      Logger.root.info('GET ${request.method} from ${target.networkAddress}');
-    }
     // Mark request as pending.
     assert(_pendingRequests.containsKey(serial) == false);
     _pendingRequests[serial] = request;
@@ -284,6 +285,12 @@
                              'method': request.method,
                              'params': request.params});
     }
+    if (request.method != 'getTagProfile' &&
+        request.method != 'getIsolateMetric' &&
+        request.method != 'getVMMetric') {
+      Logger.root.info(
+          'GET [${serial}] ${request.method} from ${target.networkAddress}');
+    }
     // Send message.
     _webSocket.send(message);
   }
diff --git a/dart/runtime/observatory/lib/src/app/application.dart b/dart/runtime/observatory/lib/src/app/application.dart
index c5413c9..d06c6e1 100644
--- a/dart/runtime/observatory/lib/src/app/application.dart
+++ b/dart/runtime/observatory/lib/src/app/application.dart
@@ -51,9 +51,11 @@
 
   void removePauseEvents(Isolate isolate) {
     bool isPauseEvent(var event) {
-      return (event.eventType == 'IsolateInterrupted' ||
-              event.eventType == 'BreakpointReached' ||
-              event.eventType == 'ExceptionThrown');
+      return (event.eventType == ServiceEvent.kPauseStart ||
+              event.eventType == ServiceEvent.kPauseExit ||
+              event.eventType == ServiceEvent.kPauseBreakpoint ||
+              event.eventType == ServiceEvent.kPauseInterrupted ||
+              event.eventType == ServiceEvent.kPauseException);
     }
 
     notifications.removeWhere((oldEvent) {
@@ -64,46 +66,29 @@
 
   void _onEvent(ServiceEvent event) {
     switch(event.eventType) {
-      case 'IsolateCreated':
+      case ServiceEvent.kIsolateStart:
+      case ServiceEvent.kGraph:
+      case ServiceEvent.kBreakpointAdded:
+      case ServiceEvent.kBreakpointResolved:
+      case ServiceEvent.kBreakpointRemoved:
+      case ServiceEvent.kGC:
         // Ignore for now.
         break;
 
-      case 'IsolateResumed':
-        event.isolate.pauseEvent = null;
-        break;
-
-      case 'IsolateShutdown':
-        // TODO(turnidge): Should we show the user isolate shutdown events?
-        // What if there are hundreds of them?  Coalesce multiple
-        // shutdown events into one notification?
+      case ServiceEvent.kIsolateExit:
+      case ServiceEvent.kResume:
         removePauseEvents(event.isolate);
-
-        // TODO(turnidge): Reload the isolate for now in case it is
-        // paused.  We may need to distinguish an IsolateShutdown
-        // event from a "paused at isolate shutdown" event.
-        event.isolate.reload();
         break;
 
-      case 'BreakpointResolved':
-        event.isolate.reloadBreakpoints();
-        break;
-
-      case 'BreakpointReached':
-      case 'IsolateInterrupted':
-      case 'ExceptionThrown':
-        event.isolate.pauseEvent = event;
+      case ServiceEvent.kPauseStart:
+      case ServiceEvent.kPauseExit:
+      case ServiceEvent.kPauseBreakpoint:
+      case ServiceEvent.kPauseInterrupted:
+      case ServiceEvent.kPauseException:
         removePauseEvents(event.isolate);
         notifications.add(event);
         break;
 
-      case '_Graph':
-        event.isolate.loadHeapSnapshot(event);
-        break;
-
-      case 'GC':
-        // Ignore GC events for now.
-        break;
-
       default:
         // Ignore unrecognized events.
         Logger.root.severe('Unrecognized event: $event');
@@ -217,7 +202,7 @@
 
   void _removeDisconnectEvents() {
     notifications.removeWhere((oldEvent) {
-        return (oldEvent.eventType == 'VMDisconnected');
+        return (oldEvent.eventType == ServiceEvent.kVMDisconnected);
       });
   }
 
diff --git a/dart/runtime/observatory/lib/src/cli/command.dart b/dart/runtime/observatory/lib/src/cli/command.dart
index 30a7874..67b21c2 100644
--- a/dart/runtime/observatory/lib/src/cli/command.dart
+++ b/dart/runtime/observatory/lib/src/cli/command.dart
@@ -4,11 +4,26 @@
 
 part of cli;
 
-// Splits a line into a list of string args.
+// Splits a line into a list of string args.  Each arg retains any
+// trailing whitespace so that we can reconstruct the original command
+// line from the pieces.
 List<String> _splitLine(String line) {
-  var args = line.split(' ').where((arg) {
-      return arg != ' ' && arg != '';
-    }).toList();
+  line = line.trimLeft();
+  var args = [];
+  var codes = line.codeUnits;
+
+  int pos = 0;
+  while (pos < line.length) {
+    int startPos = pos;
+
+    // Advance to end of word.
+    for (; pos < line.length && line[pos] != ' '; pos++);
+
+    // Advance to end of spaces.
+    for (; pos < line.length && line[pos] == ' '; pos++);
+
+    args.add(line.substring(startPos, pos));
+  }
   return args;
 }
 
@@ -17,7 +32,7 @@
   if (count == 0) {
     return '';
   }
-  return '${args.sublist(0, count).join(" ")} ';
+  return '${args.sublist(0, count).join('')}';
 }
 
 // Shared functionality for RootCommand and Command.
@@ -46,11 +61,12 @@
   Future run(List<String> args);
 
   // Returns a list of local subcommands which match the args.
-  List<Command> _matchLocal(String arg, bool preferExact) {
+  List<Command> _matchLocal(String argWithSpace, bool preferExact) {
     var matches = new List<Command>();
+    var arg = argWithSpace.trimRight();
     for (var child in _children) {
       if (child.name.startsWith(arg)) {
-        if (preferExact && child.name == arg) {
+        if (preferExact && ((child.name == arg) || (child.alias == arg))) {
           return [child];
         }
         matches.add(child);
@@ -220,6 +236,8 @@
   Command(this.name, List<Command> children) : super(children);
 
   final String name;
+  String alias;
+
   String get fullName {
     if (_parent is RootCommand) {
       return name;
diff --git a/dart/runtime/observatory/lib/src/debugger/debugger.dart b/dart/runtime/observatory/lib/src/debugger/debugger.dart
index d028c36..97a6ff5 100644
--- a/dart/runtime/observatory/lib/src/debugger/debugger.dart
+++ b/dart/runtime/observatory/lib/src/debugger/debugger.dart
@@ -8,4 +8,5 @@
 abstract class Debugger {
   Isolate get isolate;
   ServiceMap get stack;
+  int get currentFrame;
 }
diff --git a/dart/runtime/observatory/lib/src/debugger/source_location.dart b/dart/runtime/observatory/lib/src/debugger/source_location.dart
index 07ab3f6..f14d87b 100644
--- a/dart/runtime/observatory/lib/src/debugger/source_location.dart
+++ b/dart/runtime/observatory/lib/src/debugger/source_location.dart
@@ -48,7 +48,7 @@
       return new Future.value(new SourceLocation.error(
           'A script must be provided when the stack is empty'));
     }
-    var frame = stack['frames'][0];
+    var frame = stack['frames'][debugger.currentFrame];
     Script script = frame['script'];
     return script.load().then((_) {
       var line = script.tokenToLine(frame['tokenPos']);
diff --git a/dart/runtime/observatory/lib/src/elements/cpu_profile.html b/dart/runtime/observatory/lib/src/elements/cpu_profile.html
index c5e5cf7..4893f99 100644
--- a/dart/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/dart/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -153,15 +153,17 @@
               </select>
             </div>
           </div>
+          <!--- Experimental
           <div class="memberItem">
             <div class="memberName">Call Tree Direction</div>
             <div class="memberValue">
               <select value="{{directionSelector}}">
-                <!--- Experimental <option value="Down">Top down</option> --->
+                <option value="Down">Top down</option>
                 <option value="Up">Bottom up</option>
               </select>
             </div>
           </div>
+           --->
         </div>
       </template>
       <template if="{{ state == 'Loaded' && directionSelector == 'Down' }}">
diff --git a/dart/runtime/observatory/lib/src/elements/debugger.dart b/dart/runtime/observatory/lib/src/elements/debugger.dart
index e9d1623..4a9bdf8 100644
--- a/dart/runtime/observatory/lib/src/elements/debugger.dart
+++ b/dart/runtime/observatory/lib/src/elements/debugger.dart
@@ -28,6 +28,14 @@
 class HelpCommand extends DebuggerCommand {
   HelpCommand(Debugger debugger) : super(debugger, 'help', []);
 
+  String _nameAndAlias(Command cmd) {
+    if (cmd.alias == null) {
+      return cmd.name;
+    } else {
+      return '${cmd.name}, ${cmd.alias}';
+    }
+  }
+
   Future run(List<String> args) {
     var con = debugger.console;
     if (args.length == 0) {
@@ -36,14 +44,16 @@
       commands.sort((a, b) => a.name.compareTo(b.name));
       con.print('List of commands:\n');
       for (var command in commands) {
-        con.print('${command.name.padRight(12)} - ${command.helpShort}');
+        con.print('${_nameAndAlias(command).padRight(12)} '
+                  '- ${command.helpShort}');
       }
       con.print(
           "\nFor more information on a specific command type 'help <command>'\n"
           "\n"
           "Command prefixes are accepted (e.g. 'h' for 'help')\n"
           "Hit [TAB] to complete a command (try 'i[TAB][TAB]')\n"
-          "Hit [ENTER] to repeat the last command\n");
+          "Hit [ENTER] to repeat the last command\n"
+          "Use up/down arrow for command history\n");
       return new Future.value(null);
     } else {
       // Print any matching commands.
@@ -56,7 +66,7 @@
       }
       con.print('');
       for (var command in commands) {
-        con.printBold(command.fullName);
+        con.printBold(_nameAndAlias(command));
         con.print(command.helpLong);
 
         var newArgs = [];
@@ -94,6 +104,138 @@
       '        help <command>  - Help for a specific command\n';
 }
 
+class PrintCommand extends DebuggerCommand {
+  PrintCommand(Debugger debugger) : super(debugger, 'print', []) {
+    alias = 'p';
+  }
+
+  Future run(List<String> args) {
+    if (args.length < 1) {
+      debugger.console.print('print expects arguments');
+      return new Future.value(null);
+    }
+    var expr = args.join('');
+    return debugger.isolate.evalFrame(debugger.currentFrame, expr)
+      .then((response) {
+          if (response is DartError) {
+            debugger.console.print(response.message);
+          } else {
+            debugger.console.print('= ', newline:false);
+            debugger.console.printRef(response);
+          }
+      });
+  }
+
+  String helpShort = 'Evaluate and print an expression in the current frame';
+
+  String helpLong =
+      'Evaluate and print an expression in the current frame.\n'
+      '\n'
+      'Syntax: print <expression>\n'
+      '        p <expression>\n';
+}
+
+class DownCommand extends DebuggerCommand {
+  DownCommand(Debugger debugger) : super(debugger, 'down', []);
+
+  Future run(List<String> args) {
+    int count = 1;
+    if (args.length == 1) {
+      count = int.parse(args[0]);
+    } else if (args.length > 1) {
+      debugger.console.print('down expects 0 or 1 argument');
+      return new Future.value(null);
+    }
+    if (debugger.currentFrame == null) {
+      debugger.console.print('No stack');
+      return new Future.value(null);
+    }
+    try {
+      debugger.currentFrame -= count;
+      debugger.console.print('frame = ${debugger.currentFrame}');
+    } catch (e) {
+      debugger.console.print('frame must be in range [${e.start},${e.end-1}]');
+    }
+    return new Future.value(null);
+  }
+
+  String helpShort = 'Move down one or more frames';
+
+  String helpLong =
+      'Move down one or more frames.\n'
+      '\n'
+      'Syntax: down\n'
+      '        down <count>\n';
+}
+
+class UpCommand extends DebuggerCommand {
+  UpCommand(Debugger debugger) : super(debugger, 'up', []);
+
+  Future run(List<String> args) {
+    int count = 1;
+    if (args.length == 1) {
+      count = int.parse(args[0]);
+    } else if (args.length > 1) {
+      debugger.console.print('up expects 0 or 1 argument');
+      return new Future.value(null);
+    }
+    if (debugger.currentFrame == null) {
+      debugger.console.print('No stack');
+      return new Future.value(null);
+    }
+    try {
+      debugger.currentFrame += count;
+      debugger.console.print('frame = ${debugger.currentFrame}');
+    } on RangeError catch (e) {
+      debugger.console.print('frame must be in range [${e.start},${e.end-1}]');
+    }
+    return new Future.value(null);
+  }
+
+  String helpShort = 'Move up one or more frames';
+
+  String helpLong =
+      'Move up one or more frames.\n'
+      '\n'
+      'Syntax: up\n'
+      '        up <count>\n';
+}
+
+class FrameCommand extends DebuggerCommand {
+  FrameCommand(Debugger debugger) : super(debugger, 'frame', []) {
+    alias = 'f';
+  }
+
+  Future run(List<String> args) {
+    int frame = 1;
+    if (args.length == 1) {
+      frame = int.parse(args[0]);
+    } else {
+      debugger.console.print('frame expects 1 argument');
+      return new Future.value(null);
+    }
+    if (debugger.currentFrame == null) {
+      debugger.console.print('No stack');
+      return new Future.value(null);
+    }
+    try {
+      debugger.currentFrame = frame;
+      debugger.console.print('frame = ${debugger.currentFrame}');
+    } on RangeError catch (e) {
+      debugger.console.print('frame must be in range [${e.start},${e.end-1}]');
+    }
+    return new Future.value(null);
+  }
+
+  String helpShort = 'Set the current frame';
+
+  String helpLong =
+      'Set the current frame.\n'
+      '\n'
+      'Syntax: frame <number>\n'
+      '        f <count>\n';
+}
+
 class PauseCommand extends DebuggerCommand {
   PauseCommand(Debugger debugger) : super(debugger, 'pause', []);
 
@@ -115,7 +257,9 @@
 }
 
 class ContinueCommand extends DebuggerCommand {
-  ContinueCommand(Debugger debugger) : super(debugger, 'continue', []);
+  ContinueCommand(Debugger debugger) : super(debugger, 'continue', []) {
+    alias = 'c';
+  }
 
   Future run(List<String> args) {
     if (debugger.isolatePaused()) {
@@ -133,7 +277,8 @@
   String helpLong =
       'Continue running the isolate.\n'
       '\n'
-      'Syntax: continue\n';
+      'Syntax: continue\n'
+      '        c\n';
 }
 
 class NextCommand extends DebuggerCommand {
@@ -142,11 +287,11 @@
   Future run(List<String> args) {
     if (debugger.isolatePaused()) {
       var event = debugger.isolate.pauseEvent;
-      if (event.eventType == 'IsolateCreated') {
+      if (event.eventType == ServiceEvent.kPauseStart) {
         debugger.console.print("Type 'continue' to start the isolate");
         return new Future.value(null);
       }
-      if (event.eventType == 'IsolateShutdown') {
+      if (event.eventType == ServiceEvent.kPauseExit) {
         debugger.console.print("Type 'continue' to exit the isolate");
         return new Future.value(null);
       }
@@ -174,11 +319,11 @@
   Future run(List<String> args) {
     if (debugger.isolatePaused()) {
       var event = debugger.isolate.pauseEvent;
-      if (event.eventType == 'IsolateCreated') {
+      if (event.eventType == ServiceEvent.kPauseStart) {
         debugger.console.print("Type 'continue' to start the isolate");
         return new Future.value(null);
       }
-      if (event.eventType == 'IsolateShutdown') {
+      if (event.eventType == ServiceEvent.kPauseExit) {
         debugger.console.print("Type 'continue' to exit the isolate");
         return new Future.value(null);
       }
@@ -190,7 +335,7 @@
   }
 
   String helpShort =
-      'Continue running the isolate until it reaches the  next source location';
+      'Continue running the isolate until it reaches the next source location';
 
   String helpLong =
       'Continue running the isolate until it reaches the next source '
@@ -258,13 +403,6 @@
       // TODO(turnidge): Adding a duplicate breakpoint is
       // currently ignored.  May want to change the protocol to
       // inform us when this happens.
-
-      // The BreakpointResolved event prints resolved
-      // breakpoints already.  Just print the unresolved ones here.
-      Breakpoint bpt = result;
-      if (!bpt.resolved) {
-        return debugger._reportBreakpointAdded(bpt);
-      }
     }
     return new Future.value(null);
   }
@@ -330,7 +468,7 @@
               'clearing breakpoint at a specific column not yet implemented');
         }
 
-        for (var bpt in debugger.isolate.breakpoints) {
+        for (var bpt in debugger.isolate.breakpoints.values) {
           var script = bpt.script;
           if (script.id == loc.script.id) {
             assert(script.loaded);
@@ -341,12 +479,6 @@
                   debugger.console.print(
                       'Unable to clear breakpoint at ${loc}: ${result.message}');
                   return;
-                } else {
-                  // TODO(turnidge): Add a BreakpointRemoved event to
-                  // the service instead of printing here.
-                  var bpId = bpt.number;
-                  debugger.console.print('Breakpoint ${bpId} removed at ${loc}');
-                  return;
                 }
               });
             }
@@ -408,7 +540,7 @@
     for (var arg in args) {
       int id = int.parse(arg);
       var bptToRemove = null;
-      for (var bpt in debugger.isolate.breakpoints) {
+      for (var bpt in debugger.isolate.breakpoints.values) {
         if (bpt.number == id) {
           bptToRemove = bpt;
           break;
@@ -422,10 +554,7 @@
     }
     List pending = [];
     for (var bpt in toRemove) {
-      pending.add(debugger.isolate.removeBreakpoint(bpt).then((_) {
-            var id = bpt.number;
-            debugger.console.print("Removed breakpoint $id");
-          }));
+      pending.add(debugger.isolate.removeBreakpoint(bpt));
     }
     return Future.wait(pending);
   }
@@ -444,27 +573,26 @@
       : super(debugger, 'breakpoints', []);
 
   Future run(List<String> args) {
-    return debugger.isolate.reloadBreakpoints().then((_) {
-      if (debugger.isolate.breakpoints.isEmpty) {
-        debugger.console.print('No breakpoints');
-      }
-      for (var bpt in debugger.isolate.breakpoints) {
-        var bpId = bpt.number;
-        var script = bpt.script;
-        var tokenPos = bpt.tokenPos;
-        var line = script.tokenToLine(tokenPos);
-        var col = script.tokenToCol(tokenPos);
-        var extras = new StringBuffer();
-        if (!bpt.resolved) {
-          extras.write(' unresolved');
-        }
-        if (!bpt.enabled) {
-          extras.write(' disabled');
-        }
+    if (debugger.isolate.breakpoints.isEmpty) {
+      debugger.console.print('No breakpoints');
+    }
+    List bpts = debugger.isolate.breakpoints.values.toList();
+    bpts.sort((a, b) => a.number - b.number);
+    for (var bpt in bpts) {
+      var bpId = bpt.number;
+      var script = bpt.script;
+      var tokenPos = bpt.tokenPos;
+      var line = script.tokenToLine(tokenPos);
+      var col = script.tokenToCol(tokenPos);
+      if (!bpt.resolved) {
         debugger.console.print(
-            'Breakpoint ${bpId} at ${script.name}:${line}:${col}${extras}');
+            'Future breakpoint ${bpId} at ${script.name}:${line}:${col}');
+      } else {
+        debugger.console.print(
+            'Breakpoint ${bpId} at ${script.name}:${line}:${col}');
       }
-    });
+    }
+    return new Future.value(null);
   }
 
   String helpShort = 'List all breakpoints';
@@ -495,10 +623,31 @@
       'Syntax: info isolates\n';
 }
 
+class InfoFrameCommand extends DebuggerCommand {
+  InfoFrameCommand(Debugger debugger) : super(debugger, 'frame', []);
+
+  Future run(List<String> args) {
+    if (args.length > 0) {
+      debugger.console.print('info frame expects 1 argument');
+      return new Future.value(null);
+    }
+    debugger.console.print('frame = ${debugger.currentFrame}');
+    return new Future.value(null);
+  }
+
+  String helpShort = 'Show current frame';
+
+  String helpLong =
+      'Show current frame.\n'
+      '\n'
+      'Syntax: info frame\n';
+}
+
 class InfoCommand extends DebuggerCommand {
   InfoCommand(Debugger debugger) : super(debugger, 'info', [
       new InfoBreakpointsCommand(debugger),
       new InfoIsolatesCommand(debugger),
+      new InfoFrameCommand(debugger),
   ]);
 
   Future run(List<String> args) {
@@ -578,11 +727,28 @@
   DebuggerConsoleElement console;
   DebuggerStackElement stackElement;
   ServiceMap stack;
-  int currentFrame = 0;
+
+  int get currentFrame => _currentFrame;
+  void set currentFrame(int value) {
+    if (value != null && (value < 0 || value >= stackDepth)) {
+      throw new RangeError.range(value, 0, stackDepth);
+    }
+    _currentFrame = value;
+    if (stackElement != null) {
+      stackElement.setCurrentFrame(value);
+    }
+  }
+  int _currentFrame = null;
+
+  int get stackDepth => stack['frames'].length;
 
   ObservatoryDebugger() {
     cmd = new RootCommand([
         new HelpCommand(this),
+        new PrintCommand(this),
+        new DownCommand(this),
+        new UpCommand(this),
+        new FrameCommand(this),
         new PauseCommand(this),
         new ContinueCommand(this),
         new NextCommand(this),
@@ -635,7 +801,9 @@
     // TODO(turnidge): Stop relying on the isolate to track the last
     // pause event.  Since we listen to events directly in the
     // debugger, this could introduce a race.
-    return isolate.pauseEvent != null;
+    return (isolate != null &&
+            isolate.pauseEvent != null &&
+            isolate.pauseEvent.eventType != ServiceEvent.kResume);
   }
 
   void warnOutOfDate() {
@@ -653,6 +821,11 @@
       // TODO(turnidge): Replace only the changed part of the stack to
       // reduce flicker.
       stackElement.updateStack(stack, pauseEvent);
+      if (stack['frames'].length > 0) {
+        currentFrame = 0;
+      } else {
+        currentFrame = null;
+      }
     });
   }
 
@@ -669,10 +842,10 @@
   }
 
   void _reportPause(ServiceEvent event) {
-    if (event.eventType == 'IsolateCreated') {
+    if (event.eventType == ServiceEvent.kPauseStart) {
       console.print(
           "Paused at isolate start (type 'continue' to start the isolate')");
-    } else if (event.eventType == 'IsolateShutdown') {
+    } else if (event.eventType == ServiceEvent.kPauseExit) {
       console.print(
           "Paused at isolate exit (type 'continue' to exit the isolate')");
     }
@@ -696,7 +869,22 @@
     }
   }
 
-  Future _reportBreakpointAdded(Breakpoint bpt) {
+  Future _reportBreakpointEvent(ServiceEvent event) {
+    var bpt = event.breakpoint;
+    var verb = null;
+    switch (event.eventType) {
+      case ServiceEvent.kBreakpointAdded:
+        verb = 'added';
+        break;
+      case ServiceEvent.kBreakpointResolved:
+        verb = 'resolved';
+        break;
+      case ServiceEvent.kBreakpointRemoved:
+        verb = 'removed';
+        break;
+      default:
+        break;
+    }
     var script = bpt.script;
     return script.load().then((_) {
       var bpId = bpt.number;
@@ -704,14 +892,11 @@
       var line = script.tokenToLine(tokenPos);
       var col = script.tokenToCol(tokenPos);
       if (bpt.resolved) {
-        // TODO(turnidge): If this was a future breakpoint before, we
-        // should change the message to say that the breakpoint was 'resolved',
-        // rather than 'added'.
         console.print(
-            'Breakpoint ${bpId} added at ${script.name}:${line}:${col}');
+            'Breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}');
       } else {
         console.print(
-            'Future breakpoint ${bpId} added at ${script.name}:${line}:${col}');
+            'Future breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}');
       }
     });
   }
@@ -721,30 +906,34 @@
       return;
     }
     switch(event.eventType) {
-      case 'IsolateShutdown':
+      case ServiceEvent.kIsolateExit:
         console.print('Isolate shutdown');
         isolate = null;
         break;
 
-      case 'BreakpointReached':
-      case 'IsolateInterrupted':
-      case 'ExceptionThrown':
+      case ServiceEvent.kPauseStart:
+      case ServiceEvent.kPauseExit:
+      case ServiceEvent.kPauseBreakpoint:
+      case ServiceEvent.kPauseInterrupted:
+      case ServiceEvent.kPauseException:
         _refreshStack(event).then((_) {
           _reportPause(event);
         });
         break;
 
-      case 'IsolateResumed':
+      case ServiceEvent.kResume:
         console.print('Continuing...');
         break;
 
-      case 'BreakpointResolved':
-        _reportBreakpointAdded(event.breakpoint);
+      case ServiceEvent.kBreakpointAdded:
+      case ServiceEvent.kBreakpointResolved:
+      case ServiceEvent.kBreakpointRemoved:
+        _reportBreakpointEvent(event);
         break;
 
-      case '_Graph':
-      case 'IsolateCreated':
-      case 'GC':
+      case ServiceEvent.kIsolateStart:
+      case ServiceEvent.kGraph:
+      case ServiceEvent.kGC:
         // Ignore these events for now.
         break;
 
@@ -866,13 +1055,19 @@
   @published Isolate isolate;
   @observable bool hasStack = false;
   @observable bool isSampled = false;
+  @observable int currentFrame;
   ObservatoryDebugger debugger;
 
-  _addFrame(List frameList, ObservableMap frameInfo, bool expand) {
+  _addFrame(List frameList, ObservableMap frameInfo) {
     DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
-    frameElement.expand = expand;
     frameElement.frame = frameInfo;
 
+    if (frameInfo['depth'] == currentFrame) {
+      frameElement.setCurrent(true);
+    } else {
+      frameElement.setCurrent(false);
+    }
+
     var li = new LIElement();
     li.classes.add('list-group-item');
     li.children.insert(0, frameElement);
@@ -916,13 +1111,12 @@
       // Add new frames to the top of stack.
       newCount = newFrames.length - frameElements.length;
       for (int i = newCount-1; i >= 0; i--) {
-        _addFrame(frameElements, newFrames[i], i == 0);
+        _addFrame(frameElements, newFrames[i]);
       }
     }
     assert(frameElements.length == newFrames.length);
 
     if (frameElements.isNotEmpty) {
-      frameElements[0].children[0].expand = true;
       for (int i = newCount; i < frameElements.length; i++) {
         frameElements[i].children[0].updateFrame(newFrames[i]);
       }
@@ -932,6 +1126,19 @@
     hasStack = frameElements.isNotEmpty;
   }
 
+  void setCurrentFrame(int value) {
+    currentFrame = value;
+    List frameElements = $['frameList'].children;
+    for (var frameElement in frameElements) {
+      var dbgFrameElement = frameElement.children[0];
+      if (dbgFrameElement.frame['depth'] == currentFrame) {
+        dbgFrameElement.setCurrent(true);
+      } else {
+        dbgFrameElement.setCurrent(false);
+      }
+    }
+  }
+
   Set<Script> activeScripts() {
     var s = new Set<Script>();
     List frameElements = $['frameList'].children;
@@ -964,8 +1171,35 @@
 class DebuggerFrameElement extends ObservatoryElement {
   @published ObservableMap frame;
 
-  // When true, the frame will start out expanded.
-  @published bool expand = false;
+  // Is this the current frame?
+  bool _current = false;
+
+  // Has this frame been pinned open?
+  bool _pinned = false;
+
+  void setCurrent(bool value) {
+    busy = true;
+    frame['function'].load().then((func) {
+      _current = value;
+      var frameOuter = $['frameOuter'];
+      if (_current) {
+        frameOuter.classes.add('current');
+        expanded = true;
+        frameOuter.classes.add('shadow');
+        scrollIntoView();
+      } else {
+        frameOuter.classes.remove('current');
+        if (_pinned) {
+          expanded = true;
+          frameOuter.classes.add('shadow');
+        } else {
+          expanded = false;
+          frameOuter.classes.remove('shadow');
+        }
+      }
+      busy = false;
+    });
+  }
 
   @observable String scriptHeight;
   @observable bool expanded = false;
@@ -993,23 +1227,19 @@
     scriptHeight = '${windowHeight ~/ 1.6}px';
   }
 
-  void expandChanged(oldValue) {
-    if (expand != expanded) {
-      toggleExpand(null, null, null);
-    }
-  }
-
   void toggleExpand(var a, var b, var c) {
     if (busy) {
       return;
     }
     busy = true;
     frame['function'].load().then((func) {
-        expanded = !expanded;
+        _pinned = !_pinned;
         var frameOuter = $['frameOuter'];
-        if (expanded) {
+        if (_pinned) {
+          expanded = true;
           frameOuter.classes.add('shadow');
         } else {
+          expanded = false;
           frameOuter.classes.remove('shadow');
         }
         busy = false;
@@ -1038,11 +1268,23 @@
     var span = new SpanElement();
     span.classes.add('bold');
     span.appendText(line);
-    span.appendText('\n');
+    if (newline) {
+      span.appendText('\n');
+    }
     $['consoleText'].children.add(span);
     span.scrollIntoView();
   }
 
+  void printRef(Instance ref, { bool newline:true }) {
+    var refElement = new Element.tag('instance-ref');
+    refElement.ref = ref;
+    $['consoleText'].children.add(refElement);
+    if (newline) {
+      this.newline();
+    }
+    refElement.scrollIntoView();
+  }
+
   void newline() {
     var br = new BRElement();
     $['consoleText'].children.add(br);
diff --git a/dart/runtime/observatory/lib/src/elements/debugger.html b/dart/runtime/observatory/lib/src/elements/debugger.html
index 06731c5..59ccda8 100644
--- a/dart/runtime/observatory/lib/src/elements/debugger.html
+++ b/dart/runtime/observatory/lib/src/elements/debugger.html
@@ -191,6 +191,11 @@
         box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.16),
                      0 2px 5px 0 rgba(0, 0, 0, 0.26);
       }
+      .current {
+        box-shadow:  0 2px 10px 0 rgba(0, 0, 0, 0.26),
+                     0 2px 5px 0 rgba(0, 0, 0, 0.46);
+        border: 1px solid #444;
+      }
       .frameSummaryText {
         display: inline-block;
         padding: 5px;
diff --git a/dart/runtime/observatory/lib/src/elements/isolate_summary.dart b/dart/runtime/observatory/lib/src/elements/isolate_summary.dart
index 07d647a..cefc373 100644
--- a/dart/runtime/observatory/lib/src/elements/isolate_summary.dart
+++ b/dart/runtime/observatory/lib/src/elements/isolate_summary.dart
@@ -22,26 +22,6 @@
   IsolateRunStateElement.created() : super.created();
 
   @published Isolate isolate;
-
-  Future pause(_) {
-    return isolate.pause();
-  }
-  Future resume(_) {
-    app.removePauseEvents(isolate);
-    return isolate.resume();
-  }
-  Future stepInto(_) {
-    app.removePauseEvents(isolate);
-    return isolate.stepInto();
-  }
-  Future stepOver(_) {
-    app.removePauseEvents(isolate);
-    return isolate.stepOver();
-  }
-  Future stepOut(_) {
-    app.removePauseEvents(isolate);
-    return isolate.stepOut();
-  }
 }
 
 @CustomTag('isolate-location')
diff --git a/dart/runtime/observatory/lib/src/elements/isolate_summary.html b/dart/runtime/observatory/lib/src/elements/isolate_summary.html
index cd29e17..89ea848 100644
--- a/dart/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/dart/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -41,7 +41,7 @@
 
 <polymer-element name="isolate-run-state" extends="observatory-element">
   <template>
-    <template if="{{ isolate.pauseEvent != null }}">
+    <template if="{{ isolate.paused }}">
       <strong>paused</strong>
     </template>
 
@@ -62,21 +62,21 @@
 <polymer-element name="isolate-location" extends="observatory-element">
   <template>
     <template if="{{ isolate.pauseEvent != null }}">
-      <template if="{{ isolate.pauseEvent.eventType == 'IsolateCreated' }}">
+      <template if="{{ isolate.pauseEvent.eventType == 'PauseStart' }}">
         at isolate start
       </template>
 
-      <template if="{{ isolate.pauseEvent.eventType == 'IsolateShutdown' }}">
+      <template if="{{ isolate.pauseEvent.eventType == 'PauseExit' }}">
         at isolate exit
       </template>
 
-      <template if="{{ isolate.pauseEvent.eventType == 'IsolateInterrupted' ||
-                       isolate.pauseEvent.eventType == 'BreakpointReached' ||
-                       isolate.pauseEvent.eventType == 'ExceptionThrown' }}">
+      <template if="{{ isolate.pauseEvent.eventType == 'PauseInterrupted' ||
+                       isolate.pauseEvent.eventType == 'PauseBreakpoint' ||
+                       isolate.pauseEvent.eventType == 'PauseException' }}">
         <template if="{{ isolate.pauseEvent.breakpoint != null }}">
           by breakpoint
         </template>
-        <template if="{{ isolate.pauseEvent.eventType == 'ExceptionThrown' }}">
+        <template if="{{ isolate.pauseEvent.eventType == 'PauseException' }}">
           by exception
         </template>
         at
diff --git a/dart/runtime/observatory/lib/src/elements/script_inset.dart b/dart/runtime/observatory/lib/src/elements/script_inset.dart
index cc4787a..73ee457 100644
--- a/dart/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/dart/runtime/observatory/lib/src/elements/script_inset.dart
@@ -284,15 +284,19 @@
       return;
     }
     busy = true;
-    if (line.bpt == null) {
+    if (line.breakpoints == null) {
       // No breakpoint.  Add it.
       line.script.isolate.addBreakpoint(line.script, line.line).then((_) {
           busy = false;
       });
     } else {
       // Existing breakpoint.  Remove it.
-      line.script.isolate.removeBreakpoint(line.bpt).then((_) {
-          busy = false;
+      List pending = [];
+      for (var bpt in line.breakpoints) {
+        pending.add(line.script.isolate.removeBreakpoint(bpt));
+      }
+      Future.wait(pending).then((_) {
+        busy = false;
       });
     }
   }
diff --git a/dart/runtime/observatory/lib/src/elements/script_inset.html b/dart/runtime/observatory/lib/src/elements/script_inset.html
index a8fb001..ac7262c 100644
--- a/dart/runtime/observatory/lib/src/elements/script_inset.html
+++ b/dart/runtime/observatory/lib/src/elements/script_inset.html
@@ -90,23 +90,23 @@
         <div class="busyBreakpoint">B</div>
       </template>
 
-      <template if="{{ line.bpt == null && !line.possibleBpt }}">
+      <template if="{{ line.breakpoints == null && !line.possibleBpt }}">
         <div class="emptyBreakpoint">&nbsp;</div>
       </template>
 
-      <template if="{{ line.bpt == null && line.possibleBpt && !busy}}">
+      <template if="{{ line.breakpoints == null && line.possibleBpt && !busy}}">
         <div class="possibleBreakpoint">
           <a on-click="{{ toggleBreakpoint }}">B</a>
         </div>
       </template>
 
-      <template if="{{ line.bpt != null && !line.bpt.resolved && !busy}}">
+      <template if="{{ line.breakpoints != null && !line.breakpointResolved && !busy}}">
         <div class="unresolvedBreakpoint">
           <a on-click="{{ toggleBreakpoint }}">B</a>
         </div>
       </template>
 
-      <template if="{{ line.bpt != null && line.bpt.resolved && !busy}}">
+      <template if="{{ line.breakpoints != null && line.breakpointResolved && !busy}}">
         <div class="resolvedBreakpoint">
           <a on-click="{{ toggleBreakpoint }}">B</a>
         </div>
diff --git a/dart/runtime/observatory/lib/src/elements/script_ref.dart b/dart/runtime/observatory/lib/src/elements/script_ref.dart
index ab31c8e..2f30e26 100644
--- a/dart/runtime/observatory/lib/src/elements/script_ref.dart
+++ b/dart/runtime/observatory/lib/src/elements/script_ref.dart
@@ -38,7 +38,8 @@
       if (ref.loaded) {
         // Script is loaded, get the line number.
         Script script = ref;
-        return '${super.name}:${script.tokenToLine(pos)}';
+        return '${super.name}:${script.tokenToLine(pos)}:'
+            '${script.tokenToCol(pos)}';
       } else {
         ref.load().then(_updateProperties);
       }
diff --git a/dart/runtime/observatory/lib/src/service/object.dart b/dart/runtime/observatory/lib/src/service/object.dart
index 925e0e7..2bd63a2 100644
--- a/dart/runtime/observatory/lib/src/service/object.dart
+++ b/dart/runtime/observatory/lib/src/service/object.dart
@@ -364,16 +364,16 @@
       new StreamController.broadcast();
 
   bool _isIsolateLifecycleEvent(String eventType) {
-    return _isIsolateShutdownEvent(eventType) ||
-           _isIsolateCreatedEvent(eventType);
+    return _isIsolateExitEvent(eventType) ||
+           _isIsolateStartEvent(eventType);
   }
 
-  bool _isIsolateShutdownEvent(String eventType) {
-    return (eventType == 'IsolateShutdown');
+  bool _isIsolateExitEvent(String eventType) {
+    return (eventType == ServiceEvent.kIsolateExit);
   }
 
-  bool _isIsolateCreatedEvent(String eventType) {
-    return (eventType == 'IsolateCreated');
+  bool _isIsolateStartEvent(String eventType) {
+    return (eventType == ServiceEvent.kIsolateStart);
   }
 
   void postServiceEvent(String response, ByteData data) {
@@ -399,17 +399,17 @@
     if (_isIsolateLifecycleEvent(eventType)) {
       String isolateId = map['isolate']['id'];
       var event;
-      if (_isIsolateCreatedEvent(eventType)) {
-        _onIsolateCreated(map['isolate']);
+      if (_isIsolateStartEvent(eventType)) {
+        _onIsolateStart(map['isolate']);
         // By constructing the event *after* adding the isolate to the
         // isolate cache, the call to getFromMap will use the cached Isolate.
         event = new ServiceObject._fromMap(this, map);
       } else {
-        assert(_isIsolateShutdownEvent(eventType));
+        assert(_isIsolateExitEvent(eventType));
         // By constructing the event *before* removing the isolate from the
         // isolate cache, the call to getFromMap will use the cached Isolate.
         event = new ServiceObject._fromMap(this, map);
-        _onIsolateShutdown(isolateId);
+        _onIsolateExit(isolateId);
       }
       assert(event != null);
       events.add(event);
@@ -426,11 +426,12 @@
           return;
         }
         var event = new ServiceObject._fromMap(owningIsolate, map);
+        owningIsolate._onEvent(event);
         events.add(event);
     });
   }
 
-  Isolate _onIsolateCreated(Map isolateMap) {
+  Isolate _onIsolateStart(Map isolateMap) {
     var isolateId = isolateMap['id'];
     assert(!_isolateCache.containsKey(isolateId));
     Isolate isolate = new ServiceObject._fromMap(this, isolateMap);
@@ -443,7 +444,7 @@
     return isolate;
   }
 
-  void _onIsolateShutdown(String isolateId) {
+  void _onIsolateExit(String isolateId) {
     assert(_isolateCache.containsKey(isolateId));
     _isolateCache.remove(isolateId);
     notifyPropertyChange(#isolates, true, false);
@@ -478,12 +479,12 @@
 
     // Process shutdown.
     for (var isolateId in shutdownIsolates) {
-      _onIsolateShutdown(isolateId);
+      _onIsolateExit(isolateId);
     }
 
     // Process creation.
     for (var isolateMap in createdIsolates) {
-      _onIsolateCreated(isolateMap);
+      _onIsolateStart(isolateMap);
     }
   }
 
@@ -505,6 +506,10 @@
       // We should never see an unknown isolate here.
       throw new UnimplementedError();
     }
+    var mapIsRef = _hasRef(map['type']);
+    if (!mapIsRef) {
+      isolate.update(map);
+    }
     return isolate;
   }
 
@@ -774,11 +779,24 @@
   @observable ObservableMap counters = new ObservableMap();
 
   @observable ServiceEvent pauseEvent = null;
-  bool get _isPaused => pauseEvent != null;
 
+  void _updateRunState() {
+    topFrame = (pauseEvent != null ? pauseEvent.topFrame : null);
+    paused = (pauseEvent != null &&
+              pauseEvent.eventType != ServiceEvent.kResume);
+    running = (!paused && topFrame != null);
+    idle = (!paused && topFrame == null);
+    notifyPropertyChange(#topFrame, 0, 1);
+    notifyPropertyChange(#paused, 0, 1);
+    notifyPropertyChange(#running, 0, 1);
+    notifyPropertyChange(#idle, 0, 1);
+  }
+
+  @observable bool paused = false;
   @observable bool running = false;
   @observable bool idle = false;
   @observable bool loading = true;
+
   @observable bool ioEnabled = false;
 
   Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
@@ -844,7 +862,10 @@
     String mapId = map['id'];
     var obj = (mapId != null) ? _cache[mapId] : null;
     if (obj != null) {
-      // Consider calling update when map is not a reference.
+      var mapIsRef = _hasRef(map['type']);
+      if (!mapIsRef) {
+        obj.update(map);
+      }
       return obj;
     }
     // Build the object from the map directly.
@@ -862,12 +883,7 @@
 
   Future<ServiceObject> invokeRpc(String method, Map params) {
     return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
-      var obj = new ServiceObject._fromMap(this, response);
-      if ((obj != null) && obj.canCache) {
-        String objId = obj.id;
-        _cache.putIfAbsent(objId, () => obj);
-      }
-      return obj;
+      return getFromMap(response);
     });
   }
 
@@ -912,9 +928,11 @@
   @observable HeapSnapshot latestSnapshot;
   Completer<HeapSnapshot> _snapshotFetch;
 
-  void loadHeapSnapshot(ServiceEvent event) {
+  void _loadHeapSnapshot(ServiceEvent event) {
     latestSnapshot = new HeapSnapshot(this, event.data);
-    _snapshotFetch.complete(latestSnapshot);
+    if (_snapshotFetch != null) {
+      _snapshotFetch.complete(latestSnapshot);
+    }
   }
 
   Future<HeapSnapshot> fetchHeapSnapshot() {
@@ -940,7 +958,6 @@
     _loaded = true;
     loading = false;
 
-    reloadBreakpoints();
     _upgradeCollection(map, isolate);
     if (map['rootLib'] == null ||
         map['timers'] == null ||
@@ -952,11 +969,6 @@
     if (map['entry'] != null) {
       entry = map['entry'];
     }
-    if (map['topFrame'] != null) {
-      topFrame = map['topFrame'];
-    } else {
-      topFrame = null ;
-    }
 
     var countersMap = map['tagCounters'];
     if (countersMap != null) {
@@ -994,6 +1006,7 @@
     timers['dart'] = timerMap['time_dart_execution'];
 
     updateHeapsFromMap(map['heaps']);
+    _updateBreakpoints(map['breakpoints']);
 
     List features = map['features'];
     if (features != null) {
@@ -1003,10 +1016,8 @@
         }
       }
     }
-    // Isolate status
     pauseEvent = map['pauseEvent'];
-    running = (!_isPaused && map['topFrame'] != null);
-    idle = (!_isPaused && map['topFrame'] == null);
+    _updateRunState();
     error = map['error'];
 
     libraries.clear();
@@ -1023,71 +1034,74 @@
       });
   }
 
-  ObservableList<Breakpoint> breakpoints = new ObservableList();
+  ObservableMap<int, Breakpoint> breakpoints = new ObservableMap();
 
-  void _removeBreakpoint(Breakpoint bpt) {
-    var script = bpt.script;
-    var tokenPos = bpt.tokenPos;
-    assert(tokenPos != null);
-    if (script.loaded) {
-      var line = script.tokenToLine(tokenPos);
-      assert(line != null);
-      if (script.lines[line - 1] != null) {
-        assert(script.lines[line - 1].bpt == bpt);
-        script.lines[line - 1].bpt = null;
+  void _updateBreakpoints(List newBpts) {
+    // Build a map of new breakpoints.
+    var newBptMap = {};
+    newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt));
+
+    // Remove any old breakpoints which no longer exist.
+    List toRemove = [];
+    breakpoints.forEach((key, _) {
+      if (!newBptMap.containsKey(key)) {
+        toRemove.add(key);
       }
-    }
+    });
+    toRemove.forEach((key) => breakpoints.remove(key));
+
+    // Add all new breakpoints.
+    breakpoints.addAll(newBptMap);
   }
 
   void _addBreakpoint(Breakpoint bpt) {
-    var script = bpt.script;
-    var tokenPos = bpt.tokenPos;
-    assert(tokenPos != null);
-    if (script.loaded) {
-      var line = script.tokenToLine(tokenPos);
-      assert(line != null);
-      assert(script.lines[line - 1].bpt == null);
-      script.lines[line - 1].bpt = bpt;
-    } else {
-      // Load the script and then plop in the breakpoint.
-      script.load().then((_) {
-          _addBreakpoint(bpt);
-      });
-    }
+    breakpoints[bpt.number] = bpt;
   }
 
-  void _updateBreakpoints(ServiceMap newBreakpoints) {
-    // Remove all of the old breakpoints from the Script lines.
-    if (breakpoints != null) {
-      for (var bpt in breakpoints) {
-        _removeBreakpoint(bpt);
-      }
-    }
-    // Add all of the new breakpoints to the Script lines.
-    for (var bpt in newBreakpoints['breakpoints']) {
-      _addBreakpoint(bpt);
-    }
-    breakpoints.clear();
-    breakpoints.addAll(newBreakpoints['breakpoints']);
-
-    // Sort the breakpoints by breakpointNumber.
-    breakpoints.sort((a, b) => (a.number - b.number));
+  void _removeBreakpoint(Breakpoint bpt) {
+    breakpoints.remove(bpt.number);
+    bpt.remove();
   }
 
-  Future<ServiceObject> _inProgressReloadBpts;
+  void _onEvent(ServiceEvent event) {
+    assert(event.eventType != ServiceEvent.kIsolateStart &&
+           event.eventType != ServiceEvent.kIsolateExit);
+    switch(event.eventType) {
+      case ServiceEvent.kBreakpointAdded:
+        _addBreakpoint(event.breakpoint);
+        break;
 
-  Future reloadBreakpoints() {
-    // TODO(turnidge): Can reusing the Future here ever cause us to
-    // get stale breakpoints?
-    if (_inProgressReloadBpts == null) {
-      _inProgressReloadBpts =
-          invokeRpc('getBreakpoints', {}).then((newBpts) {
-              _updateBreakpoints(newBpts);
-          }).whenComplete(() {
-              _inProgressReloadBpts = null;
-          });
+      case ServiceEvent.kBreakpointResolved:
+        // Update occurs as side-effect of caching.
+        break;
+
+      case ServiceEvent.kBreakpointRemoved:
+        _removeBreakpoint(event.breakpoint);
+        break;
+
+      case ServiceEvent.kPauseStart:
+      case ServiceEvent.kPauseExit:
+      case ServiceEvent.kPauseBreakpoint:
+      case ServiceEvent.kPauseInterrupted:
+      case ServiceEvent.kPauseException:
+      case ServiceEvent.kResume:
+        pauseEvent = event;
+        _updateRunState();
+        break;
+
+      case ServiceEvent.kGraph:
+        _loadHeapSnapshot(event);
+        break;
+
+      case ServiceEvent.kGC:
+        // Ignore GC events for now.
+        break;
+
+      default:
+        // Log unrecognized events.
+        Logger.root.severe('Unrecognized event: $event');
+        break;
     }
-    return _inProgressReloadBpts;
   }
 
   Future<ServiceObject> addBreakpoint(Script script, int line) {
@@ -1107,53 +1121,26 @@
         // Unable to set a breakpoint at desired line.
         script.lines[line - 1].possibleBpt = false;
       }
-      // TODO(turnidge): Instead of reloading all of the breakpoints,
-      // rely on events to update the breakpoint list.
-      return reloadBreakpoints().then((_) {
-        return result;
-      });
+      return result;
     });
   }
 
   Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
     return invokeRpc('addBreakpointAtEntry',
-                     { 'functionId': function.id }).then((result) {
-        // TODO(turnidge): Instead of reloading all of the breakpoints,
-        // rely on events to update the breakpoint list.
-        return reloadBreakpoints().then((_) {
-            return result;
-        });
-      });
+                     { 'functionId': function.id });
   }
 
   Future removeBreakpoint(Breakpoint bpt) {
     return invokeRpc('removeBreakpoint',
-                     { 'breakpointId': bpt.id }).then((result) {
-        if (result is DartError) {
-          // TODO(turnidge): Handle this more gracefully.
-          Logger.root.severe(result.message);
-          return result;
-        }
-        if (pauseEvent != null &&
-            pauseEvent.breakpoint != null &&
-            (pauseEvent.breakpoint.id == bpt.id)) {
-          return isolate.reload();
-        } else {
-          return reloadBreakpoints();
-        }
-      });
+                     { 'breakpointId': bpt.id });
   }
 
-  // TODO(turnidge): If the user invokes pause (or other rpcs) twice,
-  // they could get a race.  Consider returning an "in progress"
-  // future to avoid this.
   Future pause() {
     return invokeRpc('pause', {}).then((result) {
         if (result is DartError) {
           // TODO(turnidge): Handle this more gracefully.
           Logger.root.severe(result.message);
         }
-        return isolate.reload();
       });
   }
 
@@ -1163,7 +1150,6 @@
           // TODO(turnidge): Handle this more gracefully.
           Logger.root.severe(result.message);
         }
-        return isolate.reload();
       });
   }
 
@@ -1173,7 +1159,6 @@
           // TODO(turnidge): Handle this more gracefully.
           Logger.root.severe(result.message);
         }
-        return isolate.reload();
       });
   }
 
@@ -1183,7 +1168,6 @@
           // TODO(turnidge): Handle this more gracefully.
           Logger.root.severe(result.message);
         }
-        return isolate.reload();
       });
   }
 
@@ -1193,7 +1177,6 @@
           // TODO(turnidge): Handle this more gracefully.
           Logger.root.severe(result.message);
         }
-        return isolate.reload();
       });
   }
 
@@ -1216,6 +1199,15 @@
     return invokeRpc('eval', params);
   }
 
+  Future<ServiceObject> evalFrame(int framePos,
+                                  String expression) {
+    Map params = {
+      'frame': framePos,
+      'expression': expression,
+    };
+    return invokeRpc('evalFrame', params);
+  }
+
   Future<ServiceObject> getRetainedSize(ServiceObject target) {
     Map params = {
       'targetId': target.id,
@@ -1319,14 +1311,10 @@
 
   ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner);
 
-  void _upgradeValues() {
-    assert(owner != null);
-    _upgradeCollection(_map, owner);
-  }
-
   void _update(ObservableMap map, bool mapIsRef) {
     _loaded = !mapIsRef;
 
+    _upgradeCollection(map, owner);
     // TODO(turnidge): Currently _map.clear() prevents us from
     // upgrading an already upgraded submap.  Is clearing really the
     // right thing to do here?
@@ -1335,7 +1323,6 @@
 
     name = _map['name'];
     vmName = (_map.containsKey('vmName') ? _map['vmName'] : name);
-    _upgradeValues();
   }
 
   // Forward Map interface calls.
@@ -1432,14 +1419,31 @@
 
 /// A [ServiceEvent] is an asynchronous event notification from the vm.
 class ServiceEvent extends ServiceObject {
+  /// The possible 'eventType' values.
+  static const kIsolateStart       = 'IsolateStart';
+  static const kIsolateExit        = 'IsolateExit';
+  static const kPauseStart         = 'PauseStart';
+  static const kPauseExit          = 'PauseExit';
+  static const kPauseBreakpoint    = 'PauseBreakpoint';
+  static const kPauseInterrupted   = 'PauseInterrupted';
+  static const kPauseException     = 'PauseException';
+  static const kResume             = 'Resume';
+  static const kBreakpointAdded    = 'BreakpointAdded';
+  static const kBreakpointResolved = 'BreakpointResolved';
+  static const kBreakpointRemoved  = 'BreakpointRemoved';
+  static const kGraph              = '_Graph';
+  static const kGC                 = 'GC';
+  static const kVMDisconnected     = 'VMDisconnected';
+
   ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner);
 
   ServiceEvent.vmDisconencted() : super._empty(null) {
-    eventType = 'VMDisconnected';
+    eventType = kVMDisconnected;
   }
 
   @observable String eventType;
   @observable Breakpoint breakpoint;
+  @observable ServiceMap topFrame;
   @observable ServiceMap exception;
   @observable ByteData data;
   @observable int count;
@@ -1453,6 +1457,9 @@
     if (map['breakpoint'] != null) {
       breakpoint = map['breakpoint'];
     }
+    if (map['topFrame'] != null) {
+      topFrame = map['topFrame'];
+    }
     if (map['exception'] != null) {
       exception = map['exception'];
     }
@@ -1465,8 +1472,12 @@
   }
 
   String toString() {
-    return 'ServiceEvent of type $eventType with '
-        '${data == null ? 0 : data.lengthInBytes} bytes of binary data';
+    if (data == null) {
+      return "ServiceEvent(owner='${owner.id}', type='${eventType}')";
+    } else {
+      return "ServiceEvent(owner='${owner.id}', type='${eventType}', "
+          "data.lengthInBytes=${data.lengthInBytes})";
+    }
   }
 }
 
@@ -1488,19 +1499,44 @@
   // The breakpoint has been assigned to a final source location.
   @observable bool resolved;
 
-  // The breakpoint is active.
-  @observable bool enabled;
-
   void _update(ObservableMap map, bool mapIsRef) {
     _loaded = true;
     _upgradeCollection(map, owner);
 
+    var newNumber = map['breakpointNumber'];
+    var newScript = map['location']['script'];
+    var newTokenPos = map['location']['tokenPos'];
+
+    // number and script never change.
+    assert((number == null) || (number == newNumber));
+    assert((script == null) || (script == newScript));
+
     number = map['breakpointNumber'];
     script = map['location']['script'];
-    tokenPos = map['location']['tokenPos'];
-
     resolved = map['resolved'];
-    enabled = map['enabled'];
+    bool tokenPosChanged = tokenPos != newTokenPos;
+
+    if (script.loaded &&
+        (tokenPos != null) &&
+        tokenPosChanged) {
+      // The breakpoint has moved.  Remove it and add it later.
+      script._removeBreakpoint(this);
+    }
+
+    tokenPos = newTokenPos;
+    if (script.loaded && tokenPosChanged) {
+      script._addBreakpoint(this);
+    }
+  }
+
+  void remove() {
+    // Remove any references to this breakpoint.  It has been removed.
+    script._removeBreakpoint(this);
+    if ((isolate.pauseEvent != null) &&
+        (isolate.pauseEvent.breakpoint != null) &&
+        (isolate.pauseEvent.breakpoint.id == id)) {
+      isolate.pauseEvent.breakpoint = null;
+    }
   }
 
   String toString() {
@@ -1900,6 +1936,7 @@
       return;
     }
 
+    _loaded = true;
     isStatic = map['static'];
     isConst = map['const'];
     parent = map['parent'];
@@ -1969,8 +2006,9 @@
   final int line;
   final String text;
   @observable int hits;
-  @observable Breakpoint bpt;
   @observable bool possibleBpt = true;
+  @observable bool breakpointResolved = false;
+  @observable Set<Breakpoint> breakpoints;
 
   bool get isBlank {
     // Compute isBlank on demand.
@@ -2015,13 +2053,22 @@
 
   ScriptLine(this.script, this.line, this.text) {
     possibleBpt = !_isTrivialLine(text);
+  }
 
-    // TODO(turnidge): This is not so efficient.  Consider improving.
-    for (var bpt in this.script.isolate.breakpoints) {
-      if (bpt.script == this.script &&
-          bpt.script.tokenToLine(bpt.tokenPos) == line) {
-        this.bpt = bpt;
-      }
+  void addBreakpoint(Breakpoint bpt) {
+    if (breakpoints == null) {
+      breakpoints = new Set<Breakpoint>();
+    }
+    breakpoints.add(bpt);
+    breakpointResolved = breakpointResolved || bpt.resolved;
+  }
+
+  void removeBreakpoint(Breakpoint bpt) {
+    assert(breakpoints != null && breakpoints.contains(bpt));
+    breakpoints.remove(bpt);
+    if (breakpoints.isEmpty) {
+      breakpoints = null;
+      breakpointResolved = false;
     }
   }
 }
@@ -2064,8 +2111,8 @@
     if (mapIsRef) {
       return;
     }
-    _processSource(map['source']);
     _parseTokenPosTable(map['tokenPosTable']);
+    _processSource(map['source']);
     owningLibrary = map['owningLibrary'];
   }
 
@@ -2145,6 +2192,12 @@
     for (var i = 0; i < sourceLines.length; i++) {
       lines.add(new ScriptLine(this, i + 1, sourceLines[i]));
     }
+    for (var bpt in isolate.breakpoints.values) {
+      if (bpt.script == this) {
+        _addBreakpoint(bpt);
+      }
+    }
+
     _applyHitsToLines();
     // Notify any Observers that this Script's state has changed.
     notifyChange(null);
@@ -2156,6 +2209,18 @@
       line.hits = hits;
     }
   }
+
+  void _addBreakpoint(Breakpoint bpt) {
+    var line = tokenToLine(bpt.tokenPos);
+    getLine(line).addBreakpoint(bpt);
+  }
+
+  void _removeBreakpoint(Breakpoint bpt) {
+    var line = tokenToLine(bpt.tokenPos);
+    if (line != null) {
+      getLine(line).removeBreakpoint(bpt);
+    }
+  }
 }
 
 class PcDescriptor extends Observable {
diff --git a/dart/runtime/observatory/test/code_test.dart b/dart/runtime/observatory/test/code_test.dart
index c12b6f3..16806ee 100644
--- a/dart/runtime/observatory/test/code_test.dart
+++ b/dart/runtime/observatory/test/code_test.dart
@@ -35,7 +35,7 @@
       Completer completer = new Completer();
       List events = [];
       isolate.vm.events.stream.listen((ServiceEvent event) {
-        if (event.eventType == 'BreakpointReached') {
+        if (event.eventType == ServiceEvent.kPauseBreakpoint) {
           print('Breakpoint reached');
           completer.complete();
         }
diff --git a/dart/runtime/observatory/test/command_test.dart b/dart/runtime/observatory/test/command_test.dart
index 8159981..260684e 100644
--- a/dart/runtime/observatory/test/command_test.dart
+++ b/dart/runtime/observatory/test/command_test.dart
@@ -124,7 +124,7 @@
   });
 
   // Locals + subcommands, single local match.
-  cmd.completeCommand('count th ').then((result) {
+  cmd.completeCommand('count th').then((result) {
     expect(result, equals(['count three ']));
   });
 
@@ -138,9 +138,9 @@
     expect(result, equals(['co chocula ']));
   });
 
-  // We gobble spare spaces, even in the prefix.
+  // We gobble spare spaces in the prefix but not elsewhere.
   cmd.completeCommand('    game    chec').then((result) {
-    expect(result, equals(['game checkers ']));
+    expect(result, equals(['game    checkers ']));
   });
 }
 
@@ -155,7 +155,7 @@
       out.clear();
       // Substring dispatch works.
       cmd.runCommand('al cat mouse').then(expectAsync((_) {
-          expect(out.toString(), contains('executing alpha([cat, mouse])\n'));
+          expect(out.toString(), contains('executing alpha([cat , mouse])\n'));
       }));
   }));
 }
@@ -203,11 +203,25 @@
   }));
 }
 
+void testCommandRunAlias() {
+  // Run a simple command.
+  StringBuffer out = new StringBuffer();
+  var aliasCmd = new TestCommand(out, 'alpha', []);
+  aliasCmd.alias = 'a';
+  RootCommand cmd = new RootCommand([aliasCmd,
+                                     new TestCommand(out, 'ankle', [])]);
+
+  cmd.runCommand('a 55').then(expectAsync((_) {
+    expect(out.toString(), equals('executing alpha([55])\n'));
+  }));
+}
+
 main() {
   test('command completion test suite', testCommandComplete);
   test('run a simple command', testCommandRunSimple);
   test('run a subcommand', testCommandRunSubcommand);
   test('run a command which is not found', testCommandRunNotFound);
   test('run a command which is ambiguous', testCommandRunAmbiguous);
+  test('run a command using an alias', testCommandRunAlias);
 }
 
diff --git a/dart/runtime/observatory/test/coverage_test.dart b/dart/runtime/observatory/test/coverage_test.dart
index 67d0504..207b67d 100644
--- a/dart/runtime/observatory/test/coverage_test.dart
+++ b/dart/runtime/observatory/test/coverage_test.dart
@@ -58,7 +58,7 @@
       Completer completer = new Completer();
       List events = [];
       isolate.vm.events.stream.listen((ServiceEvent event) {
-        if (event.eventType == 'BreakpointReached') {
+        if (event.eventType == ServiceEvent.kPauseBreakpoint) {
           print('Breakpoint reached');
           completer.complete();
         }
diff --git a/dart/runtime/observatory/test/debugging_test.dart b/dart/runtime/observatory/test/debugging_test.dart
index 51204e7..751ec00 100644
--- a/dart/runtime/observatory/test/debugging_test.dart
+++ b/dart/runtime/observatory/test/debugging_test.dart
@@ -25,8 +25,10 @@
 // Pause
 (Isolate isolate) {
   Completer completer = new Completer();
-  isolate.vm.events.stream.listen((ServiceEvent event) {
-    if (event.eventType == 'IsolateInterrupted') {
+  var subscription;
+  subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+    if (event.eventType == ServiceEvent.kPauseInterrupted) {
+      subscription.cancel();
       completer.complete();
     }
   });
@@ -36,9 +38,16 @@
 
 // Resume
 (Isolate isolate) {
-  return isolate.resume().then((_) {
-      expect(isolate.pauseEvent == null, isTrue);
+  Completer completer = new Completer();
+  var subscription;
+  subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+    if (event.eventType == ServiceEvent.kResume) {
+      subscription.cancel();
+      completer.complete();
+    }
   });
+  isolate.resume();
+  return completer.future;
 },
 
 // Add breakpoint
@@ -49,15 +58,10 @@
       List events = [];
       var subscription;
       subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
-        if (event.eventType.startsWith('Breakpoint')) {
-          events.add(event);
-          if (events.length == 2) {
-            expect(events[0].eventType, equals('BreakpointResolved'));
-            expect(events[1].eventType, equals('BreakpointReached'));
-            print('Breakpoint reached');
-            subscription.cancel();
-            completer.complete();
-          }
+        if (event.eventType == ServiceEvent.kPauseBreakpoint) {
+          print('Breakpoint reached');
+          subscription.cancel();
+          completer.complete();
         }
       });
 
@@ -91,7 +95,7 @@
   List events = [];
   var subscription;
   subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
-    if (event.eventType.startsWith('BreakpointReached')) {
+    if (event.eventType == ServiceEvent.kPauseBreakpoint) {
       print('Breakpoint reached');
       subscription.cancel();
       completer.complete();
@@ -114,18 +118,38 @@
 
 // Remove breakpoint
 (Isolate isolate) {
-  expect(isolate.breakpoints.length, equals(1));
-  var bpt = isolate.breakpoints[0];
-  return isolate.removeBreakpoint(bpt).then((_) {
+  // Set up a listener to wait for breakpoint events.
+  Completer completer = new Completer();
+  List events = [];
+  var subscription;
+  subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+    if (event.eventType == ServiceEvent.kBreakpointRemoved) {
+      print('Breakpoint removed');
       expect(isolate.breakpoints.length, equals(0));
+      subscription.cancel();
+      completer.complete();
+    }
+  });
+
+  expect(isolate.breakpoints.length, equals(1));
+  var bpt = isolate.breakpoints.values.first;
+  return isolate.removeBreakpoint(bpt).then((_) {
+    return completer.future;
   });
 },
 
 // Resume
 (Isolate isolate) {
-  return isolate.resume().then((_) {
-      expect(isolate.pauseEvent == null, isTrue);
+  Completer completer = new Completer();
+  var subscription;
+  subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
+    if (event.eventType == ServiceEvent.kResume) {
+      subscription.cancel();
+      completer.complete();
+    }
   });
+  isolate.resume();
+  return completer.future;
 },
 
 // Add breakpoint at function entry
@@ -135,7 +159,7 @@
   List events = [];
   var subscription;
   subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
-    if (event.eventType.startsWith('BreakpointReached')) {
+    if (event.eventType == ServiceEvent.kPauseBreakpoint) {
       print('Breakpoint reached');
       subscription.cancel();
       completer.complete();
diff --git a/dart/runtime/observatory/test/eval_test.dart b/dart/runtime/observatory/test/eval_test.dart
index 7c5d77c..8355f7e 100644
--- a/dart/runtime/observatory/test/eval_test.dart
+++ b/dart/runtime/observatory/test/eval_test.dart
@@ -35,7 +35,7 @@
       Completer completer = new Completer();
       List events = [];
       isolate.vm.events.stream.listen((ServiceEvent event) {
-        if (event.eventType == 'BreakpointReached') {
+        if (event.eventType == ServiceEvent.kPauseBreakpoint) {
           print('Breakpoint reached');
           completer.complete();
         }
diff --git a/dart/runtime/observatory/test/gc_test.dart b/dart/runtime/observatory/test/gc_test.dart
index 7f2c441..11ba8c5 100644
--- a/dart/runtime/observatory/test/gc_test.dart
+++ b/dart/runtime/observatory/test/gc_test.dart
@@ -27,7 +27,7 @@
   // Expect at least this many GC events.
   int gcCountdown = 3;
   isolate.vm.events.stream.listen((ServiceEvent event) {
-    if (event.eventType == 'GC' && --gcCountdown == 0) {
+    if (event.eventType == ServiceEvent.kGC && --gcCountdown == 0) {
       completer.complete();
     }
   });
diff --git a/dart/runtime/observatory/test/graph_test.dart b/dart/runtime/observatory/test/graph_test.dart
index db16681..a496088 100644
--- a/dart/runtime/observatory/test/graph_test.dart
+++ b/dart/runtime/observatory/test/graph_test.dart
@@ -39,7 +39,7 @@
 (Isolate isolate) {
   Completer completer = new Completer();
   isolate.vm.events.stream.listen((ServiceEvent event) {
-    if (event.eventType == '_Graph') {
+    if (event.eventType == ServiceEvent.kGraph) {
       ReadStream reader = new ReadStream(event.data);
       ObjectGraph graph = new ObjectGraph(reader);
       expect(fooId, isNotNull);
diff --git a/dart/runtime/observatory/test/isolate_lifecycle_test.dart b/dart/runtime/observatory/test/isolate_lifecycle_test.dart
index 97411d2..c814ca9 100644
--- a/dart/runtime/observatory/test/isolate_lifecycle_test.dart
+++ b/dart/runtime/observatory/test/isolate_lifecycle_test.dart
@@ -44,7 +44,7 @@
     var pausedCount = 0;
     var runningCount = 0;
     for (var isolate in vm.isolates) {
-      if (isolate.pauseEvent != null) {
+      if (isolate.paused) {
         pausedCount++;
       } else {
         runningCount++;
@@ -56,7 +56,7 @@
   (VM vm) async {
     var resumedReceived = 0;
     var eventsDone = processServiceEvents(vm, (event, sub, completer) {
-      if (event.eventType.startsWith('IsolateShutdown')) {
+      if (event.eventType == ServiceEvent.kIsolateExit) {
         resumedReceived++;
         if (resumedReceived == resumeCount) {
           sub.cancel();
@@ -84,7 +84,7 @@
     var pausedCount = 0;
     var runningCount = 0;
     for (var isolate in vm.isolates) {
-      if (isolate.pauseEvent != null) {
+      if (isolate.paused) {
         pausedCount++;
       } else {
         runningCount++;
diff --git a/dart/runtime/observatory/test/source_location_test.dart b/dart/runtime/observatory/test/source_location_test.dart
index 5c24d32..e0cdd21 100644
--- a/dart/runtime/observatory/test/source_location_test.dart
+++ b/dart/runtime/observatory/test/source_location_test.dart
@@ -22,6 +22,7 @@
 
   Isolate isolate;
   ServiceMap stack;
+  int currentFrame = 0;
 }
 
 void source_location_dummy_function() {
@@ -54,7 +55,7 @@
       // Listen for breakpoint event.
       Completer completer = new Completer();
       isolate.vm.events.stream.listen((ServiceEvent event) {
-        if (event.eventType == 'BreakpointReached') {
+        if (event.eventType == ServiceEvent.kPauseBreakpoint) {
           completer.complete();
         }
       });
diff --git a/dart/runtime/vm/assembler_x64.cc b/dart/runtime/vm/assembler_x64.cc
index a3e6c26..dcf41c2 100644
--- a/dart/runtime/vm/assembler_x64.cc
+++ b/dart/runtime/vm/assembler_x64.cc
@@ -722,21 +722,21 @@
 
 void Assembler::addpl(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitREX_RB(dst, src);
   EmitUint8(0x66);
+  EmitREX_RB(dst, src);
   EmitUint8(0x0F);
   EmitUint8(0xFE);
-  EmitXmmRegisterOperand(dst, src);
+  EmitXmmRegisterOperand(dst & 7, src);
 }
 
 
 void Assembler::subpl(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  EmitREX_RB(dst, src);
   EmitUint8(0x66);
+  EmitREX_RB(dst, src);
   EmitUint8(0x0F);
   EmitUint8(0xFA);
-  EmitXmmRegisterOperand(dst, src);
+  EmitXmmRegisterOperand(dst & 7, src);
 }
 
 
diff --git a/dart/runtime/vm/assembler_x64_test.cc b/dart/runtime/vm/assembler_x64_test.cc
index eafb765..3a35086 100644
--- a/dart/runtime/vm/assembler_x64_test.cc
+++ b/dart/runtime/vm/assembler_x64_test.cc
@@ -2298,6 +2298,36 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(PackedIntOperations2, assembler) {
+  // Note: on Windows 64 XMM6-XMM15 are callee save.
+  const intptr_t cpu_register_set = 0;
+  const intptr_t fpu_register_set =
+      ((1 << XMM10) | (1 << XMM11)) & CallingConventions::kVolatileXmmRegisters;
+  __ PushRegisters(cpu_register_set, fpu_register_set);
+  __ movl(RAX, Immediate(0x2));
+  __ movd(XMM10, RAX);
+  __ shufps(XMM10, XMM10, Immediate(0x0));
+  __ movl(RAX, Immediate(0x1));
+  __ movd(XMM11, RAX);
+  __ shufps(XMM11, XMM11, Immediate(0x0));
+  __ addpl(XMM10, XMM11);  // 0x3
+  __ addpl(XMM10, XMM10);  // 0x6
+  __ subpl(XMM10, XMM11);  // 0x5
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM10);
+  __ popq(RAX);
+  __ PopRegisters(cpu_register_set, fpu_register_set);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedIntOperations2, test) {
+  typedef uint32_t (*PackedIntOperationsCode)();
+  uint32_t res = reinterpret_cast<PackedIntOperationsCode>(test->entry())();
+  EXPECT_EQ(static_cast<uword>(0x5), res);
+}
+
+
 ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
   __ movq(RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
   __ movd(XMM0, RAX);
diff --git a/dart/runtime/vm/ast_transformer.cc b/dart/runtime/vm/ast_transformer.cc
index 3acd1d0..dacabbf 100644
--- a/dart/runtime/vm/ast_transformer.cc
+++ b/dart/runtime/vm/ast_transformer.cc
@@ -66,10 +66,10 @@
       Z, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_));
   const String& symbol = String::ZoneHandle(Z, Symbols::New(cnt_str));
   ASSERT(!symbol.IsNull());
-  // Look up the variable through the preamble scope.
-  LocalVariable* await_tmp = preamble_->scope()->LookupVariable(symbol, false);
+  // Look up the variable in the scope used for async temp variables.
+  LocalVariable* await_tmp = function_top_->LocalLookupVariable(symbol);
   if (await_tmp == NULL) {
-    // If we need a new temp variable, we add it to the function's top scope.
+    // We need a new temp variable; add it to the function's top scope.
     await_tmp = new (Z) LocalVariable(
         Scanner::kNoSourcePos, symbol, Type::ZoneHandle(Type::DynamicType()));
     function_top_->AddVariable(await_tmp);
diff --git a/dart/runtime/vm/code_descriptors.cc b/dart/runtime/vm/code_descriptors.cc
index 1757c13..233d1b6 100644
--- a/dart/runtime/vm/code_descriptors.cc
+++ b/dart/runtime/vm/code_descriptors.cc
@@ -84,4 +84,42 @@
   return map.raw();
 }
 
+
+RawExceptionHandlers* ExceptionHandlerList::FinalizeExceptionHandlers(
+    uword entry_point) const {
+  intptr_t num_handlers = Length();
+  if (num_handlers == 0) {
+    return Object::empty_exception_handlers().raw();
+  }
+  const ExceptionHandlers& handlers =
+      ExceptionHandlers::Handle(ExceptionHandlers::New(num_handlers));
+  for (intptr_t i = 0; i < num_handlers; i++) {
+    // Assert that every element in the array has been initialized.
+    if (list_[i].handler_types == NULL) {
+      // Unreachable handler, entry not computed.
+      // Initialize it to some meaningful value.
+      const bool has_catch_all = false;
+      // Check it is uninitialized.
+      ASSERT((list_[i].outer_try_index == -1) &&
+             (list_[i].pc_offset == ExceptionHandlers::kInvalidPcOffset));
+      handlers.SetHandlerInfo(i,
+                              list_[i].outer_try_index,
+                              list_[i].pc_offset,
+                              list_[i].needs_stacktrace,
+                              has_catch_all);
+      handlers.SetHandledTypes(i, Array::null_array());
+    } else {
+      const bool has_catch_all = ContainsDynamic(*list_[i].handler_types);
+      handlers.SetHandlerInfo(i,
+                              list_[i].outer_try_index,
+                              list_[i].pc_offset,
+                              list_[i].needs_stacktrace,
+                              has_catch_all);
+      handlers.SetHandledTypes(i, *list_[i].handler_types);
+    }
+  }
+  return handlers.raw();
+}
+
+
 }  // namespace dart
diff --git a/dart/runtime/vm/code_descriptors.h b/dart/runtime/vm/code_descriptors.h
index d5ea730..796f290 100644
--- a/dart/runtime/vm/code_descriptors.h
+++ b/dart/runtime/vm/code_descriptors.h
@@ -116,7 +116,7 @@
   void AddPlaceHolder() {
     struct HandlerDesc data;
     data.outer_try_index = -1;
-    data.pc_offset = -1;
+    data.pc_offset = ExceptionHandlers::kInvalidPcOffset;
     data.handler_types = NULL;
     data.needs_stacktrace = false;
     list_.Add(data);
@@ -162,27 +162,7 @@
     return false;
   }
 
-
-  RawExceptionHandlers* FinalizeExceptionHandlers(uword entry_point) {
-    intptr_t num_handlers = Length();
-    if (num_handlers == 0) {
-      return Object::empty_exception_handlers().raw();
-    }
-    const ExceptionHandlers& handlers =
-        ExceptionHandlers::Handle(ExceptionHandlers::New(num_handlers));
-    for (intptr_t i = 0; i < num_handlers; i++) {
-      // Assert that every element in the array has been initialized.
-      ASSERT(list_[i].handler_types != NULL);
-      bool has_catch_all = ContainsDynamic(*list_[i].handler_types);
-      handlers.SetHandlerInfo(i,
-                              list_[i].outer_try_index,
-                              list_[i].pc_offset,
-                              list_[i].needs_stacktrace,
-                              has_catch_all);
-      handlers.SetHandledTypes(i, *list_[i].handler_types);
-    }
-    return handlers.raw();
-  }
+  RawExceptionHandlers* FinalizeExceptionHandlers(uword entry_point) const;
 
  private:
   GrowableArray<struct HandlerDesc> list_;
diff --git a/dart/runtime/vm/dart_api_impl.cc b/dart/runtime/vm/dart_api_impl.cc
index 6c45e4e..c087c0e 100644
--- a/dart/runtime/vm/dart_api_impl.cc
+++ b/dart/runtime/vm/dart_api_impl.cc
@@ -30,6 +30,7 @@
 #include "vm/profiler.h"
 #include "vm/resolver.h"
 #include "vm/reusable_handles.h"
+#include "vm/service_event.h"
 #include "vm/service_isolate.h"
 #include "vm/service.h"
 #include "vm/stack_frame.h"
@@ -1566,12 +1567,7 @@
 
   ASSERT(isolate->GetAndClearResumeRequest() == false);
   isolate->message_handler()->HandleOOBMessages();
-  bool resume = isolate->GetAndClearResumeRequest();
-  if (resume && Service::NeedsDebuggerEvents()) {
-    DebuggerEvent resumeEvent(isolate, DebuggerEvent::kIsolateResumed);
-    Service::HandleDebuggerEvent(&resumeEvent);
-  }
-  return resume;
+  return isolate->GetAndClearResumeRequest();
 }
 
 
diff --git a/dart/runtime/vm/debugger.cc b/dart/runtime/vm/debugger.cc
index d9a8d97..1834063 100644
--- a/dart/runtime/vm/debugger.cc
+++ b/dart/runtime/vm/debugger.cc
@@ -19,6 +19,7 @@
 #include "vm/object_store.h"
 #include "vm/os.h"
 #include "vm/port.h"
+#include "vm/service_event.h"
 #include "vm/service_isolate.h"
 #include "vm/service.h"
 #include "vm/stack_frame.h"
@@ -116,7 +117,7 @@
   function_ = func.raw();
   token_pos_ = token_pos;
   end_token_pos_ = token_pos;
-  line_number_ = -1;  // Recalcualte lazily.
+  line_number_ = -1;  // Recalculate lazily.
   is_resolved_ = true;
 }
 
@@ -173,7 +174,6 @@
 
   jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id());
   jsobj.AddProperty("breakpointNumber", id());
-  jsobj.AddProperty("enabled", IsEnabled());
   jsobj.AddProperty("resolved", IsResolved());
 
   Library& library = Library::Handle(isolate);
@@ -230,13 +230,25 @@
 
   // Give the event to the Service first, as the debugger event handler
   // may go into a message loop and the Service will not.
-  if (Service::NeedsDebuggerEvents()) {
-    Service::HandleDebuggerEvent(event);
+  //
+  // kBreakpointResolved events are handled differently in the vm
+  // service, so suppress them here.
+  if (Service::NeedsDebuggerEvents() &&
+      (event->type() != DebuggerEvent::kBreakpointResolved)) {
+    ServiceEvent service_event(event);
+    Service::HandleEvent(&service_event);
   }
 
   if (event_handler_ != NULL) {
     (*event_handler_)(event);
   }
+
+  if (Service::NeedsDebuggerEvents() && event->IsPauseEvent()) {
+    // If we were paused, notify the service that we have resumed.
+    ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
+    service_event.set_top_frame(event->top_frame());
+    Service::HandleEvent(&service_event);
+  }
 }
 
 
@@ -247,6 +259,7 @@
     if (type == DebuggerEvent::kIsolateInterrupted) {
       DebuggerStackTrace* trace = CollectStackTrace();
       ASSERT(trace->Length() > 0);
+      event.set_top_frame(trace->FrameAt(0));
       ASSERT(stack_trace_ == NULL);
       stack_trace_ = trace;
       resume_action_ = kContinue;
@@ -269,6 +282,18 @@
 }
 
 
+// The vm service handles breakpoint notifications in a different way
+// than the regular debugger breakpoint notifications.
+static void SendServiceBreakpointEvent(ServiceEvent::EventType type,
+                                       SourceBreakpoint* bpt) {
+  if (Service::NeedsDebuggerEvents() /*&& !bpt->IsOneShot()*/) {
+    ServiceEvent service_event(Isolate::Current(), type);
+    service_event.set_breakpoint(bpt);
+    Service::HandleEvent(&service_event);
+  }
+}
+
+
 const char* Debugger::QualifiedFunctionName(const Function& func) {
   const String& func_name = String::Handle(func.name());
   Class& func_class = Class::Handle(func.Owner());
@@ -509,47 +534,6 @@
 }
 
 
-const char* DebuggerEvent::EventTypeToCString(EventType type) {
-  switch (type) {
-    case kBreakpointReached:
-      return "BreakpointReached";
-    case kBreakpointResolved:
-      return "BreakpointResolved";
-    case kExceptionThrown:
-      return "ExceptionThrown";
-    case kIsolateCreated:
-      return "IsolateCreated";
-    case kIsolateShutdown:
-      return "IsolateShutdown";
-    case kIsolateInterrupted:
-      return "IsolateInterrupted";
-    case kIsolateResumed:
-      return "IsolateResumed";
-    default:
-      UNREACHABLE();
-      return "Unknown";
-  }
-}
-
-
-void DebuggerEvent::PrintJSON(JSONStream* js) const {
-  JSONObject jsobj(js);
-  jsobj.AddProperty("type", "ServiceEvent");
-  // TODO(turnidge): Drop the 'id' for things like DebuggerEvent.
-  jsobj.AddProperty("id", "");
-  jsobj.AddProperty("eventType", EventTypeToCString(type()));
-  jsobj.AddProperty("isolate", isolate());
-  if ((type() == kBreakpointResolved || type() == kBreakpointReached) &&
-      breakpoint() != NULL) {
-    // TODO(turnidge): Make this a breakpoint ref.
-    jsobj.AddProperty("breakpoint", breakpoint());
-  }
-  if (type() == kExceptionThrown) {
-    jsobj.AddProperty("exception", *(exception()));
-  }
-}
-
-
 ActivationFrame* DebuggerStackTrace::GetHandlerFrame(
     const Instance& exc_obj) const {
   ExceptionHandlers& handlers = ExceptionHandlers::Handle();
@@ -744,7 +728,10 @@
   ASSERT(i < desc_indices_.length());
   intptr_t desc_index = desc_indices_[i];
   ASSERT(name != NULL);
-  *name ^= var_descriptors_.GetName(desc_index);
+
+  const String& tmp = String::Handle(var_descriptors_.GetName(desc_index));
+  *name ^= String::IdentifierPrettyName(tmp);
+
   RawLocalVarDescriptors::VarInfo var_info;
   var_descriptors_.GetInfo(desc_index, &var_info);
   ASSERT(token_pos != NULL);
@@ -888,6 +875,7 @@
 
 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj) {
   const Script& script = Script::Handle(SourceScript());
+  jsobj->AddProperty("type", "Frame");
   jsobj->AddProperty("script", script);
   jsobj->AddProperty("tokenPos", TokenPos());
   jsobj->AddProperty("function", function());
@@ -1411,6 +1399,8 @@
   }
   DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown);
   event.set_exception(&exc);
+  ASSERT(stack_trace->Length() > 0);
+  event.set_top_frame(stack_trace->FrameAt(0));
   ASSERT(stack_trace_ == NULL);
   stack_trace_ = stack_trace;
   Pause(&event);
@@ -1732,6 +1722,7 @@
                   line_number);
       }
       SignalBpResolved(bpt);
+      SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
       return bpt;
     }
   }
@@ -1749,6 +1740,7 @@
   if (bpt == NULL) {
     bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos);
     RegisterSourceBreakpoint(bpt);
+    SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
   }
   bpt->Enable();
   return bpt;
@@ -2373,6 +2365,7 @@
                     requested_end_pos);
         }
         SignalBpResolved(bpt);
+        SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
       }
       ASSERT(bpt->IsResolved());
       if (FLAG_verbose_debug) {
@@ -2530,6 +2523,7 @@
       } else {
         prev_bpt->set_next(curr_bpt->next());
       }
+      SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
 
       // Remove references from code breakpoints to this source breakpoint,
       // and disable the code breakpoints.
diff --git a/dart/runtime/vm/debugger.h b/dart/runtime/vm/debugger.h
index 3f9c207..69b03d1 100644
--- a/dart/runtime/vm/debugger.h
+++ b/dart/runtime/vm/debugger.h
@@ -277,8 +277,6 @@
                                DebuggerStackTrace* stack);
 
 
-// TODO(turnidge): At some point we may want to turn this into a class
-// hierarchy.
 class DebuggerEvent {
  public:
   enum EventType {
@@ -288,7 +286,6 @@
     kIsolateCreated = 4,
     kIsolateShutdown = 5,
     kIsolateInterrupted = 6,
-    kIsolateResumed = 7,
   };
 
   explicit DebuggerEvent(Isolate* isolate, EventType event_type)
@@ -302,12 +299,18 @@
 
   EventType type() const { return type_; }
 
+  bool IsPauseEvent() const {
+    return (type_ == kBreakpointReached ||
+            type_ == kIsolateInterrupted ||
+            type_ == kExceptionThrown);
+  }
+
   ActivationFrame* top_frame() const {
-    ASSERT(type_ == kBreakpointReached);
+    ASSERT(IsPauseEvent());
     return top_frame_;
   }
   void set_top_frame(ActivationFrame* frame) {
-    ASSERT(type_ == kBreakpointReached);
+    ASSERT(IsPauseEvent());
     top_frame_ = frame;
   }
 
@@ -333,10 +336,6 @@
     return isolate_->main_port();
   }
 
-  void PrintJSON(JSONStream* js) const;
-
-  static const char* EventTypeToCString(EventType type);
-
  private:
   Isolate* isolate_;
   EventType type_;
diff --git a/dart/runtime/vm/debugger_test.cc b/dart/runtime/vm/debugger_test.cc
index 4c3afa6..5545700 100644
--- a/dart/runtime/vm/debugger_test.cc
+++ b/dart/runtime/vm/debugger_test.cc
@@ -70,14 +70,14 @@
     ExpectSubstringF(
         js.ToCString(),
         "[{\"type\":\"Breakpoint\",\"id\":\"breakpoints\\/2\","
-        "\"breakpointNumber\":2,\"enabled\":true,\"resolved\":false,"
+        "\"breakpointNumber\":2,\"resolved\":false,"
         "\"location\":{\"type\":\"Location\","
         "\"script\":{\"type\":\"@Script\","
         "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
         "\"name\":\"test-lib\","
         "\"kind\":\"script\"},\"tokenPos\":14}},"
         "{\"type\":\"Breakpoint\",\"id\":\"breakpoints\\/1\","
-        "\"breakpointNumber\":1,\"enabled\":true,\"resolved\":false,"
+        "\"breakpointNumber\":1,\"resolved\":false,"
         "\"location\":{\"type\":\"Location\","
         "\"script\":{\"type\":\"@Script\","
         "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
diff --git a/dart/runtime/vm/exceptions.cc b/dart/runtime/vm/exceptions.cc
index 6ece008..f3cbb88 100644
--- a/dart/runtime/vm/exceptions.cc
+++ b/dart/runtime/vm/exceptions.cc
@@ -231,7 +231,7 @@
       StubCode::JumpToExceptionHandlerEntryPoint());
 
   // Unpoison the stack before we tear it down in the generated stub code.
-  uword current_sp = reinterpret_cast<uword>(&program_counter) - 1024;
+  uword current_sp = Isolate::GetCurrentStackPointer() - 1024;
   ASAN_UNPOISON(reinterpret_cast<void*>(current_sp),
                 stack_pointer - current_sp);
 
diff --git a/dart/runtime/vm/flow_graph_builder.cc b/dart/runtime/vm/flow_graph_builder.cc
index 86f27e0..e175da5 100644
--- a/dart/runtime/vm/flow_graph_builder.cc
+++ b/dart/runtime/vm/flow_graph_builder.cc
@@ -4292,7 +4292,10 @@
     intptr_t outer_try_index = node->try_index();
     owner()->set_try_index(outer_try_index);
   }
-  BuildRestoreContext(node->context_var());
+
+  // Note: do not restore the saved_try_context here since the inlined
+  // code is running at he context level of the return or jump instruction
+  // that follows the inlined code. See issue 22822.
 
   JoinEntryInstr* finally_entry =
       new(I) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index());
diff --git a/dart/runtime/vm/il_printer.cc b/dart/runtime/vm/il_printer.cc
index c94497a..0d79149 100644
--- a/dart/runtime/vm/il_printer.cc
+++ b/dart/runtime/vm/il_printer.cc
@@ -485,12 +485,12 @@
 
 
 void LoadLocalInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s", local().name().ToCString());
+  f->Print("%s @%d", local().name().ToCString(), local().index());
 }
 
 
 void StoreLocalInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s, ", local().name().ToCString());
+  f->Print("%s @%d, ", local().name().ToCString(), local().index());
   value()->PrintTo(f);
 }
 
@@ -1146,9 +1146,9 @@
     f->Print(" ");
   }
   if (GetDeoptId() != Isolate::kNoDeoptId) {
-    f->Print("goto:%" Pd " %" Pd "", GetDeoptId(), successor()->block_id());
+    f->Print("goto:%" Pd " B%" Pd "", GetDeoptId(), successor()->block_id());
   } else {
-    f->Print("goto: %" Pd "", successor()->block_id());
+    f->Print("goto: B%" Pd "", successor()->block_id());
   }
 }
 
diff --git a/dart/runtime/vm/isolate.cc b/dart/runtime/vm/isolate.cc
index 214956a..d2a5f54 100644
--- a/dart/runtime/vm/isolate.cc
+++ b/dart/runtime/vm/isolate.cc
@@ -27,6 +27,7 @@
 #include "vm/profiler.h"
 #include "vm/reusable_handles.h"
 #include "vm/service.h"
+#include "vm/service_event.h"
 #include "vm/service_isolate.h"
 #include "vm/simulator.h"
 #include "vm/stack_frame.h"
@@ -114,6 +115,8 @@
   const char* name() const;
   void MessageNotify(Message::Priority priority);
   bool HandleMessage(Message* message);
+  void NotifyPauseOnStart();
+  void NotifyPauseOnExit();
 
 #if defined(DEBUG)
   // Check that it is safe to access this handler.
@@ -431,6 +434,24 @@
 }
 
 
+void IsolateMessageHandler::NotifyPauseOnStart() {
+  StartIsolateScope start_isolate(isolate());
+  StackZone zone(I);
+  HandleScope handle_scope(I);
+  ServiceEvent pause_event(isolate(), ServiceEvent::kPauseStart);
+  Service::HandleEvent(&pause_event);
+}
+
+
+void IsolateMessageHandler::NotifyPauseOnExit() {
+  StartIsolateScope start_isolate(isolate());
+  StackZone zone(I);
+  HandleScope handle_scope(I);
+  ServiceEvent pause_event(isolate(), ServiceEvent::kPauseExit);
+  Service::HandleEvent(&pause_event);
+}
+
+
 #if defined(DEBUG)
 void IsolateMessageHandler::CheckAccess() {
   ASSERT(IsCurrentIsolate());
@@ -1541,32 +1562,29 @@
     heap()->PrintToJSONObject(Heap::kOld, &jsheap);
   }
 
-  // TODO(turnidge): Don't compute a full stack trace every time we
-  // request an isolate's info.
-  DebuggerStackTrace* stack = debugger()->StackTrace();
-  if (stack->Length() > 0) {
-    JSONObject jsframe(&jsobj, "topFrame");
-
-    ActivationFrame* frame = stack->FrameAt(0);
-    frame->PrintToJSONObject(&jsobj);
-    // TODO(turnidge): Implement depth differently -- differentiate
-    // inlined frames.
-    jsobj.AddProperty("depth", (intptr_t)0);
-  }
   jsobj.AddProperty("livePorts", message_handler()->live_ports());
   jsobj.AddProperty("pauseOnExit", message_handler()->pause_on_exit());
 
-  // TODO(turnidge): Make the debugger support paused_on_start/exit.
   if (message_handler()->paused_on_start()) {
     ASSERT(debugger()->PauseEvent() == NULL);
-    DebuggerEvent pauseEvent(this, DebuggerEvent::kIsolateCreated);
-    jsobj.AddProperty("pauseEvent", &pauseEvent);
+    ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
+    jsobj.AddProperty("pauseEvent", &pause_event);
   } else if (message_handler()->paused_on_exit()) {
     ASSERT(debugger()->PauseEvent() == NULL);
-    DebuggerEvent pauseEvent(this, DebuggerEvent::kIsolateShutdown);
-    jsobj.AddProperty("pauseEvent", &pauseEvent);
+    ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
+    jsobj.AddProperty("pauseEvent", &pause_event);
   } else if (debugger()->PauseEvent() != NULL) {
-    jsobj.AddProperty("pauseEvent", debugger()->PauseEvent());
+    ServiceEvent pause_event(debugger()->PauseEvent());
+    jsobj.AddProperty("pauseEvent", &pause_event);
+  } else {
+    ServiceEvent pause_event(this, ServiceEvent::kResume);
+
+    // TODO(turnidge): Don't compute a full stack trace.
+    DebuggerStackTrace* stack = debugger()->StackTrace();
+    if (stack->Length() > 0) {
+      pause_event.set_top_frame(stack->FrameAt(0));
+    }
+    jsobj.AddProperty("pauseEvent", &pause_event);
   }
 
   const Library& lib =
@@ -1610,6 +1628,10 @@
     }
   }
   {
+    JSONArray breakpoints(&jsobj, "breakpoints");
+    debugger()->PrintBreakpointsToJSONArray(&breakpoints);
+  }
+  {
     JSONArray features_array(&jsobj, "features");
     if (is_io_enabled) {
       features_array.AddValue("io");
diff --git a/dart/runtime/vm/json_stream.cc b/dart/runtime/vm/json_stream.cc
index d4ae6a1..388c0d3 100644
--- a/dart/runtime/vm/json_stream.cc
+++ b/dart/runtime/vm/json_stream.cc
@@ -10,6 +10,7 @@
 #include "vm/message.h"
 #include "vm/metrics.h"
 #include "vm/object.h"
+#include "vm/service_event.h"
 #include "vm/unicode.h"
 
 
@@ -88,15 +89,20 @@
   uint8_t* data = NULL;
   MessageWriter writer(&data, &allocator, false);
   writer.WriteMessage(reply);
-  PortMap::PostMessage(new Message(port, data,
-                                   writer.BytesWritten(),
-                                   Message::kNormalPriority));
+  bool result = PortMap::PostMessage(new Message(port, data,
+                                                 writer.BytesWritten(),
+                                                 Message::kNormalPriority));
   if (FLAG_trace_service) {
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
     const char* isolate_name = isolate->name();
-    OS::Print("Isolate %s processed service request %s in %" Pd64" us.\n",
-              isolate_name, method_, process_delta_micros);
+    if (result) {
+      OS::Print("Isolate %s processed service request %s in %" Pd64" us.\n",
+                isolate_name, method_, process_delta_micros);
+    } else {
+      OS::Print("Isolate %s FAILED to post response for service request %s.\n",
+                isolate_name, method_);
+    }
   }
 }
 
@@ -243,7 +249,7 @@
 }
 
 
-void JSONStream::PrintValue(const DebuggerEvent* event) {
+void JSONStream::PrintValue(const ServiceEvent* event) {
   PrintCommaIfNeeded();
   event->PrintJSON(this);
 }
@@ -305,7 +311,7 @@
 }
 
 
-void JSONStream::PrintProperty(const char* name, const DebuggerEvent* event) {
+void JSONStream::PrintProperty(const char* name, const ServiceEvent* event) {
   PrintPropertyName(name);
   PrintValue(event);
 }
diff --git a/dart/runtime/vm/json_stream.h b/dart/runtime/vm/json_stream.h
index b15c3d5..17792cc 100644
--- a/dart/runtime/vm/json_stream.h
+++ b/dart/runtime/vm/json_stream.h
@@ -11,17 +11,17 @@
 
 namespace dart {
 
-class DebuggerEvent;
-class Field;
 class Array;
+class Field;
 class GrowableObjectArray;
 class Instance;
 class JSONArray;
 class JSONObject;
+class Metric;
 class Object;
+class ServiceEvent;
 class SourceBreakpoint;
 class String;
-class Metric;
 class Zone;
 
 class JSONStream : ValueObject {
@@ -86,7 +86,7 @@
   void PrintfValue(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
   void PrintValue(const Object& o, bool ref = true);
   void PrintValue(SourceBreakpoint* bpt);
-  void PrintValue(const DebuggerEvent* event);
+  void PrintValue(const ServiceEvent* event);
   void PrintValue(Metric* metric);
   void PrintValue(Isolate* isolate, bool ref = true);
   bool PrintValueStr(const String& s, intptr_t limit);
@@ -102,7 +102,7 @@
   PRINTF_ATTRIBUTE(3, 4);
   void PrintProperty(const char* name, const Object& o, bool ref = true);
 
-  void PrintProperty(const char* name, const DebuggerEvent* event);
+  void PrintProperty(const char* name, const ServiceEvent* event);
   void PrintProperty(const char* name, SourceBreakpoint* bpt);
   void PrintProperty(const char* name, Metric* metric);
   void PrintProperty(const char* name, Isolate* isolate);
@@ -170,7 +170,7 @@
   void AddProperty(const char* name, const Object& obj, bool ref = true) const {
     stream_->PrintProperty(name, obj, ref);
   }
-  void AddProperty(const char* name, const DebuggerEvent* event) const {
+  void AddProperty(const char* name, const ServiceEvent* event) const {
     stream_->PrintProperty(name, event);
   }
   void AddProperty(const char* name, SourceBreakpoint* bpt) const {
@@ -224,7 +224,7 @@
   void AddValue(SourceBreakpoint* bpt) const {
     stream_->PrintValue(bpt);
   }
-  void AddValue(const DebuggerEvent* event) const {
+  void AddValue(const ServiceEvent* event) const {
     stream_->PrintValue(event);
   }
   void AddValue(Metric* metric) const {
diff --git a/dart/runtime/vm/message_handler.cc b/dart/runtime/vm/message_handler.cc
index 6ca2fb1..68344cb 100644
--- a/dart/runtime/vm/message_handler.cc
+++ b/dart/runtime/vm/message_handler.cc
@@ -38,6 +38,7 @@
       paused_(0),
       pause_on_start_(false),
       pause_on_exit_(false),
+      paused_on_start_(false),
       paused_on_exit_(false),
       pool_(NULL),
       task_(NULL),
@@ -93,33 +94,36 @@
 
 
 void MessageHandler::PostMessage(Message* message, bool before_events) {
-  MonitorLocker ml(&monitor_);
-  if (FLAG_trace_isolates) {
-    const char* source_name = "<native code>";
-    Isolate* source_isolate = Isolate::Current();
-    if (source_isolate) {
-      source_name = source_isolate->name();
+  Message::Priority saved_priority;
+  {
+    MonitorLocker ml(&monitor_);
+    if (FLAG_trace_isolates) {
+      const char* source_name = "<native code>";
+      Isolate* source_isolate = Isolate::Current();
+      if (source_isolate) {
+        source_name = source_isolate->name();
+      }
+      OS::Print("[>] Posting message:\n"
+                "\tlen:        %" Pd "\n"
+                "\tsource:     %s\n"
+                "\tdest:       %s\n"
+                "\tdest_port:  %" Pd64 "\n",
+                message->len(), source_name, name(), message->dest_port());
     }
-    OS::Print("[>] Posting message:\n"
-              "\tsource:     %s\n"
-              "\tdest:       %s\n"
-              "\tdest_port:  %" Pd64 "\n",
-              source_name, name(), message->dest_port());
-  }
 
-  Message::Priority saved_priority = message->priority();
-  if (message->IsOOB()) {
-    oob_queue_->Enqueue(message, before_events);
-  } else {
-    queue_->Enqueue(message, before_events);
-  }
-  message = NULL;  // Do not access message.  May have been deleted.
+    saved_priority = message->priority();
+    if (message->IsOOB()) {
+      oob_queue_->Enqueue(message, before_events);
+    } else {
+      queue_->Enqueue(message, before_events);
+    }
+    message = NULL;  // Do not access message.  May have been deleted.
 
-  if (pool_ != NULL && task_ == NULL) {
-    task_ = new MessageHandlerTask(this);
-    pool_->Run(task_);
+    if (pool_ != NULL && task_ == NULL) {
+      task_ = new MessageHandlerTask(this);
+      pool_->Run(task_);
+    }
   }
-
   // Invoke any custom message notification.
   MessageNotify(saved_priority);
 }
@@ -146,11 +150,13 @@
       Message::kNormalPriority : Message::kOOBPriority;
   Message* message = DequeueMessage(min_priority);
   while (message != NULL) {
+    intptr_t message_len = message->len();
     if (FLAG_trace_isolates) {
       OS::Print("[<] Handling message:\n"
+                "\tlen:        %" Pd "\n"
                 "\thandler:    %s\n"
                 "\tport:       %" Pd64 "\n",
-                name(), message->dest_port());
+                message_len, name(), message->dest_port());
     }
 
     // Release the monitor_ temporarily while we handle the message.
@@ -163,9 +169,10 @@
     monitor_.Enter();
     if (FLAG_trace_isolates) {
       OS::Print("[.] Message handled:\n"
+                "\tlen:        %" Pd "\n"
                 "\thandler:    %s\n"
                 "\tport:       %" Pd64 "\n",
-                name(), saved_dest_port);
+                message_len, name(), saved_dest_port);
     }
     if (!result) {
       // If we hit an error, we're done processing messages.
@@ -225,11 +232,17 @@
     // if we have one.  For an isolate, this will run the isolate's
     // main() function.
     if (pause_on_start()) {
+      if (!paused_on_start_) {
+        NotifyPauseOnStart();
+        paused_on_start_ = true;
+      }
       HandleMessages(false, false);
       if (pause_on_start()) {
         // Still paused.
         task_ = NULL;  // No task in queue.
         return;
+      } else {
+        paused_on_start_ = false;
       }
     }
 
@@ -251,11 +264,14 @@
 
     if (!ok || !HasLivePorts()) {
       if (pause_on_exit()) {
-        if (FLAG_trace_service_pause_events && !paused_on_exit_) {
-          OS::PrintErr("Isolate %s paused before exiting. "
+        if (!paused_on_exit_) {
+          if (FLAG_trace_service_pause_events) {
+            OS::PrintErr("Isolate %s paused before exiting. "
                        "Use the Observatory to release it.\n", name());
+          }
+          NotifyPauseOnExit();
+          paused_on_exit_ = true;
         }
-        paused_on_exit_ = true;
       } else {
         if (FLAG_trace_isolates) {
         OS::Print("[-] Stopping message handler (%s):\n"
diff --git a/dart/runtime/vm/message_handler.h b/dart/runtime/vm/message_handler.h
index 0e08377..a2a07bf 100644
--- a/dart/runtime/vm/message_handler.h
+++ b/dart/runtime/vm/message_handler.h
@@ -81,7 +81,7 @@
   bool paused_on_start() const {
     // If pause_on_start_ is still set, tell the user we are paused,
     // even if we haven't hit the pause point yet.
-    return pause_on_start_;
+    return paused_on_start_;
   }
 
   bool pause_on_exit() const {
@@ -144,6 +144,9 @@
   // Returns true on success.
   virtual bool HandleMessage(Message* message) = 0;
 
+  virtual void NotifyPauseOnStart() {}
+  virtual void NotifyPauseOnExit() {}
+
  private:
   friend class PortMap;
   friend class MessageHandlerTestPeer;
@@ -167,6 +170,7 @@
   intptr_t paused_;  // The number of pause messages received.
   bool pause_on_start_;
   bool pause_on_exit_;
+  bool paused_on_start_;
   bool paused_on_exit_;
   ThreadPool* pool_;
   ThreadPool::Task* task_;
diff --git a/dart/runtime/vm/object.cc b/dart/runtime/vm/object.cc
index ea3c6d9..dd85273 100644
--- a/dart/runtime/vm/object.cc
+++ b/dart/runtime/vm/object.cc
@@ -1542,6 +1542,10 @@
   cls = Class::New<MirrorReference>();
   cls = Class::New<UserTag>();
 
+  const Context& context = Context::Handle(isolate,
+                                           Context::New(0, Heap::kOld));
+  object_store->set_empty_context(context);
+
   StubCode::InitBootstrapStubs(isolate);
 }
 
@@ -13461,20 +13465,21 @@
 
 const char* UnhandledException::ToErrorCString() const {
   Isolate* isolate = Isolate::Current();
-  if (exception() == isolate->object_store()->out_of_memory()) {
-    return "Unhandled exception:\nOut of memory";
-  }
-  if (exception() == isolate->object_store()->stack_overflow()) {
-    return "Unhandled exception:\nStack overflow";
-  }
   HANDLESCOPE(isolate);
   Object& strtmp = Object::Handle();
-  const Instance& exc = Instance::Handle(exception());
-  strtmp = DartLibraryCalls::ToString(exc);
-  const char* exc_str =
-      "<Received error while converting exception to string>";
-  if (!strtmp.IsError()) {
-    exc_str = strtmp.ToCString();
+  const char* exc_str;
+  if (exception() == isolate->object_store()->out_of_memory()) {
+    exc_str = "Out of Memory";
+  } else if (exception() == isolate->object_store()->stack_overflow()) {
+    exc_str = "Stack Overflow";
+  } else {
+    const Instance& exc = Instance::Handle(exception());
+    strtmp = DartLibraryCalls::ToString(exc);
+    if (!strtmp.IsError()) {
+      exc_str = strtmp.ToCString();
+    } else {
+      exc_str = "<Received error while converting exception to string>";
+    }
   }
   const Instance& stack = Instance::Handle(stacktrace());
   strtmp = DartLibraryCalls::ToString(stack);
@@ -13483,11 +13488,8 @@
   if (!strtmp.IsError()) {
     stack_str = strtmp.ToCString();
   }
-
   const char* format = "Unhandled exception:\n%s\n%s";
-  int len = (strlen(exc_str) + strlen(stack_str) + strlen(format)
-             - 4    // Two '%s'
-             + 1);  // '\0'
+  intptr_t len = OS::SNPrint(NULL, 0, format, exc_str, stack_str);
   char* chars = isolate->current_zone()->Alloc<char>(len);
   OS::SNPrint(chars, len, format, exc_str, stack_str);
   return chars;
diff --git a/dart/runtime/vm/object.h b/dart/runtime/vm/object.h
index 0b0eb5e..7981b2b 100644
--- a/dart/runtime/vm/object.h
+++ b/dart/runtime/vm/object.h
@@ -3490,6 +3490,8 @@
 
 class ExceptionHandlers : public Object {
  public:
+  static const intptr_t kInvalidPcOffset = 0;
+
   intptr_t num_entries() const;
 
   void GetHandlerInfo(intptr_t try_index,
diff --git a/dart/runtime/vm/parser.cc b/dart/runtime/vm/parser.cc
index f79e6d4..05334bc 100644
--- a/dart/runtime/vm/parser.cc
+++ b/dart/runtime/vm/parser.cc
@@ -8157,12 +8157,15 @@
   ExpectToken(Token::kWHILE);
   ExpectToken(Token::kLPAREN);
   SequenceNode* await_preamble = NULL;
-  AstNode* cond_expr = ParseAwaitableExpr(
-      kAllowConst, kConsumeCascades, &await_preamble);
-  // No need for special handling of the await preamble as we can just append o
-  // it to the loop body.
+  intptr_t expr_pos = TokenPos();
+  AstNode* cond_expr =
+      ParseAwaitableExpr(kAllowConst, kConsumeCascades, &await_preamble);
   if (await_preamble != NULL) {
-    dowhile_body->Add(await_preamble);
+    // Prepend the preamble to the condition.
+    LetNode* await_cond = new(Z) LetNode(expr_pos);
+    await_cond->AddNode(await_preamble);
+    await_cond->AddNode(cond_expr);
+    cond_expr = await_cond;
   }
   ExpectToken(Token::kRPAREN);
   ExpectSemicolon();
diff --git a/dart/runtime/vm/profiler_service.cc b/dart/runtime/vm/profiler_service.cc
index b6e6018..dd3d124 100644
--- a/dart/runtime/vm/profiler_service.cc
+++ b/dart/runtime/vm/profiler_service.cc
@@ -174,7 +174,9 @@
   intptr_t inclusive_ticks() const {
     return inclusive_ticks_;
   }
-
+  void inc_inclusive_ticks() {
+    inclusive_ticks_++;
+  }
   intptr_t exclusive_ticks() const {
     return exclusive_ticks_;
   }
@@ -436,6 +438,9 @@
   void set_inclusive_ticks(intptr_t inclusive_ticks) {
     inclusive_ticks_ = inclusive_ticks;
   }
+  void inc_inclusive_ticks() {
+    inclusive_ticks_++;
+  }
 
   intptr_t exclusive_ticks() const { return exclusive_ticks_; }
   void set_exclusive_ticks(intptr_t exclusive_ticks) {
@@ -1412,7 +1417,7 @@
         dead_code_table_(dead_code_table),
         tag_code_table_(tag_code_table),
         function_table_(function_table),
-        inclusive_(false),
+        inclusive_tree_(false),
         trace_(false),
         trace_code_filter_(NULL) {
     ASSERT(live_code_table_ != NULL);
@@ -1439,9 +1444,9 @@
   }
 
   void VisitSample(Sample* sample) {
-    inclusive_ = false;
+    inclusive_tree_ = false;
     ProcessSampleExclusive(sample);
-    inclusive_ = true;
+    inclusive_tree_ = true;
     ProcessSampleInclusive(sample);
   }
 
@@ -1457,6 +1462,12 @@
     return tag_order_;
   }
 
+  bool vm_tags_emitted() const {
+    return (tag_order_ == ProfilerService::kUserVM) ||
+           (tag_order_ == ProfilerService::kVMUser) ||
+           (tag_order_ == ProfilerService::kVM);
+  }
+
   void set_tag_order(ProfilerService::TagOrder tag_order) {
     tag_order_ = tag_order;
   }
@@ -1468,6 +1479,7 @@
     ProfileFunctionTrieNode* current = inclusive_root_;
     current = AppendTags(sample, current);
     if (sample->truncated_trace()) {
+      InclusiveTickTruncatedTag();
       current = AppendTruncatedTag(current);
     }
     // Walk the sampled PCs.
@@ -1475,11 +1487,12 @@
       if (sample->At(i) == 0) {
         continue;
       }
-      // If we aren't sampled out of an exit frame and this is the top
-      // frame.
-      bool exclusive_tick = (i == 0) && !sample->exit_frame_sample();
-      current = ProcessPC(sample->At(i), sample->timestamp(), current,
-                          visited(), exclusive_tick,
+      current = ProcessPC(sample->At(i),
+                          sample->timestamp(),
+                          current,
+                          visited(),
+                          (i == 0),
+                          sample->exit_frame_sample() && (i == 0),
                           sample->missing_frame_inserted());
     }
   }
@@ -1494,11 +1507,12 @@
       if (sample->At(i) == 0) {
         break;
       }
-      // If we aren't sampled out of an exit frame and this is the top
-      // frame.
-      bool exclusive_tick = (i == 0) && !sample->exit_frame_sample();
-      current = ProcessPC(sample->At(i), sample->timestamp(), current,
-                          visited(), exclusive_tick,
+      current = ProcessPC(sample->At(i),
+                          sample->timestamp(),
+                          current,
+                          visited(),
+                          (i == 0),
+                          sample->exit_frame_sample() && (i == 0),
                           sample->missing_frame_inserted());
     }
     if (sample->truncated_trace()) {
@@ -1527,6 +1541,12 @@
     return current;
   }
 
+  void InclusiveTickTruncatedTag() {
+    intptr_t index = tag_code_table_->FindIndex(VMTag::kTruncatedTagId);
+    CodeRegion* region = tag_code_table_->At(index);
+    ProfileFunction* function = region->function();
+    function->inc_inclusive_ticks();
+  }
 
   ProfileFunctionTrieNode* AppendVMTag(Sample* sample,
                                        ProfileFunctionTrieNode* current) {
@@ -1624,10 +1644,12 @@
     OS::Print("\n");
   }
 
-  ProfileFunctionTrieNode* ProcessPC(uword pc, int64_t timestamp,
+  ProfileFunctionTrieNode* ProcessPC(uword pc,
+                                     int64_t timestamp,
                                      ProfileFunctionTrieNode* current,
                                      intptr_t inclusive_serial,
-                                     bool exclusive,
+                                     bool top_frame,
+                                     bool exit_frame,
                                      bool missing_frame_inserted) {
     CodeRegion* region = FindCodeObject(pc, timestamp);
     if (region == NULL) {
@@ -1652,12 +1674,12 @@
         OS::Print("[%" Px "] X - %s (%s)\n",
                   pc, function->name(), region_name);
       }
-      if (!inclusive_) {
-        function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
-      }
-      current = current->GetChild(function->index());
-      current->AddCodeObjectIndex(code_index);
-      current->Tick();
+      current = ProcessFunction(function,
+                                current,
+                                inclusive_serial,
+                                top_frame,
+                                exit_frame,
+                                code_index);
       if ((trace_code_filter_ != NULL) &&
           (strstr(region_name, trace_code_filter_) != NULL)) {
         trace_ = true;
@@ -1668,14 +1690,18 @@
       return current;
     }
 
-    if (inclusive_) {
+    if (inclusive_tree_) {
       for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
         Function* inlined_function = inlined_functions[i];
         ASSERT(inlined_function != NULL);
         ASSERT(!inlined_function->IsNull());
-        current = ProcessInlinedFunction(
-            inlined_function, current, inclusive_serial, exclusive, code_index);
-        exclusive = false;
+        current = ProcessInlinedFunction(inlined_function,
+                                         current,
+                                         inclusive_serial,
+                                         top_frame,
+                                         exit_frame,
+                                         code_index);
+        top_frame = false;
       }
     } else {
       for (intptr_t i = 0; i < inlined_functions.length(); i++) {
@@ -1687,9 +1713,13 @@
           OS::Print("[%" Px "] %" Pd " - %s (%s)\n",
                   pc, i, inline_name, region_name);
         }
-        current = ProcessInlinedFunction(
-            inlined_function, current, inclusive_serial, exclusive, code_index);
-        exclusive = false;
+        current = ProcessInlinedFunction(inlined_function,
+                                         current,
+                                         inclusive_serial,
+                                         top_frame,
+                                         exit_frame,
+                                         code_index);
+        top_frame = false;
         if ((trace_code_filter_ != NULL) &&
             (strstr(region_name, trace_code_filter_) != NULL)) {
           trace_ = true;
@@ -1707,16 +1737,44 @@
       Function* inlined_function,
       ProfileFunctionTrieNode* current,
       intptr_t inclusive_serial,
-      bool exclusive,
+      bool top_frame,
+      bool exit_frame,
       intptr_t code_index) {
     ProfileFunction* function =
         function_table_->LookupOrAdd(*inlined_function);
     ASSERT(function != NULL);
+    return ProcessFunction(function,
+                           current,
+                           inclusive_serial,
+                           top_frame,
+                           exit_frame,
+                           code_index);
+  }
+
+  ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function,
+                                           ProfileFunctionTrieNode* current,
+                                           intptr_t inclusive_serial,
+                                           bool top_frame,
+                                           bool exit_frame,
+                                           intptr_t code_index) {
+    const bool exclusive = top_frame && !exit_frame;
+    if (!inclusive_tree_) {
+      // We process functions for the inclusive and exclusive trees.
+      // Only tick the function for the exclusive tree.
+      function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
+    }
     function->AddCodeObjectIndex(code_index);
-    function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
+
     current = current->GetChild(function->index());
     current->AddCodeObjectIndex(code_index);
-    current->Tick();
+    if (top_frame) {
+      if (!exit_frame || vm_tags_emitted()) {
+        // Only tick if this isn't an exit frame or VM tags are emitted.
+        current->Tick();
+      }
+    } else {
+      current->Tick();
+    }
     return current;
   }
 
@@ -1749,7 +1807,7 @@
   CodeRegionTable* dead_code_table_;
   CodeRegionTable* tag_code_table_;
   ProfileFunctionTable* function_table_;
-  bool inclusive_;
+  bool inclusive_tree_;
   bool trace_;
   const char* trace_code_filter_;
 };
@@ -1892,6 +1950,12 @@
     return tag_order_;
   }
 
+  bool vm_tags_emitted() const {
+    return (tag_order_ == ProfilerService::kUserVM) ||
+           (tag_order_ == ProfilerService::kVMUser) ||
+           (tag_order_ == ProfilerService::kVM);
+  }
+
   void set_tag_order(ProfilerService::TagOrder tag_order) {
     tag_order_ = tag_order;
   }
@@ -1934,7 +1998,16 @@
         continue;
       }
       current = current->GetChild(index);
-      current->Tick();
+      if (i == 0) {
+        // Executing PC.
+        if (!sample->exit_frame_sample() || vm_tags_emitted()) {
+          // Only tick if this isn't an exit frame or VM tags are emitted.
+          current->Tick();
+        }
+      } else {
+        // Caller PCs.
+        current->Tick();
+      }
     }
     if (sample->truncated_trace()) {
       current = AppendTruncatedTag(current);
@@ -2136,7 +2209,8 @@
         intptr_t total_live_code_objects = live_code_table.Length();
         intptr_t total_dead_code_objects = dead_code_table.Length();
         intptr_t total_tag_code_objects = tag_code_table.Length();
-        OS::Print("Processed %" Pd " frames\n", frames);
+        OS::Print(
+            "Processed %" Pd " samples with %" Pd " frames\n", samples, frames);
         OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
                   total_live_code_objects,
                   total_dead_code_objects,
@@ -2174,6 +2248,11 @@
         code_trie_builder.exclusive_root()->SortByCount();
         code_trie_builder.inclusive_root()->SortByCount();
       }
+      if (FLAG_trace_profiler) {
+        OS::Print("Code Trie Root Count: E: %" Pd " I: %" Pd "\n",
+                  code_trie_builder.exclusive_root()->count(),
+                  code_trie_builder.inclusive_root()->count());
+      }
       ProfileFunctionTrieBuilder function_trie_builder(isolate,
                                                        &live_code_table,
                                                        &dead_code_table,
@@ -2188,6 +2267,11 @@
         function_trie_builder.exclusive_root()->SortByCount();
         function_trie_builder.inclusive_root()->SortByCount();
       }
+      if (FLAG_trace_profiler) {
+        OS::Print("Function Trie Root Count: E: %" Pd " I: %" Pd "\n",
+                  function_trie_builder.exclusive_root()->count(),
+                  function_trie_builder.inclusive_root()->count());
+      }
       {
         ScopeTimer sw("CpuProfileJSONStream", FLAG_trace_profiler);
         // Serialize to JSON.
diff --git a/dart/runtime/vm/raw_object_snapshot.cc b/dart/runtime/vm/raw_object_snapshot.cc
index 49d25ec..232ed6f 100644
--- a/dart/runtime/vm/raw_object_snapshot.cc
+++ b/dart/runtime/vm/raw_object_snapshot.cc
@@ -1366,23 +1366,26 @@
 
   // Allocate context object.
   int32_t num_vars = reader->Read<int32_t>();
-  Context& context = Context::ZoneHandle(
-      reader->isolate(), NEW_OBJECT_WITH_LEN(Context, num_vars));
+  Context& context = Context::ZoneHandle(reader->isolate());
   reader->AddBackRef(object_id, &context, kIsDeserialized);
+  if (num_vars == 0) {
+    context ^= reader->object_store()->empty_context();
+  } else {
+    context ^= NEW_OBJECT_WITH_LEN(Context, num_vars);
 
-  // Set the object tags.
-  context.set_tags(tags);
+    // Set the object tags.
+    context.set_tags(tags);
 
-  // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
-    context.StorePointer((context.raw()->from() + i),
-                         reader->PassiveObjectHandle()->raw());
+    // Set all the object fields.
+    // TODO(5411462): Need to assert No GC can happen here, even though
+    // allocations may happen.
+    intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from());
+    for (intptr_t i = 0; i <= num_flds; i++) {
+      (*reader->PassiveObjectHandle()) = reader->ReadObjectRef();
+      context.StorePointer((context.raw()->from() + i),
+                           reader->PassiveObjectHandle()->raw());
+    }
   }
-
   return context.raw();
 }
 
@@ -1400,11 +1403,13 @@
   writer->WriteTags(writer->GetObjectTags(this));
 
   // Write out num of variables in the context.
-  writer->Write<int32_t>(ptr()->num_variables_);
-
-  // Write out all the object pointer fields.
-  SnapshotWriterVisitor visitor(writer);
-  visitor.VisitPointers(from(), to(ptr()->num_variables_));
+  int32_t num_variables = ptr()->num_variables_;
+  writer->Write<int32_t>(num_variables);
+  if (num_variables != 0) {
+    // Write out all the object pointer fields.
+    SnapshotWriterVisitor visitor(writer);
+    visitor.VisitPointers(from(), to(num_variables));
+  }
 }
 
 
diff --git a/dart/runtime/vm/service.cc b/dart/runtime/vm/service.cc
index f62e38f..b8cea45 100644
--- a/dart/runtime/vm/service.cc
+++ b/dart/runtime/vm/service.cc
@@ -27,6 +27,7 @@
 #include "vm/port.h"
 #include "vm/profiler_service.h"
 #include "vm/reusable_handles.h"
+#include "vm/service_event.h"
 #include "vm/service_isolate.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
@@ -462,6 +463,10 @@
       }
       if (method->entry(isolate, &js)) {
         js.PostReply();
+      } else {
+        // NOTE(turnidge): All message handlers currently return true,
+        // so this case shouldn't be reached, at present.
+        UNIMPLEMENTED();
       }
       return;
     }
@@ -501,13 +506,18 @@
 }
 
 
+bool Service::NeedsEvents() {
+  return ServiceIsolate::IsRunning();
+}
+
+
 bool Service::NeedsDebuggerEvents() {
-  return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyDebugMask);
+  return NeedsEvents() && EventMaskHas(kEventFamilyDebugMask);
 }
 
 
 bool Service::NeedsGCEvents() {
-  return ServiceIsolate::IsRunning() && EventMaskHas(kEventFamilyGCMask);
+  return NeedsEvents() && EventMaskHas(kEventFamilyGCMask);
 }
 
 
@@ -516,7 +526,9 @@
 }
 
 
-void Service::SendEvent(intptr_t eventId, const Object& eventMessage) {
+void Service::SendEvent(intptr_t eventFamilyId,
+                        intptr_t eventType,
+                        const Object& eventMessage) {
   if (!ServiceIsolate::IsRunning()) {
     return;
   }
@@ -524,10 +536,12 @@
   ASSERT(isolate != NULL);
   HANDLESCOPE(isolate);
 
-  // Construct a list of the form [eventId, eventMessage].
+  // Construct a list of the form [eventFamilyId, eventMessage].
+  //
+  // TODO(turnidge): Revisit passing the eventFamilyId here at all.
   const Array& list = Array::Handle(Array::New(2));
   ASSERT(!list.IsNull());
-  list.SetAt(0, Integer::Handle(Integer::New(eventId)));
+  list.SetAt(0, Integer::Handle(Integer::New(eventFamilyId)));
   list.SetAt(1, eventMessage);
 
   // Push the event to port_.
@@ -537,7 +551,7 @@
   intptr_t len = writer.BytesWritten();
   if (FLAG_trace_service) {
     OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
-              eventId, len);
+              eventType, len);
   }
   // TODO(turnidge): For now we ignore failure to send an event.  Revisit?
   PortMap::PostMessage(
@@ -545,7 +559,7 @@
 }
 
 
-void Service::SendEvent(intptr_t eventId,
+void Service::SendEvent(intptr_t eventFamilyId,
                         const String& meta,
                         const uint8_t* data,
                         intptr_t size) {
@@ -571,7 +585,8 @@
     offset += size;
   }
   ASSERT(offset == total_bytes);
-  SendEvent(eventId, message);
+  // TODO(turnidge): Pass the real eventType here.
+  SendEvent(eventFamilyId, 0, message);
 }
 
 
@@ -579,15 +594,16 @@
   JSONStream js;
   event->PrintJSON(&js);
   const String& message = String::Handle(String::New(js.ToCString()));
-  SendEvent(kEventFamilyGC, message);
+  // TODO(turnidge): Pass the real eventType here.
+  SendEvent(kEventFamilyGC, 0, message);
 }
 
 
-void Service::HandleDebuggerEvent(DebuggerEvent* event) {
+void Service::HandleEvent(ServiceEvent* event) {
   JSONStream js;
   event->PrintJSON(&js);
   const String& message = String::Handle(String::New(js.ToCString()));
-  SendEvent(kEventFamilyDebug, message);
+  SendEvent(kEventFamilyDebug, event->type(), message);
 }
 
 
@@ -1513,6 +1529,32 @@
 }
 
 
+static const MethodParameter* eval_frame_params[] = {
+  ISOLATE_PARAMETER,
+  new UIntParameter("frame", true),
+  new MethodParameter("expression", true),
+  NULL,
+};
+
+
+static bool EvalFrame(Isolate* isolate, JSONStream* js) {
+  DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
+  intptr_t framePos = UIntParameter::Parse(js->LookupParam("frame"));
+  if (framePos > stack->Length()) {
+    PrintInvalidParamError(js, "frame");
+    return true;
+  }
+  ActivationFrame* frame = stack->FrameAt(framePos);
+
+  const char* expr = js->LookupParam("expression");
+  const String& expr_str = String::Handle(isolate, String::New(expr));
+
+  const Object& result = Object::Handle(frame->Evaluate(expr_str));
+  result.PrintJSON(js, true);
+  return true;
+}
+
+
 static const MethodParameter* get_call_site_data_params[] = {
   ISOLATE_PARAMETER,
   new IdParameter("targetId", true),
@@ -2016,8 +2058,8 @@
     jsobj.AddProperty("type", "Success");
     jsobj.AddProperty("id", "");
     {
-      DebuggerEvent resumeEvent(isolate, DebuggerEvent::kIsolateResumed);
-      Service::HandleDebuggerEvent(&resumeEvent);
+      ServiceEvent event(isolate, ServiceEvent::kResume);
+      Service::HandleEvent(&event);
     }
     return true;
   }
@@ -2054,21 +2096,6 @@
 }
 
 
-static const MethodParameter* get_breakpoints_params[] = {
-  ISOLATE_PARAMETER,
-  NULL,
-};
-
-
-static bool GetBreakpoints(Isolate* isolate, JSONStream* js) {
-  JSONObject jsobj(js);
-  jsobj.AddProperty("type", "BreakpointList");
-  JSONArray jsarr(&jsobj, "breakpoints");
-  isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
-  return true;
-}
-
-
 static const MethodParameter* pause_params[] = {
   ISOLATE_PARAMETER,
   NULL,
@@ -2515,10 +2542,10 @@
     clear_cpu_profile_params },
   { "eval", Eval,
     eval_params },
+  { "evalFrame", EvalFrame,
+    eval_frame_params },
   { "getAllocationProfile", GetAllocationProfile,
     get_allocation_profile_params },
-  { "getBreakpoints", GetBreakpoints,
-    get_breakpoints_params },
   { "getCallSiteData", GetCallSiteData,
     get_call_site_data_params },
   { "getClassList", GetClassList,
diff --git a/dart/runtime/vm/service.h b/dart/runtime/vm/service.h
index 2a9078f..c63f15d 100644
--- a/dart/runtime/vm/service.h
+++ b/dart/runtime/vm/service.h
@@ -13,7 +13,6 @@
 namespace dart {
 
 class Array;
-class DebuggerEvent;
 class EmbedderServiceHandler;
 class GCEvent;
 class Instance;
@@ -21,6 +20,7 @@
 class JSONStream;
 class Object;
 class RawInstance;
+class ServiceEvent;
 class String;
 
 class Service : public AllStatic {
@@ -33,10 +33,11 @@
 
   static bool EventMaskHas(uint32_t mask);
   static void SetEventMask(uint32_t mask);
+  static bool NeedsEvents();
   static bool NeedsDebuggerEvents();
   static bool NeedsGCEvents();
 
-  static void HandleDebuggerEvent(DebuggerEvent* event);
+  static void HandleEvent(ServiceEvent* event);
   static void HandleGCEvent(GCEvent* event);
 
   static void RegisterIsolateEmbedderCallback(
@@ -67,7 +68,9 @@
   static EmbedderServiceHandler* FindIsolateEmbedderHandler(const char* name);
   static EmbedderServiceHandler* FindRootEmbedderHandler(const char* name);
 
-  static void SendEvent(intptr_t eventId, const Object& eventMessage);
+  static void SendEvent(intptr_t eventFamilyId,
+                        intptr_t eventType,
+                        const Object& eventMessage);
   // Does not take ownership of 'data'.
   static void SendEvent(intptr_t eventId,
                         const String& meta,
diff --git a/dart/runtime/vm/service/client.dart b/dart/runtime/vm/service/client.dart
index a9cbd38..1fd4f44 100644
--- a/dart/runtime/vm/service/client.dart
+++ b/dart/runtime/vm/service/client.dart
@@ -25,12 +25,16 @@
 
   /// Call to process a message. Response will be posted with 'seq'.
   void onMessage(var seq, Message message) {
-    // Call post when the response arrives.
-    message.response.then((response) {
-      post(seq, response);
-    });
-    // Send message to service.
-    service.route(message);
+    try {
+      // Send message to service.
+      service.route(message).then((response) {
+        // Call post when the response arrives.
+        post(seq, response);
+      });
+    } catch (e, st) {
+      message.setErrorResponse('Internal error: $e');
+      post(seq, message.response);
+    }
   }
 
   /// When implementing, responsible for sending [response] to the client.
diff --git a/dart/runtime/vm/service/message.dart b/dart/runtime/vm/service/message.dart
index 2b3f038..b465499 100644
--- a/dart/runtime/vm/service/message.dart
+++ b/dart/runtime/vm/service/message.dart
@@ -10,6 +10,9 @@
   /// Future of response.
   Future<String> get response => _completer.future;
 
+  // Client-side identifier for this message.
+  final serial;
+
   // In new messages.
   final String method;
 
@@ -30,8 +33,8 @@
     });
   }
 
-  Message.fromJsonRpc(this.method, Map rpcParams) {
-    params.addAll(rpcParams);
+  Message.fromJsonRpc(Map map) : serial = map['id'], method = map['method'] {
+    params.addAll(map['params']);
   }
 
   static String _methodNameFromUri(Uri uri) {
@@ -76,11 +79,8 @@
     final receivePort = new RawReceivePort();
     receivePort.handler = (value) {
       receivePort.close();
-      if (value is Exception) {
-        _completer.completeError(value);
-      } else {
-        _completer.complete(value);
-      }
+      assert(value is String);
+      _completer.complete(value);
     };
     var keys = _makeAllString(params.keys.toList(growable:false));
     var values = _makeAllString(params.values.toList(growable:false));
@@ -90,7 +90,14 @@
         ..[2] = method
         ..[3] = keys
         ..[4] = values;
-    sendIsolateServiceMessage(sendPort, request);
+    if (!sendIsolateServiceMessage(sendPort, request)) {
+      _completer.complete(JSON.encode({
+          'type': 'ServiceError',
+          'id': '',
+          'kind': 'InternalError',
+          'message': 'could not send message [${serial}] to isolate',
+      }));
+    }
     return _completer.future;
   }
 
@@ -98,11 +105,8 @@
     final receivePort = new RawReceivePort();
     receivePort.handler = (value) {
       receivePort.close();
-      if (value is Exception) {
-        _completer.completeError(value);
-      } else {
-        _completer.complete(value);
-      }
+      assert(value is String);
+      _completer.complete(value);
     };
     var keys = _makeAllString(params.keys.toList(growable:false));
     var values = _makeAllString(params.values.toList(growable:false));
@@ -132,7 +136,7 @@
   }
 }
 
-void sendIsolateServiceMessage(SendPort sp, List m)
+bool sendIsolateServiceMessage(SendPort sp, List m)
     native "VMService_SendIsolateServiceMessage";
 
 void sendRootServiceMessage(List m)
diff --git a/dart/runtime/vm/service/service.idl b/dart/runtime/vm/service/service.idl
index 2764e23..1b825a1 100644
--- a/dart/runtime/vm/service/service.idl
+++ b/dart/runtime/vm/service/service.idl
@@ -14,9 +14,6 @@
   // The response is a subtype of Object or ObjectRef.
   getObjectByAddress(address string, ref bool) Response
 
-  // Returns the list of breakpoints for an isolate.
-  getBreakpoints(isolateId string) BreakpointList
-
   // Adds a breakpoint at the specified line.
   //
   // TODO(turnidge): Make line an int instead of a string.
@@ -177,7 +174,6 @@
 // A <code>Breakpoint</code> describes a debugger breakpoint.
 struct Breakpoint extends Object {
   breakpointNumber int
-  enabled          bool
   resolved         bool
   location         Location
 }
@@ -308,12 +304,6 @@
 }
 
 
-// A list of <code>Breakpoint</code>
-struct BreakpointList extends Response {
-  breakpoints []Breakpoint
-}
-
-
 // An <code>AllocationProfile</code> encodes an allocation profile.
 struct AllocationProfile extends Response {
   todo int
diff --git a/dart/runtime/vm/service_event.cc b/dart/runtime/vm/service_event.cc
new file mode 100644
index 0000000..9f7c63d
--- /dev/null
+++ b/dart/runtime/vm/service_event.cc
@@ -0,0 +1,103 @@
+// 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.
+
+#include "vm/service_event.h"
+
+namespace dart {
+
+// Translate from the legacy DebugEvent to a ServiceEvent.
+static ServiceEvent::EventType TranslateEventType(
+    DebuggerEvent::EventType type) {
+    switch (type) {
+      case DebuggerEvent::kIsolateCreated:
+        return ServiceEvent::kIsolateStart;
+
+      case DebuggerEvent::kIsolateShutdown:
+        return ServiceEvent::kIsolateExit;
+
+      case DebuggerEvent::kBreakpointReached:
+        return ServiceEvent::kPauseBreakpoint;
+
+      case DebuggerEvent::kIsolateInterrupted:
+        return ServiceEvent::kPauseInterrupted;
+
+      case DebuggerEvent::kExceptionThrown:
+        return ServiceEvent::kPauseException;
+
+      default:
+        UNREACHABLE();
+        return ServiceEvent::kIllegal;
+    }
+}
+
+ServiceEvent::ServiceEvent(const DebuggerEvent* debugger_event)
+    : isolate_(debugger_event->isolate()),
+      type_(TranslateEventType(debugger_event->type())),
+      breakpoint_(NULL),
+      top_frame_(NULL),
+      exception_(NULL) {
+  DebuggerEvent::EventType type = debugger_event->type();
+  if (type == DebuggerEvent::kBreakpointReached) {
+    set_breakpoint(debugger_event->breakpoint());
+  }
+  if (type == DebuggerEvent::kExceptionThrown) {
+    set_exception(debugger_event->exception());
+  }
+  if (type == DebuggerEvent::kBreakpointReached ||
+      type == DebuggerEvent::kIsolateInterrupted ||
+      type == DebuggerEvent::kExceptionThrown) {
+    set_top_frame(debugger_event->top_frame());
+  }
+}
+
+
+const char* ServiceEvent::EventTypeToCString(EventType type) {
+  switch (type) {
+    case kIsolateStart:
+      return "IsolateStart";
+    case kIsolateExit:
+      return "IsolateExit";
+    case kPauseStart:
+      return "PauseStart";
+    case kPauseExit:
+      return "PauseExit";
+    case kPauseBreakpoint:
+      return "PauseBreakpoint";
+    case kPauseInterrupted:
+      return "PauseInterrupted";
+    case kPauseException:
+      return "PauseException";
+    case kResume:
+      return "Resume";
+    case kBreakpointAdded:
+      return "BreakpointAdded";
+    case kBreakpointResolved:
+      return "BreakpointResolved";
+    case kBreakpointRemoved:
+      return "BreakpointRemoved";
+    default:
+      UNREACHABLE();
+      return "Unknown";
+  }
+}
+
+
+void ServiceEvent::PrintJSON(JSONStream* js) const {
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "ServiceEvent");
+  jsobj.AddProperty("eventType", EventTypeToCString(type()));
+  jsobj.AddProperty("isolate", isolate());
+  if (breakpoint() != NULL) {
+    jsobj.AddProperty("breakpoint", breakpoint());
+  }
+  if (top_frame() != NULL) {
+    JSONObject jsFrame(&jsobj, "topFrame");
+    top_frame()->PrintToJSONObject(&jsFrame);
+  }
+  if (exception() != NULL) {
+    jsobj.AddProperty("exception", *(exception()));
+  }
+}
+
+}  // namespace dart
diff --git a/dart/runtime/vm/service_event.h b/dart/runtime/vm/service_event.h
new file mode 100644
index 0000000..b55d0a8
--- /dev/null
+++ b/dart/runtime/vm/service_event.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef VM_SERVICE_EVENT_H_
+#define VM_SERVICE_EVENT_H_
+
+#include "vm/debugger.h"
+
+class DebuggerEvent;
+
+namespace dart {
+
+class ServiceEvent {
+ public:
+  enum EventType {
+    kIsolateStart,       // New isolate has started
+    kIsolateExit,        // Isolate has exited
+
+    kPauseStart,         // --pause-isolates-on-start
+    kPauseExit,          // --pause-isolates-on-exit
+    kPauseBreakpoint,
+    kPauseInterrupted,
+    kPauseException,
+    kResume,
+
+    kBreakpointAdded,
+    kBreakpointResolved,
+    kBreakpointRemoved,
+
+    kIllegal,
+  };
+
+  ServiceEvent(Isolate* isolate, EventType event_type)
+      : isolate_(isolate),
+        type_(event_type),
+        breakpoint_(NULL),
+        top_frame_(NULL),
+        exception_(NULL) {}
+
+  explicit ServiceEvent(const DebuggerEvent* debugger_event);
+
+  Isolate* isolate() const { return isolate_; }
+
+  EventType type() const { return type_; }
+
+  SourceBreakpoint* breakpoint() const {
+    return breakpoint_;
+  }
+  void set_breakpoint(SourceBreakpoint* bpt) {
+    ASSERT(type() == kPauseBreakpoint ||
+           type() == kBreakpointAdded ||
+           type() == kBreakpointResolved ||
+           type() == kBreakpointRemoved);
+    breakpoint_ = bpt;
+  }
+
+  ActivationFrame* top_frame() const {
+    return top_frame_;
+  }
+  void set_top_frame(ActivationFrame* frame) {
+    ASSERT(type() == kPauseBreakpoint ||
+           type() == kPauseInterrupted ||
+           type() == kPauseException ||
+           type() == kResume);
+    top_frame_ = frame;
+  }
+
+  const Object* exception() const {
+    return exception_;
+  }
+  void set_exception(const Object* exception) {
+    ASSERT(type_ == kPauseException);
+    exception_ = exception;
+  }
+
+  void PrintJSON(JSONStream* js) const;
+
+  static const char* EventTypeToCString(EventType type);
+
+ private:
+  Isolate* isolate_;
+  EventType type_;
+  SourceBreakpoint* breakpoint_;
+  ActivationFrame* top_frame_;
+  const Object* exception_;
+};
+
+}  // namespace dart
+
+#endif  // VM_SERVICE_EVENT_H_
diff --git a/dart/runtime/vm/service_isolate.cc b/dart/runtime/vm/service_isolate.cc
index fd82c5a..650b040 100644
--- a/dart/runtime/vm/service_isolate.cc
+++ b/dart/runtime/vm/service_isolate.cc
@@ -219,8 +219,10 @@
     writer.WriteMessage(message);
 
     // TODO(turnidge): Throw an exception when the return value is false?
-    PortMap::PostMessage(new Message(sp.Id(), data, writer.BytesWritten(),
-                                     Message::kOOBPriority));
+    bool result = PortMap::PostMessage(
+        new Message(sp.Id(), data, writer.BytesWritten(),
+                    Message::kOOBPriority));
+    arguments->SetReturn(Bool::Get(result));
   }
 
   static void SendRootServiceMessage(Dart_NativeArguments args) {
diff --git a/dart/runtime/vm/snapshot.cc b/dart/runtime/vm/snapshot.cc
index a3544ad..8ef91b4 100644
--- a/dart/runtime/vm/snapshot.cc
+++ b/dart/runtime/vm/snapshot.cc
@@ -243,8 +243,9 @@
 
   // First create a function object and associate it with the specified
   // 'object_id'.
-  Function& func = Function::ZoneHandle(isolate(), Function::null());
-  AddBackRef(object_id, &func, kIsDeserialized);
+  Function& func = Function::Handle(isolate(), Function::null());
+  Instance& obj = Instance::ZoneHandle(isolate(), Instance::null());
+  AddBackRef(object_id, &obj, kIsDeserialized);
 
   // Read the library/class/function information and lookup the function.
   str_ ^= ReadObjectImpl();
@@ -273,7 +274,8 @@
   ASSERT(!func.IsNull());
 
   // Return the associated implicit static closure.
-  return func.ImplicitStaticClosure();
+  obj = func.ImplicitStaticClosure();
+  return obj.raw();
 }
 
 
diff --git a/dart/runtime/vm/vm_sources.gypi b/dart/runtime/vm/vm_sources.gypi
index 5eaba92..d2dc6b5 100644
--- a/dart/runtime/vm/vm_sources.gypi
+++ b/dart/runtime/vm/vm_sources.gypi
@@ -384,6 +384,8 @@
     'scopes_test.cc',
     'service.cc',
     'service.h',
+    'service_event.cc',
+    'service_event.h',
     'service_isolate.cc',
     'service_isolate.h',
     'service_test.cc',
diff --git a/dart/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/dart/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index 89766d1..4b5a2ad 100644
--- a/dart/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/dart/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -3734,7 +3734,7 @@
   Stream get stream => controller.stream;
   bool stopRunning = false;
   bool isAdding = false;
-  bool get isPaused => controller.isPaused;
+  bool isPaused = false;
   add(event) => controller.add(event);
   addStream(Stream stream) {
     return controller.addStream(stream, cancelOnError: false);
@@ -3751,12 +3751,16 @@
           wrapped(null);
         });
       },
-      onResume: () {
+      onPause: () {
+        isPaused = true;
+      }, onResume: () {
+        isPaused = false;
         if (!isAdding) {
           asyncStarHelper(null, body, this);
         }
       }, onCancel: () {
         stopRunning = true;
+        if (isPaused) asyncStarHelper(null, body, this);
       });
   }
 }
diff --git a/dart/tests/compiler/dart2js/async_await_js_transform_test.dart b/dart/tests/compiler/dart2js/async_await_js_transform_test.dart
index be164df..a193616 100644
--- a/dart/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/dart/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -95,42 +95,40 @@
             // Function start
             __handler = 3;
           case 7:
-            // continue __outer
-          case 8:
             // while condition
-            __handler = 10;
+            __handler = 9;
             inner:
               while (true) {
                 __next = [6];
                 // goto finally
-                __goto = 11;
+                __goto = 10;
                 break __outer1;
                 break;
               }
             while (true) {
               __next = [1, 4];
               // goto finally
-              __goto = 11;
+              __goto = 10;
               break __outer1;
             }
-            __goto = 13;
+            __goto = 12;
             return thenHelper(foo(), __body, __completer);
-          case 13:
+          case 12:
             // returning from await.
             __helper = __result;
-            __next.push(12);
+            __next.push(11);
             // goto finally
-            __goto = 11;
+            __goto = 10;
             break;
-          case 10:
+          case 9:
             // uncaught
             __next = [3];
-          case 11:
+          case 10:
             // finally
             __handler = 3;
             foo();
             // goto while condition
-            __goto = 8;
+            __goto = 7;
             break;
             __returnValue = 2;
             __next = [1];
@@ -140,12 +138,12 @@
             // goto the next finally handler
             __goto = __next.pop();
             break;
-          case 12:
+          case 11:
             // after finally
             // goto while condition
-            __goto = 8;
+            __goto = 7;
             break;
-          case 9:
+          case 8:
             // after while
           case 6:
             // break __outer
@@ -923,45 +921,55 @@
             break;
           }
         case 7:
-          // continue lab
-        case 8:
           // switch
           __temp1 = y;
           if (__temp1 === 0) {
             // goto case
+            __goto = 9;
+            break;
+          }
+          if (__temp1 === 0) {
+            // goto case
             __goto = 10;
             break;
           }
-          if (__temp1 === 0) {
+          __goto = 12;
+          return thenHelper(bar(), __body, __completer);
+        case 12:
+          // returning from await.
+          if (__temp1 === __result) {
             // goto case
             __goto = 11;
             break;
           }
-          __goto = 13;
-          return thenHelper(bar(), __body, __completer);
-        case 13:
-          // returning from await.
-          if (__temp1 === __result) {
-            // goto case
-            __goto = 12;
-            break;
-          }
           if (__temp1 === x) {
             // goto case
-            __goto = 14;
+            __goto = 13;
             break;
           }
           // goto default
-          __goto = 15;
+          __goto = 14;
           break;
-        case 10:
+        case 9:
           // case
           foo();
+        case 10:
+          // case
+          __temp1 = print;
+          __goto = 15;
+          return thenHelper(foo1(x), __body, __completer);
+        case 15:
+          // returning from await.
+          __temp1(__result);
+          __returnValue = y;
+          // goto return
+          __goto = 1;
+          break;
         case 11:
           // case
           __temp1 = print;
           __goto = 16;
-          return thenHelper(foo1(x), __body, __completer);
+          return thenHelper(foobar(x), __body, __completer);
         case 16:
           // returning from await.
           __temp1(__result);
@@ -969,19 +977,7 @@
           // goto return
           __goto = 1;
           break;
-        case 12:
-          // case
-          __temp1 = print;
-          __goto = 17;
-          return thenHelper(foobar(x), __body, __completer);
-        case 17:
-          // returning from await.
-          __temp1(__result);
-          __returnValue = y;
-          // goto return
-          __goto = 1;
-          break;
-        case 14:
+        case 13:
           // case
           if (a)
             throw new Error();
@@ -990,12 +986,12 @@
             __goto = 3;
             break;
           }
-        case 15:
+        case 14:
           // default
           // goto break lab
           __goto = 6;
           break;
-        case 9:
+        case 8:
           // after switch
           foo();
         case 6:
diff --git a/dart/tests/isolate/issue_22778_test.dart b/dart/tests/isolate/issue_22778_test.dart
new file mode 100644
index 0000000..d9e3973
--- /dev/null
+++ b/dart/tests/isolate/issue_22778_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:isolate";
+import "package:expect/expect.dart";
+
+func(){}
+
+main() {
+  var r = new RawReceivePort();
+  r.handler = (v) {
+    Expect.isTrue(v[0] == v[1]);
+    r.close();
+  };
+  r.sendPort.send([func, func]);
+}
diff --git a/dart/tests/language/async_and_or_test.dart b/dart/tests/language/async_and_or_test.dart
index 78a3758..15955f0 100644
--- a/dart/tests/language/async_and_or_test.dart
+++ b/dart/tests/language/async_and_or_test.dart
@@ -4,8 +4,8 @@
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
 
-@NoInline
-@AssumeDynamic
+@NoInline()
+@AssumeDynamic()
 confuse(x) {
   return x;
 }
diff --git a/dart/tests/language/async_continue_label_test.dart b/dart/tests/language/async_continue_label_test.dart
new file mode 100644
index 0000000..d2d7cc8
--- /dev/null
+++ b/dart/tests/language/async_continue_label_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+// Two loop variables
+test1() async {
+  var r = 0;
+  label:
+  for(var i = 1, j =
+      await /// await_in_init: ok
+                     10; i < 10 && j > 
+      await /// await_in_condition: ok
+                                       -5; j--, i +=
+      await /// await_in_update: ok
+                                                     1) {
+    if (i < 
+        await /// await_in_body: ok
+            5 || j < -5) {
+      continue label;
+    }
+    r++;
+  }
+  Expect.equals(5, r);
+}
+
+// One loop variable
+test2() async {
+  var r = 0;
+  label:
+  for(var i = 
+     await /// await_in_init: ok
+              0; i < 
+     await /// await_in_condition: ok
+                     10; i +=
+     await /// await_in_update: ok
+                              1) {
+    if (i <
+        await /// await_in_body: ok
+            5) {
+      continue label;
+    }
+    r++;
+  }
+  Expect.equals(5, r);
+}
+
+// Variable not declared in initializer;
+test3() async {
+  var r = 0, i, j;
+  label:
+  for(i =
+      await /// await_in_init: ok
+           0; i < 
+      await /// await_in_condition: ok
+                   10; i +=
+      await /// await_in_update: ok
+                            1) {
+    if (i < 
+        await /// await_in_body: ok
+            5) {
+      continue label;
+    }
+    r++;
+  }
+  Expect.equals(5, r);
+}
+
+// Nested loop
+test4() async {
+  var r = 0;
+  label:
+  for(var i = 
+      await /// await_in_init: ok
+              0; i <
+      await /// await_in_condition: ok
+                      10; i+=
+      await /// await_in_update: ok
+                              1) {
+    if (i <
+        await /// await_in_body: ok
+            5) {
+      for (int i = 0; i < 10; i++) {
+        continue label;
+      } 
+    }
+    r++;
+  }
+  Expect.equals(5, r);
+}
+
+test() async {
+  await test1();
+  await test2();
+  await test3();
+  await test4();
+}
+
+main() {
+  asyncStart();
+  test().then((_) => asyncEnd());
+}
diff --git a/dart/tests/language/issue22800_test.dart b/dart/tests/language/issue22800_test.dart
new file mode 100644
index 0000000..035aa31
--- /dev/null
+++ b/dart/tests/language/issue22800_test.dart
@@ -0,0 +1,20 @@
+// 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.
+
+// Check proper exception handler finalization, even for unreachable handlers.
+
+void main() {
+  try {
+    print("Starting here");
+    throw 0;
+    try {
+    } catch (e) {
+    }
+  } catch (e) {
+    print("Caught in here: $e");
+  }
+  try {
+  } catch (e) {
+  }
+}
diff --git a/dart/tests/language/issue_22780_test.dart b/dart/tests/language/issue_22780_test.dart
new file mode 100644
index 0000000..6e54dcf
--- /dev/null
+++ b/dart/tests/language/issue_22780_test.dart
@@ -0,0 +1,7 @@
+// 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.
+
+main() {
+  f() => "Oh, the joy of ${f()}"; print(f()); /// 01: runtime error
+}
diff --git a/dart/tests/language/language.status b/dart/tests/language/language.status
index 194f526..a4b2459 100644
--- a/dart/tests/language/language.status
+++ b/dart/tests/language/language.status
@@ -45,7 +45,6 @@
 async_throw_in_catch_test: Crash, RuntimeError # Issue 21404 or it could be a test error
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
-async_throw_in_catch_test: Timeout, Fail # Issue 21404 or it could be a test error
 
 [ $compiler == none && $runtime == vm ]
 class_keyword_test/02: MissingCompileTimeError # Issue 13627
diff --git a/dart/tests/language/language_dart2js.status b/dart/tests/language/language_dart2js.status
index 122beb3..5ccdf36 100644
--- a/dart/tests/language/language_dart2js.status
+++ b/dart/tests/language/language_dart2js.status
@@ -7,6 +7,9 @@
 sync_generator2_test/08: MissingCompileTimeError # Issue 22324
 sync_generator2_test/10: MissingCompileTimeError # Issue 22324
 
+async_star_test/02: RuntimeError # 22853
+async_star_test/05: RuntimeError, Timeout
+
 [ $compiler == dart2js && $runtime == jsshell ]
 await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
 
diff --git a/dart/tests/language/regress_22777_test.dart b/dart/tests/language/regress_22777_test.dart
new file mode 100644
index 0000000..74f0849
--- /dev/null
+++ b/dart/tests/language/regress_22777_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+var a = 0;
+
+testSync () {
+  do {
+    continue;
+  } while (throw "Error");
+  a = 100;
+}
+
+testAsync() async {
+  do {
+    continue;
+  } while (await (throw "Error"));
+  a = 100;
+}
+
+test() async {
+  try {
+    testSync();
+  } catch (e) {
+    Expect.equals(e, "Error");
+  }
+  Expect.equals(a, 0);
+
+  try {
+    await testAsync();
+  } catch (e) {
+    Expect.equals(e, "Error");
+  }
+  Expect.equals(a, 0);
+}
+
+main() {
+  asyncStart();
+  test().then((_) => asyncEnd());
+}
\ No newline at end of file
diff --git a/dart/tests/language/regress_22822_test.dart b/dart/tests/language/regress_22822_test.dart
new file mode 100644
index 0000000..ad990c7
--- /dev/null
+++ b/dart/tests/language/regress_22822_test.dart
@@ -0,0 +1,27 @@
+// 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.
+
+// Regression test for issue 22822. The assignment in the finally block
+// used to crash because it was executed at context level 1 instead of
+// context level 2.
+
+import 'package:expect/expect.dart';
+
+test(b) {
+  try {
+    for (int i = 0; i < 10; i++) {
+      // Closurizing i and b, thus the return statement
+      // executes at context level 2, and the code in
+      // the finally block runs at context level 1.
+      return () => i + b;
+    }
+  } finally {
+    b = 10;
+  }
+}
+
+main() {
+  var c = test(0);
+  Expect.equals(10, c());
+}
diff --git a/dart/tools/VERSION b/dart/tools/VERSION
index f71127e..db3bd8d 100644
--- a/dart/tools/VERSION
+++ b/dart/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 9
 PATCH 0
 PRERELEASE 10
-PRERELEASE_PATCH 7
+PRERELEASE_PATCH 8