dart-sdk/sdk/lib/vmservice/running_isolates.dart
Vyacheslav Egorov b2eab8b96e [VM/Service] Restore zero-copying handling of JSON messages in vmservice.
In 5a44162c97 in attempt to adhere to declared
method signatures we lost zero-copying JSON decoding of responses from
VM: `Message.sendToVM` was changed to always decode the response into
string before passing it to the caller and the logic to use fused
JSON decoding was removed. This increased peak memory consumption by
the VM Service.

This commit addresses the issue by restoring the zero-copying JSON decoding
logic while adding a wrapper around responses that make it clear what kind
of data is passed around and how that data is encoded and handled.

We introduce a class `Response` which can contain either a Dart string, a
binary data (represented as a Uint8List) or utf8 encoded string (represented
as a Uint8List). This class is used in all places where previously a String
or dynamic were used, e.g. MessageRouter.routeRequest is changed to return
Future<Response> rather than Future<String>. This allows callees to
decode JSON responses without copying them into Dart heap while
maintaining sufficient level of typing to make the code easy to reason about.

This commit also removes some dead code from the VM service related to old
Service API and TAR assets unpacking (which has been long done in C++).

Bug: https://github.com/flutter/flutter/issues/13626
Change-Id: Ifbba56944a552034a0f802a965a313326a1236e7
Reviewed-on: https://dart-review.googlesource.com/30280
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
2017-12-18 19:06:06 +00:00

65 lines
1.9 KiB
Dart

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._vmservice;
class RunningIsolates implements MessageRouter {
final Map<int, RunningIsolate> isolates = new Map<int, RunningIsolate>();
int _rootPortId;
RunningIsolates();
void isolateStartup(int portId, SendPort sp, String name) {
if (_rootPortId == null) {
_rootPortId = portId;
}
var ri = new RunningIsolate(portId, sp, name);
isolates[portId] = ri;
}
void isolateShutdown(int portId, SendPort sp) {
if (_rootPortId == portId) {
_rootPortId = null;
}
isolates.remove(portId);
}
Future<Response> routeRequest(Message message) {
String isolateParam = message.params['isolateId'];
int isolateId;
if (!isolateParam.startsWith('isolates/')) {
message.setErrorResponse(
kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
return message.response;
}
isolateParam = isolateParam.substring('isolates/'.length);
if (isolateParam == 'root') {
isolateId = _rootPortId;
} else {
try {
isolateId = int.parse(isolateParam);
} catch (e) {
message.setErrorResponse(
kInvalidParams, "invalid 'isolateId' parameter: $isolateParam");
return message.response;
}
}
var isolate = isolates[isolateId];
if (isolate == null) {
// There is some chance that this isolate may have lived before,
// so return a sentinel rather than an error.
var result = {
'type': 'Sentinel',
'kind': 'Collected',
'valueAsString': '<collected>',
};
message.setResponse(encodeResult(message, result));
return message.response;
}
return isolate.routeRequest(message);
}
void routeResponse(Message message) {}
}