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 |