| Index: runtime/observatory/lib/src/service/object.dart
|
| diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
|
| index cf244e4f427e61f878649d51958cf95c628e7584..1a5ad42f372ea7aa17c864c754b836c00fd5d077 100644
|
| --- a/runtime/observatory/lib/src/service/object.dart
|
| +++ b/runtime/observatory/lib/src/service/object.dart
|
| @@ -217,6 +217,9 @@ abstract class ServiceObject extends Observable {
|
| case 'SourceLocation':
|
| obj = new SourceLocation._empty(owner);
|
| break;
|
| + case 'UnresolvedSourceLocation':
|
| + obj = new UnresolvedSourceLocation._empty(owner);
|
| + break;
|
| case 'Object':
|
| switch (vmType) {
|
| case 'ICData':
|
| @@ -432,6 +435,16 @@ class SourceLocation extends ServiceObject {
|
| int tokenPos;
|
| int endTokenPos;
|
|
|
| + Future<int> getLine() async {
|
| + await script.load();
|
| + return script.tokenToLine(tokenPos);
|
| + }
|
| +
|
| + Future<int> getColumn() async {
|
| + await script.load();
|
| + return script.tokenToCol(tokenPos);
|
| + }
|
| +
|
| SourceLocation._empty(ServiceObject owner) : super._empty(owner);
|
|
|
| void _update(ObservableMap map, bool mapIsRef) {
|
| @@ -439,8 +452,15 @@ class SourceLocation extends ServiceObject {
|
| _upgradeCollection(map, owner);
|
| script = map['script'];
|
| tokenPos = map['tokenPos'];
|
| - assert(script != null && tokenPos != null);
|
| endTokenPos = map['endTokenPos'];
|
| +
|
| + assert(script != null && tokenPos != null);
|
| + }
|
| +
|
| + Future<String> toUserString() async {
|
| + int line = await getLine();
|
| + int column = await getColumn();
|
| + return '${script.name}:${line}:${column}';
|
| }
|
|
|
| String toString() {
|
| @@ -452,6 +472,86 @@ class SourceLocation extends ServiceObject {
|
| }
|
| }
|
|
|
| +/// An [UnresolvedSourceLocation] represents a location in the source
|
| +// code which has not been precisely mapped to a token position.
|
| +class UnresolvedSourceLocation extends ServiceObject {
|
| + Script script;
|
| + String scriptUri;
|
| + int line;
|
| + int column;
|
| + int tokenPos;
|
| +
|
| + Future<int> getLine() async {
|
| + if (tokenPos != null) {
|
| + await script.load();
|
| + return script.tokenToLine(tokenPos);
|
| + } else {
|
| + return line;
|
| + }
|
| + }
|
| +
|
| + Future<int> getColumn() async {
|
| + if (tokenPos != null) {
|
| + await script.load();
|
| + return script.tokenToCol(tokenPos);
|
| + } else {
|
| + return column;
|
| + }
|
| + }
|
| +
|
| + UnresolvedSourceLocation._empty(ServiceObject owner) : super._empty(owner);
|
| +
|
| + void _update(ObservableMap map, bool mapIsRef) {
|
| + assert(!mapIsRef);
|
| + _upgradeCollection(map, owner);
|
| + script = map['script'];
|
| + scriptUri = map['scriptUri'];
|
| + line = map['line'];
|
| + column = map['column'];
|
| + tokenPos = map['tokenPos'];
|
| +
|
| + assert(script != null || scriptUri != null);
|
| + assert(line != null || tokenPos != null);
|
| + }
|
| +
|
| + Future<String> toUserString() async {
|
| + StringBuffer sb = new StringBuffer();
|
| +
|
| + int line = await getLine();
|
| + int column = await getColumn();
|
| +
|
| + if (script != null) {
|
| + sb.write('${script.name}:');
|
| + } else {
|
| + sb.write('${scriptUri}:');
|
| + }
|
| + if (column != null) {
|
| + sb.write('${line}:${column}');
|
| + } else {
|
| + sb.write('${line}');
|
| + }
|
| + return sb.toString();
|
| + }
|
| +
|
| + String toString() {
|
| + StringBuffer sb = new StringBuffer();
|
| + if (script != null) {
|
| + sb.write('${script.name}:');
|
| + } else {
|
| + sb.write('${scriptUri}:');
|
| + }
|
| + if (tokenPos != null) {
|
| + sb.write('token(${tokenPos})');
|
| + } else if (column != null) {
|
| + sb.write('${line}:${column}');
|
| + } else {
|
| + sb.write('${line}');
|
| + }
|
| + sb.write('[unresolved]');
|
| + return sb.toString();
|
| + }
|
| +}
|
| +
|
| class _EventStreamState {
|
| VM _vm;
|
| String streamId;
|
| @@ -1390,13 +1490,17 @@ class Isolate extends ServiceObjectOwner with Coverage {
|
| }
|
| }
|
|
|
| - Future<ServiceObject> addBreakpoint(Script script, int line) async {
|
| + Future<ServiceObject> addBreakpoint(
|
| + Script script, int line, [int col]) async {
|
| // TODO(turnidge): Pass line as an int instead of a string.
|
| try {
|
| Map params = {
|
| 'scriptId': script.id,
|
| - 'line': '$line',
|
| + 'line': line.toString(),
|
| };
|
| + if (col != null) {
|
| + params['column'] = col.toString();
|
| + }
|
| Breakpoint bpt = await invokeRpc('addBreakpoint', params);
|
| if (bpt.resolved &&
|
| script.loaded &&
|
| @@ -1414,6 +1518,18 @@ class Isolate extends ServiceObjectOwner with Coverage {
|
| }
|
| }
|
|
|
| + Future<ServiceObject> addBreakpointByScriptUri(
|
| + String uri, int line, [int col]) {
|
| + Map params = {
|
| + 'scriptUri': uri,
|
| + 'line': line.toString(),
|
| + };
|
| + if (col != null) {
|
| + params['column'] = col.toString();
|
| + }
|
| + return invokeRpc('addBreakpoint', params);
|
| + }
|
| +
|
| Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
|
| return invokeRpc('addBreakpointAtEntry',
|
| { 'functionId': function.id });
|
| @@ -1855,8 +1971,11 @@ class Breakpoint extends ServiceObject {
|
| // A unique integer identifier for this breakpoint.
|
| @observable int number;
|
|
|
| - // Source location information.
|
| - @observable SourceLocation location;
|
| + // Either SourceLocation or UnresolvedSourceLocation.
|
| + @observable ServiceObject location;
|
| +
|
| + // The breakpoint is in a file which is not yet loaded.
|
| + @observable bool latent;
|
|
|
| // The breakpoint has been assigned to a final source location.
|
| @observable bool resolved;
|
| @@ -1869,38 +1988,25 @@ class Breakpoint extends ServiceObject {
|
| // number never changes.
|
| assert((number == null) || (number == newNumber));
|
| number = newNumber;
|
| -
|
| resolved = map['resolved'];
|
|
|
| var oldLocation = location;
|
| var newLocation = map['location'];
|
| - var oldScript;
|
| - var newScript;
|
| - var oldTokenPos;
|
| - var newTokenPos;
|
| - if (oldLocation != null) {
|
| - oldScript = location.script;
|
| - oldTokenPos = location.tokenPos;
|
| - }
|
| - if (newLocation != null) {
|
| - newScript = newLocation.script;
|
| - newTokenPos = newLocation.tokenPos;
|
| - }
|
| - // script never changes
|
| - assert((oldScript == null) || (oldScript == newScript));
|
| - bool tokenPosChanged = oldTokenPos != newTokenPos;
|
| - if (newScript.loaded &&
|
| - (newTokenPos != null) &&
|
| - tokenPosChanged) {
|
| - // The breakpoint has moved. Remove it and add it later.
|
| - if (oldScript != null) {
|
| + if (oldLocation is UnresolvedSourceLocation &&
|
| + newLocation is SourceLocation) {
|
| + // Breakpoint has been resolved. Remove old breakpoint.
|
| + var oldScript = oldLocation.script;
|
| + if (oldScript != null && oldScript.loaded) {
|
| oldScript._removeBreakpoint(this);
|
| }
|
| }
|
| location = newLocation;
|
| - if (newScript.loaded && tokenPosChanged) {
|
| + var newScript = location.script;
|
| + if (newScript != null && newScript.loaded) {
|
| newScript._addBreakpoint(this);
|
| }
|
| +
|
| + assert(resolved || location is UnresolvedSourceLocation);
|
| }
|
|
|
| void remove() {
|
| @@ -2893,12 +2999,22 @@ class Script extends HeapObject with Coverage {
|
| }
|
|
|
| void _addBreakpoint(Breakpoint bpt) {
|
| - var line = tokenToLine(bpt.location.tokenPos);
|
| + var line;
|
| + if (bpt.location.tokenPos != null) {
|
| + line = tokenToLine(bpt.location.tokenPos);
|
| + } else {
|
| + line = bpt.location.line;
|
| + }
|
| getLine(line).addBreakpoint(bpt);
|
| }
|
|
|
| void _removeBreakpoint(Breakpoint bpt) {
|
| - var line = tokenToLine(bpt.location.tokenPos);
|
| + var line;
|
| + if (bpt.location.tokenPos != null) {
|
| + line = tokenToLine(bpt.location.tokenPos);
|
| + } else {
|
| + line = bpt.location.line;
|
| + }
|
| if (line != null) {
|
| getLine(line).removeBreakpoint(bpt);
|
| }
|
|
|