Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1405)

Unified Diff: pkg/dartino_compiler/lib/src/debug_service_protocol.dart

Issue 1987673002: Initial Implementation of the vm-service protocol (Closed) Base URL: git@github.com:dartino/sdk.git@master
Patch Set: Keep track of terminated state Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/dartino_compiler/lib/debug_state.dart ('k') | pkg/dartino_compiler/lib/src/hub/sentence_parser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/dartino_compiler/lib/src/debug_service_protocol.dart
diff --git a/pkg/dartino_compiler/lib/src/debug_service_protocol.dart b/pkg/dartino_compiler/lib/src/debug_service_protocol.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c21df67cc9e8f4c913bc81f548c29eddb31339ba
--- /dev/null
+++ b/pkg/dartino_compiler/lib/src/debug_service_protocol.dart
@@ -0,0 +1,881 @@
+// Copyright (c) 2016, the Dartino 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.md file.
+
+/// An implementation of the vm service-protocol in terms of a DartinoVmContext.
+/// Processes are mapped to isolates.
+// TODO(sigurdm): Handle processes better.
+// TODO(sigurdm): Find a way to represent fibers.
+// TODO(sigurdm): Represent remote values.
+// TODO(sigurdm): Use https://pub.dartlang.org/packages/json_rpc_2 for serving.
+
+import "dart:async" show Future;
+
+import 'dart:convert' show JSON;
+
+import 'dart:io' show File, HttpServer, WebSocket, WebSocketTransformer;
+
+import 'hub/session_manager.dart' show SessionState;
+
+import 'guess_configuration.dart' show dartinoVersion;
+
+import '../debug_state.dart'
+ show BackTrace, BackTraceFrame, Breakpoint, RemoteObject;
+
+import '../vm_context.dart' show DartinoVmContext, DebugListener;
+
+import '../dartino_system.dart'
+ show DartinoFunction, DartinoFunctionKind, DartinoSystem;
+
+import 'debug_info.dart' show DebugInfo, ScopeInfo, SourceLocation;
+
+import 'dartino_compiler_implementation.dart'
+ show DartinoCompilerImplementation;
+
+import 'codegen_visitor.dart' show LocalValue;
+
+import '../program_info.dart' show Configuration;
+
+import 'package:collection/collection.dart' show binarySearch;
+
+import 'package:compiler/src/scanner/scanner.dart' show Scanner;
+import 'package:compiler/src/tokens/token.dart' show Token;
+import 'package:compiler/src/io/source_file.dart' show SourceFile;
+import 'package:compiler/src/elements/visitor.dart' show BaseElementVisitor;
+import 'package:compiler/src/elements/elements.dart'
+ show
+ CompilationUnitElement,
+ Element,
+ FunctionElement,
+ LibraryElement,
+ MemberElement,
+ ScopeContainerElement;
+
+const bool logging = const bool.fromEnvironment("dartino-log-debug-server");
+
+//TODO(danrubel): Verify const map values
+const Map<String, dynamic> dartCoreLibRefDesc = const <String, dynamic>{
+ "type": "@Library",
+ "id": "libraries/dart:core",
+ "fixedId": true,
+ "name": "dart:core",
+ "uri": "dart:core",
+};
+
+//TODO(danrubel): Verify correct id
+const String nullId = "objects/Null";
+
+//TODO(danrubel): Verify const map values
+const Map<String, dynamic> nullClassRefDesc = const <String, dynamic>{
+ "type": "@Class",
+ "id": "classes/NullClass",
+ "name": "NullClass",
+};
+
+//TODO(danrubel): Verify const map values
+const Map<String, dynamic> nullRefDesc = const <String, dynamic>{
+ "type": "@Null",
+ "id": nullId,
+ "kind": "Null",
+ "class": nullClassRefDesc,
+ "valueAsString": "null",
+};
+
+//TODO(danrubel): Verify const map values
+const Map<String, dynamic> nullDesc = const <String, dynamic>{
+ "type": "Null",
+ "id": nullId,
+ "kind": "Null",
+ "class": nullClassRefDesc,
+ "valueAsString": "null",
+};
+
+class DebugServer {
+ Future<int> serveSingleShot(SessionState state,
+ {int port: 0, Uri snapshotLocation}) async {
+ HttpServer server = await HttpServer.bind("127.0.0.1", port);
+ // The Atom Dartino plugin waits for "localhost:<port-number>"
+ // to determine the observatory port for debugging.
+ print("localhost:${server.port}");
+ WebSocket socket = await server.transform(new WebSocketTransformer()).first;
+ await new DebugConnection(state, socket, snapshotLocation: snapshotLocation)
+ .serve();
+ await state.vmContext.terminate();
+ await server.close();
+ return 0;
+ }
+}
+
+class DebugConnection implements DebugListener {
+ final Map<String, bool> streams = new Map<String, bool>();
+
+ DartinoVmContext get vmContext => state.vmContext;
+ final SessionState state;
+ final WebSocket socket;
+ final Uri snapshotLocation;
+
+ final Map<Uri, List<int>> tokenTables = new Map<Uri, List<int>>();
+
+ Map lastPauseEvent;
+
+ DebugConnection(this.state, this.socket, {this.snapshotLocation});
+
+ List<int> makeTokenTable(CompilationUnitElement compilationUnit) {
+ // TODO(sigurdm): Are these cached somewhere?
+ Token t = new Scanner(compilationUnit.script.file).tokenize();
+ List<int> result = new List<int>();
+ while (t.next != t) {
+ result.add(t.charOffset);
+ t = t.next;
+ }
+ return result;
+ }
+
+ void send(Map message) {
+ if (logging) {
+ print("Sending ${JSON.encode(message)}");
+ }
+ socket.add(JSON.encode(message));
+ }
+
+ void setStream(String streamId, bool value) {
+ streams[streamId] = value;
+ }
+
+ Map<String, CompilationUnitElement> scripts =
+ new Map<String, CompilationUnitElement>();
+
+ Map frameDesc(BackTraceFrame frame, int index) {
+ List<Map> vars = new List<Map>();
+ for (ScopeInfo current = frame.scopeInfo();
+ current != ScopeInfo.sentinel;
+ current = current.previous) {
+ vars.add({
+ "type": "BoundVariable",
+ "name": current.name,
+ "value": valueDesc(current.lookup(current.name))
+ });
+ }
+ return {
+ "type": "Frame",
+ "index": index,
+ "function": functionRef(frame.function),
+ "code": {
+ "id": "code-id", //TODO(danrubel): what is the unique id here?
+ "type": "@Code",
+ "name": "code-name", // TODO(sigurdm): How to create a name here?
+ "kind": "Dart",
+ },
+ "location": locationDesc(frame.sourceLocation(), false),
+ "vars": vars,
+ };
+ }
+
+ Map locationDesc(SourceLocation location, bool includeEndToken) {
+ // TODO(sigurdm): Investigate when this happens.
+ if (location == null || location.file == null)
+ return {
+ "type": "SourceLocation",
+ "script": scriptRef(Uri.parse('file:///unknown')),
+ "tokenPos": 0,
+ };
+ Uri uri = location.file.uri;
+ // TODO(sigurdm): Avoid this. The uri should be the same as we get from
+ // `CompilationUnit.script.file.uri`.
+ uri = new File(new File.fromUri(uri).resolveSymbolicLinksSync()).uri;
+
+ int tokenPos =
+ binarySearch(tokenTables[location.file.uri], location.span.begin);
+
+ Map result = {
+ "type": "SourceLocation",
+ "script": scriptRef(location.file.uri),
+ "tokenPos": tokenPos,
+ };
+ if (includeEndToken) {
+ int endTokenPos =
+ binarySearch(tokenTables[location.file.uri], location.span.end);
+ result["endTokenPos"] = endTokenPos;
+ }
+
+ return result;
+ }
+
+ Map isolateRef(int isolateId) {
+ return {
+ "name": "Isolate $isolateId",
+ "id": "isolates/$isolateId",
+ "fixedId": true,
+ "type": "@Isolate",
+ "number": "$isolateId"
+ };
+ }
+
+ Map libraryRef(LibraryElement library) {
+ return {
+ "type": "@Library",
+ "id": "libraries/${library.canonicalUri}",
+ "fixedId": true,
+ "name": "${library.canonicalUri}",
+ "uri": "${library.canonicalUri}",
+ };
+ }
+
+ Map libraryDesc(LibraryElement library) {
+ return {
+ "type": "Library",
+ "id": "libraries/${library.canonicalUri}",
+ "fixedId": true,
+ "name": "${library.canonicalUri}",
+ "uri": "${library.canonicalUri}",
+ // TODO(danrubel): determine proper values for the next entry
+ "debuggable": true,
+ // TODO(sigurdm): The following fields are not used by the atom-debugger.
+ // We might want to include them to get full compatibility with the
+ // observatory.
+ "dependencies": [],
+ "classes": [],
+ "variables": [],
+ "functions": [],
+ "scripts": library.compilationUnits
+ .map((CompilationUnitElement compilationUnit) =>
+ scriptRef(compilationUnit.script.resourceUri))
+ .toList()
+ };
+ }
+
+ Map breakpointDesc(Breakpoint breakpoint) {
+ DebugInfo debugInfo =
+ state.vmContext.debugState.getDebugInfo(breakpoint.function);
+ SourceLocation location = debugInfo.locationFor(breakpoint.bytecodeIndex);
+ return {
+ "type": "Breakpoint",
+ "breakpointNumber": breakpoint.id,
+ "id": "breakpoints/${breakpoint.id}",
+ "fixedId": true,
+ "resolved": true,
+ "location": locationDesc(location, false),
+ };
+ }
+
+ Map scriptRef(Uri uri) {
+ return {
+ "type": "@Script",
+ "id": "scripts/${uri}",
+ "fixedId": true,
+ "uri": "${uri}",
+ "_kind": "script"
+ };
+ }
+
+ Map scriptDesc(CompilationUnitElement compilationUnit) {
+ String text = compilationUnit.script.text;
+ SourceFile file = compilationUnit.script.file;
+ List<List<int>> tokenPosTable = [];
+ List<int> tokenTable = tokenTables[compilationUnit.script.resourceUri];
+ int currentLine = -1;
+ for (int i = 0; i < tokenTable.length; i++) {
+ int line = file.getLine(tokenTable[i]);
+ int column = file.getColumn(line, tokenTable[i]);
+ if (line != currentLine) {
+ currentLine = line;
+ // The debugger lines starts from 1.
+ tokenPosTable.add([currentLine + 1]);
+ }
+ tokenPosTable.last.add(i);
+ tokenPosTable.last.add(column);
+ }
+ return {
+ "type": "Script",
+ "id": "scripts/${compilationUnit.script.resourceUri}",
+ "fixedId": true,
+ "uri": "${compilationUnit.script.resourceUri}",
+ "library": libraryRef(compilationUnit.library),
+ "source": text,
+ "tokenPosTable": tokenPosTable,
+ "lineOffset": 0, // TODO(sigurdm): What is this?
+ "columnOffset": 0, // TODO(sigurdm): What is this?
+ };
+ }
+
+ String functionKind(DartinoFunctionKind kind) {
+ return {
+ DartinoFunctionKind.NORMAL: "RegularFunction",
+ DartinoFunctionKind.LAZY_FIELD_INITIALIZER: "Stub",
+ DartinoFunctionKind.INITIALIZER_LIST: "RegularFunction",
+ DartinoFunctionKind.PARAMETER_STUB: "Stub",
+ DartinoFunctionKind.ACCESSOR: "GetterFunction"
+ }[kind];
+ }
+
+ Map functionRef(DartinoFunction function) {
+ String name = function.name;
+ //TODO(danrubel): Investigate why this happens.
+ if (name == null || name.isEmpty) name = 'unknown';
+ return {
+ "type": "@Function",
+ "id": "functions/${function.functionId}",
+ "fixedId": true,
+ "name": "${name}",
+ // TODO(sigurdm): All kinds of owner.
+ "owner": libraryRef(function?.element?.library ?? state.compiler.mainApp),
+ "static": function.element?.isStatic ?? false,
+ "const": function.element?.isConst ?? false,
+ "_kind": functionKind(function.kind),
+ };
+ }
+
+ Map functionDesc(DartinoFunction function) {
+ FunctionElement element = function.element;
+ return {
+ "type": "Function",
+ "id": "functions/${function.functionId}",
+ // TODO(sigurdm): All kinds of owner.
+ "owner": libraryRef(element.library),
+ "static": element.isStatic,
+ "const": element.isConst,
+ "_kind": functionKind(function.kind),
+ };
+ }
+
+ Map valueDesc(LocalValue lookup) {
+ //TODO(danrubel): Translate local value into description?
+ // Need to return an @InstanceRef or Sentinel
+ return nullRefDesc;
+ }
+
+ initialize(DartinoCompilerImplementation compiler) {
+ for (LibraryElement library in compiler.libraryLoader.libraries) {
+ cacheScripts(LibraryElement library) {
+ for (CompilationUnitElement compilationUnit
+ in library.compilationUnits) {
+ Uri uri = compilationUnit.script.file.uri;
+ scripts["scripts/$uri"] = compilationUnit;
+ tokenTables[uri] = makeTokenTable(compilationUnit);
+ }
+ }
+ cacheScripts(library);
+ if (library.isPatched) {
+ cacheScripts(library.patch);
+ }
+ }
+ }
+
+ serve() async {
+ vmContext.listeners.add(this);
+
+ await vmContext.initialize(state, snapshotLocation: snapshotLocation);
+
+ initialize(state.compiler.compiler);
+
+ await for (var message in socket) {
+ if (message is! String) throw "Expected String";
+ var decodedMessage = JSON.decode(message);
+ if (logging) {
+ print("Received $decodedMessage");
+ }
+
+ if (decodedMessage is! Map) throw "Expected Map";
+ var id = decodedMessage['id'];
+ void sendResult(Map result) {
+ Map message = {"jsonrpc": "2.0", "result": result, "id": id};
+ send(message);
+ }
+ void sendError(Map error) {
+ Map message = {"jsonrpc": "2.0", "error": error, "id": id};
+ send(message);
+ }
+ switch (decodedMessage["method"]) {
+ case "streamListen":
+ setStream(decodedMessage["params"]["streamId"], true);
+ sendResult({"type": "Success"});
+ break;
+ case "streamCancel":
+ setStream(decodedMessage["streamId"], false);
+ sendResult({"type": "Success"});
+ break;
+ case "getVersion":
+ sendResult({"type": "Version", "major": 3, "minor": 4});
+ break;
+ case "getVM":
+ List<int> isolates = await state.vmContext.processes();
+ sendResult({
+ "type": "VM",
+ "name": "dartino-vm",
+ "architectureBits": {
+ Configuration.Offset64BitsDouble: 64,
+ Configuration.Offset64BitsFloat: 64,
+ Configuration.Offset32BitsDouble: 32,
+ Configuration.Offset32BitsFloat: 32,
+ }[vmContext.configuration],
+ // TODO(sigurdm): Can we give a better description?
+ "targetCPU": "${vmContext.configuration}",
+ // TODO(sigurdm): Can we give a better description?
+ "hostCPU": "${vmContext.configuration}",
+ "version": "$dartinoVersion",
+ // TODO(sigurdm): Can we say something meaningful?
+ "pid": 0,
+ // TODO(sigurdm): Implement a startTime for devices with a clock.
+ "startTime": 0,
+ "isolates": isolates.map(isolateRef).toList()
+ });
+ break;
+ case "getIsolate":
+ String isolateIdString = decodedMessage["params"]["isolateId"];
+ int isolateId = int.parse(
+ isolateIdString.substring(isolateIdString.indexOf("/") + 1));
+
+ sendResult({
+ "type": "Isolate",
+ "runnable": true,
+ "livePorts": 0,
+ "startTime": 0,
+ "name": "Isolate $isolateId",
+ "number": "$isolateId",
+ // TODO(sigurdm): This seems to be required by the observatory.
+ "_originNumber": "$isolateId",
+ "breakpoints":
+ state.vmContext.breakpoints().map(breakpointDesc).toList(),
+ "rootLib": libraryRef(state.compiler.compiler.mainApp),
+ "id": "$isolateIdString",
+ "libraries": state.compiler.compiler.libraryLoader.libraries
+ .map(libraryRef)
+ .toList(),
+ "pauseEvent": lastPauseEvent,
+ // TODO(danrubel): determine proper values for these 2 entries
+ "pauseOnExit": false,
+ "exceptionPauseMode": "Unhandled",
+ // Needed by observatory.
+ "_debuggerSettings": {"_exceptions": "unhandled"},
+ });
+ break;
+ case "addBreakpoint":
+ String scriptId = decodedMessage["params"]["scriptId"];
+ Uri uri = scripts[scriptId].script.resourceUri;
+ int line = decodedMessage["params"]["line"];
+ int column = decodedMessage["params"]["column"] ?? 1;
+ // TODO(sigurdm): Use the isolateId.
+ Breakpoint breakpoint =
+ await state.vmContext.setFileBreakpoint(uri, line, column);
+ if (breakpoint != null) {
+ sendResult({
+ "type": "Breakpoint",
+ "id": "breakpoints/${breakpoint.id}",
+ "breakpointNumber": breakpoint.id,
+ "resolved": true,
+ "location": locationDesc(
+ breakpoint.location(vmContext.debugState), false),
+ });
+ } else {
+ sendError({"code": 102, "message": "Cannot add breakpoint"});
+ }
+ break;
+ case "removeBreakpoint":
+ String breakpointId = decodedMessage["params"]["breakpointId"];
+ int id =
+ int.parse(breakpointId.substring(breakpointId.indexOf("/") + 1));
+ if (vmContext.isRunning || vmContext.isTerminated) {
+ sendError({"code": 106, "message": "Isolate must be paused"});
+ break;
+ }
+ Breakpoint breakpoint = await vmContext.deleteBreakpoint(id);
+ if (breakpoint == null) {
+ // TODO(sigurdm): Is this the right message?
+ sendError({"code": 102, "message": "Cannot remove breakpoint"});
+ } else {
+ sendResult({"type": "Success"});
+ }
+ break;
+ case "getObject":
+ // TODO(sigurdm): should not be ignoring the isolate id.
+ String id = decodedMessage["params"]["objectId"];
+ int slashIndex = id.indexOf('/');
+ switch (id.substring(0, slashIndex)) {
+ case "libraries":
+ String uri = id.substring(slashIndex + 1);
+ sendResult(libraryDesc(state.compiler.compiler.libraryLoader
+ .lookupLibrary(Uri.parse(uri))));
+ break;
+ case "scripts":
+ sendResult(scriptDesc(scripts[id]));
+ break;
+ case "functions":
+ sendResult(functionDesc(vmContext.dartinoSystem.functionsById[
+ int.parse(id.substring(slashIndex + 1))]));
+ break;
+ case "objects":
+ if (id == nullId) {
+ sendResult(nullDesc);
+ } else {
+ //TODO(danrubel): Need to return an Instance description
+ // or Sentinel for the given @InstanceRef
+ throw 'Unknown object: $id';
+ }
+ break;
+ default:
+ throw "Unsupported object type $id";
+ }
+ break;
+ case "getStack":
+ String isolateIdString = decodedMessage["params"]["isolateId"];
+ int isolateId = int.parse(
+ isolateIdString.substring(isolateIdString.indexOf("/") + 1));
+ BackTrace backTrace =
+ await state.vmContext.backTrace(processId: isolateId);
+ List frames = [];
+ int index = 0;
+ for (BackTraceFrame frame in backTrace.frames) {
+ frames.add(frameDesc(frame, index));
+ index++;
+ }
+
+ sendResult({"type": "Stack", "frames": frames, "messages": [],});
+ break;
+ case "getSourceReport":
+ String scriptId = decodedMessage["params"]["scriptId"];
+ CompilationUnitElement compilationUnit = scripts[scriptId];
+ Uri scriptUri = compilationUnit.script.file.uri;
+ List<int> tokenTable = tokenTables[scriptUri];
+
+ // We do not support coverage.
+ assert(decodedMessage["params"]["reports"]
+ .contains("PossibleBreakpoints"));
+ int tokenPos = decodedMessage["params"]["tokenPos"] ?? 0;
+ int endTokenPos =
+ decodedMessage["params"]["endTokenPos"] ?? tokenTable.length - 1;
+ int startPos = tokenTable[tokenPos];
+ int endPos = tokenTable[endTokenPos];
+ List<int> possibleBreakpoints = new List<int>();
+ DartinoSystem system = state.compilationResults.last.system;
+ for (FunctionElement function
+ in FunctionsFinder.findNestedFunctions(compilationUnit)) {
+ DartinoFunction dartinoFunction =
+ system.functionsByElement[function];
+ if (dartinoFunction == null) break;
+ DebugInfo info = state.compiler
+ .createDebugInfo(system.functionsByElement[function], system);
+ if (info == null) break;
+ for (SourceLocation location in info.locations) {
+ // TODO(sigurdm): Investigate these.
+ if (location == null || location.span == null) continue;
+ int position = location.span.begin;
+ if (!(position >= startPos && position <= endPos)) continue;
+ possibleBreakpoints.add(binarySearch(tokenTable, position));
+ }
+ }
+ Map range = {
+ "scriptIndex": 0,
+ "compiled": true,
+ "startPos": tokenPos,
+ "endPos": endTokenPos,
+ "possibleBreakpoints": possibleBreakpoints,
+ "callSites": [],
+ };
+ sendResult({
+ "type": "SourceReport",
+ "ranges": [range],
+ "scripts": [scriptRef(scriptUri)],
+ });
+ break;
+ case "resume":
+ // TODO(sigurdm): use isolateId.
+ String stepOption = decodedMessage["params"]["step"];
+ switch (stepOption) {
+ case "Into":
+ // TODO(sigurdm): avoid needing await here.
+ await vmContext.step();
+ sendResult({"type": "Success"});
+ break;
+ case "Over":
+ // TODO(sigurdm): avoid needing await here.
+ await vmContext.stepOver();
+ sendResult({"type": "Success"});
+ break;
+ case "Out":
+ // TODO(sigurdm): avoid needing await here.
+ await vmContext.stepOut();
+ sendResult({"type": "Success"});
+ break;
+ case "OverAsyncSuspension":
+ sendError({
+ "code": 100,
+ "message": "Feature is disabled",
+ "data": {
+ "details":
+ "Stepping over async suspensions is not implemented",
+ }
+ });
+ break;
+ default:
+ assert(stepOption == null);
+ if (vmContext.isScheduled) {
+ // TODO(sigurdm): Ensure other commands are not issued during
+ // this.
+ vmContext.cont();
+ } else {
+ vmContext.startRunning();
+ }
+ sendResult({"type": "Success"});
+ }
+ break;
+ case "setExceptionPauseMode":
+ // TODO(sigurdm): implement exception-pause-mode.
+ sendResult({"type": "Success"});
+ break;
+ case "pause":
+ await vmContext.interrupt();
+ sendResult({"type": "Success"});
+ break;
+ case "addBreakpointWithScriptUri":
+ // TODO(sigurdm): Use the isolateId.
+ String scriptUri = decodedMessage["params"]["scriptUri"];
+ int line = decodedMessage["params"]["line"] ?? 1;
+ int column = decodedMessage["params"]["column"] ?? 1;
+ if (vmContext.isRunning) {
+ sendError({"code": 102, "message": "Cannot add breakpoint"});
+ break;
+ }
+ Breakpoint breakpoint = await vmContext.setFileBreakpoint(
+ Uri.parse(scriptUri), line, column);
+ if (breakpoint == null) {
+ sendError({"code": 102, "message": "Cannot add breakpoint"});
+ } else {
+ sendResult({
+ "type": "Breakpoint",
+ "id": "breakpoints/${breakpoint.id}",
+ "breakpointNumber": breakpoint.id,
+ "resolved": true,
+ "location": locationDesc(
+ breakpoint.location(vmContext.debugState), false),
+ });
+ }
+ break;
+ default:
+ sendError({
+ "code": 100,
+ "message": "Feature is disabled",
+ "data": {
+ "details":
+ "Request type ${decodedMessage["method"]} not implemented",
+ }
+ });
+ if (logging) {
+ print("Unhandled request type: ${decodedMessage["method"]}");
+ }
+ }
+ }
+ }
+
+ void streamNotify(String streamId, Map event) {
+ if (streams[streamId] ?? false) {
+ send({
+ "method": "streamNotify",
+ "params": {"streamId": streamId, "event": event,},
+ "jsonrpc": "2.0",
+ });
+ }
+ }
+
+ @override
+ breakpointAdded(int processId, Breakpoint breakpoint) {
+ streamNotify("Debug", {
+ "type": "Event",
+ "kind": "BreakpointAdded",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ "breakpoint": breakpointDesc(breakpoint),
+ });
+ }
+
+ @override
+ breakpointRemoved(int processId, Breakpoint breakpoint) {
+ streamNotify("Debug", {
+ "type": "Event",
+ "kind": "BreakpointRemoved",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ "breakpoint": breakpointDesc(breakpoint),
+ });
+ }
+
+ @override
+ gc(int processId) {
+ // TODO(sigurdm): Implement gc notification.
+ }
+
+ @override
+ lostConnection() {
+ socket.close();
+ }
+
+ @override
+ pauseBreakpoint(
+ int processId, BackTraceFrame topFrame, Breakpoint breakpoint) {
+ //TODO(danrubel): are there any other breakpoints
+ // at which we are currently paused for a PauseBreakpoint event?
+ List<Breakpoint> pauseBreakpoints = <Breakpoint>[];
+ pauseBreakpoints.add(breakpoint);
+ Map event = {
+ "type": "Event",
+ "kind": "PauseBreakpoint",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ "topFrame": frameDesc(topFrame, 0),
+ "atAsyncSuspension": false,
+ "breakpoint": breakpointDesc(breakpoint),
+ "pauseBreakpoints":
+ new List.from(pauseBreakpoints.map((bp) => breakpointDesc(bp))),
+ };
+ lastPauseEvent = event;
+ streamNotify("Debug", event);
+ }
+
+ @override
+ pauseException(int processId, BackTraceFrame topFrame, RemoteObject thrown) {
+ Map event = {
+ "type": "Event",
+ "kind": "PauseException",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ "topFrame": frameDesc(topFrame, 0),
+ "atAsyncSuspension": false,
+ // TODO(sigurdm): pass thrown as an instance.
+ };
+ streamNotify("Debug", event);
+ }
+
+ @override
+ pauseExit(int processId, BackTraceFrame topFrame) {
+ // TODO(sigurdm): implement pauseExit
+ }
+
+ @override
+ pauseInterrupted(int processId, BackTraceFrame topFrame) {
+ Map event = {
+ "type": "Event",
+ "kind": "PauseInterrupted",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ "topFrame": frameDesc(topFrame, 0),
+ "atAsyncSuspension": false,
+ };
+ lastPauseEvent = event;
+ streamNotify("Debug", event);
+ }
+
+ @override
+ pauseStart(int processId) {
+ Map event = {
+ "type": "Event",
+ "kind": "PauseStart",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ };
+ lastPauseEvent = event;
+ streamNotify("Debug", event);
+ }
+
+ @override
+ processExit(int processId) {
+ streamNotify("Isolate", {
+ "type": "Event",
+ "kind": "IsolateExit",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ });
+ socket.close();
+ }
+
+ @override
+ processRunnable(int processId) {
+ Map event = {
+ "type": "Event",
+ "kind": "IsolateRunnable",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ };
+ streamNotify("Isolate", event);
+ }
+
+ @override
+ processStart(int processId) {
+ streamNotify("Isolate", {
+ "type": "Event",
+ "kind": "IsolateStart",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ });
+ }
+
+ @override
+ resume(int processId) {
+ Map event = {
+ "type": "Event",
+ "kind": "Resume",
+ "isolate": isolateRef(processId),
+ "timestamp": new DateTime.now().millisecondsSinceEpoch,
+ };
+ BackTraceFrame topFrame = vmContext.debugState.topFrame;
+ if (topFrame != null) {
+ event["topFrame"] = frameDesc(vmContext.debugState.topFrame, 0);
+ }
+ lastPauseEvent = event;
+ streamNotify("Debug", event);
+ }
+
+ @override
+ writeStdErr(int processId, List<int> data) {
+ Map event = {
+ "type": "Event",
+ "kind": "WriteEvent",
+ "bytes": new String.fromCharCodes(data),
+ };
+ streamNotify("Stderr", event);
+ }
+
+ @override
+ writeStdOut(int processId, List<int> data) {
+ Map event = {
+ "type": "Event",
+ "kind": "WriteEvent",
+ "bytes": new String.fromCharCodes(data),
+ };
+ streamNotify("Stdout", event);
+ }
+
+ @override
+ terminated() {}
+}
+
+class FunctionsFinder extends BaseElementVisitor {
+ final List<FunctionElement> result = new List<FunctionElement>();
+
+ FunctionsFinder();
+
+ static List<FunctionElement> findNestedFunctions(
+ CompilationUnitElement element) {
+ FunctionsFinder finder = new FunctionsFinder();
+ finder.visit(element);
+ return finder.result;
+ }
+
+ visit(Element e, [arg]) => e.accept(this, arg);
+
+ visitElement(Element e, _) {}
+
+ visitFunctionElement(FunctionElement element, _) {
+ result.add(element);
+ MemberElement memberContext = element.memberContext;
+ if (memberContext == element) {
+ memberContext.nestedClosures.forEach(visit);
+ }
+ }
+
+ visitScopeContainerElement(ScopeContainerElement e, _) {
+ e.forEachLocalMember(visit);
+ }
+
+ visitCompilationUnitElement(CompilationUnitElement e, _) {
+ e.forEachLocalMember(visit);
+ }
+}
« no previous file with comments | « pkg/dartino_compiler/lib/debug_state.dart ('k') | pkg/dartino_compiler/lib/src/hub/sentence_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698