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 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 static const int maxUnsignedDataPerByte = byteMask; | 214 static const int maxUnsignedDataPerByte = byteMask; |
| 215 } | 215 } |
| 216 | 216 |
| 217 class ObjectVertex { | 217 class ObjectVertex { |
| 218 // 0 represents invalid/uninitialized, 1 is the root. | 218 // 0 represents invalid/uninitialized, 1 is the root. |
| 219 final int _id; | 219 final int _id; |
| 220 final ObjectGraph _graph; | 220 final ObjectGraph _graph; |
| 221 | 221 |
| 222 ObjectVertex._(this._id, this._graph); | 222 ObjectVertex._(this._id, this._graph); |
| 223 | 223 |
| 224 bool get isRoot => _id == 1; | 224 bool get isRoot => ROOT == _id; |
| 225 | 225 |
| 226 bool operator ==(other) => _id == other._id && _graph == other._graph; | 226 bool operator ==(other) => _id == other._id && _graph == other._graph; |
| 227 int get hashCode => _id; | 227 int get hashCode => _id; |
| 228 | 228 |
| 229 int get retainedSize => _graph._retainedSizes[_id]; | 229 int get retainedSize => _graph._retainedSizes[_id]; |
| 230 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); | 230 ObjectVertex get dominator => new ObjectVertex._(_graph._doms[_id], _graph); |
| 231 | 231 |
| 232 int get shallowSize => _graph._shallowSizes[_id]; | 232 int get shallowSize => _graph._shallowSizes[_id]; |
| 233 int get vmCid => _graph._cids[_id]; | 233 int get vmCid => _graph._cids[_id]; |
| 234 | 234 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 265 return strAddr; | 265 return strAddr; |
| 266 } | 266 } |
| 267 | 267 |
| 268 List<ObjectVertex> dominatorTreeChildren() { | 268 List<ObjectVertex> dominatorTreeChildren() { |
| 269 var N = _graph._N; | 269 var N = _graph._N; |
| 270 var doms = _graph._doms; | 270 var doms = _graph._doms; |
| 271 | 271 |
| 272 var parentId = _id; | 272 var parentId = _id; |
| 273 var domChildren = []; | 273 var domChildren = []; |
| 274 | 274 |
| 275 for (var childId = 1; childId <= N; childId++) { | 275 for (var childId = ROOT; childId <= N; childId++) { |
| 276 if (doms[childId] == parentId) { | 276 if (doms[childId] == parentId) { |
| 277 domChildren.add(new ObjectVertex._(childId, _graph)); | 277 domChildren.add(new ObjectVertex._(childId, _graph)); |
| 278 } | 278 } |
| 279 } | 279 } |
| 280 | 280 |
| 281 return domChildren; | 281 return domChildren; |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 | 284 |
| 285 // A node in the dominator tree where siblings with the same class are merged. | |
| 286 // That is, a set of objects with the same cid whose parent chains in the | |
| 287 // dominator tree have the same cids at each level. [id_] is the representative | |
| 288 // object of this set. The other members of the set are found by walking the | |
| 289 // mergedDomNext links until finding the sentinel node or a node with a | |
| 290 // different class. | |
| 291 class MergedObjectVertex { | |
| 292 final int _id; | |
| 293 final ObjectGraph _graph; | |
| 294 | |
| 295 MergedObjectVertex._(this._id, this._graph); | |
| 296 | |
| 297 bool get isRoot => ROOT == _id; | |
| 298 | |
| 299 bool operator ==(other) => _id == other._id && _graph == other._graph; | |
| 300 int get hashCode => _id; | |
| 301 | |
| 302 int get vmCid => _graph._cids[_id]; | |
| 303 | |
| 304 int get shallowSize { | |
| 305 var cids = _graph._cids; | |
| 306 var size = 0; | |
| 307 var sibling = _id; | |
| 308 while (sibling != SENTINEL && | |
| 309 cids[sibling] == cids[_id]) { | |
| 310 size += _graph._shallowSizes[sibling]; | |
| 311 sibling = _graph._mergedDomNext[sibling]; | |
| 312 } | |
| 313 return size; | |
| 314 } | |
| 315 int get retainedSize { | |
| 316 var cids = _graph._cids; | |
| 317 var size = 0; | |
| 318 var sibling = _id; | |
| 319 while (sibling != SENTINEL && | |
| 320 cids[sibling] == cids[_id]) { | |
| 321 size += _graph._retainedSizes[sibling]; | |
| 322 sibling = _graph._mergedDomNext[sibling]; | |
| 323 } | |
| 324 return size; | |
| 325 } | |
| 326 int get instanceCount { | |
| 327 var cids = _graph._cids; | |
| 328 var count = 0; | |
| 329 var sibling = _id; | |
| 330 while (sibling != SENTINEL && | |
| 331 cids[sibling] == cids[_id]) { | |
| 332 count++; | |
| 333 sibling = _graph._mergedDomNext[sibling]; | |
| 334 } | |
| 335 return count; | |
| 336 } | |
| 337 | |
| 338 List<ObjectVertex> dominatorTreeChildren() { | |
| 339 var next = _graph._mergedDomNext; | |
| 340 var cids = _graph._cids; | |
| 341 | |
| 342 var domChildren = []; | |
| 343 var prev = SENTINEL; | |
| 344 var child = _graph._mergedDomHead[_id]; | |
| 345 // Walk the list of children and look for the representative objects, i.e. | |
| 346 // the first sibling of each cid. | |
| 347 while (child != SENTINEL) { | |
| 348 if (prev == SENTINEL || | |
| 349 cids[prev] != cids[child]) { | |
| 350 domChildren.add(new MergedObjectVertex._(child, _graph)); | |
| 351 } | |
| 352 prev = child; | |
| 353 child = next[child]; | |
| 354 } | |
| 355 | |
| 356 return domChildren; | |
| 357 } | |
| 358 } | |
| 359 | |
| 285 class _SuccessorsIterable extends IterableBase<ObjectVertex> { | 360 class _SuccessorsIterable extends IterableBase<ObjectVertex> { |
| 286 final ObjectGraph _graph; | 361 final ObjectGraph _graph; |
| 287 final int _id; | 362 final int _id; |
| 288 | 363 |
| 289 _SuccessorsIterable(this._graph, this._id); | 364 _SuccessorsIterable(this._graph, this._id); |
| 290 | 365 |
| 291 Iterator<ObjectVertex> get iterator => new _SuccessorsIterator(_graph, _id); | 366 Iterator<ObjectVertex> get iterator => new _SuccessorsIterator(_graph, _id); |
| 292 } | 367 } |
| 293 | 368 |
| 294 class _SuccessorsIterator implements Iterator<ObjectVertex> { | 369 class _SuccessorsIterator implements Iterator<ObjectVertex> { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 | 404 |
| 330 _VerticesIterator(this._graph); | 405 _VerticesIterator(this._graph); |
| 331 | 406 |
| 332 bool moveNext() { | 407 bool moveNext() { |
| 333 if (_nextId == _graph._N) return false; | 408 if (_nextId == _graph._N) return false; |
| 334 current = new ObjectVertex._(_nextId++, _graph); | 409 current = new ObjectVertex._(_nextId++, _graph); |
| 335 return true; | 410 return true; |
| 336 } | 411 } |
| 337 } | 412 } |
| 338 | 413 |
| 414 const ROOT = 1; | |
|
Cutch
2016/11/15 14:50:42
move these to the top and add doc comments
rmacnak
2016/11/15 17:40:28
Done.
| |
| 415 const SENTINEL = 0; | |
| 416 | |
| 339 class ObjectGraph { | 417 class ObjectGraph { |
| 340 ObjectGraph(List<ByteData> chunks, int nodeCount) | 418 ObjectGraph(List<ByteData> chunks, int nodeCount) |
| 341 : this._chunks = chunks, | 419 : this._chunks = chunks, |
| 342 this._N = nodeCount; | 420 this._N = nodeCount; |
| 343 | 421 |
| 344 int get size => _size; | 422 int get size => _size; |
| 345 int get vertexCount => _N; | 423 int get vertexCount => _N; |
| 346 int get edgeCount => _E; | 424 int get edgeCount => _E; |
| 347 | 425 |
| 348 ObjectVertex get root => new ObjectVertex._(1, this); | 426 ObjectVertex get root => new ObjectVertex._(ROOT, this); |
| 427 MergedObjectVertex get mergedRoot => new MergedObjectVertex._(ROOT, this); | |
| 349 Iterable<ObjectVertex> get vertices => new _VerticesIterable(this); | 428 Iterable<ObjectVertex> get vertices => new _VerticesIterable(this); |
| 350 | 429 |
| 351 Iterable<ObjectVertex> getMostRetained({int classId, int limit}) { | 430 Iterable<ObjectVertex> getMostRetained({int classId, int limit}) { |
| 352 List<ObjectVertex> _mostRetained = | 431 List<ObjectVertex> _mostRetained = |
| 353 new List<ObjectVertex>.from(vertices.where((u) => !u.isRoot)); | 432 new List<ObjectVertex>.from(vertices.where((u) => !u.isRoot)); |
| 354 _mostRetained.sort((u, v) => v.retainedSize - u.retainedSize); | 433 _mostRetained.sort((u, v) => v.retainedSize - u.retainedSize); |
| 355 | 434 |
| 356 var result = _mostRetained; | 435 var result = _mostRetained; |
| 357 if (classId != null) { | 436 if (classId != null) { |
| 358 result = result.where((u) => u.vmCid == classId); | 437 result = result.where((u) => u.vmCid == classId); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 374 | 453 |
| 375 controller.add(["Remapping $_E references...", 15.0]); | 454 controller.add(["Remapping $_E references...", 15.0]); |
| 376 await new Future(() => _remapEdges()); | 455 await new Future(() => _remapEdges()); |
| 377 | 456 |
| 378 _addrToId = null; | 457 _addrToId = null; |
| 379 _chunks = null; | 458 _chunks = null; |
| 380 | 459 |
| 381 controller.add(["Finding depth-first order...", 30.0]); | 460 controller.add(["Finding depth-first order...", 30.0]); |
| 382 await new Future(() => _dfs()); | 461 await new Future(() => _dfs()); |
| 383 | 462 |
| 384 controller.add(["Finding predecessors...", 45.0]); | 463 controller.add(["Finding predecessors...", 40.0]); |
| 385 await new Future(() => _buildPredecessors()); | 464 await new Future(() => _buildPredecessors()); |
| 386 | 465 |
| 387 controller.add(["Finding dominators...", 60.0]); | 466 controller.add(["Finding dominators...", 50.0]); |
| 388 await new Future(() => _buildDominators()); | 467 await new Future(() => _buildDominators()); |
| 389 | 468 |
| 390 _firstPreds = null; | 469 _firstPreds = null; |
| 391 _preds = null; | 470 _preds = null; |
| 392 | 471 |
| 393 _semi = null; | 472 _semi = null; |
| 394 _parent = null; | 473 _parent = null; |
| 395 | 474 |
| 396 controller.add(["Finding retained sizes...", 75.0]); | 475 controller.add(["Finding retained sizes...", 60.0]); |
| 397 await new Future(() => _calculateRetainedSizes()); | 476 await new Future(() => _calculateRetainedSizes()); |
| 398 | 477 |
| 399 _vertex = null; | 478 _vertex = null; |
| 400 | 479 |
| 401 controller.add(["Loaded", 100.0]); | 480 controller.add(["Linking dominator tree children...", 70.0]); |
| 481 await new Future(() => _linkDominatorChildren()); | |
| 482 | |
| 483 controller.add(["Sorting dominator tree children...", 80.0]); | |
| 484 await new Future(() => _sortDominatorChildren()); | |
| 485 | |
| 486 controller.add(["Merging dominator tree siblings...", 90.0]); | |
| 487 await new Future(() => _mergeDominatorSiblings()); | |
| 488 | |
| 489 controller.add(["Processed", 100.0]); | |
| 402 controller.close(); | 490 controller.close(); |
| 403 }()); | 491 }()); |
| 404 return controller.stream; | 492 return controller.stream; |
| 405 } | 493 } |
| 406 | 494 |
| 407 List<ByteData> _chunks; | 495 List<ByteData> _chunks; |
| 408 | 496 |
| 409 int _kObjectAlignment; | 497 int _kObjectAlignment; |
| 410 int _N; | 498 int _N; |
| 411 int _E; | 499 int _E; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 424 AddressMapper _addrToId; | 512 AddressMapper _addrToId; |
| 425 Uint32List _vertex; | 513 Uint32List _vertex; |
| 426 Uint32List _parent; | 514 Uint32List _parent; |
| 427 Uint32List _semi; | 515 Uint32List _semi; |
| 428 Uint32List _firstPreds; // Offset into preds. | 516 Uint32List _firstPreds; // Offset into preds. |
| 429 Uint32List _preds; | 517 Uint32List _preds; |
| 430 | 518 |
| 431 // Outputs. | 519 // Outputs. |
| 432 Uint32List _doms; | 520 Uint32List _doms; |
| 433 Uint32List _retainedSizes; | 521 Uint32List _retainedSizes; |
| 522 Uint32List _mergedDomHead; | |
| 523 Uint32List _mergedDomNext; | |
| 434 | 524 |
| 435 void _remapNodes() { | 525 void _remapNodes() { |
| 436 var N = _N; | 526 var N = _N; |
| 437 var E = 0; | 527 var E = 0; |
| 438 var addrToId = new AddressMapper(N); | 528 var addrToId = new AddressMapper(N); |
| 439 | 529 |
| 440 var addressesHigh = new Uint32List(N + 1); | 530 var addressesHigh = new Uint32List(N + 1); |
| 441 var addressesLow = new Uint32List(N + 1); | 531 var addressesLow = new Uint32List(N + 1); |
| 442 var shallowSizes = new Uint32List(N + 1); | 532 var shallowSizes = new Uint32List(N + 1); |
| 443 var cids = new Uint16List(N + 1); | 533 var cids = new Uint16List(N + 1); |
| 444 | 534 |
| 445 var stream = new ReadStream(_chunks); | 535 var stream = new ReadStream(_chunks); |
| 446 stream.readUnsigned(); | 536 stream.readUnsigned(); |
| 447 _kObjectAlignment = stream.clampedUint32; | 537 _kObjectAlignment = stream.clampedUint32; |
| 448 | 538 |
| 449 var id = 1; | 539 var id = ROOT; |
| 450 while (stream.pendingBytes > 0) { | 540 while (stream.pendingBytes > 0) { |
| 451 stream.readUnsigned(); // addr | 541 stream.readUnsigned(); // addr |
| 452 addrToId.put(stream.high, stream.mid, stream.low, id); | 542 addrToId.put(stream.high, stream.mid, stream.low, id); |
| 453 addressesHigh[id] = stream.highUint32; | 543 addressesHigh[id] = stream.highUint32; |
| 454 addressesLow[id] = stream.lowUint32; | 544 addressesLow[id] = stream.lowUint32; |
| 455 stream.readUnsigned(); // shallowSize | 545 stream.readUnsigned(); // shallowSize |
| 456 shallowSizes[id] = stream.clampedUint32; | 546 shallowSizes[id] = stream.clampedUint32; |
| 457 stream.readUnsigned(); // cid | 547 stream.readUnsigned(); // cid |
| 458 cids[id] = stream.clampedUint32; | 548 cids[id] = stream.clampedUint32; |
| 459 | 549 |
| 460 stream.readUnsigned(); | 550 stream.readUnsigned(); |
| 461 while (!stream.isZero) { | 551 while (!stream.isZero) { |
| 462 E++; | 552 E++; |
| 463 stream.readUnsigned(); | 553 stream.readUnsigned(); |
| 464 } | 554 } |
| 465 id++; | 555 id++; |
| 466 } | 556 } |
| 467 assert(id == (N + 1)); | 557 assert(id == (N + 1)); |
| 468 | 558 |
| 469 var root = addrToId.get(0, 0, 0); | 559 assert(ROOT == addrToId.get(0, 0, 0)); |
| 470 assert(root == 1); | |
| 471 | 560 |
| 472 _E = E; | 561 _E = E; |
| 473 _addrToId = addrToId; | 562 _addrToId = addrToId; |
| 474 _addressesLow = addressesLow; | 563 _addressesLow = addressesLow; |
| 475 _addressesHigh = addressesHigh; | 564 _addressesHigh = addressesHigh; |
| 476 _shallowSizes = shallowSizes; | 565 _shallowSizes = shallowSizes; |
| 477 _cids = cids; | 566 _cids = cids; |
| 478 } | 567 } |
| 479 | 568 |
| 480 void _remapEdges() { | 569 void _remapEdges() { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 | 616 |
| 528 var stackNodes = new Uint32List(N); | 617 var stackNodes = new Uint32List(N); |
| 529 var stackCurrentEdgePos = new Uint32List(N); | 618 var stackCurrentEdgePos = new Uint32List(N); |
| 530 | 619 |
| 531 var vertex = new Uint32List(N + 1); | 620 var vertex = new Uint32List(N + 1); |
| 532 var semi = new Uint32List(N + 1); | 621 var semi = new Uint32List(N + 1); |
| 533 var parent = new Uint32List(N + 1); | 622 var parent = new Uint32List(N + 1); |
| 534 var dfsNumber = 0; | 623 var dfsNumber = 0; |
| 535 | 624 |
| 536 var stackTop = 0; | 625 var stackTop = 0; |
| 537 var root = 1; | |
| 538 | 626 |
| 539 // Push root. | 627 // Push root. |
| 540 stackNodes[0] = root; | 628 stackNodes[0] = ROOT; |
| 541 stackCurrentEdgePos[0] = firstSuccs[root]; | 629 stackCurrentEdgePos[0] = firstSuccs[ROOT]; |
| 542 | 630 |
| 543 while (stackTop >= 0) { | 631 while (stackTop >= 0) { |
| 544 var v = stackNodes[stackTop]; | 632 var v = stackNodes[stackTop]; |
| 545 var edgePos = stackCurrentEdgePos[stackTop]; | 633 var edgePos = stackCurrentEdgePos[stackTop]; |
| 546 | 634 |
| 547 if (semi[v] == 0) { | 635 if (semi[v] == 0) { |
| 548 // First visit. | 636 // First visit. |
| 549 dfsNumber++; | 637 dfsNumber++; |
| 550 semi[v] = dfsNumber; | 638 semi[v] = dfsNumber; |
| 551 vertex[dfsNumber] = v; | 639 vertex[dfsNumber] = v; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 564 stackNodes[stackTop] = childId; | 652 stackNodes[stackTop] = childId; |
| 565 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; | 653 stackCurrentEdgePos[stackTop] = firstSuccs[childId]; |
| 566 } | 654 } |
| 567 } else { | 655 } else { |
| 568 // Done with all children. | 656 // Done with all children. |
| 569 stackTop--; | 657 stackTop--; |
| 570 } | 658 } |
| 571 } | 659 } |
| 572 | 660 |
| 573 assert(dfsNumber == N); | 661 assert(dfsNumber == N); |
| 574 for (var i = 1; i <= N; i++) { | 662 for (var i = ROOT; i <= N; i++) { |
| 575 assert(semi[i] != 0); | 663 assert(semi[i] != SENTINEL); |
| 576 } | 664 } |
| 577 assert(parent[1] == 0); | 665 assert(parent[ROOT] == SENTINEL); |
| 578 for (var i = 2; i <= N; i++) { | 666 for (var i = ROOT + 1; i <= N; i++) { |
| 579 assert(parent[i] != 0); | 667 assert(parent[i] != SENTINEL); |
| 580 } | 668 } |
| 581 | 669 |
| 582 _vertex = vertex; | 670 _vertex = vertex; |
| 583 _semi = semi; | 671 _semi = semi; |
| 584 _parent = parent; | 672 _parent = parent; |
| 585 } | 673 } |
| 586 | 674 |
| 587 void _buildPredecessors() { | 675 void _buildPredecessors() { |
| 588 var N = _N; | 676 var N = _N; |
| 589 var E = _E; | 677 var E = _E; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 preds[predIndex] = i; | 717 preds[predIndex] = i; |
| 630 } | 718 } |
| 631 } | 719 } |
| 632 | 720 |
| 633 _firstPreds = firstPreds; | 721 _firstPreds = firstPreds; |
| 634 _preds = preds; | 722 _preds = preds; |
| 635 } | 723 } |
| 636 | 724 |
| 637 static int _eval(int v, Uint32List ancestor, Uint32List semi, | 725 static int _eval(int v, Uint32List ancestor, Uint32List semi, |
| 638 Uint32List label, Uint32List stackNode, Uint8List stackState) { | 726 Uint32List label, Uint32List stackNode, Uint8List stackState) { |
| 639 if (ancestor[v] == 0) { | 727 if (ancestor[v] == SENTINEL) { |
| 640 return label[v]; | 728 return label[v]; |
| 641 } else { | 729 } else { |
| 642 { | 730 { |
| 643 // Inlined 'compress' with an explicit stack to prevent JS stack | 731 // Inlined 'compress' with an explicit stack to prevent JS stack |
| 644 // overflow. | 732 // overflow. |
| 645 var top = 0; | 733 var top = 0; |
| 646 stackNode[top] = v; | 734 stackNode[top] = v; |
| 647 stackState[top] = 0; | 735 stackState[top] = 0; |
| 648 while (top >= 0) { | 736 while (top >= 0) { |
| 649 var v = stackNode[top]; | 737 var v = stackNode[top]; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 // in a Flowgraph." | 800 // in a Flowgraph." |
| 713 void _buildDominators() { | 801 void _buildDominators() { |
| 714 var N = _N; | 802 var N = _N; |
| 715 | 803 |
| 716 var vertex = _vertex; | 804 var vertex = _vertex; |
| 717 var semi = _semi; | 805 var semi = _semi; |
| 718 var parent = _parent; | 806 var parent = _parent; |
| 719 var firstPreds = _firstPreds; | 807 var firstPreds = _firstPreds; |
| 720 var preds = _preds; | 808 var preds = _preds; |
| 721 | 809 |
| 722 var root = 1; | |
| 723 var dom = new Uint32List(N + 1); | 810 var dom = new Uint32List(N + 1); |
| 724 | 811 |
| 725 var ancestor = new Uint32List(N + 1); | 812 var ancestor = new Uint32List(N + 1); |
| 726 var label = new Uint32List(N + 1); | 813 var label = new Uint32List(N + 1); |
| 727 for (var i = 1; i <= N; i++) { | 814 for (var i = 1; i <= N; i++) { |
| 728 label[i] = i; | 815 label[i] = i; |
| 729 } | 816 } |
| 730 var buckets = new List(N + 1); | 817 var buckets = new List(N + 1); |
| 731 var child = new Uint32List(N + 1); | 818 var child = new Uint32List(N + 1); |
| 732 var size = new Uint32List(N + 1); | 819 var size = new Uint32List(N + 1); |
| 733 for (var i = 1; i <= N; i++) { | 820 for (var i = 1; i <= N; i++) { |
| 734 size[i] = 1; | 821 size[i] = 1; |
| 735 } | 822 } |
| 736 var stackNode = new Uint32List(N + 1); | 823 var stackNode = new Uint32List(N + 1); |
| 737 var stackState = new Uint8List(N + 1); | 824 var stackState = new Uint8List(N + 1); |
| 738 | 825 |
| 739 for (var i = N; i > 1; i--) { | 826 for (var i = N; i > 1; i--) { |
| 740 var w = vertex[i]; | 827 var w = vertex[i]; |
| 741 assert(w != root); | 828 assert(w != ROOT); |
| 742 | 829 |
| 743 // Lengauer & Tarjan Step 2. | 830 // Lengauer & Tarjan Step 2. |
| 744 var startPred = firstPreds[w]; | 831 var startPred = firstPreds[w]; |
| 745 var limitPred = firstPreds[w + 1]; | 832 var limitPred = firstPreds[w + 1]; |
| 746 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { | 833 for (var predIndex = startPred; predIndex < limitPred; predIndex++) { |
| 747 var v = preds[predIndex]; | 834 var v = preds[predIndex]; |
| 748 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 835 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
| 749 if (semi[u] < semi[w]) { | 836 if (semi[u] < semi[w]) { |
| 750 semi[w] = semi[u]; | 837 semi[w] = semi[u]; |
| 751 } | 838 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 764 tmp = parent[w]; | 851 tmp = parent[w]; |
| 765 var bucket = buckets[tmp]; | 852 var bucket = buckets[tmp]; |
| 766 buckets[tmp] = null; | 853 buckets[tmp] = null; |
| 767 if (bucket != null) { | 854 if (bucket != null) { |
| 768 for (var v in bucket) { | 855 for (var v in bucket) { |
| 769 var u = _eval(v, ancestor, semi, label, stackNode, stackState); | 856 var u = _eval(v, ancestor, semi, label, stackNode, stackState); |
| 770 dom[v] = semi[u] < semi[v] ? u : parent[w]; | 857 dom[v] = semi[u] < semi[v] ? u : parent[w]; |
| 771 } | 858 } |
| 772 } | 859 } |
| 773 } | 860 } |
| 774 for (var i = 1; i <= N; i++) { | 861 for (var i = ROOT; i <= N; i++) { |
| 775 assert(buckets[i] == null); | 862 assert(buckets[i] == null); |
| 776 } | 863 } |
| 777 // Lengauer & Tarjan Step 4. | 864 // Lengauer & Tarjan Step 4. |
| 778 for (var i = 2; i <= N; i++) { | 865 for (var i = 2; i <= N; i++) { |
| 779 var w = vertex[i]; | 866 var w = vertex[i]; |
| 780 if (dom[w] != vertex[semi[w]]) { | 867 if (dom[w] != vertex[semi[w]]) { |
| 781 dom[w] = dom[dom[w]]; | 868 dom[w] = dom[dom[w]]; |
| 782 } | 869 } |
| 783 } | 870 } |
| 784 | 871 |
| 785 _doms = dom; | 872 _doms = dom; |
| 786 } | 873 } |
| 787 | 874 |
| 788 void _calculateRetainedSizes() { | 875 void _calculateRetainedSizes() { |
| 789 var N = _N; | 876 var N = _N; |
| 790 | 877 |
| 791 var size = 0; | 878 var size = 0; |
| 792 var shallowSizes = _shallowSizes; | 879 var shallowSizes = _shallowSizes; |
| 793 var vertex = _vertex; | 880 var vertex = _vertex; |
| 794 var doms = _doms; | 881 var doms = _doms; |
| 795 | 882 |
| 796 // Sum shallow sizes. | 883 // Sum shallow sizes. |
| 797 for (var i = 1; i < N; i++) { | 884 for (var i = ROOT; i < N; i++) { |
| 798 size += shallowSizes[i]; | 885 size += shallowSizes[i]; |
| 799 } | 886 } |
| 800 | 887 |
| 801 // Start with retained size as shallow size. | 888 // Start with retained size as shallow size. |
| 802 var retainedSizes = new Uint32List.fromList(shallowSizes); | 889 var retainedSizes = new Uint32List.fromList(shallowSizes); |
| 803 | 890 |
| 804 // In post order (bottom up), add retained size to dominator's retained | 891 // In post order (bottom up), add retained size to dominator's retained |
| 805 // size, skipping root. | 892 // size, skipping root. |
| 806 for (var i = N; i > 1; i--) { | 893 for (var i = N; i > 1; i--) { |
| 807 var v = vertex[i]; | 894 var v = vertex[i]; |
| 808 assert(v != 1); | 895 assert(v != ROOT); |
| 809 retainedSizes[doms[i]] += retainedSizes[i]; | 896 retainedSizes[doms[i]] += retainedSizes[i]; |
| 810 } | 897 } |
| 811 | 898 |
| 812 _retainedSizes = retainedSizes; | 899 _retainedSizes = retainedSizes; |
| 813 _size = size; | 900 _size = size; |
| 814 } | 901 } |
| 902 | |
| 903 // Build linked lists of the children for each node in the dominator tree. | |
| 904 void _linkDominatorChildren() { | |
| 905 var N = _N; | |
| 906 var doms = _doms; | |
| 907 var head = new Uint32List(N + 1); | |
| 908 var next = new Uint32List(N + 1); | |
| 909 | |
| 910 for (var child = ROOT; child <= N; child++) { | |
| 911 var parent = doms[child]; | |
| 912 next[child] = head[parent]; | |
| 913 head[parent] = child; | |
| 914 } | |
| 915 | |
| 916 _mergedDomHead = head; | |
| 917 _mergedDomNext = next; | |
| 918 } | |
| 919 | |
| 920 // Merge the given lists according to the given key in ascending order. | |
| 921 // Returns the head of the merged list. | |
| 922 static int _mergeSorted(int head1, int head2, | |
| 923 Uint32List next, Uint16List key) { | |
| 924 var head = head1; | |
| 925 var beforeInsert = SENTINEL; | |
| 926 var afterInsert = head1; | |
| 927 var startInsert = head2; | |
| 928 | |
| 929 while (startInsert != SENTINEL) { | |
| 930 while ((afterInsert != SENTINEL) && | |
| 931 (key[afterInsert] <= key[startInsert])) { | |
| 932 beforeInsert = afterInsert; | |
| 933 afterInsert = next[beforeInsert]; | |
| 934 } | |
| 935 | |
| 936 var endInsert = startInsert; | |
| 937 var peek = next[endInsert]; | |
| 938 | |
| 939 while ((peek != SENTINEL) && (key[peek] < key[afterInsert])) { | |
| 940 endInsert = peek; | |
| 941 peek = next[endInsert]; | |
| 942 } | |
| 943 assert(endInsert != SENTINEL); | |
| 944 | |
| 945 if (beforeInsert == SENTINEL) { | |
| 946 head = startInsert; | |
| 947 } else { | |
| 948 next[beforeInsert] = startInsert; | |
| 949 } | |
| 950 next[endInsert] = afterInsert; | |
| 951 | |
| 952 startInsert = peek; | |
| 953 beforeInsert = endInsert; | |
| 954 } | |
| 955 | |
| 956 return head; | |
| 957 } | |
| 958 | |
| 959 void _sortDominatorChildren() { | |
| 960 var N = _N; | |
| 961 var cids = _cids; | |
| 962 var head = _mergedDomHead; | |
| 963 var next = _mergedDomNext; | |
| 964 | |
| 965 // Returns the new head of the sorted list. | |
| 966 int sort(int head) { | |
| 967 if (head == SENTINEL) return SENTINEL; | |
| 968 if (next[head] == SENTINEL) return head; | |
| 969 | |
| 970 // Find the middle of the list. | |
| 971 int head1 = head; | |
| 972 int slow = head; | |
| 973 int fast = head; | |
| 974 while (next[fast] != SENTINEL && | |
| 975 next[next[fast]] != SENTINEL) { | |
| 976 slow = next[slow]; | |
| 977 fast = next[next[fast]]; | |
| 978 } | |
| 979 | |
| 980 // Split the list in half. | |
| 981 int head2 = next[slow]; | |
| 982 next[slow] = SENTINEL; | |
| 983 | |
| 984 // Recursively sort the sublists and merge. | |
| 985 assert(head1 != head2); | |
| 986 int newHead1 = sort(head1); | |
| 987 int newHead2 = sort(head2); | |
| 988 return _mergeSorted(newHead1, newHead2, next, cids); | |
| 989 } | |
| 990 | |
| 991 // Sort all list of dominator tree children by cid. | |
| 992 for (var parent = ROOT; parent <= N; parent++) { | |
| 993 head[parent] = sort(head[parent]); | |
| 994 } | |
| 995 } | |
| 996 | |
| 997 void _mergeDominatorSiblings() { | |
| 998 var N = _N; | |
| 999 var cids = _cids; | |
| 1000 var head = _mergedDomHead; | |
| 1001 var next = _mergedDomNext; | |
| 1002 var workStack = new Uint32List(N); | |
| 1003 var workStackTop = 0; | |
| 1004 | |
| 1005 mergeChildrenAndSort(var parent1, var end) { | |
| 1006 assert(parent1 != SENTINEL); | |
| 1007 if (next[parent1] == end) return; | |
| 1008 | |
| 1009 // Find the middle of the list. | |
| 1010 int cid = cids[parent1]; | |
| 1011 int slow = parent1; | |
| 1012 int fast = parent1; | |
| 1013 while (next[fast] != end && | |
| 1014 next[next[fast]] != end) { | |
| 1015 slow = next[slow]; | |
| 1016 fast = next[next[fast]]; | |
| 1017 } | |
| 1018 | |
| 1019 int parent2 = next[slow]; | |
| 1020 | |
| 1021 assert(parent2 != SENTINEL); | |
| 1022 assert(parent1 != parent2); | |
| 1023 assert(cids[parent1] == cids[parent2]); | |
| 1024 | |
| 1025 // Recursively sort the sublists. | |
| 1026 mergeChildrenAndSort(parent1, parent2); | |
| 1027 mergeChildrenAndSort(parent2, end); | |
| 1028 | |
| 1029 // Merge sorted sublists. | |
| 1030 head[parent1] = _mergeSorted(head[parent1], head[parent2], next, cids); | |
| 1031 | |
| 1032 // Children moved to parent1. | |
| 1033 head[parent2] = SENTINEL; | |
| 1034 } | |
| 1035 | |
| 1036 // Push root. | |
| 1037 workStack[workStackTop++] = ROOT; | |
| 1038 | |
| 1039 while (workStackTop > 0) { | |
| 1040 var parent = workStack[--workStackTop]; | |
| 1041 | |
| 1042 var prev = SENTINEL; | |
| 1043 var child = head[parent]; | |
| 1044 while (child != SENTINEL) { | |
| 1045 // Push child. | |
| 1046 workStack[workStackTop++] = child; | |
| 1047 | |
| 1048 // Find next sibling with a different cid. | |
| 1049 var after = child; | |
| 1050 while (after != SENTINEL && | |
| 1051 cids[after] == cids[child]) { | |
| 1052 after = next[after]; | |
| 1053 } | |
| 1054 | |
| 1055 // From all the siblings between child and after, take their children, | |
| 1056 // merge them and given to child. | |
| 1057 mergeChildrenAndSort(child, after); | |
| 1058 | |
| 1059 child = after; | |
| 1060 } | |
| 1061 } | |
| 1062 } | |
| 815 } | 1063 } |
| OLD | NEW |