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

Side by Side Diff: pkg/fletchc/lib/vm_session.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 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
« no previous file with comments | « pkg/fletchc/lib/vm_commands.dart ('k') | pkg/fletchc/samples/fletchc_driver/target.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, 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 library fletch.vm_session;
6
7 import 'dart:core';
8 import 'dart:async';
9 import 'dart:convert';
10 import 'dart:io' hide exit;
11
12 import 'dart:typed_data' show
13 ByteData,
14 Uint8List;
15
16 import 'vm_commands.dart';
17 import 'fletch_system.dart';
18
19 import 'incremental/fletchc_incremental.dart'
20 show IncrementalCompiler;
21
22 import 'src/codegen_visitor.dart';
23 import 'src/debug_info.dart';
24
25 // TODO(ahe): Get rid of this import.
26 import 'src/fletch_backend.dart' show FletchBackend;
27
28 import 'src/fletch_selector.dart' show
29 FletchSelector,
30 SelectorKind;
31
32 import 'debug_state.dart';
33
34 import 'src/shared_command_infrastructure.dart' show
35 CommandTransformerBuilder,
36 toUint8ListView;
37
38 import 'src/hub/session_manager.dart' show
39 SessionState;
40
41 part 'vm_command_reader.dart';
42 part 'input_handler.dart';
43
44 /// Encapsulates a TCP connection to a running fletch-vm and provides a
45 /// [VmCommand] based view on top of it.
46 class FletchVmSession {
47 /// The outgoing connection to the fletch-vm.
48 final StreamSink<List<int>> _outgoingSink;
49
50 final Sink<List<int>> stdoutSink;
51 final Sink<List<int>> stderrSink;
52
53 /// The VM command reader reads data from the vm, converts the data
54 /// into a [VmCommand], and provides a stream iterator iterating over
55 /// these commands.
56 /// If the [VmCommand] is for stdout or stderr the reader automatically
57 /// forwards them to the stdout/stderr sinks and does not add them to the
58 /// iterator.
59 final VmCommandReader _commandReader;
60
61 /// Completes when the underlying TCP connection is terminated.
62 final Future _done;
63
64 bool _connectionIsDead = false;
65 bool _drainedIncomingCommands = false;
66
67 // TODO(ahe): Get rid of this. See also issue 67.
68 bool silent = false;
69
70 /// When true, messages generated by this class (or its subclasses) will not
71 /// contain IDs. Note: we only hide these IDs for debugger tests that use
72 /// golden files.
73 bool hideRawIds = false;
74
75 /// When true, don't use colors to highlight focus when printing code.
76 /// This is currently only true when running tests to avoid having to deal
77 /// with color control characters in the expected files.
78 bool colorsDisabled = false;
79
80 VmCommand connectionError = new ConnectionError("Connection is closed", null);
81
82 FletchVmSession(Socket vmSocket,
83 Sink<List<int>> stdoutSink,
84 Sink<List<int>> stderrSink)
85 : _outgoingSink = vmSocket,
86 this.stdoutSink = stdoutSink,
87 this.stderrSink = stderrSink,
88 _done = vmSocket.done,
89 _commandReader = new VmCommandReader(vmSocket, stdoutSink, stderrSink) {
90 _done.catchError((_, __) {}).then((_) {
91 _connectionIsDead = true;
92 });
93 }
94
95 void writeStdout(String s) {
96 if (!silent && stdoutSink != null) stdoutSink.add(UTF8.encode(s));
97 }
98
99 void writeStdoutLine(String s) => writeStdout("$s\n");
100
101 /// Convenience around [runCommands] for running just a single command.
102 Future<VmCommand> runCommand(VmCommand command) {
103 return runCommands([command]);
104 }
105
106 /// Sends the given commands to a fletch-vm and reads response commands
107 /// (if necessary).
108 ///
109 /// If all commands have been successfully applied and responses been awaited,
110 /// this function will complete with the last received [VmCommand] from the
111 /// remote peer (or `null` if there was none).
112 Future<VmCommand> runCommands(List<VmCommand> commands) async {
113 if (commands.any((VmCommand c) => c.numberOfResponsesExpected == null)) {
114 throw new ArgumentError(
115 'The runComands() method will read response commands and therefore '
116 'needs to know how many to read. One of the given commands does'
117 'not specify how many commands the response will have.');
118 }
119
120 VmCommand lastResponse;
121 for (VmCommand command in commands) {
122 await sendCommand(command);
123 for (int i = 0; i < command.numberOfResponsesExpected; i++) {
124 lastResponse = await readNextCommand();
125 }
126 }
127 return lastResponse;
128 }
129
130 /// Sends all given [VmCommand]s to a fletch-vm.
131 Future sendCommands(List<VmCommand> commands) async {
132 for (var command in commands) {
133 await sendCommand(command);
134 }
135 }
136
137 /// Sends a [VmCommand] to a fletch-vm.
138 Future sendCommand(VmCommand command) async {
139 if (_connectionIsDead) {
140 throw new StateError(
141 'Trying to send command ${command} to fletch-vm, but '
142 'the connection is already closed.');
143 }
144 command.addTo(_outgoingSink);
145 }
146
147 /// Will read the next [VmCommand] the fletch-vm sends to us.
148 Future<VmCommand> readNextCommand({bool force: true}) async {
149 if (_drainedIncomingCommands) {
150 return connectionError;
151 }
152
153 _drainedIncomingCommands = !await _commandReader.iterator.moveNext()
154 .catchError((error, StackTrace trace) {
155 connectionError = new ConnectionError(error, trace);
156 return false;
157 });
158
159 if (_drainedIncomingCommands && force) {
160 return connectionError;
161 }
162
163 return _commandReader.iterator.current;
164 }
165
166 /// Closes the connection to the fletch-vm and drains the remaining response
167 /// commands.
168 ///
169 /// If [ignoreExtraCommands] is `false` it will throw a StateError if the
170 /// fletch-vm sent any commands.
171 Future shutdown({bool ignoreExtraCommands: false}) async {
172 await _outgoingSink.close().catchError((_) {});
173
174 while (!_drainedIncomingCommands) {
175 VmCommand response = await readNextCommand(force: false);
176 if (!ignoreExtraCommands && response != null) {
177 await kill();
178 throw new StateError(
179 "Got unexpected command from fletch-vm during shutdown "
180 "($response)");
181 }
182 }
183
184 return _done;
185 }
186
187 Future interrupt() {
188 return sendCommand(const ProcessDebugInterrupt());
189 }
190
191 /// Closes the connection to the fletch-vm. It does not wait until it shuts
192 /// down.
193 ///
194 /// This method will never complete with an exception.
195 Future kill() async {
196 _connectionIsDead = true;
197 _drainedIncomingCommands = true;
198
199 await _outgoingSink.close().catchError((_) {});
200 var value = _commandReader.iterator.cancel();
201 if (value != null) {
202 await value.catchError((_) {});
203 }
204 _drainedIncomingCommands = true;
205 }
206 }
207
208 /// Extends a bare [FletchVmSession] with debugging functionality.
209 class Session extends FletchVmSession {
210 final IncrementalCompiler compiler;
211 final Future processExitCodeFuture;
212
213 DebugState debugState;
214 FletchSystem fletchSystem;
215 bool loaded = false;
216 bool running = false;
217 bool terminated = false;
218
219 Session(Socket fletchVmSocket,
220 this.compiler,
221 Sink<List<int>> stdoutSink,
222 Sink<List<int>> stderrSink,
223 [this.processExitCodeFuture])
224 : super(fletchVmSocket, stdoutSink, stderrSink) {
225 // We send many small packages, so use no-delay.
226 fletchVmSocket.setOption(SocketOption.TCP_NODELAY, true);
227 // TODO(ajohnsen): Should only be initialized on debug()/testDebugger().
228 debugState = new DebugState(this);
229 }
230
231 Future applyDelta(FletchDelta delta) async {
232 VmCommand response = await runCommands(delta.commands);
233 fletchSystem = delta.system;
234 return response;
235 }
236
237 Future<HandShakeResult> handShake(String version) async {
238 VmCommand command = await runCommand(new HandShake(version));
239 if (command != null && command is HandShakeResult) return command;
240 return null;
241 }
242
243 Future disableVMStandardOutput() async {
244 await runCommand(const DisableStandardOutput());
245 }
246
247 // Returns either a [WriteSnapshotResult] or a [ConnectionError].
248 Future<VmCommand> writeSnapshot(String snapshotPath) async {
249 VmCommand result = await runCommand(new WriteSnapshot(snapshotPath));
250 await shutdown();
251 return result;
252 }
253
254 Future enableDebugger() async {
255 await runCommand(const Debugging());
256 }
257
258 Future spawnProcess() async {
259 await runCommand(const ProcessSpawnForMain());
260 }
261
262 Future run() async {
263 await spawnProcess();
264 loaded = true;
265 await runCommand(const ProcessRun());
266 // NOTE: The [ProcessRun] command normally results in a
267 // [ProcessTerminated] command. But if the compiler emitted a compile time
268 // error, the fletch-vm will just halt()/exit() and we therefore get no
269 // response.
270 var command = await readNextCommand(force: false);
271 if (command != null && command is! ProcessTerminated) {
272 throw new Exception('Expected process to finish complete with '
273 '[ProcessTerminated] but got [$command]');
274 }
275 await shutdown();
276 }
277
278 Future<int> debug(
279 Stream<String> inputLines,
280 Uri base,
281 SessionState state,
282 {bool echo: false}) async {
283 await enableDebugger();
284 await spawnProcess();
285 return new InputHandler(this, inputLines, echo, base).run(state);
286 }
287
288 Future terminateSession() async {
289 await runCommand(const SessionEnd());
290 if (processExitCodeFuture != null) await processExitCodeFuture;
291 await shutdown();
292 terminated = true;
293 }
294
295 // This method handles the various responses a command can return to indicate
296 // the process has stopped running.
297 // The session's state is updated to match the current state of the vm.
298 Future<VmCommand> handleProcessStop(VmCommand response) async {
299 debugState.reset();
300 switch (response.code) {
301 case VmCommandCode.UncaughtException:
302 case VmCommandCode.ProcessCompileTimeError:
303 running = false;
304 break;
305
306 case VmCommandCode.ProcessTerminated:
307 running = false;
308 loaded = false;
309 // TODO(ahe): Let the caller terminate the session. See issue 67.
310 await terminateSession();
311 break;
312
313 case VmCommandCode.ConnectionError:
314 running = false;
315 loaded = false;
316 await shutdown();
317 terminated = true;
318 break;
319
320 case VmCommandCode.ProcessBreakpoint:
321 ProcessBreakpoint command = response;
322 var function = fletchSystem.lookupFunctionById(command.functionId);
323 debugState.topFrame = new BackTraceFrame(
324 function, command.bytecodeIndex, compiler, debugState);
325 running = true;
326 break;
327
328 default:
329 throw new StateError(
330 "Unhandled response from Fletch VM connection: ${response.code}");
331
332 }
333 return response;
334 }
335
336 Future<VmCommand> debugRun() async {
337 assert(!loaded);
338 assert(!running);
339 loaded = true;
340 running = true;
341 await sendCommand(const ProcessRun());
342 return handleProcessStop(await readNextCommand());
343 }
344
345 Future setBreakpointHelper(String name,
346 FletchFunction function,
347 int bytecodeIndex) async {
348 ProcessSetBreakpoint response = await runCommands([
349 new PushFromMap(MapId.methods, function.functionId),
350 new ProcessSetBreakpoint(bytecodeIndex),
351 ]);
352 int breakpointId = response.value;
353 var breakpoint = new Breakpoint(name, bytecodeIndex, breakpointId);
354 debugState.breakpoints[breakpointId] = breakpoint;
355 return breakpoint;
356 }
357
358 // TODO(ager): Let setBreakpoint return a stream instead and deal with
359 // error situations such as bytecode indices that are out of bounds for
360 // some of the methods with the given name.
361 Future setBreakpoint({String methodName, int bytecodeIndex}) async {
362 Iterable<FletchFunction> functions =
363 fletchSystem.functionsWhere((f) => f.name == methodName);
364 List<Breakpoint> breakpoints = [];
365 for (FletchFunction function in functions) {
366 breakpoints.add(
367 await setBreakpointHelper(methodName, function, bytecodeIndex));
368 }
369 return breakpoints;
370 }
371
372 Future setFileBreakpointFromPosition(String name,
373 Uri file,
374 int position) async {
375 if (position == null) {
376 return null;
377 }
378 DebugInfo debugInfo = compiler.debugInfoForPosition(
379 file,
380 position,
381 fletchSystem);
382 if (debugInfo == null) {
383 return null;
384 }
385 SourceLocation location = debugInfo.locationForPosition(position);
386 if (location == null) {
387 return null;
388 }
389 FletchFunction function = debugInfo.function;
390 int bytecodeIndex = location.bytecodeIndex;
391 return setBreakpointHelper(function.name, function, bytecodeIndex);
392 }
393
394 Future setFileBreakpointFromPattern(Uri file,
395 int line,
396 String pattern) async {
397 assert(line > 0);
398 int position = compiler.positionInFileFromPattern(file, line - 1, pattern);
399 return setFileBreakpointFromPosition(
400 '$file:$line:$pattern', file, position);
401 }
402
403 Future setFileBreakpoint(Uri file, int line, int column) async {
404 assert(line > 0 && column > 0);
405 int position = compiler.positionInFile(file, line - 1, column - 1);
406 return setFileBreakpointFromPosition('$file:$line:$column', file, position);
407 }
408
409 Future doDeleteBreakpoint(int id) async {
410 ProcessDeleteBreakpoint response =
411 await runCommand(new ProcessDeleteBreakpoint(id));
412 assert(response.id == id);
413 }
414
415 Future<Breakpoint> deleteBreakpoint(int id) async {
416 if (!debugState.breakpoints.containsKey(id)) {
417 return null;
418 }
419 await doDeleteBreakpoint(id);
420 return debugState.breakpoints.remove(id);
421 }
422
423 List<Breakpoint> breakpoints() {
424 assert(debugState.breakpoints != null);
425 return debugState.breakpoints.values.toList();
426 }
427
428 Iterable<Uri> findSourceFiles(Pattern pattern) {
429 return compiler.findSourceFiles(pattern);
430 }
431
432 bool stepMadeProgress(BackTraceFrame frame) {
433 return frame.functionId != debugState.topFrame.functionId ||
434 frame.bytecodePointer != debugState.topFrame.bytecodePointer;
435 }
436
437 Future<VmCommand> stepTo(int functionId, int bcp) async {
438 assert(running);
439 VmCommand response = await runCommand(new ProcessStepTo(functionId, bcp));
440 return handleProcessStop(response);
441 }
442
443 Future<VmCommand> step() async {
444 assert(running);
445 final SourceLocation previous = debugState.currentLocation;
446 final BackTraceFrame initialFrame = debugState.topFrame;
447 VmCommand response;
448 do {
449 int bcp = debugState.topFrame.stepBytecodePointer(previous);
450 if (bcp != -1) {
451 response = await stepTo(debugState.topFrame.functionId, bcp);
452 } else {
453 response = await stepBytecode();
454 }
455 } while (running &&
456 debugState.atLocation(previous) &&
457 stepMadeProgress(initialFrame));
458 return response;
459 }
460
461 Future<VmCommand> stepOver() async {
462 assert(running);
463 VmCommand response;
464 final SourceLocation previous = debugState.currentLocation;
465 final BackTraceFrame initialFrame = debugState.topFrame;
466 do {
467 response = await stepOverBytecode();
468 } while (running &&
469 debugState.atLocation(previous) &&
470 stepMadeProgress(initialFrame));
471 return response;
472 }
473
474 Future<VmCommand> stepOut() async {
475 assert(running);
476 BackTrace trace = await backTrace();
477 // If we are at the last frame, just continue. This will either terminate
478 // the process or stop at any user configured breakpoints.
479 if (trace.visibleFrames <= 1) return cont();
480
481 // Since we know there is at least two visible frames at this point stepping
482 // out will hit a visible frame before the process terminates, hence we can
483 // step out until we either hit another breakpoint or a visible frame, ie.
484 // we skip internal frame and stop at the next visible frame.
485 SourceLocation return_location = trace.visibleFrame(1).sourceLocation();
486 VmCommand response;
487 do {
488 await sendCommand(const ProcessStepOut());
489 ProcessSetBreakpoint setBreakpoint = await readNextCommand();
490 assert(setBreakpoint.value != -1);
491
492 // handleProcessStop resets the debugState and sets the top frame if it
493 // hits either the above setBreakpoint or another breakpoint.
494 response = await handleProcessStop(await readNextCommand());
495 bool success =
496 response is ProcessBreakpoint &&
497 response.breakpointId == setBreakpoint.value;
498 if (!success) {
499 await doDeleteBreakpoint(setBreakpoint.value);
500 return response;
501 }
502 } while (!debugState.topFrame.isVisible);
503 if (running && debugState.atLocation(return_location)) {
504 response = await step();
505 }
506 return response;
507 }
508
509 Future<VmCommand> restart() async {
510 assert(loaded);
511 assert(debugState.currentBackTrace != null);
512 assert(debugState.currentBackTrace.length > 1);
513 int frame = debugState.actualCurrentFrameNumber;
514 return handleProcessStop(await runCommand(new ProcessRestartFrame(frame)));
515 }
516
517 Future<VmCommand> stepBytecode() async {
518 assert(running);
519 return handleProcessStop(await runCommand(const ProcessStep()));
520 }
521
522 Future<VmCommand> stepOverBytecode() async {
523 assert(running);
524 await sendCommand(const ProcessStepOver());
525 ProcessSetBreakpoint setBreakpoint = await readNextCommand();
526 VmCommand response = await handleProcessStop(await readNextCommand());
527 bool success =
528 response is ProcessBreakpoint &&
529 response.breakpointId == setBreakpoint.value;
530 if (!success && !terminated && setBreakpoint.value != -1) {
531 // Delete the initial one-time breakpoint as it wasn't hit.
532 await doDeleteBreakpoint(setBreakpoint.value);
533 }
534 return response;
535 }
536
537 Future<VmCommand> cont() async {
538 assert(running);
539 return handleProcessStop(await runCommand(const ProcessContinue()));
540 }
541
542 bool selectFrame(int frame) {
543 if (debugState.currentBackTrace == null ||
544 debugState.currentBackTrace.actualFrameNumber(frame) == -1) {
545 return false;
546 }
547 debugState.currentFrame = frame;
548 return true;
549 }
550
551 BackTrace stackTraceFromBacktraceResponse(
552 ProcessBacktrace backtraceResponse) {
553 int frames = backtraceResponse.frames;
554 BackTrace stackTrace = new BackTrace(frames, debugState);
555 for (int i = 0; i < frames; ++i) {
556 int functionId = backtraceResponse.functionIds[i];
557 FletchFunction function = fletchSystem.lookupFunctionById(functionId);
558 if (function == null) {
559 function = const FletchFunction.missing();
560 }
561 stackTrace.addFrame(
562 compiler,
563 new BackTraceFrame(function,
564 backtraceResponse.bytecodeIndices[i],
565 compiler,
566 debugState));
567 }
568 return stackTrace;
569 }
570
571 Future<RemoteObject> uncaughtException() async {
572 assert(loaded);
573 assert(!terminated);
574 if (debugState.currentUncaughtException == null) {
575 await sendCommand(const ProcessUncaughtExceptionRequest());
576 VmCommand response = await readNextCommand();
577 if (response is DartValue) {
578 debugState.currentUncaughtException = new RemoteValue(response);
579 } else {
580 assert(response is InstanceStructure);
581 List<DartValue> fields = await readInstanceStructureFields(response);
582 debugState.currentUncaughtException =
583 new RemoteInstance(response, fields);
584 }
585 }
586 return debugState.currentUncaughtException;
587 }
588
589 Future<BackTrace> backTrace() async {
590 assert(loaded);
591 if (debugState.currentBackTrace == null) {
592 ProcessBacktrace backtraceResponse =
593 await runCommand(const ProcessBacktraceRequest());
594 debugState.currentBackTrace =
595 stackTraceFromBacktraceResponse(backtraceResponse);
596 }
597 return debugState.currentBackTrace;
598 }
599
600 Future<BackTrace> backtraceForFiber(int fiber) async {
601 ProcessBacktrace backtraceResponse =
602 await runCommand(new ProcessFiberBacktraceRequest(fiber));
603 return stackTraceFromBacktraceResponse(backtraceResponse);
604 }
605
606 Future<List<BackTrace>> fibers() async {
607 assert(running);
608 await runCommand(const NewMap(MapId.fibers));
609 ProcessNumberOfStacks response =
610 await runCommand(const ProcessAddFibersToMap());
611 int numberOfFibers = response.value;
612 List<BackTrace> stacktraces = new List(numberOfFibers);
613 for (int i = 0; i < numberOfFibers; i++) {
614 stacktraces[i] = await backtraceForFiber(i);
615 }
616 await runCommand(const DeleteMap(MapId.fibers));
617 return stacktraces;
618 }
619
620 Future<List<int>> processes() async {
621 assert(running);
622 ProcessGetProcessIdsResult response =
623 await runCommand(const ProcessGetProcessIds());
624 return response.ids;
625 }
626
627 Future<BackTrace> processStack(int processId) async {
628 assert(running);
629 ProcessBacktrace backtraceResponse =
630 await runCommand(new ProcessBacktraceRequest(processId));
631 return stackTraceFromBacktraceResponse(backtraceResponse);
632 }
633
634 String dartValueToString(DartValue value) {
635 if (value is Instance) {
636 Instance i = value;
637 String className = fletchSystem.lookupClassById(i.classId).name;
638 return "Instance of '$className'";
639 } else {
640 return value.dartToString();
641 }
642 }
643
644 String instanceStructureToString(InstanceStructure structure,
645 List<DartValue> fields) {
646 int classId = structure.classId;
647 FletchClass klass = fletchSystem.lookupClassById(classId);
648
649 // TODO(fletchc-team): This should be more strict and a compiler bug
650 // should be reported to the user in order for us to get a bugreport.
651 if (klass == null) {
652 return 'Unknown (Fletch compiler was unable to find exception class)';
653 }
654
655 StringBuffer sb = new StringBuffer();
656 sb.writeln("Instance of '${klass.name}' {");
657 for (int i = 0; i < structure.fields; i++) {
658 DartValue value = fields[i];
659 String fieldName = debugState.lookupFieldName(klass, i);
660 if (fieldName == null) {
661 fieldName = '<unnamed>';
662 }
663 sb.writeln(' $fieldName: ${dartValueToString(value)}');
664 }
665 sb.write('}');
666 return '$sb';
667 }
668
669 String noSuchMethodErrorToString(List<DartValue> nsmFields) {
670 assert(nsmFields.length == 3);
671 DartValue receiver = nsmFields[0];
672 ClassValue receiverClass = nsmFields[1];
673 Integer receiverSelector = nsmFields[2];
674 FletchSelector selector = new FletchSelector(receiverSelector.value);
675
676 String method =
677 fletchSystem.lookupSymbolBySelector(selector.encodedSelector);
678 FletchClass klass = fletchSystem.lookupClassById(receiverClass.classId);
679 // TODO(ahe): If FletchClass is a synthetic closure class, improve the
680 // message. For example, "(local) function `foo` takes 3 arguments, but
681 // called with 4" instead of "Class '<internal>' has no method named 'call'
682 // that takes 4 arguments".
683 String name = klass.name;
684 String raw = hideRawIds
685 ? "" : " (${receiverClass.classId}::${selector.encodedSelector})";
686 // TODO(ahe): Lookup the name in the receiverClass and include that as a
687 // suggestion in the error mesage.
688 switch (selector.kind) {
689 case SelectorKind.Method:
690 return "NoSuchMethodError: Class '$name' has no method named "
691 "'$method' that takes ${selector.arity} arguments$raw";
692
693 case SelectorKind.Getter:
694 return "NoSuchMethodError: "
695 "Class '$name' has no getter named '$method'$raw";
696
697 case SelectorKind.Setter:
698 return "NoSuchMethodError: "
699 "Class '$name' has no setter named '$method'$raw";
700 }
701 }
702
703 Future<List<DartValue>> readInstanceStructureFields(
704 InstanceStructure structure) async {
705 List<DartValue> fields = <DartValue>[];
706 for (int i = 0; i < structure.fields; i++) {
707 fields.add(await readNextCommand());
708 }
709 return fields;
710 }
711
712 String exceptionToString(RemoteObject exception) {
713 String message;
714 if (exception is RemoteValue) {
715 message = dartValueToString(exception.value);
716 } else if (exception is RemoteInstance) {
717 InstanceStructure structure = exception.instance;
718 int classId = structure.classId;
719 FletchClass klass = fletchSystem.lookupClassById(classId);
720
721 FletchBackend backend = compiler.compiler.backend;
722 var fletchNoSuchMethodErrorClass = fletchSystem.lookupClassByElement(
723 backend.fletchNoSuchMethodErrorClass);
724
725 if (klass == fletchNoSuchMethodErrorClass) {
726 message = noSuchMethodErrorToString(exception.fields);
727 } else {
728 message = instanceStructureToString(
729 exception.instance, exception.fields);
730 }
731 } else {
732 throw new UnimplementedError();
733 }
734 return 'Uncaught exception: $message';
735 }
736
737 Future<RemoteValue> processVariable(String name) async {
738 assert(loaded);
739 LocalValue local = await lookupValue(name);
740 return local != null ? await processLocal(local) : null;
741 }
742
743 Future<RemoteObject> processVariableStructure(String name) async {
744 assert(loaded);
745 LocalValue local = await lookupValue(name);
746 return local != null ? await processLocalStructure(local) : null;
747 }
748
749 Future<List<RemoteObject>> processAllVariables() async {
750 assert(loaded);
751 BackTrace trace = await backTrace();
752 ScopeInfo info = trace.scopeInfoForCurrentFrame;
753 List<RemoteObject> variables = [];
754 for (ScopeInfo current = info;
755 current != ScopeInfo.sentinel;
756 current = current.previous) {
757 variables.add(await processLocal(current.local, current.name));
758 }
759 return variables;
760 }
761
762 Future<LocalValue> lookupValue(String name) async {
763 assert(loaded);
764 BackTrace trace = await backTrace();
765 return trace.scopeInfoForCurrentFrame.lookup(name);
766 }
767
768 Future<RemoteValue> processLocal(LocalValue local, [String name]) async {
769 var actualFrameNumber = debugState.actualCurrentFrameNumber;
770 VmCommand response = await runCommand(
771 new ProcessLocal(actualFrameNumber, local.slot));
772 assert(response is DartValue);
773 return new RemoteValue(response, name: name);
774 }
775
776 Future<RemoteObject> processLocalStructure(LocalValue local) async {
777 var frameNumber = debugState.actualCurrentFrameNumber;
778 await sendCommand(new ProcessLocalStructure(frameNumber, local.slot));
779 VmCommand response = await readNextCommand();
780 if (response is DartValue) {
781 return new RemoteValue(response);
782 } else {
783 assert(response is InstanceStructure);
784 List<DartValue> fields = await readInstanceStructureFields(response);
785 return new RemoteInstance(response, fields);
786 }
787 }
788
789 String remoteObjectToString(RemoteObject object) {
790 String message;
791 if (object is RemoteValue) {
792 message = dartValueToString(object.value);
793 } else if (object is RemoteInstance) {
794 message = instanceStructureToString(object.instance, object.fields);
795 } else {
796 throw new UnimplementedError();
797 }
798 if (object.name != null) {
799 // Prefix with name.
800 message = "${object.name}: $message";
801 }
802 return message;
803 }
804
805 bool toggleInternal() {
806 debugState.showInternalFrames = !debugState.showInternalFrames;
807 if (debugState.currentBackTrace != null) {
808 debugState.currentBackTrace.visibilityChanged();
809 }
810 return debugState.showInternalFrames;
811 }
812
813 bool toggleVerbose() {
814 debugState.verbose = !debugState.verbose;
815 return debugState.verbose;
816 }
817
818 // This method is a helper method for computing the default output for one
819 // of the stop command results. There are currently the following stop
820 // responses:
821 // ProcessTerminated
822 // ProcessBreakpoint
823 // UncaughtException
824 // ProcessCompileError
825 // ConnectionError
826 Future<String> processStopResponseToString(
827 VmCommand response,
828 SessionState state) async {
829 if (response is UncaughtException) {
830 StringBuffer sb = new StringBuffer();
831 // Print the exception first, followed by a stack trace.
832 RemoteObject exception = await uncaughtException();
833 sb.writeln(exceptionToString(exception));
834 BackTrace trace = await backTrace();
835 assert(trace != null);
836 sb.write(trace.format());
837 String result = '$sb';
838 if (!result.endsWith('\n')) result = '$result\n';
839 return result;
840
841 } else if (response is ProcessBreakpoint) {
842 // Print the current line of source code.
843 BackTrace trace = await backTrace();
844 assert(trace != null);
845 BackTraceFrame topFrame = trace.visibleFrame(0);
846 if (topFrame != null) {
847 String result;
848 if (debugState.verbose) {
849 result = topFrame.list(state, contextLines: 0);
850 } else {
851 result = topFrame.shortString();
852 }
853 if (!result.endsWith('\n')) result = '$result\n';
854 return result;
855 }
856 } else if (response is ProcessCompileTimeError) {
857 // TODO(wibling): add information to ProcessCompileTimeError about the
858 // specific error and print here.
859 return '';
860 } else if (response is ProcessTerminated) {
861 return '### process terminated\n';
862
863 } else if (response is ConnectionError) {
864 return '### lost connection to the virtual machine\n';
865 }
866 return '';
867 }
868 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/vm_commands.dart ('k') | pkg/fletchc/samples/fletchc_driver/target.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698