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