| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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 #include "vm/flow_graph_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 | 56 |
| 57 | 57 |
| 58 static intptr_t ToInstructionEnd(intptr_t pos) { | 58 static intptr_t ToInstructionEnd(intptr_t pos) { |
| 59 return (pos | 1); | 59 return (pos | 1); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) | 63 FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph) |
| 64 : flow_graph_(flow_graph), | 64 : flow_graph_(flow_graph), |
| 65 reaching_defs_(flow_graph), | 65 reaching_defs_(flow_graph), |
| 66 mint_values_(NULL), | 66 value_representations_(flow_graph.max_virtual_register_number()), |
| 67 block_order_(flow_graph.reverse_postorder()), | 67 block_order_(flow_graph.reverse_postorder()), |
| 68 postorder_(flow_graph.postorder()), | 68 postorder_(flow_graph.postorder()), |
| 69 live_out_(block_order_.length()), | 69 live_out_(block_order_.length()), |
| 70 kill_(block_order_.length()), | 70 kill_(block_order_.length()), |
| 71 live_in_(block_order_.length()), | 71 live_in_(block_order_.length()), |
| 72 vreg_count_(flow_graph.max_virtual_register_number()), | 72 vreg_count_(flow_graph.max_virtual_register_number()), |
| 73 live_ranges_(flow_graph.max_virtual_register_number()), | 73 live_ranges_(flow_graph.max_virtual_register_number()), |
| 74 cpu_regs_(), | 74 cpu_regs_(), |
| 75 fpu_regs_(), | 75 fpu_regs_(), |
| 76 blocked_cpu_registers_(), | 76 blocked_cpu_registers_(), |
| 77 blocked_fpu_registers_(), | 77 blocked_fpu_registers_(), |
| 78 cpu_spill_slot_count_(0) { | 78 cpu_spill_slot_count_(0) { |
| 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); | 79 for (intptr_t i = 0; i < vreg_count_; i++) live_ranges_.Add(NULL); |
| 80 for (intptr_t i = 0; i < vreg_count_; i++) { |
| 81 value_representations_.Add(kNoRepresentation); |
| 82 } |
| 80 | 83 |
| 81 // All registers are marked as "not blocked" (array initialized to false). | 84 // All registers are marked as "not blocked" (array initialized to false). |
| 82 // Mark the unavailable ones as "blocked" (true). | 85 // Mark the unavailable ones as "blocked" (true). |
| 83 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { | 86 for (intptr_t i = 0; i < kFirstFreeCpuRegister; i++) { |
| 84 blocked_cpu_registers_[i] = true; | 87 blocked_cpu_registers_[i] = true; |
| 85 } | 88 } |
| 86 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { | 89 for (intptr_t i = kLastFreeCpuRegister + 1; i < kNumberOfCpuRegisters; i++) { |
| 87 blocked_cpu_registers_[i] = true; | 90 blocked_cpu_registers_[i] = true; |
| 88 } | 91 } |
| 89 blocked_cpu_registers_[CTX] = true; | 92 blocked_cpu_registers_[CTX] = true; |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 // Shrink the first use interval. It was optimistically expanded to | 381 // Shrink the first use interval. It was optimistically expanded to |
| 379 // cover the the block from the start to the last use in the block. | 382 // cover the the block from the start to the last use in the block. |
| 380 ASSERT(first_use_interval_->start_ <= pos); | 383 ASSERT(first_use_interval_->start_ <= pos); |
| 381 first_use_interval_->start_ = pos; | 384 first_use_interval_->start_ = pos; |
| 382 } | 385 } |
| 383 } | 386 } |
| 384 | 387 |
| 385 | 388 |
| 386 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { | 389 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { |
| 387 if (live_ranges_[vreg] == NULL) { | 390 if (live_ranges_[vreg] == NULL) { |
| 388 Location::Representation rep = | 391 Representation rep = value_representations_[vreg]; |
| 389 mint_values_->Contains(vreg) ? Location::kMint : Location::kDouble; | 392 ASSERT(rep != kNoRepresentation); |
| 390 live_ranges_[vreg] = new LiveRange(vreg, rep); | 393 live_ranges_[vreg] = new LiveRange(vreg, rep); |
| 391 } | 394 } |
| 392 return live_ranges_[vreg]; | 395 return live_ranges_[vreg]; |
| 393 } | 396 } |
| 394 | 397 |
| 395 | 398 |
| 396 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { | 399 LiveRange* FlowGraphAllocator::MakeLiveRangeForTemporary() { |
| 397 Location::Representation ignored = Location::kDouble; | 400 // Representation does not matter for temps. |
| 401 Representation ignored = kNoRepresentation; |
| 398 LiveRange* range = new LiveRange(kTempVirtualRegister, ignored); | 402 LiveRange* range = new LiveRange(kTempVirtualRegister, ignored); |
| 399 #if defined(DEBUG) | 403 #if defined(DEBUG) |
| 400 temporaries_.Add(range); | 404 temporaries_.Add(range); |
| 401 #endif | 405 #endif |
| 402 return range; | 406 return range; |
| 403 } | 407 } |
| 404 | 408 |
| 405 | 409 |
| 406 void FlowGraphAllocator::BlockRegisterLocation(Location loc, | 410 void FlowGraphAllocator::BlockRegisterLocation(Location loc, |
| 407 intptr_t from, | 411 intptr_t from, |
| 408 intptr_t to, | 412 intptr_t to, |
| 409 bool* blocked_registers, | 413 bool* blocked_registers, |
| 410 LiveRange** blocking_ranges) { | 414 LiveRange** blocking_ranges) { |
| 411 if (blocked_registers[loc.register_code()]) { | 415 if (blocked_registers[loc.register_code()]) { |
| 412 return; | 416 return; |
| 413 } | 417 } |
| 414 | 418 |
| 415 if (blocking_ranges[loc.register_code()] == NULL) { | 419 if (blocking_ranges[loc.register_code()] == NULL) { |
| 416 Location::Representation ignored = Location::kDouble; | 420 Representation ignored = kNoRepresentation; |
| 417 LiveRange* range = new LiveRange(kNoVirtualRegister, ignored); | 421 LiveRange* range = new LiveRange(kNoVirtualRegister, ignored); |
| 418 blocking_ranges[loc.register_code()] = range; | 422 blocking_ranges[loc.register_code()] = range; |
| 419 range->set_assigned_location(loc); | 423 range->set_assigned_location(loc); |
| 420 #if defined(DEBUG) | 424 #if defined(DEBUG) |
| 421 temporaries_.Add(range); | 425 temporaries_.Add(range); |
| 422 #endif | 426 #endif |
| 423 } | 427 } |
| 424 | 428 |
| 425 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); | 429 blocking_ranges[loc.register_code()]->AddUseInterval(from, to); |
| 426 } | 430 } |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 // [--) | 950 // [--) |
| 947 // | 951 // |
| 948 // The stack bitmap describes the position i. | 952 // The stack bitmap describes the position i. |
| 949 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { | 953 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { |
| 950 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), | 954 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), |
| 951 pos, | 955 pos, |
| 952 pos + 1); | 956 pos + 1); |
| 953 } | 957 } |
| 954 | 958 |
| 955 for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) { | 959 for (intptr_t reg = 0; reg < kNumberOfFpuRegisters; reg++) { |
| 956 Location::Representation ignored = Location::kDouble; | 960 Representation ignored = kNoRepresentation; |
| 957 BlockLocation( | 961 BlockLocation( |
| 958 Location::FpuRegisterLocation(static_cast<FpuRegister>(reg), ignored), | 962 Location::FpuRegisterLocation(static_cast<FpuRegister>(reg), ignored), |
| 959 pos, | 963 pos, |
| 960 pos + 1); | 964 pos + 1); |
| 961 } | 965 } |
| 962 | 966 |
| 963 | 967 |
| 964 #if defined(DEBUG) | 968 #if defined(DEBUG) |
| 965 // Verify that temps, inputs and output were specified as fixed | 969 // Verify that temps, inputs and output were specified as fixed |
| 966 // locations. Every register is blocked now so attempt to | 970 // locations. Every register is blocked now so attempt to |
| (...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1585 } | 1589 } |
| 1586 range = range->next_sibling(); | 1590 range = range->next_sibling(); |
| 1587 } | 1591 } |
| 1588 } | 1592 } |
| 1589 | 1593 |
| 1590 | 1594 |
| 1591 void FlowGraphAllocator::Spill(LiveRange* range) { | 1595 void FlowGraphAllocator::Spill(LiveRange* range) { |
| 1592 LiveRange* parent = GetLiveRange(range->vreg()); | 1596 LiveRange* parent = GetLiveRange(range->vreg()); |
| 1593 if (parent->spill_slot().IsInvalid()) { | 1597 if (parent->spill_slot().IsInvalid()) { |
| 1594 AllocateSpillSlotFor(parent); | 1598 AllocateSpillSlotFor(parent); |
| 1595 if (register_kind_ == Location::kRegister) { | 1599 if (range->representation() == kTagged) { |
| 1596 MarkAsObjectAtSafepoints(parent); | 1600 MarkAsObjectAtSafepoints(parent); |
| 1597 } | 1601 } |
| 1598 } | 1602 } |
| 1599 range->set_assigned_location(parent->spill_slot()); | 1603 range->set_assigned_location(parent->spill_slot()); |
| 1600 ConvertAllUses(range); | 1604 ConvertAllUses(range); |
| 1601 } | 1605 } |
| 1602 | 1606 |
| 1603 | 1607 |
| 1604 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( | 1608 intptr_t FlowGraphAllocator::FirstIntersectionWithAllocated( |
| 1605 intptr_t reg, LiveRange* unallocated) { | 1609 intptr_t reg, LiveRange* unallocated) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1741 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { | 1745 if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) { |
| 1742 used_on_backedge[reg] = true; | 1746 used_on_backedge[reg] = true; |
| 1743 } | 1747 } |
| 1744 } | 1748 } |
| 1745 } | 1749 } |
| 1746 | 1750 |
| 1747 if (used_on_backedge[candidate]) { | 1751 if (used_on_backedge[candidate]) { |
| 1748 TRACE_ALLOC(OS::Print( | 1752 TRACE_ALLOC(OS::Print( |
| 1749 "considering %s for v%"Pd": has interference on the back edge" | 1753 "considering %s for v%"Pd": has interference on the back edge" |
| 1750 " {loop [%"Pd", %"Pd")}\n", | 1754 " {loop [%"Pd", %"Pd")}\n", |
| 1751 MakeRegisterLocation(candidate, Location::kDouble).Name(), | 1755 MakeRegisterLocation(candidate, kUnboxedDouble).Name(), |
| 1752 unallocated->vreg(), | 1756 unallocated->vreg(), |
| 1753 loop_header->entry()->start_pos(), | 1757 loop_header->entry()->start_pos(), |
| 1754 loop_header->last_block()->end_pos())); | 1758 loop_header->last_block()->end_pos())); |
| 1755 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1759 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1756 if (blocked_registers_[reg] || | 1760 if (blocked_registers_[reg] || |
| 1757 (reg == candidate) || | 1761 (reg == candidate) || |
| 1758 used_on_backedge[reg]) { | 1762 used_on_backedge[reg]) { |
| 1759 continue; | 1763 continue; |
| 1760 } | 1764 } |
| 1761 | 1765 |
| 1762 const intptr_t intersection = | 1766 const intptr_t intersection = |
| 1763 FirstIntersectionWithAllocated(reg, unallocated); | 1767 FirstIntersectionWithAllocated(reg, unallocated); |
| 1764 if (intersection >= free_until) { | 1768 if (intersection >= free_until) { |
| 1765 candidate = reg; | 1769 candidate = reg; |
| 1766 free_until = intersection; | 1770 free_until = intersection; |
| 1767 TRACE_ALLOC(OS::Print( | 1771 TRACE_ALLOC(OS::Print( |
| 1768 "found %s for v%"Pd" with no interference on the back edge\n", | 1772 "found %s for v%"Pd" with no interference on the back edge\n", |
| 1769 MakeRegisterLocation(candidate, Location::kDouble).Name(), | 1773 MakeRegisterLocation(candidate, kUnboxedDouble).Name(), |
| 1770 candidate)); | 1774 candidate)); |
| 1771 break; | 1775 break; |
| 1772 } | 1776 } |
| 1773 } | 1777 } |
| 1774 } | 1778 } |
| 1775 } | 1779 } |
| 1776 | 1780 |
| 1777 ASSERT(0 <= kMaxPosition); | 1781 ASSERT(0 <= kMaxPosition); |
| 1778 if (free_until != kMaxPosition) { | 1782 if (free_until != kMaxPosition) { |
| 1779 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { | 1783 for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) { |
| 1780 if (blocked_registers_[reg] || (reg == candidate)) continue; | 1784 if (blocked_registers_[reg] || (reg == candidate)) continue; |
| 1781 const intptr_t intersection = | 1785 const intptr_t intersection = |
| 1782 FirstIntersectionWithAllocated(reg, unallocated); | 1786 FirstIntersectionWithAllocated(reg, unallocated); |
| 1783 if (intersection > free_until) { | 1787 if (intersection > free_until) { |
| 1784 candidate = reg; | 1788 candidate = reg; |
| 1785 free_until = intersection; | 1789 free_until = intersection; |
| 1786 if (free_until == kMaxPosition) break; | 1790 if (free_until == kMaxPosition) break; |
| 1787 } | 1791 } |
| 1788 } | 1792 } |
| 1789 } | 1793 } |
| 1790 | 1794 |
| 1791 // All registers are blocked by active ranges. | 1795 // All registers are blocked by active ranges. |
| 1792 if (free_until <= unallocated->Start()) return false; | 1796 if (free_until <= unallocated->Start()) return false; |
| 1793 | 1797 |
| 1794 TRACE_ALLOC(OS::Print("assigning free register ")); | 1798 TRACE_ALLOC(OS::Print("assigning free register ")); |
| 1795 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1799 TRACE_ALLOC(MakeRegisterLocation(candidate, kUnboxedDouble).Print()); |
| 1796 TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg())); | 1800 TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg())); |
| 1797 | 1801 |
| 1798 if (free_until != kMaxPosition) { | 1802 if (free_until != kMaxPosition) { |
| 1799 // There was an intersection. Split unallocated. | 1803 // There was an intersection. Split unallocated. |
| 1800 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); | 1804 TRACE_ALLOC(OS::Print(" splitting at %"Pd"\n", free_until)); |
| 1801 LiveRange* tail = unallocated->SplitAt(free_until); | 1805 LiveRange* tail = unallocated->SplitAt(free_until); |
| 1802 AddToUnallocated(tail); | 1806 AddToUnallocated(tail); |
| 1803 } | 1807 } |
| 1804 | 1808 |
| 1805 registers_[candidate].Add(unallocated); | 1809 registers_[candidate].Add(unallocated); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1888 (register_use != NULL) ? register_use->pos() | 1892 (register_use != NULL) ? register_use->pos() |
| 1889 : unallocated->Start(); | 1893 : unallocated->Start(); |
| 1890 if (free_until < register_use_pos) { | 1894 if (free_until < register_use_pos) { |
| 1891 // Can't acquire free register. Spill until we really need one. | 1895 // Can't acquire free register. Spill until we really need one. |
| 1892 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); | 1896 ASSERT(unallocated->Start() < ToInstructionStart(register_use_pos)); |
| 1893 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); | 1897 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); |
| 1894 return; | 1898 return; |
| 1895 } | 1899 } |
| 1896 | 1900 |
| 1897 TRACE_ALLOC(OS::Print("assigning blocked register ")); | 1901 TRACE_ALLOC(OS::Print("assigning blocked register ")); |
| 1898 TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print()); | 1902 TRACE_ALLOC(MakeRegisterLocation(candidate, kUnboxedDouble).Print()); |
| 1899 TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n", | 1903 TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n", |
| 1900 unallocated->vreg(), blocked_at)); | 1904 unallocated->vreg(), blocked_at)); |
| 1901 | 1905 |
| 1902 if (blocked_at < unallocated->End()) { | 1906 if (blocked_at < unallocated->End()) { |
| 1903 // Register is blocked before the end of the live range. Split the range | 1907 // Register is blocked before the end of the live range. Split the range |
| 1904 // at latest at blocked_at position. | 1908 // at latest at blocked_at position. |
| 1905 LiveRange* tail = SplitBetween(unallocated, | 1909 LiveRange* tail = SplitBetween(unallocated, |
| 1906 unallocated->Start(), | 1910 unallocated->Start(), |
| 1907 blocked_at + 1); | 1911 blocked_at + 1); |
| 1908 AddToUnallocated(tail); | 1912 AddToUnallocated(tail); |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 } else { | 2394 } else { |
| 2391 AddMoveAt(range->Start() + 1, | 2395 AddMoveAt(range->Start() + 1, |
| 2392 range->spill_slot(), | 2396 range->spill_slot(), |
| 2393 range->assigned_location()); | 2397 range->assigned_location()); |
| 2394 } | 2398 } |
| 2395 } | 2399 } |
| 2396 } | 2400 } |
| 2397 | 2401 |
| 2398 | 2402 |
| 2399 void FlowGraphAllocator::CollectRepresentations() { | 2403 void FlowGraphAllocator::CollectRepresentations() { |
| 2400 mint_values_ = new BitVector(flow_graph_.max_virtual_register_number()); | 2404 // Parameters. |
| 2405 GraphEntryInstr* graph_entry = flow_graph_.graph_entry(); |
| 2406 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); ++i) { |
| 2407 Definition* def = (*graph_entry->initial_definitions())[i]; |
| 2408 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2409 } |
| 2401 | 2410 |
| 2402 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); | 2411 for (BlockIterator it = flow_graph_.reverse_postorder_iterator(); |
| 2403 !it.Done(); | 2412 !it.Done(); |
| 2404 it.Advance()) { | 2413 it.Advance()) { |
| 2405 BlockEntryInstr* block = it.Current(); | 2414 BlockEntryInstr* block = it.Current(); |
| 2406 // TODO(fschneider): Support unboxed mint representation for phis. | 2415 // Phis. |
| 2416 if (block->IsJoinEntry()) { |
| 2417 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2418 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 2419 PhiInstr* phi = it.Current(); |
| 2420 if ((phi != NULL) && (phi->ssa_temp_index() >= 0)) { |
| 2421 value_representations_[phi->ssa_temp_index()] = phi->representation(); |
| 2422 } |
| 2423 } |
| 2424 } |
| 2425 // Normal instructions. |
| 2407 for (ForwardInstructionIterator instr_it(block); | 2426 for (ForwardInstructionIterator instr_it(block); |
| 2408 !instr_it.Done(); | 2427 !instr_it.Done(); |
| 2409 instr_it.Advance()) { | 2428 instr_it.Advance()) { |
| 2410 Definition* defn = instr_it.Current()->AsDefinition(); | 2429 Definition* def = instr_it.Current()->AsDefinition(); |
| 2411 if ((defn != NULL) && | 2430 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { |
| 2412 (defn->ssa_temp_index() >= 0) && | 2431 value_representations_[def->ssa_temp_index()] = def->representation(); |
| 2413 (defn->representation() == kUnboxedMint)) { | |
| 2414 mint_values_->Add(defn->ssa_temp_index()); | |
| 2415 } | 2432 } |
| 2416 } | 2433 } |
| 2417 } | 2434 } |
| 2418 } | 2435 } |
| 2419 | 2436 |
| 2420 | 2437 |
| 2421 void FlowGraphAllocator::AllocateRegisters() { | 2438 void FlowGraphAllocator::AllocateRegisters() { |
| 2422 CollectRepresentations(); | 2439 CollectRepresentations(); |
| 2423 | 2440 |
| 2424 EliminateEnvironments(); | 2441 EliminateEnvironments(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2486 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2503 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2487 function.ToFullyQualifiedCString()); | 2504 function.ToFullyQualifiedCString()); |
| 2488 FlowGraphPrinter printer(flow_graph_, true); | 2505 FlowGraphPrinter printer(flow_graph_, true); |
| 2489 printer.PrintBlocks(); | 2506 printer.PrintBlocks(); |
| 2490 OS::Print("----------------------------------------------\n"); | 2507 OS::Print("----------------------------------------------\n"); |
| 2491 } | 2508 } |
| 2492 } | 2509 } |
| 2493 | 2510 |
| 2494 | 2511 |
| 2495 } // namespace dart | 2512 } // namespace dart |
| OLD | NEW |