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

Side by Side 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: Merge 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dartino project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file.
4
5 /// An implementation of the vm service-protocol in terms of a DartinoVmContext.
6 /// Processes are mapped to isolates.
7 // TODO(sigurdm): Handle processes better.
8 // TODO(sigurdm): Find a way to represent fibers.
9 // TODO(sigurdm): Represent remote values.
10
11 import "dart:async" show Future;
12
13 import 'dart:convert' show JSON;
14
15 import 'dart:io' show File, HttpServer, WebSocket, WebSocketTransformer;
16
17 import 'hub/session_manager.dart' show SessionState;
18
19 import 'guess_configuration.dart' show dartinoVersion;
20
21 import '../debug_state.dart'
22 show BackTrace, BackTraceFrame, Breakpoint, RemoteObject;
23
24 import '../vm_context.dart' show DartinoVmContext, DebugListener;
25
26 import '../dartino_system.dart'
27 show DartinoFunction, DartinoFunctionKind, DartinoSystem;
28
29 import 'debug_info.dart' show DebugInfo, ScopeInfo, SourceLocation;
30
31 import 'dartino_compiler_implementation.dart'
32 show DartinoCompilerImplementation;
33
34 import 'codegen_visitor.dart' show LocalValue;
35
36 import '../program_info.dart' show Configuration;
37
38 import 'package:compiler/src/scanner/scanner.dart' show Scanner;
39 import 'package:compiler/src/tokens/token.dart' show Token;
40 import 'package:compiler/src/io/source_file.dart' show SourceFile;
41 import 'package:compiler/src/elements/visitor.dart' show BaseElementVisitor;
42 import 'package:compiler/src/elements/elements.dart'
43 show
44 CompilationUnitElement,
45 Element,
46 FunctionElement,
47 LibraryElement,
48 MemberElement,
49 ScopeContainerElement;
50
51 // import 'package:stack_trace/stack_trace.dart';
52
53 const bool logging = const bool.fromEnvironment("dartino-log-debug-server");
54
55 //TODO(danrubel): Verify const map values
56 const Map<String, dynamic> dartCoreLibRefDesc = const <String, dynamic>{
57 "type": "@Library",
58 "id": "libraries/dart:core",
59 "fixedId": true,
60 "name": "dart:core",
61 "uri": "dart:core",
62 };
63
64 //TODO(danrubel): Verify correct id
65 const String nullId = "objects/Null";
66
67 //TODO(danrubel): Verify const map values
68 const Map<String, dynamic> nullClassRefDesc = const <String, dynamic>{
69 "type": "@Class",
70 "id": "classes/NullClass",
71 "name": "NullClass",
72 };
73
74 //TODO(danrubel): Verify const map values
75 const Map<String, dynamic> nullRefDesc = const <String, dynamic>{
76 "type": "@Null",
77 "id": nullId,
78 "kind": "Null",
79 "class": nullClassRefDesc,
80 "valueAsString": "null",
81 };
82
83 //TODO(danrubel): Verify const map values
84 const Map<String, dynamic> nullDesc = const <String, dynamic>{
85 "type": "Null",
86 "id": nullId,
87 "kind": "Null",
88 "class": nullClassRefDesc,
89 "valueAsString": "null",
90 };
91
92 class DebugServer {
93 Future<int> serveSingleShot(SessionState state,
94 {int port: 0, Uri snapshotLocation}) async {
95 HttpServer server = await HttpServer.bind("127.0.0.1", port);
96 // The Atom Dartino plugin waits for "localhost:<port-number>"
97 // to determine the observatory port for debugging.
98 print("localhost:${server.port}");
99 WebSocket socket = await server.transform(new WebSocketTransformer()).first;
100 // await Chain.capture(() async {
Søren Gjesse 2016/06/13 13:06:30 What is the cost of having this always be there?
sigurdm 2016/06/14 08:17:21 I removed it.
101 await new DebugConnection(state, socket, snapshotLocation: snapshotLocation)
102 .serve();
103 // }, onError: (final error, final Chain chain) {
104 // print("$error ${chain.terse}");
105 // });
106 await state.vmContext.terminate();
107 await server.close();
108 return 0;
109 }
110 }
111
112 class DebugConnection implements DebugListener {
113 final Map<String, bool> streams = new Map<String, bool>();
114
115 DartinoVmContext get vmContext => state.vmContext;
116 final SessionState state;
117 final WebSocket socket;
118 final Uri snapshotLocation;
119
120 final Map<Uri, List<int>> tokenTables = new Map<Uri, List<int>>();
121
122 Map lastPauseEvent;
123
124 DebugConnection(this.state, this.socket, {this.snapshotLocation});
125
126 List<int> makeTokenTable(CompilationUnitElement compilationUnit) {
127 // TODO(sigurdm): Are these cached somewhere?
128 Token t = new Scanner(compilationUnit.script.file).tokenize();
129 List<int> result = new List<int>();
130 while (t.next != t) {
131 result.add(t.charOffset);
132 t = t.next;
133 }
134 return result;
135 }
136
137 void send(Map message) {
138 if (logging) {
139 print("Sending ${JSON.encode(message)}");
140 }
141 socket.add(JSON.encode(message));
142 }
143
144 void setStream(String streamId, bool value) {
145 streams[streamId] = value;
146 }
147
148 Map<String, CompilationUnitElement> scripts =
149 new Map<String, CompilationUnitElement>();
150
151 static int binarySearch(List<int> table, int needle) {
Søren Gjesse 2016/06/13 13:06:30 Maybe use binarySearch from the collection package
sigurdm 2016/06/14 08:17:21 Good idea! Done
152 int l = 0;
153 int r = table.length - 1;
154 while (true) {
155 if (l > r) return -1;
156 int m = (l + r) ~/ 2;
157 int a = table[m];
158 if (a < needle) {
159 l = m + 1;
160 } else if (a > needle) {
161 r = m - 1;
162 } else {
163 return m;
164 }
165 }
166 }
167
168 Map frameDesc(BackTraceFrame frame, int index) {
169 List<Map> vars = new List<Map>();
170 for (ScopeInfo current = frame.scopeInfo();
171 current != ScopeInfo.sentinel;
172 current = current.previous) {
173 vars.add({
174 "type": "BoundVariable",
175 "name": current.name,
176 "value": valueDesc(current.lookup(current.name))
177 });
178 }
179 return {
180 "type": "Frame",
181 "index": index,
182 "function": functionRef(frame.function),
183 "code": {
184 "id": "code-id", //TODO(danrubel): what is the unique id here?
185 "type": "@Code",
186 "name": "code-name", // TODO(sigurdm): How to create a name here?
187 "kind": "Dart",
188 },
189 "location": locationDesc(frame.sourceLocation(), false),
190 "vars": vars,
191 };
192 }
193
194 Map locationDesc(SourceLocation location, bool includeEndToken) {
195 // TODO(sigurdm): Investigate when this happens.
196 if (location == null || location.file == null)
197 return {
198 "type": "SourceLocation",
199 "script": scriptRef(Uri.parse('file:///unknown')),
200 "tokenPos": 0,
201 };
202 Uri uri = location.file.uri;
203 // TODO(sigurdm): Avoid this. The uri should be the same as we get from
204 // `CompilationUnit.script.file.uri`.
205 uri = new File(new File.fromUri(uri).resolveSymbolicLinksSync()).uri;
206
207 int tokenPos =
208 binarySearch(tokenTables[location.file.uri], location.span.begin);
209
210 Map result = {
211 "type": "SourceLocation",
212 "script": scriptRef(location.file.uri),
213 "tokenPos": tokenPos,
214 };
215 if (includeEndToken) {
216 int endTokenPos =
217 binarySearch(tokenTables[location.file.uri], location.span.end);
218 result["endTokenPos"] = endTokenPos;
219 }
220
221 return result;
222 }
223
224 Map isolateRef(int isolateId) {
225 return {
226 "name": "Isolate $isolateId",
227 "id": "isolates/$isolateId",
228 "fixedId": true,
229 "type": "@Isolate",
230 "number": "$isolateId"
231 };
232 }
233
234 Map libraryRef(LibraryElement library) {
235 return {
236 "type": "@Library",
237 "id": "libraries/${library.canonicalUri}",
238 "fixedId": true,
239 "name": "${library.canonicalUri}",
240 "uri": "${library.canonicalUri}",
241 };
242 }
243
244 Map libraryDesc(LibraryElement library) {
245 return {
246 "type": "Library",
247 "id": "libraries/${library.canonicalUri}",
248 "fixedId": true,
249 "name": "${library.canonicalUri}",
250 "uri": "${library.canonicalUri}",
251 // TODO(danrubel): determine proper values for the next entry
252 "debuggable": true,
253 // TODO(sigurdm): The following fields are not used by the atom-debugger.
254 // We might want to include them to get full compatibility with the
255 // observatory.
256 "dependencies": [],
257 "classes": [],
258 "variables": [],
259 "functions": [],
260 "scripts": library.compilationUnits
261 .map((CompilationUnitElement compilationUnit) =>
262 scriptRef(compilationUnit.script.resourceUri))
263 .toList()
264 };
265 }
266
267 Map breakpointDesc(Breakpoint breakpoint) {
268 DebugInfo debugInfo =
269 state.vmContext.debugState.getDebugInfo(breakpoint.function);
270 SourceLocation location = debugInfo.locationFor(breakpoint.bytecodeIndex);
271 return {
272 "type": "Breakpoint",
273 "breakpointNumber": breakpoint.id,
274 "id": "breakpoints/${breakpoint.id}",
275 "fixedId": true,
276 "resolved": true,
277 "location": locationDesc(location, false),
278 };
279 }
280
281 Map scriptRef(Uri uri) {
282 return {
283 "type": "@Script",
284 "id": "scripts/${uri}",
285 "fixedId": true,
286 "uri": "${uri}",
287 "_kind": "script"
288 };
289 }
290
291 Map scriptDesc(CompilationUnitElement compilationUnit) {
292 String text = compilationUnit.script.text;
293 SourceFile file = compilationUnit.script.file;
294 List<List<int>> tokenPosTable = [];
295 List<int> tokenTable = tokenTables[compilationUnit.script.resourceUri];
296 int currentLine = -1;
297 for (int i = 0; i < tokenTable.length; i++) {
298 int line = file.getLine(tokenTable[i]);
299 int column = file.getColumn(line, tokenTable[i]);
300 if (line != currentLine) {
301 currentLine = line;
302 // The debugger lines starts from 1.
303 tokenPosTable.add([currentLine + 1]);
304 }
305 tokenPosTable.last.add(i);
306 tokenPosTable.last.add(column);
307 }
308 return {
309 "type": "Script",
310 "id": "scripts/${compilationUnit.script.resourceUri}",
311 "fixedId": true,
312 "uri": "${compilationUnit.script.resourceUri}",
313 "library": libraryRef(compilationUnit.library),
314 "source": text,
315 "tokenPosTable": tokenPosTable,
316 "lineOffset": 0, // TODO(sigurdm): What is this?
317 "columnOffset": 0, // TODO(sigurdm): What is this?
318 };
319 }
320
321 String functionKind(DartinoFunctionKind kind) {
322 return {
323 DartinoFunctionKind.NORMAL: "RegularFunction",
324 DartinoFunctionKind.LAZY_FIELD_INITIALIZER: "Stub",
325 DartinoFunctionKind.INITIALIZER_LIST: "RegularFunction",
326 DartinoFunctionKind.PARAMETER_STUB: "Stub",
327 DartinoFunctionKind.ACCESSOR: "GetterFunction"
328 }[kind];
329 }
330
331 Map functionRef(DartinoFunction function) {
332 String name = function.name;
333 //TODO(danrubel): Investigate why this happens.
334 if (name == null || name.isEmpty) name = 'unknown';
335 return {
336 "type": "@Function",
337 "id": "functions/${function.functionId}",
338 "fixedId": true,
339 "name": "${name}",
340 // TODO(sigurdm): All kinds of owner.
341 "owner": libraryRef(function?.element?.library ?? state.compiler.mainApp),
342 "static": function.element?.isStatic ?? false,
343 "const": function.element?.isConst ?? false,
344 "_kind": functionKind(function.kind),
345 };
346 }
347
348 Map functionDesc(DartinoFunction function) {
349 FunctionElement element = function.element;
350 return {
351 "type": "Function",
352 "id": "functions/${function.functionId}",
353 // TODO(sigurdm): All kinds of owner.
354 "owner": libraryRef(element.library),
355 "static": element.isStatic,
356 "const": element.isConst,
357 "_kind": functionKind(function.kind),
358 };
359 }
360
361 Map valueDesc(LocalValue lookup) {
362 //TODO(danrubel): Translate local value into description?
363 // Need to return an @InstanceRef or Sentinel
364 return nullRefDesc;
365 }
366
367 initialize(DartinoCompilerImplementation compiler) {
368 for (LibraryElement library in compiler.libraryLoader.libraries) {
369 cacheScripts(LibraryElement library) {
370 for (CompilationUnitElement compilationUnit
371 in library.compilationUnits) {
372 Uri uri = compilationUnit.script.file.uri;
373 scripts["scripts/$uri"] = compilationUnit;
374 tokenTables[uri] = makeTokenTable(compilationUnit);
375 }
376 }
377 cacheScripts(library);
378 if (library.isPatched) {
379 cacheScripts(library.patch);
380 }
381 }
382 }
383
384 serve() async {
385 vmContext.listeners.add(this);
386
387 await vmContext.initialize(state, snapshotLocation: snapshotLocation);
388
389 initialize(state.compiler.compiler);
390
391 await for (var message in socket) {
Søren Gjesse 2016/06/13 13:06:30 Have you checked if it is possible to re-use somet
sigurdm 2016/06/14 08:17:21 I added a TODO.
392 if (message is! String) throw "Expected String";
393 var decodedMessage = JSON.decode(message);
394 if (logging) {
395 print("Received $decodedMessage");
396 }
397
398 if (decodedMessage is! Map) throw "Expected Map";
399 var id = decodedMessage['id'];
400 void sendResult(Map result) {
401 Map message = {"jsonrpc": "2.0", "result": result, "id": id};
402 send(message);
403 }
404 void sendError(Map error) {
405 Map message = {"jsonrpc": "2.0", "error": error, "id": id};
406 send(message);
407 }
408 switch (decodedMessage["method"]) {
409 case "streamListen":
410 setStream(decodedMessage["params"]["streamId"], true);
411 sendResult({"type": "Success"});
412 break;
413 case "streamCancel":
414 setStream(decodedMessage["streamId"], false);
415 sendResult({"type": "Success"});
416 break;
417 case "getVersion":
418 sendResult({"type": "Version", "major": 3, "minor": 4});
419 break;
420 case "getVM":
421 List<int> isolates = await state.vmContext.processes();
422 sendResult({
423 "type": "VM",
424 "name": "dartino-vm",
425 "architectureBits": {
426 Configuration.Offset64BitsDouble: 64,
427 Configuration.Offset64BitsFloat: 64,
428 Configuration.Offset32BitsDouble: 32,
429 Configuration.Offset32BitsFloat: 32,
430 }[vmContext.configuration],
431 // TODO(sigurdm): Can we give a better description?
432 "targetCPU": "${vmContext.configuration}",
433 // TODO(sigurdm): Can we give a better description?
434 "hostCPU": "${vmContext.configuration}",
435 "version": "$dartinoVersion",
436 // TODO(sigurdm): Can we say something meaningful?
437 "pid": 0,
438 // TODO(sigurdm): Implement a startTime for devices with a clock.
439 "startTime": 0,
440 "isolates": isolates.map(isolateRef).toList()
441 });
442 break;
443 case "getIsolate":
444 String isolateIdString = decodedMessage["params"]["isolateId"];
445 int isolateId = int.parse(
446 isolateIdString.substring(isolateIdString.indexOf("/") + 1));
447
448 sendResult({
449 "type": "Isolate",
450 "runnable": true,
451 "livePorts": 0,
452 "startTime": 0,
453 "name": "Isolate $isolateId",
454 "number": "$isolateId",
455 // TODO(sigurdm): This seems to be required by the observatory.
456 "_originNumber": "$isolateId",
457 "breakpoints":
458 state.vmContext.breakpoints().map(breakpointDesc).toList(),
459 "rootLib": libraryRef(state.compiler.compiler.mainApp),
460 "id": "$isolateIdString",
461 "libraries": state.compiler.compiler.libraryLoader.libraries
462 .map(libraryRef)
463 .toList(),
464 "pauseEvent": lastPauseEvent,
465 // TODO(danrubel): determine proper values for these 2 entries
466 "pauseOnExit": false,
467 "exceptionPauseMode": "Unhandled",
468 // Needed by observatory.
469 "_debuggerSettings": {"_exceptions": "unhandled"},
470 });
471 break;
472 case "addBreakpoint":
473 String scriptId = decodedMessage["params"]["scriptId"];
474 Uri uri = scripts[scriptId].script.resourceUri;
475 int line = decodedMessage["params"]["line"];
476 int column = decodedMessage["params"]["column"] ?? 1;
477 // TODO(sigurdm): Use the isolateId.
478 Breakpoint breakpoint =
479 await state.vmContext.setFileBreakpoint(uri, line, column);
480 if (breakpoint != null) {
481 sendResult({
482 "type": "Breakpoint",
483 "id": "breakpoints/${breakpoint.id}",
484 "breakpointNumber": breakpoint.id,
485 "resolved": true,
486 "location": locationDesc(
487 breakpoint.location(vmContext.debugState), false),
488 });
489 } else {
490 sendError({"code": 102, "message": "Cannot add breakpoint"});
491 }
492 break;
493 case "removeBreakpoint":
494 String breakpointId = decodedMessage["params"]["breakpointId"];
495 int id =
496 int.parse(breakpointId.substring(breakpointId.indexOf("/") + 1));
497 if (vmContext.isRunning || vmContext.isTerminated) {
498 sendError({"code": 106, "message": "Isolate must be paused"});
499 break;
500 }
501 Breakpoint breakpoint = await vmContext.deleteBreakpoint(id);
502 if (breakpoint == null) {
503 // TODO(sigurdm): Is this the right message?
504 sendError({"code": 102, "message": "Cannot remove breakpoint"});
505 } else {
506 sendResult({"type": "Success"});
507 }
508 break;
509 case "getObject":
510 // TODO(sigurdm): should not be ignoring the isolate id.
511 String id = decodedMessage["params"]["objectId"];
512 int slashIndex = id.indexOf('/');
513 switch (id.substring(0, slashIndex)) {
514 case "libraries":
515 String uri = id.substring(slashIndex + 1);
516 sendResult(libraryDesc(state.compiler.compiler.libraryLoader
517 .lookupLibrary(Uri.parse(uri))));
518 break;
519 case "scripts":
520 sendResult(scriptDesc(scripts[id]));
521 break;
522 case "functions":
523 sendResult(functionDesc(vmContext.dartinoSystem.functionsById[
524 int.parse(id.substring(slashIndex + 1))]));
525 break;
526 case "objects":
527 if (id == nullId) {
528 sendResult(nullDesc);
529 } else {
530 //TODO(danrubel): Need to return an Instance description
531 // or Sentinel for the given @InstanceRef
532 throw 'Unknown object: $id';
533 }
534 break;
535 default:
536 throw "Unsupported object type $id";
537 }
538 break;
539 case "getStack":
540 String isolateIdString = decodedMessage["params"]["isolateId"];
541 int isolateId = int.parse(
542 isolateIdString.substring(isolateIdString.indexOf("/") + 1));
543 BackTrace backTrace =
544 await state.vmContext.backTrace(processId: isolateId);
545 List frames = [];
546 int index = 0;
547 for (BackTraceFrame frame in backTrace.frames) {
548 frames.add(frameDesc(frame, index));
549 index++;
550 }
551
552 sendResult({"type": "Stack", "frames": frames, "messages": [],});
553 break;
554 case "getSourceReport":
555 String scriptId = decodedMessage["params"]["scriptId"];
556 CompilationUnitElement compilationUnit = scripts[scriptId];
557 Uri scriptUri = compilationUnit.script.file.uri;
558 List<int> tokenTable = tokenTables[scriptUri];
559
560 // We do not support coverage.
561 assert(decodedMessage["params"]["reports"]
562 .contains("PossibleBreakpoints"));
563 int tokenPos = decodedMessage["params"]["tokenPos"] ?? 0;
564 int endTokenPos =
565 decodedMessage["params"]["endTokenPos"] ?? tokenTable.length - 1;
566 int startPos = tokenTable[tokenPos];
567 int endPos = tokenTable[endTokenPos];
568 List<int> possibleBreakpoints = new List<int>();
569 DartinoSystem system = state.compilationResults.last.system;
570 for (FunctionElement function
571 in FunctionsFinder.findNestedFunctions(compilationUnit)) {
572 DartinoFunction dartinoFunction =
573 system.functionsByElement[function];
574 if (dartinoFunction == null) break;
575 DebugInfo info = state.compiler
576 .createDebugInfo(system.functionsByElement[function], system);
577 if (info == null) break;
578 for (SourceLocation location in info.locations) {
579 // TODO(sigurdm): Investigate these.
580 if (location == null || location.span == null) continue;
581 int position = location.span.begin;
582 if (!(position >= startPos && position <= endPos)) continue;
583 possibleBreakpoints.add(binarySearch(tokenTable, position));
584 }
585 }
586 Map range = {
587 "scriptIndex": 0,
588 "compiled": true,
589 "startPos": tokenPos,
590 "endPos": endTokenPos,
591 "possibleBreakpoints": possibleBreakpoints,
592 "callSites": [],
593 };
594 sendResult({
595 "type": "SourceReport",
596 "ranges": [range],
597 "scripts": [scriptRef(scriptUri)],
598 });
599 break;
600 case "resume":
601 // TODO(sigurdm): use isolateId.
602 String stepOption = decodedMessage["params"]["step"];
603 switch (stepOption) {
604 case "Into":
605 // TODO(sigurdm): avoid needing await here.
606 await vmContext.step();
607 sendResult({"type": "Success"});
608 break;
609 case "Over":
610 // TODO(sigurdm): avoid needing await here.
611 await vmContext.stepOver();
612 sendResult({"type": "Success"});
613 break;
614 case "Out":
615 // TODO(sigurdm): avoid needing await here.
616 await vmContext.stepOut();
617 sendResult({"type": "Success"});
618 break;
619 case "OverAsyncSuspension":
620 sendError({
621 "code": 100,
622 "message": "Feature is disabled",
623 "data": {
624 "details":
625 "Stepping over async suspensions is not implemented",
626 }
627 });
628 break;
629 default:
630 assert(stepOption == null);
631 if (vmContext.isScheduled) {
632 // TODO(sigurdm): Ensure other commands are not issued during
633 // this.
634 vmContext.cont();
635 } else {
636 vmContext.startRunning();
637 }
638 sendResult({"type": "Success"});
639 }
640 break;
641 case "setExceptionPauseMode":
642 // TODO(sigurdm): implement exception-pause-mode.
643 sendResult({"type": "Success"});
644 break;
645 case "pause":
646 await vmContext.interrupt();
647 sendResult({"type": "Success"});
648 break;
649 case "addBreakpointWithScriptUri":
650 // TODO(sigurdm): Use the isolateId.
651 String scriptUri = decodedMessage["params"]["scriptUri"];
652 int line = decodedMessage["params"]["line"] ?? 1;
653 int column = decodedMessage["params"]["column"] ?? 1;
654 if (vmContext.isRunning) {
655 sendError({"code": 102, "message": "Cannot add breakpoint"});
656 break;
657 }
658 Breakpoint breakpoint = await vmContext.setFileBreakpoint(
659 Uri.parse(scriptUri), line, column);
660 if (breakpoint == null) {
661 sendError({"code": 102, "message": "Cannot add breakpoint"});
662 } else {
663 sendResult({
664 "type": "Breakpoint",
665 "id": "breakpoints/${breakpoint.id}",
666 "breakpointNumber": breakpoint.id,
667 "resolved": true,
668 "location": locationDesc(
669 breakpoint.location(vmContext.debugState), false),
670 });
671 }
672 break;
673 default:
674 sendError({
675 "code": 100,
676 "message": "Feature is disabled",
677 "data": {
678 "details":
679 "Request type ${decodedMessage["method"]} not implemented",
680 }
681 });
682 if (logging) {
683 print("Unhandled request type: ${decodedMessage["method"]}");
684 }
685 }
686 }
687 }
688
689 void streamNotify(String streamId, Map event) {
690 if (streams[streamId] ?? false) {
691 send({
692 "method": "streamNotify",
693 "params": {"streamId": streamId, "event": event,},
694 "jsonrpc": "2.0",
695 });
696 }
697 }
698
699 @override
700 breakpointAdded(int processId, Breakpoint breakpoint) {
701 streamNotify("Debug", {
702 "type": "Event",
703 "kind": "BreakpointAdded",
704 "isolate": isolateRef(processId),
705 "timestamp": new DateTime.now().millisecondsSinceEpoch,
706 "breakpoint": breakpointDesc(breakpoint),
707 });
708 }
709
710 @override
711 breakpointRemoved(int processId, Breakpoint breakpoint) {
712 streamNotify("Debug", {
713 "type": "Event",
714 "kind": "BreakpointRemoved",
715 "isolate": isolateRef(processId),
716 "timestamp": new DateTime.now().millisecondsSinceEpoch,
717 "breakpoint": breakpointDesc(breakpoint),
718 });
719 }
720
721 @override
722 gc(int processId) {
723 // TODO(sigurdm): Implement gc notification.
724 }
725
726 @override
727 lostConnection() {
728 socket.close();
729 }
730
731 @override
732 pauseBreakpoint(
733 int processId, BackTraceFrame topFrame, Breakpoint breakpoint) {
734 //TODO(danrubel): are there any other breakpoints
735 // at which we are currently paused for a PauseBreakpoint event?
736 List<Breakpoint> pauseBreakpoints = <Breakpoint>[];
737 pauseBreakpoints.add(breakpoint);
738 Map event = {
739 "type": "Event",
740 "kind": "PauseBreakpoint",
741 "isolate": isolateRef(processId),
742 "timestamp": new DateTime.now().millisecondsSinceEpoch,
743 "topFrame": frameDesc(topFrame, 0),
744 "atAsyncSuspension": false,
745 "breakpoint": breakpointDesc(breakpoint),
746 "pauseBreakpoints":
747 new List.from(pauseBreakpoints.map((bp) => breakpointDesc(bp))),
748 };
749 lastPauseEvent = event;
750 streamNotify("Debug", event);
751 }
752
753 @override
754 pauseException(int processId, BackTraceFrame topFrame, RemoteObject thrown) {
755 Map event = {
756 "type": "Event",
757 "kind": "PauseException",
758 "isolate": isolateRef(processId),
759 "timestamp": new DateTime.now().millisecondsSinceEpoch,
760 "topFrame": frameDesc(topFrame, 0),
761 "atAsyncSuspension": false,
762 // TODO(sigurdm): pass thrown as an instance.
763 };
764 streamNotify("Debug", event);
765 }
766
767 @override
768 pauseExit(int processId, BackTraceFrame topFrame) {
769 // TODO(sigurdm): implement pauseExit
770 }
771
772 @override
773 pauseInterrupted(int processId, BackTraceFrame topFrame) {
774 Map event = {
775 "type": "Event",
776 "kind": "PauseInterrupted",
777 "isolate": isolateRef(processId),
778 "timestamp": new DateTime.now().millisecondsSinceEpoch,
779 "topFrame": frameDesc(topFrame, 0),
780 "atAsyncSuspension": false,
781 };
782 lastPauseEvent = event;
783 streamNotify("Debug", event);
784 }
785
786 @override
787 pauseStart(int processId) {
788 Map event = {
789 "type": "Event",
790 "kind": "PauseStart",
791 "isolate": isolateRef(processId),
792 "timestamp": new DateTime.now().millisecondsSinceEpoch,
793 };
794 lastPauseEvent = event;
795 streamNotify("Debug", event);
796 }
797
798 @override
799 processExit(int processId) {
800 streamNotify("Isolate", {
801 "type": "Event",
802 "kind": "IsolateExit",
803 "isolate": isolateRef(processId),
804 "timestamp": new DateTime.now().millisecondsSinceEpoch,
805 });
806 socket.close();
807 }
808
809 @override
810 processRunnable(int processId) {
811 Map event = {
812 "type": "Event",
813 "kind": "IsolateRunnable",
814 "isolate": isolateRef(processId),
815 "timestamp": new DateTime.now().millisecondsSinceEpoch,
816 };
817 streamNotify("Isolate", event);
818 }
819
820 @override
821 processStart(int processId) {
822 streamNotify("Isolate", {
823 "type": "Event",
824 "kind": "IsolateStart",
825 "isolate": isolateRef(processId),
826 "timestamp": new DateTime.now().millisecondsSinceEpoch,
827 });
828 }
829
830 @override
831 resume(int processId) {
832 Map event = {
833 "type": "Event",
834 "kind": "Resume",
835 "isolate": isolateRef(processId),
836 "timestamp": new DateTime.now().millisecondsSinceEpoch,
837 };
838 BackTraceFrame topFrame = vmContext.debugState.topFrame;
839 if (topFrame != null) {
840 event["topFrame"] = frameDesc(vmContext.debugState.topFrame, 0);
841 }
842 lastPauseEvent = event;
843 streamNotify("Debug", event);
844 }
845
846 @override
847 writeStdErr(int processId, List<int> data) {
848 Map event = {
849 "type": "Event",
850 "kind": "WriteEvent",
851 "bytes": new String.fromCharCodes(data),
852 };
853 streamNotify("Stderr", event);
854 }
855
856 @override
857 writeStdOut(int processId, List<int> data) {
858 Map event = {
859 "type": "Event",
860 "kind": "WriteEvent",
861 "bytes": new String.fromCharCodes(data),
862 };
863 streamNotify("Stdout", event);
864 }
865
866 @override
867 terminated() {}
868 }
869
870 class FunctionsFinder extends BaseElementVisitor {
871 final List<FunctionElement> result = new List<FunctionElement>();
872
873 FunctionsFinder();
874
875 static List<FunctionElement> findNestedFunctions(
876 CompilationUnitElement element) {
877 FunctionsFinder finder = new FunctionsFinder();
878 finder.visit(element);
879 return finder.result;
880 }
881
882 visit(Element e, [arg]) => e.accept(this, arg);
883
884 visitElement(Element e, _) {}
885
886 visitFunctionElement(FunctionElement element, _) {
887 result.add(element);
888 MemberElement memberContext = element.memberContext;
889 if (memberContext == element) {
890 memberContext.nestedClosures.forEach(visit);
891 }
892 }
893
894 visitScopeContainerElement(ScopeContainerElement e, _) {
895 e.forEachLocalMember(visit);
896 }
897
898 visitCompilationUnitElement(CompilationUnitElement e, _) {
899 e.forEachLocalMember(visit);
900 }
901 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698