| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart 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 file. |
| 4 |
| 5 part of app; |
| 6 |
| 7 /// State for a running isolate. |
| 8 class Isolate extends Observable implements ServiceObject { |
| 9 final VM vm; |
| 10 String _id; |
| 11 String _serviceType = 'Isolate'; |
| 12 Isolate get isolate => this; |
| 13 String get link => _id; |
| 14 String get id => _id; |
| 15 String get serviceType => _serviceType; |
| 16 |
| 17 Isolate(this.vm, this._id); |
| 18 |
| 19 /// Refresh [this]. Returns a future which completes to [this]. |
| 20 Future refresh() { |
| 21 return vm.fetchMap(_id).then((m) => update(m)).then((_) => this); |
| 22 } |
| 23 |
| 24 /// Creates a link to [objectId] relative to [this]. |
| 25 String relativeLink(String objectId) => '$id/$objectId'; |
| 26 /// Creates a relative link to [objectId] with a '#/' prefix. |
| 27 String hashLink(String objectId) => '#/${relativeLink(objectId)}'; |
| 28 |
| 29 @observable Profile profile; |
| 30 @observable final Map<String, Script> scripts = |
| 31 toObservable(new Map<String, Script>()); |
| 32 @observable final List<Code> codes = new List<Code>(); |
| 33 @observable String name; |
| 34 @observable String vmName; |
| 35 @observable Map entry; |
| 36 @observable String rootLib; |
| 37 @observable final Map<String, double> timers = |
| 38 toObservable(new Map<String, double>()); |
| 39 |
| 40 @observable int newHeapUsed = 0; |
| 41 @observable int oldHeapUsed = 0; |
| 42 |
| 43 @observable Map topFrame = null; |
| 44 @observable String fileAndLine = null; |
| 45 |
| 46 Isolate.fromId(this.vm, this._id) : name = 'isolate' {} |
| 47 |
| 48 Isolate.fromMap(this.vm, Map map) |
| 49 : _id = map['id'], name = map['name'] { |
| 50 } |
| 51 |
| 52 void update(Map map) { |
| 53 if (map['type'] != 'Isolate') { |
| 54 Logger.root.severe('Unexpected message type in Isolate.update: ${map["type
"]}'); |
| 55 return; |
| 56 } |
| 57 if (map['rootLib'] == null || |
| 58 map['timers'] == null || |
| 59 map['heap'] == null) { |
| 60 Logger.root.severe("Malformed 'Isolate' response: $map"); |
| 61 return; |
| 62 } |
| 63 rootLib = map['rootLib']['id']; |
| 64 vmName = map['name']; |
| 65 if (map['entry'] != null) { |
| 66 entry = map['entry']; |
| 67 name = entry['name']; |
| 68 } else { |
| 69 // fred |
| 70 name = 'root isolate'; |
| 71 } |
| 72 if (map['topFrame'] != null) { |
| 73 topFrame = map['topFrame']; |
| 74 } |
| 75 |
| 76 var timerMap = {}; |
| 77 map['timers'].forEach((timer) { |
| 78 timerMap[timer['name']] = timer['time']; |
| 79 }); |
| 80 timers['total'] = timerMap['time_total_runtime']; |
| 81 timers['compile'] = timerMap['time_compilation']; |
| 82 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. |
| 83 timers['init'] = (timerMap['time_script_loading'] + |
| 84 timerMap['time_creating_snapshot'] + |
| 85 timerMap['time_isolate_initialization'] + |
| 86 timerMap['time_bootstrap']); |
| 87 timers['dart'] = timerMap['time_dart_execution']; |
| 88 |
| 89 newHeapUsed = map['heap']['usedNew']; |
| 90 oldHeapUsed = map['heap']['usedOld']; |
| 91 } |
| 92 |
| 93 String toString() => '$id'; |
| 94 |
| 95 Code findCodeByAddress(int address) { |
| 96 for (var i = 0; i < codes.length; i++) { |
| 97 if (codes[i].contains(address)) { |
| 98 return codes[i]; |
| 99 } |
| 100 } |
| 101 return null; |
| 102 } |
| 103 |
| 104 Code findCodeByName(String name) { |
| 105 for (var i = 0; i < codes.length; i++) { |
| 106 if (codes[i].name == name) { |
| 107 return codes[i]; |
| 108 } |
| 109 } |
| 110 return null; |
| 111 } |
| 112 |
| 113 void resetCodeTicks() { |
| 114 Logger.root.info('Reset all code ticks.'); |
| 115 for (var i = 0; i < codes.length; i++) { |
| 116 codes[i].resetTicks(); |
| 117 } |
| 118 } |
| 119 |
| 120 void updateCoverage(List coverages) { |
| 121 for (var coverage in coverages) { |
| 122 var id = coverage['script']['id']; |
| 123 var script = scripts[id]; |
| 124 if (script == null) { |
| 125 script = new Script.fromMap(coverage['script']); |
| 126 scripts[id] = script; |
| 127 } |
| 128 assert(script != null); |
| 129 script._processCoverageHits(coverage['hits']); |
| 130 } |
| 131 } |
| 132 |
| 133 // TODO(johnmccutchan): Remove this once everything is a ServiceObject. |
| 134 void _setModelResponse(String type, String modelName, dynamic model) { |
| 135 var response = { |
| 136 'type': type, |
| 137 modelName: model |
| 138 }; |
| 139 vm.app.setResponse(response); |
| 140 } |
| 141 |
| 142 void _setResponseRequestError(HttpRequest request) { |
| 143 String error = '${request.status} ${request.statusText}'; |
| 144 if (request.status == 0) { |
| 145 error = 'No service found. Did you run with --enable-vm-service ?'; |
| 146 } |
| 147 vm.app.setResponseError(error, 'RequestError'); |
| 148 } |
| 149 |
| 150 void _requestCatchError(e, st) { |
| 151 if (e is ProgressEvent) { |
| 152 _setResponseRequestError(e.target); |
| 153 } else { |
| 154 vm.app.setResponseError('$e $st'); |
| 155 } |
| 156 } |
| 157 |
| 158 static final RegExp _codeMatcher = new RegExp(r'/code/'); |
| 159 static bool isCodeId(objectId) => _codeMatcher.hasMatch(objectId); |
| 160 static int codeAddressFromRequest(String objectId) { |
| 161 Match m = _codeMatcher.matchAsPrefix(objectId); |
| 162 if (m == null) { |
| 163 return 0; |
| 164 } |
| 165 try { |
| 166 var a = int.parse(m.input.substring(m.end), radix: 16); |
| 167 return a; |
| 168 } catch (e) { |
| 169 return 0; |
| 170 } |
| 171 } |
| 172 |
| 173 /// Handle 'Code' requests |
| 174 void _getCode(String objectId) { |
| 175 var address = codeAddressFromRequest(objectId); |
| 176 if (address == 0) { |
| 177 vm.app.setResponseError('$objectId is not a valid code request.'); |
| 178 return; |
| 179 } |
| 180 var code = isolate.findCodeByAddress(address); |
| 181 if (code != null) { |
| 182 Logger.root.info( |
| 183 'Found code with 0x${address.toRadixString(16)} in isolate.'); |
| 184 _setModelResponse('Code', 'code', code); |
| 185 return; |
| 186 } |
| 187 getMap(objectId).then((map) { |
| 188 assert(map['type'] == 'Code'); |
| 189 var code = new Code.fromMap(map); |
| 190 Logger.root.info( |
| 191 'Added code with 0x${address.toRadixString(16)} to isolate.'); |
| 192 isolate.codes.add(code); |
| 193 _setModelResponse('Code', 'code', code); |
| 194 }).catchError(_requestCatchError); |
| 195 } |
| 196 |
| 197 static final RegExp _scriptMatcher = new RegExp(r'scripts/.+'); |
| 198 static bool isScriptId(objectId) => _scriptMatcher.hasMatch(objectId); |
| 199 void _getScript(String objectId) { |
| 200 var script = scripts[objectId]; |
| 201 if ((script != null) && !script.needsSource) { |
| 202 Logger.root.info('Found script ${script.scriptRef['name']} in isolate'); |
| 203 _setModelResponse('Script', 'script', script); |
| 204 return; |
| 205 } |
| 206 if (script != null) { |
| 207 // The isolate has the script but no script source code. |
| 208 getMap(objectId).then((response) { |
| 209 assert(response['type'] == 'Script'); |
| 210 script._processSource(response['source']); |
| 211 Logger.root.info( |
| 212 'Grabbed script ${script.scriptRef['name']} source.'); |
| 213 _setModelResponse('Script', 'script', script); |
| 214 }); |
| 215 return; |
| 216 } |
| 217 // New script. |
| 218 getMap(objectId).then((response) { |
| 219 assert(response['type'] == 'Script'); |
| 220 var script = new Script.fromMap(response); |
| 221 Logger.root.info( |
| 222 'Added script ${script.scriptRef['name']} to isolate.'); |
| 223 _setModelResponse('Script', 'script', script); |
| 224 scripts[objectId] = script; |
| 225 }); |
| 226 } |
| 227 |
| 228 /// Requests [objectId] from [this]. Completes to a [ServiceObject]. |
| 229 Future<ServiceObject> get(String objectId) { |
| 230 if (isCodeId(objectId)) { |
| 231 _getCode(objectId); |
| 232 // TODO(johnmccutchan): FIX. |
| 233 return null; |
| 234 } |
| 235 if (isScriptId(objectId)) { |
| 236 _getScript(objectId); |
| 237 // TODO(johnmccutchan): FIX. |
| 238 return null; |
| 239 } |
| 240 return vm.fetchMap(relativeLink(objectId)).then((m) => |
| 241 upgradeToServiceObject(objectId, m)); |
| 242 } |
| 243 |
| 244 /// Requests [objectId] from [this]. Completes to a [Map]. |
| 245 Future<ObservableMap> getMap(String objectId) { |
| 246 return vm.fetchMap(relativeLink(objectId)); |
| 247 } |
| 248 |
| 249 /// Upgrades response ([m]) for [objectId] to a [ServiceObject]. |
| 250 ServiceObject upgradeToServiceObject(String objectId, Map m) { |
| 251 return new ServiceMap.fromMap(this, m); |
| 252 } |
| 253 } |
| OLD | NEW |