Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library object_graph; | 5 library object_graph; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:typed_data'; | 9 import 'dart:typed_data'; |
| 10 | 10 |
| 11 import 'package:logging/logging.dart'; | 11 import 'package:logging/logging.dart'; |
| 12 | 12 |
| 13 // Map<[uint32, uint32, uint32], uint32> | |
| 14 class AddressMapper { | |
|
turnidge
2015/07/08 22:52:03
High level question - is it possible to write some
| |
| 15 final Uint32List _table; | |
| 16 | |
| 17 // * 4 ~/3 for 75% load factor | |
| 18 // * 4 for four-tuple entries | |
| 19 AddressMapper(int N) : _table = new Uint32List((N * 4 ~/ 3) * 4); | |
| 20 | |
| 21 // Jenkin's smi hash. | |
| 22 static int combine(int hash, int value) { | |
| 23 hash = 0x1fffffff & (hash + value); | |
| 24 hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); | |
| 25 return hash ^ (hash >> 6); | |
| 26 } | |
| 27 | |
| 28 static int finish(int hash) { | |
| 29 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | |
| 30 hash = hash ^ (hash >> 11); | |
| 31 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | |
| 32 } | |
| 33 | |
| 34 static int hash3(a, b, c) => finish(combine(combine(combine(0, a), b), c)); | |
| 35 | |
| 36 int scanFor(int high, int mid, int low) { | |
| 37 var hash = hash3(high, mid, low); | |
| 38 var start = (hash % _table.length) & ~3; | |
| 39 var index = start; | |
| 40 do { | |
| 41 if (_table[index + 3] == 0) return index; | |
| 42 if (_table[index] == high && | |
| 43 _table[index + 1] == mid && | |
| 44 _table[index + 2] == low) return index; | |
| 45 index = (index + 4) % _table.length; | |
| 46 } while (index != start); | |
| 47 | |
| 48 throw new Exception("Interal error: table full"); | |
| 49 } | |
| 50 | |
| 51 int get(int high, int mid, int low) { | |
| 52 int index = scanFor(high, mid, low); | |
| 53 if (_table[index + 3] == 0) return null; | |
| 54 return _table[index + 3]; | |
| 55 } | |
| 56 | |
| 57 int put(int high, int mid, int low, int id) { | |
| 58 if (id == 0) throw new Exception("Invalid error: invalid key"); | |
| 59 | |
| 60 int index = scanFor(high, mid, low); | |
| 61 if ((_table[index + 3] != 0)) { | |
| 62 throw new Exception("Internal error: attempt to overwrite key"); | |
| 63 } | |
| 64 _table[index] = high; | |
| 65 _table[index + 1] = mid; | |
| 66 _table[index + 2] = low; | |
| 67 _table[index + 3] = id; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 | |
| 13 // Port of dart::ReadStream from vm/datastream.h. | 72 // Port of dart::ReadStream from vm/datastream.h. |
| 14 class _ReadStream { | 73 class _ReadStream { |
| 15 int position = 0; | 74 int position = 0; |
| 16 int _size = 0; | 75 int _size = 0; |
| 17 final List<ByteData> _chunks; | 76 final List<ByteData> _chunks; |
| 18 | 77 |
| 19 _ReadStream(this._chunks) { | 78 _ReadStream(this._chunks) { |
| 20 int n = _chunks.length; | 79 int n = _chunks.length; |
| 21 for (var i = 0; i < n; i++) { | 80 for (var i = 0; i < n; i++) { |
| 22 var chunk = _chunks[i]; | 81 var chunk = _chunks[i]; |
| 23 if (i + 1 != n) { | 82 if (i + 1 != n) { |
| 24 assert(chunk.lengthInBytes == (1 << 20)); | 83 assert(chunk.lengthInBytes == (1 << 20)); |
| 25 } | 84 } |
| 26 _size += chunk.lengthInBytes; | 85 _size += chunk.lengthInBytes; |
| 27 } | 86 } |
| 28 } | 87 } |
| 29 | 88 |
| 30 int get pendingBytes => _size - position; | 89 int get pendingBytes => _size - position; |
| 31 | 90 |
| 32 int getUint8(i) { | 91 int getUint8(i) { |
| 33 return _chunks[i >> 20].getUint8(i & 0xFFFFF); | 92 return _chunks[i >> 20].getUint8(i & 0xFFFFF); |
| 34 } | 93 } |
| 35 | 94 |
| 36 int readUnsigned() { | 95 int low = 0; |
| 37 int result = 0; | 96 int mid = 0; |
| 38 int shift = 0; | 97 int high = 0; |
| 39 while (getUint8(position) <= maxUnsignedDataPerByte) { | 98 |
| 40 result |= getUint8(position) << shift; | 99 int get clampedUint32 { |
| 41 shift += dataBitsPerByte; | 100 if (high != 0 || mid > 0xF) { |
| 42 position++; | 101 return 0xFFFFFFFF; |
| 102 } else { | |
| 103 // Not shift as JS shifts are signed 32-bit. | |
| 104 return mid * 0xFFFFFFF + low; | |
| 43 } | 105 } |
| 44 result |= (getUint8(position) & byteMask) << shift; | 106 } |
| 45 position++; | 107 |
| 46 return result; | 108 bool get isZero { |
| 109 return (high == 0) && (mid == 0) && (low == 0); | |
| 110 } | |
| 111 | |
| 112 void readUnsigned() { | |
| 113 low = 0; | |
| 114 mid = 0; | |
| 115 high = 0; | |
| 116 | |
| 117 // Low 28 bits. | |
| 118 var digit = getUint8(position++); | |
| 119 if (digit > maxUnsignedDataPerByte) { | |
| 120 low |= (digit & byteMask << 0); | |
| 121 return; | |
| 122 } | |
| 123 low |= (digit << 0); | |
| 124 | |
| 125 digit = getUint8(position++); | |
| 126 if (digit > maxUnsignedDataPerByte) { | |
| 127 low |= ((digit & byteMask) << 7); | |
| 128 return; | |
| 129 } | |
| 130 low |= (digit << 7); | |
| 131 | |
| 132 digit = getUint8(position++); | |
| 133 if (digit > maxUnsignedDataPerByte) { | |
| 134 low |= ((digit & byteMask) << 14); | |
| 135 return; | |
| 136 } | |
| 137 low |= (digit << 14); | |
| 138 | |
| 139 digit = getUint8(position++); | |
| 140 if (digit > maxUnsignedDataPerByte) { | |
| 141 low |= ((digit & byteMask) << 21); | |
| 142 return; | |
| 143 } | |
| 144 low |= (digit << 21); | |
| 145 | |
| 146 // Mid 28 bits. | |
| 147 digit = getUint8(position++); | |
| 148 if (digit > maxUnsignedDataPerByte) { | |
| 149 mid |= (digit & byteMask << 0); | |
| 150 return; | |
| 151 } | |
| 152 mid |= (digit << 0); | |
| 153 | |
| 154 digit = getUint8(position++); | |
| 155 if (digit > maxUnsignedDataPerByte) { | |
| 156 mid |= ((digit & byteMask) << 7); | |
| 157 return; | |
| 158 } | |
| 159 mid |= (digit << 7); | |
| 160 | |
| 161 digit = getUint8(position++); | |
| 162 if (digit > maxUnsignedDataPerByte) { | |
| 163 mid |= ((digit & byteMask) << 14); | |
| 164 return; | |
| 165 } | |
| 166 mid |= (digit << 14); | |
| 167 | |
| 168 digit = getUint8(position++); | |
| 169 if (digit > maxUnsignedDataPerByte) { | |
| 170 mid |= ((digit & byteMask) << 21); | |
| 171 return; | |
| 172 } | |
| 173 mid |= (digit << 21); | |
| 174 | |
| 175 // High 28 bits. | |
| 176 digit = getUint8(position++); | |
| 177 if (digit > maxUnsignedDataPerByte) { | |
| 178 high |= (digit & byteMask << 0); | |
| 179 return; | |
| 180 } | |
| 181 high |= (digit << 0); | |
| 182 | |
| 183 digit = getUint8(position++); | |
| 184 if (digit > maxUnsignedDataPerByte) { | |
| 185 high |= ((digit & byteMask) << 7); | |
| 186 return; | |
| 187 } | |
| 188 high |= (digit << 7); | |
| 189 throw new Exception("Format error: snapshot field exceeds 64 bits"); | |
| 190 } | |
| 191 | |
| 192 void skipUnsigned() { | |
| 193 while (getUint8(position++) <= maxUnsignedDataPerByte); | |
| 47 } | 194 } |
| 48 | 195 |
| 49 static const int dataBitsPerByte = 7; | 196 static const int dataBitsPerByte = 7; |
| 50 static const int byteMask = (1 << dataBitsPerByte) - 1; | 197 static const int byteMask = (1 << dataBitsPerByte) - 1; |
| 51 static const int maxUnsignedDataPerByte = byteMask; | 198 static const int maxUnsignedDataPerByte = byteMask; |
| 52 } | 199 } |
| 53 | 200 |
| 54 class ObjectVertex { | 201 class ObjectVertex { |
| 55 // 0 represents invalid/uninitialized, 1 is the root. | 202 // 0 represents invalid/uninitialized, 1 is the root. |
| 56 final int _id; | 203 final int _id; |
| 57 final ObjectGraph _graph; | 204 final ObjectGraph _graph; |
| 58 | 205 |
| 59 ObjectVertex._(this._id, this._graph); | 206 ObjectVertex._(this._id, this._graph); |
| 60 | 207 |
| 61 bool get isRoot => _id == 1; | 208 bool get isRoot => _id == 1; |
| 62 | 209 |
| 63 bool operator ==(other) => _id == other._id && _graph == other._graph; | 210 bool operator ==(other) => _id == other._id && _graph == other._graph; |
| 64 int get hashCode => _id; | 211 int get hashCode => _id; |
| 65 | 212 |
| 66 int get retainedSize => _graph._retainedSizes[_id]; | 213 int get retainedSize => _graph._retainedSizes[_id]; |
| 67 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); | 214 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); |
| 68 | 215 |
| 69 int get shallowSize { | 216 int get shallowSize { |
| 70 var stream = new _ReadStream(_graph._chunks); | 217 var stream = new _ReadStream(_graph._chunks); |
| 71 stream.position = _graph._positions[_id]; | 218 stream.position = _graph._positions[_id]; |
| 72 stream.readUnsigned(); // addr | 219 stream.skipUnsigned(); // addr |
| 73 return stream.readUnsigned(); // shallowSize | 220 stream.readUnsigned(); // shallowSize |
| 221 return stream.clampedUint32; | |
| 74 } | 222 } |
| 75 | 223 |
| 76 int get vmCid { | 224 int get vmCid { |
| 77 var stream = new _ReadStream(_graph._chunks); | 225 var stream = new _ReadStream(_graph._chunks); |
| 78 stream.position = _graph._positions[_id]; | 226 stream.position = _graph._positions[_id]; |
| 79 stream.readUnsigned(); // addr | 227 stream.skipUnsigned(); // addr |
| 80 stream.readUnsigned(); // shallowSize | 228 stream.skipUnsigned(); // shallowSize |
| 81 return stream.readUnsigned(); // cid | 229 stream.readUnsigned(); // cid |
| 230 return stream.clampedUint32; | |
| 82 } | 231 } |
| 83 | 232 |
| 84 get successors => new _SuccessorsIterable(_graph, _id); | 233 get successors => new _SuccessorsIterable(_graph, _id); |
| 85 | 234 |
| 86 int get address { | 235 String get address { |
| 87 // Note that everywhere else in this file, "address" really means an address | 236 // Note that everywhere else in this file, "address" really means an address |
| 88 // scaled down by kObjectAlignment. They were scaled down so they would fit | 237 // scaled down by kObjectAlignment. They were scaled down so they would fit |
| 89 // into Smis on the client. | 238 // into Smis on the client. |
| 90 var stream = new _ReadStream(_graph._chunks); | 239 var stream = new _ReadStream(_graph._chunks); |
| 91 stream.position = _graph._positions[_id]; | 240 stream.position = _graph._positions[_id]; |
| 92 var scaledAddr = stream.readUnsigned(); | 241 stream.readUnsigned(); |
| 93 return scaledAddr * _graph._kObjectAlignment; | 242 |
| 243 // Complicated way to do (high:mid:low * _kObjectAlignment).toHexString() | |
| 244 // without intermediate values exceeding int32. | |
| 245 | |
| 246 var strAddr = ""; | |
| 247 var carry = 0; | |
| 248 combine4(nibble) { | |
| 249 nibble = nibble * _graph._kObjectAlignment + carry; | |
| 250 carry = nibble >> 4; | |
| 251 nibble = nibble & 0xF; | |
| 252 strAddr = nibble.toRadixString(16) + strAddr; | |
| 253 } | |
| 254 combine28(twentyEightBits) { | |
| 255 for (int shift = 0; shift < 28; shift += 4) { | |
| 256 combine4((twentyEightBits >> shift) & 0xF); | |
| 257 } | |
| 258 } | |
| 259 combine28(stream.low); | |
| 260 combine28(stream.mid); | |
| 261 combine28(stream.high); | |
| 262 return strAddr; | |
| 94 } | 263 } |
| 95 | 264 |
| 96 List<ObjectVertex> dominatorTreeChildren() { | 265 List<ObjectVertex> dominatorTreeChildren() { |
| 97 var N = _graph._N; | 266 var N = _graph._N; |
| 98 var doms = _graph._doms; | 267 var doms = _graph._doms; |
| 99 | 268 |
| 100 var parentId = _id; | 269 var parentId = _id; |
| 101 var domChildren = []; | 270 var domChildren = []; |
| 102 | 271 |
| 103 for (var childId = 1; childId <= N; childId++) { | 272 for (var childId = 1; childId <= N; childId++) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 121 | 290 |
| 122 class _SuccessorsIterator implements Iterator<ObjectVertex> { | 291 class _SuccessorsIterator implements Iterator<ObjectVertex> { |
| 123 final ObjectGraph _graph; | 292 final ObjectGraph _graph; |
| 124 _ReadStream _stream; | 293 _ReadStream _stream; |
| 125 | 294 |
| 126 ObjectVertex current; | 295 ObjectVertex current; |
| 127 | 296 |
| 128 _SuccessorsIterator(this._graph, int id) { | 297 _SuccessorsIterator(this._graph, int id) { |
| 129 _stream = new _ReadStream(this._graph._chunks); | 298 _stream = new _ReadStream(this._graph._chunks); |
| 130 _stream.position = _graph._positions[id]; | 299 _stream.position = _graph._positions[id]; |
| 131 _stream.readUnsigned(); // addr | 300 _stream.skipUnsigned(); // addr |
| 132 _stream.readUnsigned(); // shallowSize | 301 _stream.skipUnsigned(); // shallowSize |
| 133 var cid = _stream.readUnsigned(); | 302 _stream.skipUnsigned(); // cid |
| 134 assert((cid & ~0xFFFF) == 0); // Sanity check: cid's are 16 bit. | |
| 135 } | 303 } |
| 136 | 304 |
| 137 bool moveNext() { | 305 bool moveNext() { |
| 138 while (true) { | 306 while (true) { |
| 139 var nextAddr = _stream.readUnsigned(); | 307 _stream.readUnsigned(); |
| 140 if (nextAddr == 0) return false; | 308 if (_stream.isZero) return false; |
| 141 var nextId = _graph._addrToId[nextAddr]; | 309 var nextId = _graph._addrToId.get(_stream.high, _stream.mid, _stream.low); |
| 142 if (nextId == null) continue; // Reference to VM isolate's heap. | 310 if (nextId == null) continue; // Reference to VM isolate's heap. |
| 143 current = new ObjectVertex._(nextId, _graph); | 311 current = new ObjectVertex._(nextId, _graph); |
| 144 return true; | 312 return true; |
| 145 } | 313 } |
| 146 } | 314 } |
| 147 } | 315 } |
| 148 | 316 |
| 149 class _VerticesIterable extends IterableBase<ObjectVertex> { | 317 class _VerticesIterable extends IterableBase<ObjectVertex> { |
| 150 final ObjectGraph _graph; | 318 final ObjectGraph _graph; |
| 151 | 319 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 return this; | 393 return this; |
| 226 } | 394 } |
| 227 | 395 |
| 228 final List<ByteData> _chunks; | 396 final List<ByteData> _chunks; |
| 229 | 397 |
| 230 int _kObjectAlignment; | 398 int _kObjectAlignment; |
| 231 int _N; | 399 int _N; |
| 232 int _E; | 400 int _E; |
| 233 int _size; | 401 int _size; |
| 234 | 402 |
| 235 Map<int, int> _addrToId = new Map<int, int>(); | 403 AddressMapper _addrToId; |
| 236 | 404 |
| 237 // Indexed by node id, with id 0 representing invalid/uninitialized. | 405 // Indexed by node id, with id 0 representing invalid/uninitialized. |
| 238 Uint32List _positions; // Position of the node in the snapshot. | 406 Uint32List _positions; // Position of the node in the snapshot. |
| 239 Uint32List _postOrderOrdinals; // post-order index -> id | 407 Uint32List _postOrderOrdinals; // post-order index -> id |
| 240 Uint32List _postOrderIndices; // id -> post-order index | 408 Uint32List _postOrderIndices; // id -> post-order index |
| 241 Uint32List _firstPreds; // Offset into preds. | 409 Uint32List _firstPreds; // Offset into preds. |
| 242 Uint32List _preds; | 410 Uint32List _preds; |
| 243 Uint32List _doms; | 411 Uint32List _doms; |
| 244 Uint32List _retainedSizes; | 412 Uint32List _retainedSizes; |
| 245 | 413 |
| 246 void _buildPositions() { | 414 void _buildPositions() { |
| 247 var N = _N; | 415 var N = _N; |
| 248 var addrToId = _addrToId; | 416 var addrToId = new AddressMapper(N); |
| 249 | 417 |
| 250 var positions = new Uint32List(N + 1); | 418 var positions = new Uint32List(N + 1); |
| 251 | 419 |
| 252 var stream = new _ReadStream(_chunks); | 420 var stream = new _ReadStream(_chunks); |
| 253 _kObjectAlignment = stream.readUnsigned(); | 421 stream.readUnsigned(); |
| 422 _kObjectAlignment = stream.clampedUint32; | |
| 254 | 423 |
| 255 var id = 1; | 424 var id = 1; |
| 256 while (stream.pendingBytes > 0) { | 425 while (stream.pendingBytes > 0) { |
| 257 positions[id] = stream.position; | 426 positions[id] = stream.position; |
| 258 var addr = stream.readUnsigned(); | 427 stream.readUnsigned(); // addr |
| 259 stream.readUnsigned(); // shallowSize | 428 addrToId.put(stream.high, stream.mid, stream.low, id); |
| 260 stream.readUnsigned(); // cid | 429 stream.skipUnsigned(); // shallowSize |
| 261 addrToId[addr] = id; | 430 stream.skipUnsigned(); // cid |
| 262 | 431 |
| 263 var succAddr = stream.readUnsigned(); | 432 stream.readUnsigned(); |
| 264 while (succAddr != 0) { | 433 while (!stream.isZero) { |
| 265 succAddr = stream.readUnsigned(); | 434 stream.readUnsigned(); |
| 266 } | 435 } |
| 267 id++; | 436 id++; |
| 268 } | 437 } |
| 269 assert(id == (N + 1)); | 438 assert(id == (N + 1)); |
| 270 | 439 |
| 271 var root = addrToId[0]; | 440 var root = addrToId.get(0, 0, 0); |
| 272 assert(root == 1); | 441 assert(root == 1); |
| 273 | 442 |
| 443 _addrToId = addrToId; | |
| 274 _positions = positions; | 444 _positions = positions; |
| 275 } | 445 } |
| 276 | 446 |
| 277 void _buildPostOrder() { | 447 void _buildPostOrder() { |
| 278 var N = _N; | 448 var N = _N; |
| 279 var E = 0; | 449 var E = 0; |
| 280 var addrToId = _addrToId; | 450 var addrToId = _addrToId; |
| 281 var positions = _positions; | 451 var positions = _positions; |
| 282 | 452 |
| 283 var postOrderOrdinals = new Uint32List(N); | 453 var postOrderOrdinals = new Uint32List(N); |
| 284 var postOrderIndices = new Uint32List(N + 1); | 454 var postOrderIndices = new Uint32List(N + 1); |
| 285 var stackNodes = new Uint32List(N); | 455 var stackNodes = new Uint32List(N); |
| 286 var stackCurrentEdgePos = new Uint32List(N); | 456 var stackCurrentEdgePos = new Uint32List(N); |
| 287 | 457 |
| 288 var visited = new Uint8List(N + 1); | 458 var visited = new Uint8List(N + 1); |
| 289 var postOrderIndex = 0; | 459 var postOrderIndex = 0; |
| 290 var stackTop = 0; | 460 var stackTop = 0; |
| 291 var root = 1; | 461 var root = 1; |
| 292 | 462 |
| 293 stackNodes[0] = root; | 463 stackNodes[0] = root; |
| 294 | 464 |
| 295 var stream = new _ReadStream(_chunks); | 465 var stream = new _ReadStream(_chunks); |
| 296 stream.position = positions[root]; | 466 stream.position = positions[root]; |
| 297 stream.readUnsigned(); // addr | 467 stream.skipUnsigned(); // addr |
| 298 stream.readUnsigned(); // shallowSize | 468 stream.skipUnsigned(); // shallowSize |
| 299 stream.readUnsigned(); // cid | 469 stream.skipUnsigned(); // cid |
| 300 stackCurrentEdgePos[0] = stream.position; | 470 stackCurrentEdgePos[0] = stream.position; |
| 301 visited[root] = 1; | 471 visited[root] = 1; |
| 302 | 472 |
| 303 while (stackTop >= 0) { | 473 while (stackTop >= 0) { |
| 304 var n = stackNodes[stackTop]; | 474 var n = stackNodes[stackTop]; |
| 305 var edgePos = stackCurrentEdgePos[stackTop]; | 475 var edgePos = stackCurrentEdgePos[stackTop]; |
| 306 | 476 |
| 307 stream.position = edgePos; | 477 stream.position = edgePos; |
| 308 var childAddr = stream.readUnsigned(); | 478 stream.readUnsigned(); // childAddr |
| 309 if (childAddr != 0) { | 479 if (!stream.isZero) { |
| 310 stackCurrentEdgePos[stackTop] = stream.position; | 480 stackCurrentEdgePos[stackTop] = stream.position; |
| 311 var childId = addrToId[childAddr]; | 481 var childId = addrToId.get(stream.high, stream.mid, stream.low); |
| 312 if (childId == null) continue; // Reference to VM isolate's heap. | 482 if (childId == null) continue; // Reference to VM isolate's heap. |
| 313 E++; | 483 E++; |
| 314 if (visited[childId] == 1) continue; | 484 if (visited[childId] == 1) continue; |
| 315 | 485 |
| 316 stackTop++; | 486 stackTop++; |
| 317 stackNodes[stackTop] = childId; | 487 stackNodes[stackTop] = childId; |
| 318 | 488 |
| 319 stream.position = positions[childId]; | 489 stream.position = positions[childId]; |
| 320 stream.readUnsigned(); // addr | 490 stream.skipUnsigned(); // addr |
| 321 stream.readUnsigned(); // shallowSize | 491 stream.skipUnsigned(); // shallowSize |
| 322 stream.readUnsigned(); // cid | 492 stream.skipUnsigned(); // cid |
| 323 stackCurrentEdgePos[stackTop] = stream.position; // i.e., first edge | 493 stackCurrentEdgePos[stackTop] = stream.position; // i.e., first edge |
| 324 visited[childId] = 1; | 494 visited[childId] = 1; |
| 325 } else { | 495 } else { |
| 326 // Done with all children. | 496 // Done with all children. |
| 327 postOrderIndices[n] = postOrderIndex; | 497 postOrderIndices[n] = postOrderIndex; |
| 328 postOrderOrdinals[postOrderIndex++] = n; | 498 postOrderOrdinals[postOrderIndex++] = n; |
| 329 stackTop--; | 499 stackTop--; |
| 330 } | 500 } |
| 331 } | 501 } |
| 332 | 502 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 349 // + 1 because 0 is a sentinel | 519 // + 1 because 0 is a sentinel |
| 350 // + 1 so the number of predecessors can be found from the difference with | 520 // + 1 so the number of predecessors can be found from the difference with |
| 351 // the next node's offset. | 521 // the next node's offset. |
| 352 var numPreds = new Uint32List(N + 2); | 522 var numPreds = new Uint32List(N + 2); |
| 353 var preds = new Uint32List(E); | 523 var preds = new Uint32List(E); |
| 354 | 524 |
| 355 // Count predecessors of each node. | 525 // Count predecessors of each node. |
| 356 var stream = new _ReadStream(_chunks); | 526 var stream = new _ReadStream(_chunks); |
| 357 for (var i = 1; i <= N; i++) { | 527 for (var i = 1; i <= N; i++) { |
| 358 stream.position = positions[i]; | 528 stream.position = positions[i]; |
| 359 stream.readUnsigned(); // addr | 529 stream.skipUnsigned(); // addr |
| 360 stream.readUnsigned(); // shallowSize | 530 stream.skipUnsigned(); // shallowSize |
| 361 stream.readUnsigned(); // cid | 531 stream.skipUnsigned(); // cid |
| 362 var succAddr = stream.readUnsigned(); | 532 stream.readUnsigned(); // succAddr |
| 363 while (succAddr != 0) { | 533 while (!stream.isZero) { |
| 364 var succId = addrToId[succAddr]; | 534 var succId = addrToId.get(stream.high, stream.mid, stream.low); |
| 365 if (succId != null) { | 535 if (succId != null) { |
| 366 numPreds[succId]++; | 536 numPreds[succId]++; |
| 367 } else { | 537 } else { |
| 368 // Reference to VM isolate's heap. | 538 // Reference to VM isolate's heap. |
| 369 } | 539 } |
| 370 succAddr = stream.readUnsigned(); | 540 stream.readUnsigned(); // succAddr |
| 371 } | 541 } |
| 372 } | 542 } |
| 373 | 543 |
| 374 // Assign indices into predecessors array. | 544 // Assign indices into predecessors array. |
| 375 var firstPreds = numPreds; // Alias. | 545 var firstPreds = numPreds; // Alias. |
| 376 var nextPreds = new Uint32List(N + 1); | 546 var nextPreds = new Uint32List(N + 1); |
| 377 var predIndex = 0; | 547 var predIndex = 0; |
| 378 for (var i = 1; i <= N; i++) { | 548 for (var i = 1; i <= N; i++) { |
| 379 var thisPredIndex = predIndex; | 549 var thisPredIndex = predIndex; |
| 380 predIndex += numPreds[i]; | 550 predIndex += numPreds[i]; |
| 381 firstPreds[i] = thisPredIndex; | 551 firstPreds[i] = thisPredIndex; |
| 382 nextPreds[i] = thisPredIndex; | 552 nextPreds[i] = thisPredIndex; |
| 383 } | 553 } |
| 384 assert(predIndex == E); | 554 assert(predIndex == E); |
| 385 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. | 555 firstPreds[N + 1] = E; // Extra entry for cheap boundary detection. |
| 386 | 556 |
| 387 // Fill predecessors array. | 557 // Fill predecessors array. |
| 388 for (var i = 1; i <= N; i++) { | 558 for (var i = 1; i <= N; i++) { |
| 389 stream.position = positions[i]; | 559 stream.position = positions[i]; |
| 390 stream.readUnsigned(); // addr | 560 stream.skipUnsigned(); // addr |
| 391 stream.readUnsigned(); // shallowSize | 561 stream.skipUnsigned(); // shallowSize |
| 392 stream.readUnsigned(); // cid | 562 stream.skipUnsigned(); // cid |
| 393 var succAddr = stream.readUnsigned(); | 563 stream.readUnsigned(); // succAddr |
| 394 while (succAddr != 0) { | 564 while (!stream.isZero) { |
| 395 var succId = addrToId[succAddr]; | 565 var succId = addrToId.get(stream.high, stream.mid, stream.low); |
| 396 if (succId != null) { | 566 if (succId != null) { |
| 397 var predIndex = nextPreds[succId]++; | 567 var predIndex = nextPreds[succId]++; |
| 398 preds[predIndex] = i; | 568 preds[predIndex] = i; |
| 399 } else { | 569 } else { |
| 400 // Reference to VM isolate's heap. | 570 // Reference to VM isolate's heap. |
| 401 } | 571 } |
| 402 succAddr = stream.readUnsigned(); | 572 stream.readUnsigned(); // succAddr |
| 403 } | 573 } |
| 404 } | 574 } |
| 405 | 575 |
| 406 _firstPreds = firstPreds; | 576 _firstPreds = firstPreds; |
| 407 _preds = preds; | 577 _preds = preds; |
| 408 } | 578 } |
| 409 | 579 |
| 410 // "A Simple, Fast Dominance Algorithm" | 580 // "A Simple, Fast Dominance Algorithm" |
| 411 // Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy | 581 // Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy |
| 412 void _buildDominators() { | 582 void _buildDominators() { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 var size = 0; | 661 var size = 0; |
| 492 var positions = _positions; | 662 var positions = _positions; |
| 493 var postOrderOrdinals = _postOrderOrdinals; | 663 var postOrderOrdinals = _postOrderOrdinals; |
| 494 var doms = _doms; | 664 var doms = _doms; |
| 495 var retainedSizes = new Uint32List(N + 1); | 665 var retainedSizes = new Uint32List(N + 1); |
| 496 | 666 |
| 497 // Start with retained size as shallow size. | 667 // Start with retained size as shallow size. |
| 498 var reader = new _ReadStream(_chunks); | 668 var reader = new _ReadStream(_chunks); |
| 499 for (var i = 1; i <= N; i++) { | 669 for (var i = 1; i <= N; i++) { |
| 500 reader.position = positions[i]; | 670 reader.position = positions[i]; |
| 501 reader.readUnsigned(); // addr | 671 reader.skipUnsigned(); // addr |
| 502 var shallowSize = reader.readUnsigned(); | 672 reader.readUnsigned(); // shallowSize |
| 673 var shallowSize = reader.clampedUint32; | |
| 503 retainedSizes[i] = shallowSize; | 674 retainedSizes[i] = shallowSize; |
| 504 size += shallowSize; | 675 size += shallowSize; |
| 505 } | 676 } |
| 506 | 677 |
| 507 // In post order (bottom up), add retained size to dominator's retained | 678 // In post order (bottom up), add retained size to dominator's retained |
| 508 // size, skipping root. | 679 // size, skipping root. |
| 509 for (var o = 0; o < (N - 1); o++) { | 680 for (var o = 0; o < (N - 1); o++) { |
| 510 var i = postOrderOrdinals[o]; | 681 var i = postOrderOrdinals[o]; |
| 511 assert(i != 1); | 682 assert(i != 1); |
| 512 retainedSizes[doms[i]] += retainedSizes[i]; | 683 retainedSizes[doms[i]] += retainedSizes[i]; |
| 513 } | 684 } |
| 514 | 685 |
| 515 _retainedSizes = retainedSizes; | 686 _retainedSizes = retainedSizes; |
| 516 _size = size; | 687 _size = size; |
| 517 } | 688 } |
| 518 } | 689 } |
| OLD | NEW |